generative-ai 合同合规多智能体流水线深度解析:ADK RemoteA2aAgent 与 Go A2A 确定性策略引擎的跨语言编排

generative-ai 合同合规多智能体流水线深度解析:ADK RemoteA2aAgent 与 Go A2A 确定性策略引擎的跨语言编排 generative-ai 合同合规多智能体流水线深度解析ADK RemoteA2aAgent 与 Go A2A 确定性策略引擎的跨语言编排【免费下载链接】generative-aiSample code and notebooks for Generative AI on Google Cloud, with Gemini Enterprise Agent Platform项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai本文以agents/adk/contract-compliance-pipeline/ARCHITECTURE.md为主线拆解 generative-ai 仓库中合同合规Contract Compliance演示系统的可执行架构浏览器驾驶舱如何通过 Python FastAPI 完成确定性字段抽取再经 Google ADK 的RemoteA2aAgent通过 A2A JSON-RPCSendMessage把契约字段交给 Go 侧的确定性策略引擎完成审计裁决。读完本文你将完整掌握该流水线的运行时拓扑、A2A 报文的请求/响应结构、五种策略检查规则的实现位置以及三层信任边界的 fail-closed失败即降级人工审核设计。一、架构核心思想LLM 处理歧义确定性代码执行硬策略ARCHITECTURE.md 开宗明义地描述了当前仓库中“可执行”的架构形态——一个本地跨语言系统由四个部分构成由 Python 在/live-compliance/路径下提供的浏览器驾驶舱Browser Cockpit运行在127.0.0.1:8000的 Python FastAPI 服务运行在:8888的 Go A2A 合规服务通过 Go Agent Card 与 A2A JSON-RPCSendMessage完成的 ADKRemoteA2aAgent交接handoff。其中最关键的一句设计声明是Go 服务在设计上是确定性的。它不是 LLM 智能体而是执行需要可重复审计行为的策略阈值。这与同目录 README.md 中的核心观点一致“LLMs are useful for ambiguity. Deterministic agents should enforce hard policy.”LLM 适合处理歧义确定性智能体应该执行硬策略。如果政策规定供应商合同金额不得超过$500,000、期限不得超过 5 年、必须包含退出条款那么这些检查就应该是可审计、可重复的——这正是 Go 侧checker.go的职责。从仓库结构看该演示被刻意拆成两个独立语言栈Python 侧负责接入、抽取、会话状态与产物生成Go 侧暴露 A2A Agent Card 并通过 JSON-RPC 执行同步、无 I/O 等待的策略校验。这种分工让演示在不依赖 Gemini API key 的前提下保持完全可复现抽取夹具与策略检查均为确定性代码。二、运行时流程拓扑ARCHITECTURE.md 用一张 mermaid 流程图定义了从浏览器到 Go 裁决再回到 UI 的完整数据流注意浏览器节点发出的载荷包含三类信息样例合同文本 活动策略值 模拟器状态sample text policy simulator state。这意味着 UI 侧的策略覆盖值会真实地进入 A2A 数据部分并影响 Go 侧裁决而不是装饰性的展示项。三、实时请求路径的十步拆解ARCHITECTURE.md 将一次完整的合规审计请求归纳为 10 个步骤每一步都能在仓库源码中找到对应实现浏览器从sample-contracts/中选择内置合同夹具例如 standard-vendor-agreement.pdf。浏览器通过/api/compliance/sample-contracts/{filename}获取夹具文本。浏览器将文本、活动策略值、模拟器设置 POST 到/api/compliance/upload。Python 在 tools.py 中用确定性解析抽取合同字段。Python 分类风险等级并构建 A2A 数据载荷。Python 在 fast_api_app.py 中创建一个聚焦的RemoteA2aAgent。ADK 从GO_AGENT_CARD_URL解析 Go Agent Card。ADK 向 Go 服务发送 A2A JSON-RPCSendMessage。Go 解码 data part、执行确定性策略检查返回已完成的 A2A Task。Python 保存案件状态、生成 HTML 产物并返回 UI 可见的载荷。3.1 Python 侧的确定性抽取步骤 4 的实现是extract_contract_details_from_text(filename, text)tools.py。它并非调用 LLM而是用正则表达式提取结构化字段金额r\$[\d,](?:\.\d{2})?日期英文月份 日 年如June 1, 2026转换为 ISO 格式2026-06-01当事方匹配between ... (Contractor) and ... (Client)结构期限r(\d)\syears?责任条款段落截取LIMITATION OF LIABILITY:到INSURANCE:之间的文本用于判定“无限责任”措辞。对三份内置样例合同模块还维护了SAMPLE_CONTRACT_DETAILS映射tools.py#L127-L164保证在文本缺失时也能回退到与样例一致的结构化字段——这是演示可复现性的另一道保险。3.2 ADK RemoteA2aAgent 交接的实现细节步骤 68 集中在invoke_go_compliance_service(...)fast_api_app.py#L165-L242中几个值得注意的实现点Agent Card URL 可配置GO_AGENT_CARD_URL环境变量默认指向http://localhost:8888/.well-known/agent.jsonfast_api_app.py#L77-L80_go_jsonrpc_url()会把/.well-known/agent.json后缀剥离得到 JSON-RPC 根 URL。请求拦截器注入任务元数据RemoteA2aAgent通过A2aRemoteAgentConfig挂载RequestInterceptor(before_requestadd_task_metadata)在每次请求前把task_id写入request_metadata保证 Go 侧能按案件 ID 归档任务。DataPart 的 GenAI 编码桥接_a2a_data_part_as_genai_part()先把a2a.types.DataPart序列化为 JSON再包裹进 ADK 的A2A_DATA_PART_START_TAG/A2A_DATA_PART_END_TAG标签并封装为genai_types.Part的 inline blob——因为RemoteA2aAgent接受的是 GenAI 格式的ContentADK 内部会将其转回 A2A DataPart 发出。事件流回收原始报文runner.run_async(...)的每个事件里ADK 会把真实的 A2A 请求/响应放在event.custom_metadata的a2a:request与a2a:response键中。演示的“Agent Exchange”面板展示的就是这两份原始报文而非伪造的日志。3.3 Go 侧的 JSON-RPC 分发Go 服务端只有一个 JSON-RPC 入口HandleJSONRPCtask_handler.go#L131-L181按 method 名分发Method处理函数说明message/send/SendMessagehandleMessageSend当前 A2A 报文形态Live 演示走这里tasks/sendhandleTasksSend旧版形态保留给老客户端tasks/get/GetTaskhandleTasksGet按任务 ID 从内存 map 查询历史任务这与 ARCHITECTURE.md “Go 服务处理当前SendMessage外加遗留tasks/send和tasks/get” 的描述完全对应。validateMessagetask_handler.go#L214-L254的执行顺序是extractContractPayload找 data part→unpackContractPayload拆策略覆盖与合同字段→decodeContractDetails绑定到ContractDetails结构体→ 同步调用compliance.CheckCompliance→ 构造已完成 Task → 写入内存任务表供tasks/get查询。源码注释明确写道“Run compliance checks synchronously — pure computation, no I/O wait needed.”tasks/get的存储是进程内map[string]*Tasktask_handler.go#L105-L109重启即失——从源码结构看这是一个演示级的轻量实现而非持久化任务系统。四、A2A 报文形态Payload Shape4.1 请求信封Python 在build_go_message_payload(...)fast_api_app.py#L102-L119中构建 UI 可见的请求信封其完整形状如下来自 ARCHITECTURE.md{ jsonrpc: 2.0, id: case-{case_id}, method: SendMessage, params: { metadata: { task_id: {case_id} }, message: { messageId: case-{case_id}-request, taskId: {case_id}, role: ROLE_USER, parts: [ { data: { schema_version: contract-compliance.a2a.v1, case_id: {case_id}, contract: { contract_value: 250000.0, contractor_name: ACME CLOUD SOLUTIONS, insurance_coverage: 2000000.0, liability_limit: $1,000,000.00, term_length_years: 2, auto_renewal: false, has_termination_clause: true }, policy: { max_contract_value: 500000.0, required_insurance_minimum: 1000000.0, max_term_years: 5, required_termination_clause: true, prohibited_clauses: [unlimited liability, auto-renewal 3yr] } }, mediaType: application/json } ] } } }其中schema_version: contract-compliance.a2a.v1是双方约定的数据部分版本标识contract字段与 Go 侧ContractDetails结构体checker.go#L21-L32的 JSON tag 一一对应policy字段可选——当且仅当 UI 提交了策略覆盖值时才会出现。Go 侧对policy覆盖的处理在unpackContractPayloadtask_handler.go#L271-L298若载荷中存在policy键则decodePolicy将其反序列化为compliance.Policy并整体替换进程默认策略否则回落到启动时由InitPolicies加载的策略。此外它还会按contract→contract_details→ 平铺直传的顺序兼容三种历史载荷布局。这解释了为什么 ARCHITECTURE.md 强调 Python “只调用已配置的 Go Agent Card URL”而策略灵活性完全通过报文内的 data part 传递。4.2 响应已完成 A2A Task 中的裁决Go 返回一个已完成completed的 A2A Task其状态消息携带 data part{ passed: false, violations: [ Contract value $850000.00 exceeds company framework limit of $500000.00 ], verdict_timestamp: 2026-06-03T00:00:00Z }从completedTasktask_handler.go#L337-L368源码可以看到响应 Task 的精确形态role: ROLE_AGENT、state: TASK_STATE_COMPLETED裁决数据被封装成mediaType: application/json的 data part 放进status.message.parts。Python 侧的extract_verdict_from_go_responsefast_api_app.py#L122-L135正是沿着result.status.message.parts逐 part 查找含data键的部分来还原裁决找不到则抛出RuntimeError(Go compliance service returned no verdict data)触发后文的 fail-closed 路径。五、确定性策略引擎checker.go 的六项审计ARCHITECTURE.md 把策略检查定位在checker.go。源码中CheckCompliancechecker.go#L56-L107按固定顺序执行以下检查任一失败即追加到violations列表最终passed len(violations) 0合同金额审计contract_value max_contract_value→ “Contract value $%.2f exceeds company framework limit of $%.2f”禁止条款无限责任当策略声明unlimited liability时若liability_limit文本小写化后包含unlimited或waived→ 违规禁止条款长周期自动续约当策略声明auto-renewal 3yr且auto_renewal true term_length_years 3→ 违规保险下限insurance_coverage required_insurance_minimum→ 违规期限上限term_length_years max_term_years→ 违规退出条款required_termination_clause true且has_termination_clause false→ 违规。verdict_timestamp使用time.Now().UTC().Format(time.RFC3339)生成checker.go#L105保证裁决带可追溯的时间戳。默认策略阈值定义在 default_policy.json{ max_contract_value: 500000.0, prohibited_clauses: [unlimited liability, auto-renewal 3yr], required_insurance_minimum: 1000000.0, max_term_years: 5, required_termination_clause: true }Go 服务通过命令行参数加载该文件见 main.go#L18-L32-port默认8888-policy默认internal/policies/default_policy.json。若策略文件加载失败InitPoliciestask_handler.go#L112-L126会打印警告并回退到一套硬编码默认值与上述 JSON 完全一致。路由注册顺序也有讲究mux先注册/.well-known/agent.json再注册/确保 Agent Card 端点优先于 JSON-RPC 根路由绑定地址由HOST环境变量控制默认0.0.0.0以适配容器部署。Agent Card 本身由 card.go 的GetCard()构造名称Security Compliance Validator、版本1.0.0、唯一接口为JSONRPC绑定协议版本1.0声明contract_compliance_check技能tags: compliance / contract / validation输入输出模式均为application/json。其 URL 可通过AGENT_URL环境变量覆盖默认http://localhost:8888。六、状态机与三态可见结果ARCHITECTURE.md 将实时驾驶舱映射出的三种可见结果定义如下必须原样继承OutcomeTriggerAPPROVEDGo 返回passed: true。REVIEW_READYGo 返回passed: false且带策略违规。MANUAL_REVIEWGo 不可用或模拟器模式为Crashed (503)。文档同时指出state_schema.py 中更丰富的枚举仍保留着完整 ADK 参考路径所用的中间状态但驾驶舱在健康路径下一次 API 调用即完成。源码印证了这一点——ComplianceStep枚举state_schema.py#L18-L36定义了 7 个状态INGESTED → EXTRACTED → COMPLIANCE_PENDING → COMPLIANCE_COMPLETE → APPROVED / REVIEW_READY外加超时/失败分支的MANUAL_REVIEW。而upload_contract_file在一次请求内同步走完抽取、交接、裁决并直接落到APPROVED或REVIEW_READYfast_api_app.py#L500-L504中间态只存在于agent.py的SequentialAgent参考实现中。6.1 Fail-closed交接失败如何降级“Go 不可用”这一触发条件在源码中对应两层机制真实故障invoke_go_compliance_service抛出的ConnectionError、TimeoutError、urllib.error.URLError、RuntimeError被统一捕获案件被置为ComplianceStep.MANUAL_REVIEW并写入带 fail-safe 语义的裁决“SYSTEM TIMEOUT... Document routed for legal manager manual verification”trace 中追加resilience_fallback_gatespanfast_api_app.py#L527-L552模拟器注入当表单字段simulated_server_state crashed时代码主动raise ConnectionError(Simulated Go compliance service 503 failure)fast_api_app.py#L478-L480走与真实故障完全相同的路径——这就是 ARCHITECTURE.md 中“模拟器模式为Crashed (503)触发MANUAL_REVIEW”的底层实现。也就是说该演示的降级策略是fail-closed远端合规裁决不可得时合同绝不自动放行而是路由给人工审核。这一设计在合规场景下比 fail-open 更合理。七、信任边界Trust BoundariesARCHITECTURE.md 按三个主体划定了信任边界以下内容完整保留浏览器Browser选择内置样例合同发送策略覆盖值从不直接调用 Go 服务。Python 服务强制文件扩展名与 5MB 上传限制拒绝二进制 PDF 上传内置的.pdf文件其实是文本夹具以 basename 与根边界检查解析样例与产物路径只调用已配置的 Go Agent Card URLGo 交接失败时 fail-closed 到MANUAL_REVIEW。Go 服务在/.well-known/agent.json提供 Agent Card接受 JSON-RPC POST 请求处理当前SendMessage及遗留tasks/send、tasks/get应用来自default_policy.json或请求策略覆盖的确定性策略规则。这些边界在源码中的对应证据upload_contract_file白名单校验扩展名.pdf/.txt/.md、将文件名改写为 UUID 防注入、abspath前缀做路径穿越检查、5MB 尺寸上限并对以%PDF魔数开头的真正二进制 PDF 直接返回 400fast_api_app.py#L383-L411_secure_resolve_pathtools.py#L36-L55则对..、反斜杠与绝对路径做 fail-close 拦截。Go 侧只接受 POSTtask_handler.go#L134-L137且策略来源仅限于启动参数文件与请求载荷内嵌的policy字段两个入口。八、完整 ADK 参考路径与 Live 路径的分工ARCHITECTURE.md 的 Key Files 表把python-extraction-agent/app/agent.py标注为“更完整的 ADKSequentialAgent参考”。其模块 docstring 明确了层级结构agent.py#L15-L30SequentialAgent (coordinator) ├── Agent: extractor_agent — 解析合同抽取关键法务字段Gemini 模型 ├── RemoteA2aAgent: compliance_agent — 经 A2A 把字段发给 Go 合规服务 └── Agent: report_agent — 生成最终审计报告该参考路径中extractor_agent使用 Gemini 模型而非正则做抽取需要 Google Cloud 凭证而 Live 驾驶舱路径刻意选择“确定性抽取 一次聚焦RemoteA2aAgent调用”在稳定可复现的前提下真实演练当前 A2ASendMessage协议。理解两条路径的分工是避免误读本模块的关键浏览器演示跑的是fast_api_app.pyagent.py仅作架构参考。九、本地运行与验证方式结合 README.md 的快速开始说明验证上述架构的行为如下路径均相对于agents/adk/contract-compliance-pipeline/# 终端 1启动 Go A2A 合规智能体 cd go-compliance-agent go run cmd/server/main.go # 终端 2启动 Python FastAPI 驾驶舱 cd python-extraction-agent uv sync uv run uvicorn app.fast_api_app:app --host 127.0.0.1 --port 8000打开http://127.0.0.1:8000/live-compliance/。该路径不需要 Gemini API key。也可用 Docker Compose 一键拉起docker-compose.ymldocker-compose up --build验证点建议按架构文档逐项核对手动冒烟curl http://127.0.0.1:8888/.well-known/agent.json应返回Security Compliance Validator的 Agent Card JSONAgent Exchange 面板出现SendMessage报文且 A2A 载荷包含jsonrpc: 2.0Go 裁决在 UI 呈现生成合规证书产物可渲染产物端点/api/compliance/cases/{case_id}/artifacts/{artifact_id}由 live_compliance.py 的artifact_response提供产物写入local_artifacts/compliance/{case_id}且经过路径边界检查将模拟器切换到Crashed (503)后再运行案件结果应为MANUAL_REVIEW。单元测试覆盖Python 侧uv run pytest tests/unit -vGo 侧go test -v ./...包含 checker_test.go 与 task_handler_test.go。十、关键文件索引下表完整继承 ARCHITECTURE.md 的 Key Files 清单路径已转换为仓库根相对路径文件角色python-extraction-agent/app/static/live-compliance/index.html浏览器驾驶舱。python-extraction-agent/app/fast_api_app.pyAPI 路由、ADK 交接、案件响应。python-extraction-agent/app/tools.py确定性抽取与风险分类。python-extraction-agent/app/live_compliance.py案件状态、事件流、产物生成。python-extraction-agent/app/agent.py更完整的 ADKSequentialAgent参考。python-extraction-agent/app/state_schema.py案件状态机枚举。go-compliance-agent/internal/agentcard/card.goAgent Card。go-compliance-agent/internal/handler/task_handler.goA2A JSON-RPC 处理器。go-compliance-agent/internal/compliance/checker.go确定性策略检查器。go-compliance-agent/internal/policies/default_policy.json默认策略阈值。go-compliance-agent/cmd/server/main.goGo 服务入口与路由注册。十一、小结这套合同合规流水线给出的工程范式可归纳为三点其一按可审计性划分智能体职责——抽取环节允许不确定性演示中甚至用正则替代 LLM 换取可复现性策略裁决环节则交由确定性代码其二用 A2A 协议做跨语言粘合剂——Agent Card 负责发现JSON-RPCSendMessage负责调用结构化 DataPartschema_versioncontract 可选policy负责跨语言契约策略覆盖通过载荷内嵌而非配置通道传递其三以 fail-closed 作为合规系统的底线语义——任何交接失败都收敛到MANUAL_REVIEW绝不静默放行。若你需要在自己的 ADK 项目中编排非 LLM 的远端智能体这套 “Agent Card 发现 DataPart 载荷 请求拦截器注入任务元数据 内存会话 Runner” 的组合是一个可以直接对照 fast_api_app.py 逐步复现的最小参考实现。【免费下载链接】generative-aiSample code and notebooks for Generative AI on Google Cloud, with Gemini Enterprise Agent Platform项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考