Agent 的工具如何治理:从能力目录到一次可靠执行
工具多了以后,问题不只是模型会不会选错。能力声明、本轮暴露、输入输出契约、读写边界、执行预算和观测证据必须连接起来,才能知道一次调用为何发生、是否允许、结果能说明什么,以及何时应该停止。
先带走这三个判断
90 秒 · 调用纪事
- 查说明、算规则、读状态和提交动作提供不同证据。工具收敛要减少歧义,而不只是减少名称。
- 模型看得到工具,不等于允许执行。身份、对象、参数与具体动作的确认要在执行边界检查。
- 超时后先核对,不把未知当失败。最终还要分清“提交完成”和“业务已生效”。
文章目录
拆分能力边界
一个产品助手可以查产品说明、计算办理规则、读取申请状态,也可以提交套餐调整。它们看起来都能包装成工具,但回答的问题不同:说明查询提供文字依据,规则计算依据确定输入得出判断,状态读取报告系统事实,提交动作改变外部状态。把四类能力混成一个“万能办理工具”,会把选择、权限和结果解释的问题全部藏进描述里。
下面用一个构造场景贯穿这些问题:用户想了解下个周期如何调整套餐,先问条件,再查自己的当前状态,最后明确要求提交。场景、数字与预算都用于说明设计,不代表真实业务或线上效果。讨论重点是把能力边界、运行机制和验证要求连接起来,让同样的思路能用于其他产品助手。
| 能力 | 可信输入 | 结果能证明什么 | 主要边界 |
|---|---|---|---|
| 说明查询 | 问题与可访问的说明范围 | 找到相关依据 | 文字解释不等于资格结论 |
| 规则计算 | 规则版本和必要参数 | 在这些输入下的计算结果 | 缺少参数不能凭常识补齐 |
| 状态读取 | 已认证身份和对象范围 | 某时刻的系统记录 | 读权限与信息时效 |
| 提交动作 | 明确意图和待提交参数 | 外部系统接受或拒绝的证据 | 确认、幂等和结果核对 |
因此,工具收敛的目标不能只写“数量越少越好”。更少的工具也可能职责过宽;更多工具也可能边界清晰。真正要减少的是同一问题下的歧义、重复能力和未经约束的副作用,让模型拿到完成当前任务所需的最小充分能力。
目录与注册表
Registry 管的是已注册的执行对象:工具叫什么、属于哪个角色、是否只读、是否需要确认、超时与重试如何配置、输出有没有结构约束。能力目录回答的是产品问题:“这个助手现在能帮助我做什么?”前者服务运行时,后者服务用户理解;二者可以相互校验,却不能直接画等号。
注册表应该把工具对象、元数据和角色索引作为一致的运行账维护。一种实现是通过统一入口处理注册、替换和注销,明确拒绝重复名称,同步清理相关视图,并维护递增的变更序号。不能工具已删除,角色列表还保留;也不能只替换执行函数,却留下旧的确认标记。变更序号反映注册表变化,并不自动成为接口契约版本。
能力目录可以从已启用的技能及工具注册情况生成,避免模型根据产品说明猜测自己有没有执行能力。例如目录写“支持查询和提交套餐调整”,运行账却只有查询工具,这个能力就只能部分执行。一个条目只要挂载了任意工具就标为可用,容易把“有一部分能力”误读成“整个流程都能完成”。
我建议把可用性至少拆成三层:能力是否启用、完成目标所必需的工具是否齐备、当前身份与服务是否允许执行。规则计算可用,并不能替提交动作背书;工具已注册,也不能证明下游现在健康。目录面向用户展示“可查询,提交暂不可用”,比让模型在执行到一半时才发现缺口更准确。
目录还应记录维护责任、适用范围、弃用关系和版本,作为新增、合并与下线的依据。注册一致性解决的是运行账有没有同步,版本化解决的是消费者能否理解接口变化,健康检查解决的是此刻能否调用,完整工作流可用性解决的是用户目标能否完成。这些问题各需证据,一份静态能力宣传文案不能替代它们。
本轮工具收敛
用户问“怎样调整套餐”,本轮应优先暴露说明查询;问“我现在能调整吗”,再引入规则计算与必要状态;明确提出“现在帮我提交”,才进入提交路径。工具集随着目标变化,是为规划提供清晰边界,而不是把整个产品能力目录一次性塞给模型。
技能可以承担这层收敛:技能摘要帮助识别意图,允许工具列表决定正常路径下的暴露范围,规划提示补充顺序与解释约束。一种做法是合并主技能与辅助技能的允许列表,去重后解析已注册工具。缺失的工具不会因此凭空出现;技能中的前置提示,也不自动等于执行器强制的依赖检查。
这里有两种容易被忽略的扩张。第一,命名空间通配符或整个工具服务器的暴露会随新增注册变化;今天的窄范围,明天可能多出一个提交能力。第二,如果未命中或未选择技能时回退到角色全工具集,异常路径就会绕过正常的收敛结果。正常请求收敛得很好,并不能证明回退路径仍然收敛。
我建议将回退也设计成明确能力:先提供只读目录、说明查询或一次澄清,再按目标扩大。若仍保留全角色回退,应记录回退原因、展开后的集合与是否含写操作,单独验证这条路径。通配符可用于管理便利,但上线评审应查看实际展开结果;新增工具要能触发消费者列表变更检查。
更重要的是,暴露控制和执行授权各有职责。模型没看见某个工具,不代表恶意参数或旧计划永远到不了执行器;看见某个工具,也不代表当前用户有权限调用。执行前仍要依据认证身份、目标对象与参数检查授权。OWASP 的授权指南也要求在每次请求上验证权限;应用到 Agent,意味着不能只依赖模型可见列表或先前的路由判断。参考 OWASP 授权指南。少量全局只读辅助能力可以跨技能共享,但需要正式扩展点、范围说明与独立测试,避免临时补丁逐渐变成隐形权限体系。
契约与校验
一个稳定契约至少要说明名称与职责、输入来源、必填项和默认值、结果结构、错误分类、副作用、超时与可重试条件。描述写给模型理解,结构约束写给运行时执行。两者冲突时,模型可能按描述规划,执行器却按另一套规则报错,这不是多补一句提示就能长期解决的问题。
以规则计算为例,输入需要产品类型、生效周期、当前状态和规则版本。用户自述“我已经满足条件”可以帮助理解诉求,但不能代替状态读取;认证身份应由系统上下文注入,不应让模型从聊天文字填一个任意身份。说明查询返回的适用范围与版本,也不能丢掉后再交给规则计算。
一种基础保护是执行前校验输入模型,并在声明输出 Schema 的工具返回后,对原始结果做结构校验。HTTP 工具的响应字段定义可以生成结构约束,其他接入也可以携带输出约束。但默认可选的字段不会因为写在文档里就变成必填;没有声明约束的历史工具,也不会自动得到完整输出校验。契约评审必须查看实际生成和执行的约束。
“参数来自上游工具”“必须满足某业务条件”这样的文字元数据,不必然被运行时强制执行。类型正确只证明它是一个日期或数字,不能证明日期可用、状态仍然有效、用户有权限。工程上应把能机械校验的约束落到输入模型或规则关口,把需要业务判断的约束交给确定的服务。
契约演进也需要明确兼容面。新增可选字段通常比修改旧字段含义更容易迁移;删除字段、改变单位或把空值换成特殊字符串,都会影响消费者。建议保留契约版本与适配层,用同一组构造输入验证旧消费者,逐步提高约束强度,而不是一次严格校验让全部历史结果失效。
结果与展示分层
一次工具调用可以技术执行成功,却查不到符合范围的记录;也可以正常返回业务拒绝。反过来,请求超时意味着没有拿到确定结果,未必意味着外部系统没有处理。如果只有“成功/失败”两个字,模型很难知道该解释、追问、换路径,还是停止提交。
执行结果包可以把状态、工具名、调用标识、动作标识、尝试次数、展示文字,以及可选的业务载荷、错误、确认信息分开保存。稳定的外层结构让调用记录与后续动作关联,消费者不必从一句文字中猜调用是否发生。这个 envelope 并不保证每个业务载荷都已经统一语义,仍需工具适配和消费者契约。
| 观察到的情况 | 合理解释 | 不应推导 |
|---|---|---|
| 查询成功,结果为空 | 在本次身份、范围和时刻未找到记录 | 全系统不存在该记录 |
| 权限拒绝 | 当前调用不允许执行 | 产品永远没有这项能力 |
| 业务规则拒绝 | 当前输入不满足规则 | 服务故障或应该重复请求 |
| 超时或响应格式错误 | 调用结果需要核对 | 提交一定未发生 |
| 等待确认 | 具体动作尚待授权 | 动作已成功完成 |
原始载荷和模型可见内容也应分开。运行时可能需要完整结构处理表单或核对提交,模型只需要与当前回答相关的字段及简短依据。可以为同一次结果保留原始视图和收窄的模型视图,让各类消费者明确取用。支持这种分层不等于每个工具都已经做到了数据最小化,也不等于完整载荷可以随意进入日志。
建议额外记录查询范围、结果时间、是否截断、证据摘要与可恢复建议。未调用、无命中、降级、不可用应有各自含义,不能统一写“没有”。这些业务语义需要按能力设计,不能仅靠通用执行器猜测。尤其在提交后校验响应失败时,应该进入结果核对流程,避免把格式错误误当成安全的重试信号。
读写与确认
只读工具可以减少用户操作成本,却仍受数据权限、读取范围和成本限制。提交动作除了这些检查,还必须明确用户意图与副作用。问“怎么办理”通常需要说明,问“能不能办”通常需要规则和状态,明确要求“现在帮我提交”才构成进入提交路径的依据。
执行器应把授权、策略、确认、工具可用性与输入校验作为独立步骤,拒绝时形成可解释结果。本文采用同一任务内写操作串行的保守策略:互相独立、无副作用且声明只读的调用可以并发,写调用按依赖顺序处理;有依赖的调用先核对前置动作是否存在且执行成功。若要并发写入,应另行明确对象隔离、幂等与并发控制契约。但前置执行成功仍不等于业务资格通过,资格条件还需要读取业务载荷并在规则关口强制验证。
确认界面应展示将要改变的对象、参数、生效时间与影响,用户批准的是这份具体结果。恢复执行时应使用待确认参数,核对待确认动作、工具、凭证与版本是否仍匹配;如果用户改了目标或状态已变化,就重新构造确认。待确认快照检查与一次性凭证消费是可组合的保护,但仅有这些机制,不能推导出每个接入端都完成了完整的参数绑定和防重放验证。
还要把用户确认与外部幂等分开。确认解决“是否允许做”,幂等解决“同一动作送达多次会发生什么”。建议为提交设置稳定动作标识,下游支持幂等键时使用同一个键重试,并通过状态读取核对结果。没有幂等承诺的接口,在连接中断、超时或响应不合法后,先核对再决定是否重发。
不要把所有工具按“网络错误可重试”一刀切。服务已受理后返回错误,与连接建立前失败,可能需要不同处理;一个返回格式错误的成功提交,也不能被本地 envelope 标成失败后就忘记外部副作用。对于结果未知,助手应明确说明正在核对或需要人工检查,保留可追踪动作,而不是再发一次让用户承担重复办理风险。
独立关口、读写调度、依赖检查和确认恢复,需要与逐接口幂等承诺、结果未知状态及补偿流程一起评审。真实授权实现是否装配、例外开关是否开启、确认与下游能否协同,必须在实际接入路径上验证。开发测试里的全部放行替身可以帮助构造流程,不能成为安全验收证据。
查询完成,仍然没有足够依据
构造情形:查询某产品版本的批量导出说明。
- 执行事实
- 授权检查通过,规定范围内的查询正常完成,没有找到可支持本题的说明。
- 能得出的结论
- 本轮在该范围和时点未获得依据。不能据此断言产品不支持,也不能补写一个限制数。
- 下一步
- 若版本或对象不明确,补问;若允许查询其他已授权来源,按预算补查;仍缺依据时明确说明范围。
“没有检索到”是查询结果,不是业务上的否定答案。
提交后响应丢失,不能自动再提交
构造情形:用户已授权创建一次导出任务,提交后连接中断。
- 执行事实
- 请求可能已经被接收,助手尚未取得可确认的任务结果。
- 能得出的结论
- 操作结果待核实。不能宣布完成,也不能宣布未发生,更不能为凑成功状态另建任务。
- 下一步
- 若对方支持按稳定请求意图查询,先查状态;只有满足下游幂等契约时,才按同一意图重试。否则进入明确的核实流程。
同一次意图的重试,与用户发起第二次操作,是不同业务事件。
调用纪事 · 同一笔套餐调整
询问、确认、超时,然后呢?
固定构造记录,不会调用真实工具或发起申请。每一步都可直接选择。
对象 demo-account-01 · 目标:团队版 · 生效:下一周期。用户批准的是这份具体参数。
demo-change-001 · 实际提交 0 次
只读查询完成
用户:下个周期怎么调整套餐?
- 本步动作
- 说明查询
- 确认的事实
- 找到调整方式与条件
- 承诺边界
- 没有读取账号状态,也没有执行提交
demo-change-001 · 实际提交 0 次
本次条件满足
用户:按我现在的状态能调整吗?
- 本步动作
- 读取状态,再计算规则
- 确认的事实
- 演示账号为标准版,没有待处理调整;允许创建下周期变更计划
- 承诺边界
- 条件判断有版本和时效,尚未提交
demo-change-001 · 实际提交 0 次
具体动作获准
用户:确认按这份参数提交。
- 本步动作
- 核对待确认动作、参数、版本及当前授权
- 确认的事实
- 用户确认团队版、下一周期生效的同一份参数
- 承诺边界
- 确认不是外部受理回执
demo-change-001 · 实际提交 1 次
结果未知
- 本步动作
- submit_plan_change
- 确认的事实
- 以 demo-change-001 发送一次,等待响应超时
- 承诺边界
- 不能断言未提交,先核对外部状态
demo-change-001 · 实际提交 1 次
提交完成,待下一周期生效
- 本步动作
- read_action_status
- 确认的事实
- 动作 completed;业务变更 scheduled,下一周期生效
- 承诺边界
- 当前仍为标准版,不能称为已经生效
已核对,团队版的下周期变更计划已经登记;当前仍为标准版,团队版尚未生效。
结束本次提交流程并保留回执。
查看超时记录与核对回执
{
"action_id": "demo-change-001",
"tool": "submit_plan_change",
"attempt": 1,
"execution_status": "timeout",
"outcome": "unknown",
"next_step": "read_action_status"
}{
"action_id": "demo-change-001",
"execution_status": "ok",
"action_status": "completed",
"business_effect": "scheduled",
"effective_at": "下一周期",
"current_plan": "标准版",
"scheduled_plan": "团队版"
}这些状态名属于本演示的契约:completed 指创建变更计划已结束,scheduled 指业务变化尚未到生效时点。
调用预算
规划循环上限可以防止 Agent 无限思考,但一轮里可能并行调用多个工具,每个工具又可能重试。因此“最多若干轮”不能直接换算成调用次数或总耗时。工具描述变复杂、查询返回变长,也会增加模型输入成本,执行预算需要独立建模。
规划轮次上限、工具级超时,以及对部分瞬时错误的有限重试和退避,可以提供基础停止条件。但这些保护不能自动组合成统一的任务总预算。调用次数、并发数量、重试次数、总墙钟时间与返回大小,需要在同一任务尺度上核算,并明确每一种额度由哪个执行关口落实。
以构造方案为例,一次办理请求允许少量逻辑读取、一个待确认提交、有限物理重试,并规定整体截止时间。这里“逻辑调用”指完成一次目标能力,“物理尝试”指实际发送一次请求。两次重试不该伪装成两份新证据,也不能不计入总成本。具体额度应根据服务限制和任务复杂度确定,本文不提供通用默认值。
重复查询应有停止规则:同样参数、同样数据版本、同样结果,不因模型措辞变化就重新调用。无命中时,允许一次有意义的范围调整,随后解释边界或澄清;业务拒绝时,不通过改写参数绕过规则。并行只适用于互相独立且无副作用的读取,不能把前置状态尚未返回的提交也一起发出去。
预算耗尽应该产生可交接结果:已确认什么、什么尚未执行、哪些结果需要核对、继续需要什么条件。尤其不能在截止时间到达时,把一个已发出但结果未知的提交简单标成“没有发生”。调用去重、任务总预算与这种交接语义,需要各自的状态定义和验证,不能从单工具 timeout 推断它们已经得到保证。
上下文预算
上下文既包括用户对话,也包括工具 Schema、调用参数、返回结果与确认信息。只截掉最早的若干条消息,可能留下没有调用的结果,或者保留调用却删掉结果;模型既失去因果关系,消息协议也可能不完整。收敛本轮工具集和裁剪历史,应该共同服务于实际请求预算。
一种保持协议完整性的做法是先按普通消息、已闭合调用结果组、未闭合调用组分区,再修正裁剪边界。旧的闭合调用可以提取有限摘要,本轮用户请求、未完成调用,以及带结构化确认或表单信息的消息受到保护。保护判断使用结构字段,而不是文本里偶然出现某个标记,避免解释性文字长期占住预算。
这并不意味着摘要能代替原始证据。产品助手可以摘要“已查到适用范围和规则版本”,但决定是否提交时仍需要可核对的状态与参数;旧状态可能过期,必要时重新读取。确认凭证和参数快照应留在受保护的运行状态,摘要只保留足够规划的信息,并避免把凭证原文扩散到日志。
预算检查还应包括最终发给模型的工具 Schema 与协议字段,而不只统计内部历史文本。可以在协议转换完成后估算最终请求副本,并在超限时于模型调用前拒绝。检查若只覆盖一种协议适配路径,换一条调用路径就可能绕开它;这类估算也不是供应商实际计费 Token,不能当成精确用量。应预留生成空间,并分别记录估算输入、实际用量与裁剪原因。
可选预算机制必须核验实际启用路径,包括生效阶段、协议适配器、例外开关和失败回退,不能把一份配置文件当成运行证据。裁剪失败回退原请求,也不意味着预算就安全了:最终请求约束仍要覆盖这条回退路径。一次启用验证应证明检查确实拦在模型调用前,而不只是记录了一条“已超限”日志。
建议先用构造长对话与回放观察:裁剪前后是否仍能选择同一能力,是否保留提交依据,是否误把旧的“未完成”当成新事实。若受保护信息本身就超限,应停止或重建任务范围,不能为了塞进窗口而静默删除授权依据。摘要的可读性只是开始,语义完整性才是验证目标。
观测与隐私
只有接口耗时和异常堆栈,还不能回答用户为什么没办成。一次提交可能在授权关口被拒绝、等待确认、输入不合法、前置动作未完成,或者真正执行后超时。这些阶段应有可区分的语义,才能知道该修权限、规则、契约、交互,还是下游服务。
语义观测可以把一次逻辑工具作为父层,把授权、策略、确认、输入输出校验、依赖与恢复一致性作为关口,把物理执行尝试与重试事件作为子层。拒绝发生在执行前,就不应该生成一次“已执行”的物理请求。并行读取也应保持各自调用关系,不能把同一会话的所有事件揉成一条流水账。
建议对构造套餐请求记录:为何选择技能、本轮展开哪些工具、使用何种契约和规则版本、每个关口允许或拒绝的原因、真正发送几次请求、结果是否确定、最终回答依赖哪些证据。版本与原因比一句“工具失败”更有排查价值;敏感参数和完整响应未必需要采集。
隐私分类也应跟着工具生命周期走。一种解析顺序是明确工具配置优先,其次使用注册元数据,再以模式匹配与未知默认分类兜底。变更检查应要求所有声明工具都有显式分类,并覆盖不同字段命名形式。新增工具时同步评审采集字段、输出摘要、保留期限与访问范围,未知工具按保守策略处理,不能只等名字碰巧匹配某条正则。
业务执行载荷、模型可见视图和观测副本是三种用途。观测副本脱敏后不能回流成真实执行参数;运行时需要的原始载荷也不代表模型或日志都需要。一种清晰边界是在深复制的协议副本上保护调用参数与结果,并限制它只进入遥测通道,避免在共享对象上修改字段后意外改变业务执行。
观测失败不应替代业务决策。可以用等价性测试证明启停观测时业务结果相同,再注入遥测启动、更新或序列化异常,验证真实调用没有增减、返回结果没有改变。但“观测失败继续业务”不等于“权限失败继续执行”。权限与策略不能通过时应拒绝动作,可选遥测失败不应阻断业务;若采集脱敏失败,应丢弃或降为最小事件,不能为保留调试信息发送原文。
治理与验证
治理最终要进入工具变更流程。新增一个提交工具时,不能只检查模型是否会调用;还要证明它何时可见、哪些输入可信、谁能执行、结果怎样解释、失败是否可恢复、证据如何保留。这个过程可以小步推进,但每一步都应有明确产物。
- 先画能力与消费者关系。列出四类能力、使用它们的技能、全局辅助工具、通配符与回退路径。标记重叠职责、缺失能力和弃用别名,决定新增、合并还是替换。目录需要回答部分可用情况,普通用户无需看到内部工具名。
- 再评审一次调用的契约。用构造输入检查来源、必填与默认值,分别准备正常、空结果、业务拒绝、输入错误、输出错误和结果未知。说明查询不能冒充规则计算,状态读取必须保留范围与时效。
- 验证执行边界。检查授权拒绝是否阻断真实调用,说明性问题是否进入写路径,确认恢复是否使用待确认参数,前置不满足是否跳过后续动作。对提交超时、重复送达与响应不合法,核对外部状态并验证幂等承诺。
- 验证退化与停止。覆盖技能未命中、工具缺失、通配符新增成员、重复查询、重试耗尽、长对话裁剪和预算超限。测试必须断言真实调用次数、外部动作是否发生与最终结果语义,而不只匹配一句回复。
- 最后核对观测与交付。确认拒绝没有虚假执行尝试,重试没有重复逻辑证据,隐私采集不会污染业务载荷。将目录、契约、技能、策略、观测配置和测试结果作为同一批变更评审,保留可回退版本。
验证要对应具体结论。静态审查能说明关口放在哪里、配置关系是否完整;本地测试证明给定输入和故障下的调度、校验、去重与停止行为。模型回放检验是否选对技能和工具、是否正确解释空结果与不确定状态,真实接入验证身份、权限、时效和下游契约,业务验收确认用户目标是否完成。任何一层都不能替另一层作结论。
例如,要证明工具收敛有效,应在正常意图、含混意图和路由回退中检查实际暴露集合,并用模型回放观察误选;要证明提交安全,应在真实接入里验证拒绝、确认参数变化、重复送达和结果核对;要证明预算生效,应计数物理尝试、测量截止时间,并覆盖每条模型请求路径。观测可信还需要验证事件关系、故障隔离与隐私采集。结论只能落在已经取得证据的层级,缺少的验证应明确留下,不能换成笼统的“已治理”。
回到产品助手,一次可信流程应当能够解释:用户先问说明,所以只读依据;随后问资格,所以读取状态并计算规则;明确请求提交后,构造可审阅参数并走确认;最终依据系统回执报告结果,遇到不确定先核对。工具数量只是目录上的数字,治理真正沉淀的是每一步为什么允许、结果能证明什么,以及哪里必须停下来。
由工程实践中的判断整理,使用通用场景说明方法;示意架构、案例和数值不代表某个系统的生产验收或效果数据。
调用超时先核对结果;确认、幂等和业务生效是不同的事。
读完,留一句在书桌上
仅保存在当前浏览器。