![[从零开始搭一个企业级 Agent Harness] 4/10:为什么给 Agent 接上工具以后反而更容易出错?](/_next/image?url=%2Fblog%2Fagent-harness-covers%2Fpart-04.webp&w=3840&q=75&dpl=dpl_HKDZtjNTn1U2zk8pGrYRnYGkyGR9)
从零开始搭一个企业级 Agent Harness4/10:为什么给 Agent 接上工具以后反而更容易出错?
采购Agent现在有三个工具:查询供应商、创建采购申请、发送询价邮件。用户只说了一句:“先比较这三家,不要下单,把缺的信息问清楚。”
Agent查完供应商,想把比较结果“保存”下来,于是选择了 create_request。参数格式完全合法,工具也返回成功。几秒以后,审批队列里多出了一张真实采购申请。
模型没有漏字段。它只是理解错了“request”。这一个词,把一句错话变成了数据库里的真实记录。
工具先要说清自己会改变什么
人看到 create_request,也许熟悉公司内部命名,知道它会发起采购。模型只能根据名称、描述和参数判断。名称太泛,描述只写“创建请求”,它就很难分清创建采购申请和保存比较草稿。
我先把它拆成两个单一职责工具:save_supplier_comparison_draft只保存内部草稿,create_purchase_request会创建一张进入审批队列的业务对象。第二个工具的合同继续写清版本、副作用、所需权限、审批规则、幂等要求和返回状态。
这张采购申请还要有严格参数:供应商ID是供应商目录里的唯一编号,不能让模型根据名称临时猜一个;金额使用最小货币单位,例如把42.35美元记成4235分,避免小数计算产生歧义;币种来自允许集合,需求说明不能替代正式审批。数据格式(Schema)能拦住缺字段和错误类型;这张采购单属于哪个企业、预算是否足够、批准人是否有资格,则要到权威系统核对。
工具合同(Tool contract):工具名称、版本、用途、限制、输入、输出、副作用、权限和错误语义组成的接口约定。
Schema:对数据字段、类型、必填项和允许范围的结构化定义。
比较阶段,只让Agent看见比较工具
企业里可能有几百个API。一次全部放进上下文,不仅占用模型输入空间,还会把许多相似名字摆在模型面前。
采购任务仍在“比较供应商”阶段,工具目录只返回读取供应商、合同、报价和发送询问的工具。create_purchase_request要等用户明确选择方案、预算通过、任务进入执行阶段以后才出现。
这叫工具发现(Tool discovery):根据Agent版本、当前步骤、用户权限和风险范围,只取回眼前需要的少量工具。它先缩小模型的选择面,却不是安全授权。真正执行时,后端仍然要重新检查用户所属企业(租户)、具体采购单、金额和动作权限。
Tool discovery:根据当前任务搜索和加载所需工具的过程。
模型只提出动作,真实系统逐层接手
工具出现在列表里,也不表示模型可以直接调用真实API。我先把一次动作看成五个环节:发现工具、提出意图、检查授权、执行调用、核对结果。图里再把授权和执行之间的交接展开成九步。
沿图上的编号走:前三步先根据任务阶段找工具,再由模型提出动作;第4步政策检查可以拒绝、暂停等批准,或直接允许。获准动作在第5步拿到短期凭证,经过工具入口和后端再次授权,执行以后还要走到第9步核验业务结果。
Agent先提交工具、参数和预期效果;政策检查程序核对任务、用户、所属企业、金额和风险。政策拒绝,任务直接停止;需要人批准,动作就保存下来等待。批准以后,凭证服务签发一张只对这次采购单、这个动作有效的短期通行证,工具入口再把调用送到业务服务。这个统一检查和转发调用的工具入口,就是Action Gateway。
业务服务掌握真实采购单和预算,因此还要做最后一次对象级授权。这里的“对象”就是这张具体采购单:即使某个用户通常可以创建采购申请,后端仍要确认他有权操作当前企业的这张单。工具入口负责调用前的统一检查,后端负责它真正拥有的业务事实。两层都通过,调用才会改变数据。
Action Gateway:位于Agent与真实工具之间,执行身份、策略、验证、路由和审计检查的服务边界。
Accepted只是排进队列
发送询价邮件以后,服务返回 202 Accepted。这不代表邮件已经送达,只说明请求进入了队列。创建采购申请也可能先返回操作编号(operation ID),后台再异步完成。这个编号像取件回执,Harness以后靠它查询“处理到哪一步”,不能把回执本身当成结果。
因此工具结果要区分“还缺输入”“已经接收”“仍在处理”“成功”“失败”和“结果未知”。看到“已经接收”,Harness保存这次操作的查询编号,按服务给出的时间再次查询;看到“仍在处理”,继续等待;看到“结果未知”,进入对账;只有“成功”带回真实业务对象编号,核验程序才到业务系统检查预期效果。
这条状态线不能从“已经接收”直接跳到完成。它要先等待后台处理,再核验业务结果;工具返回一句成功字符串,不足以替业务系统签字。
2026年的进展:Gateway和MCP开始把工具接入标准化
工具跨过多个团队以后,身份检查、调用转发和运行记录如果各写一份,很容易出现规则不一致。Google Agent Gateway把用户到Agent、Agent到工具、Agent到另一个Agent的调用集中到同一个治理入口;这项能力在2026年6月18日正式可用。放进这条采购管线,它负责把调用者身份、所属企业、临时授权和观测信息一起带到工具入口,采购服务仍然检查具体采购单和预算。
另一个问题是连接格式:搜索工具、合同库和邮件服务如果各说一套“方言”,Agent应用就要为每个工具单独适配。MCP给不同语言、不同团队的工具一套共同的发现与调用方式。2026年7月28日正式发布的核心规范让每次请求自己携带协议版本、客户端身份、具备的能力和要调用的方法。工具入口不必先依赖一段长期连接状态,收到每个请求时都能重新识别与检查调用方。
购物篮或浏览器仍然可以保存业务状态。工具第一次返回购物篮编号或浏览器编号,下一次调用再把这个编号作为普通参数带回。应用因此能看见状态属于哪个租户,也能在每次请求时重新授权。
导出大报告一类长调用,不会在一次请求里立刻返回结果,因此还需要查询进度、取消任务或补充输入。MCP Tasks扩展为这类动作定义任务编号和状态,但截至2026年11月8日仍是Draft(草案)。它让调用方问“这个工具任务到哪了”;整条采购流程怎样跨天等待、恢复审批与补偿,则交给下一章的持久执行层。
MCP:Model Context Protocol,用统一协议把AI应用连接到工具、数据和其他资源。
MCP Tasks:MCP当前仍为Draft的长调用扩展,用任务编号表达查询、取消、更新或等待输入。
回到那张误建的采购申请
现在同一句“先比较,不要下单”进入系统。工具目录在比较阶段根本不展示创建采购申请;即使有人绕过发现层直接提交,政策检查仍会看到任务阶段不符;后端再用采购单与预算做最后授权。
Agent真正需要的,是保存比较草稿和向供应商询问缺失信息。它选择发送邮件,数据格式检查收件人和内容,政策确认允许外发,工具入口带上短期凭证,邮件服务返回可查询的操作编号,核验程序再等投递记录。
工具边界终于清楚了。可邮件真正发出去以后,服务可能超时,进程也可能重启。下一篇继续跟着这封邮件,看看怎样恢复任务,又不把它发送两遍。
新文章,直接发到你的邮箱。
AI、工程与实验,每月 1–2 封。
无垃圾邮件,随时取消。
