Agent 执行循环与工具选择
Agent 的执行能力来自一个循环:读取当前状态,选择下一步,执行动作,解释结果,再决定继续还是结束。真正影响可靠性的,是每一轮如何更新状态、哪些动作允许执行,以及何时认定已经完成。
ReAct 研究了推理轨迹与行动交替进行的方式,使模型能够结合环境返回的信息调整行动。工程实践中常用 Think/Action/Observation(TAO)描述类似循环,但 TAO 并非统一的学术标准,也不能与所有 ReAct 实现严格画等号。ReAct 论文
这里的 Think 表示可观测的决策接口,例如下一步动作、缺失信息和简要依据。模型输出的解释有助于排查,但不是其真实内部思考过程的完整或必然忠实记录。
1. Plan 管整体,循环推进当前任务
任务计划可以规定“收集商品信息—核验约束—比较并输出”,执行循环则判断当前缺少什么:需要检索商品、确认尺码、补查配送,还是已有足够证据直接结束。
短任务可以只使用循环;稳定流程可以只用工作流。混合系统中,代码负责明确的状态转换,模型处理运行时才出现的语义分支。不要把每次缓存读取、参数检查都变成模型决策。
读取任务状态
→ 校验目标、约束和剩余预算
→ 构造本轮候选动作
→ 提出下一步动作
→ 执行前校验并调用
→ 解析原始结果,更新状态
→ 继续、结束、澄清、重试、重规划或中断
2. 用状态支撑每一轮决策
把所有内容不断追加到聊天消息中,容易混淆旧事实、推测与最终结果。可以用下面几类状态组织信息,具体项目不必为每一类都建立独立服务。
| 状态 | 最少需要保存什么 | 解决的问题 |
|---|---|---|
| 目标 | 最终目标、当前阶段、成功标准 | 避免局部动作偏离交付物 |
| 动作 | 动作 ID、参数、原始响应引用、执行状态与耗时 | 查清做过什么,避免重复执行 |
| 观察 | 新增事实、异常、缺口、预期与实际差异 | 区分调用成功和业务进展 |
| 事实与证据 | 事实值、来源、时间、适用范围、可信状态 | 避免把推测和过期信息直接复用 |
| 控制 | 总时限、轮数、重试次数、工具与 token 预算 | 在循环无进展时可靠停止 |
目标、约束和动作结果是运行时数据,不应完全依赖模型“记住”。关键内容需要持久化;每次决策只加载相关视图,历史细节保留索引以便召回。
状态还需要权限边界。用户明确提出的约束、应用固定策略和外部工具返回的文本不是同一等级的信息。检索结果中出现“忽略前面的要求”,只能作为不可信内容处理,不能修改系统目标或获得工具权限。
3. Observation 要解释业务结果
HTTP 200 只说明一次协议层响应。返回内容可能为空、过期、部分失败,甚至是包装在正常响应中的业务错误。将原始响应直接交给下一轮,而不检查语义,容易把“调用成功”误写成“任务完成”。
{
"action_id": "inventory_query_19",
"transport_status": "ok",
"business_status": "partial",
"new_facts": [
{"product_id": "A", "size": "M", "in_stock": true,
"evidence_ref": "tool_response_19"}
],
"remaining_gaps": ["A 到杭州的承诺送达日期"],
"progress": true,
"can_finish": false
}
确定性的字段检查、状态码解析和数据存储优先由代码完成;较复杂的文本解释可以由模型提出,再校验输出结构及证据引用。工具原始响应与观察摘要分别保留,才能追查误读。
进展也要有业务含义。新增一条证据、补齐一个必要条件、使候选通过一个检查,都可以形成进展;重复返回相同结果则未必有价值。缺口减少不是万能指标,因为新证据也可能合理地暴露更多问题,应同时记录哪些假设被推翻。
4. Action 按业务职责设计
Action 可以封装一个工具、多个接口或一个子 Agent。关键是外部调用者能理解它完成什么、要求什么输入、可能产生什么影响。
例如“读取客户相关资料”可以在内部先查缓存,再查询服务,统一返回资料及新鲜度;模型不必决定缓存如何命中。相反,如果“使用缓存”与“查询最新值”对应明确的时效取舍,可以暴露为参数或分开的动作,让上层决策有依据。
| 粒度过细 | 粒度过粗 |
|---|---|
| 模型要理解底层接口和顺序,调用多、上下文膨胀 | 一个动作包含太多分支,权限、失败和恢复边界难表达 |
| 容易遗漏必要步骤 | 部分成功难以识别,难以只重试一小部分 |
职责重叠无法完全消除,但要明确行为差异。“提交退款申请”与“直接执行退款”即使对象相同,权限和副作用也不同,不应靠模糊描述区分。
封装子 Agent 时,同样需要输入输出协议、时间和调用预算、取消方式及错误结构。只传与子任务有关且获准访问的上下文;子 Agent 的结论应携带证据和不确定性,不能仅凭“另一个 Agent 已确认”升级为事实。
5. 工具描述就是执行契约的一部分
一个有效的工具定义需要说明能力、适用与不适用场景、参数、返回值和前置条件。描述帮助模型选择,执行器负责落实约束。清楚的工具边界和高相关返回值,也是官方工具设计指南强调的原则。Anthropic 工具设计指南
{
"name": "query_delivery_quote",
"description": "查询商品到指定地区的可用配送方案",
"required_params": ["product_id", "region_code", "quantity"],
"preconditions": ["商品有效", "地区已确定"],
"not_for": ["创建订单", "锁定库存", "保证未来库存不变化"],
"side_effects": "none",
"output_fields": ["options", "quoted_at", "expires_at", "warnings"],
"error_codes": ["NOT_FOUND", "UNAVAILABLE", "PERMISSION_DENIED"]
}
使用清楚的业务参数名,避免让模型推导可以由代码确定的内部值。工具返回最相关数据及必要的证据引用,不必暴露整个数据库响应;但不能为了简短省略错误、时效或结果不完整的标记。
默认值应有明确语义,尤其是金额、范围和写入目标。只读查询可以采用保守默认范围,副作用操作不能用默认值掩盖缺失授权。
6. 工具很多时,分两阶段选择
先构造合格候选,再由模型选择一个能推进当前目标的动作。
资格过滤可以结合用户权限、任务阶段、业务意图、参数是否齐备、前置状态、服务可用性以及剩余预算。权限不足的工具不能因为向量相似度高而重新进入候选。
相关性筛选可以使用标签、描述检索、历史成功情况或轻量模型粗筛。最终决策再加载候选的完整定义、必要状态和边界例子。召回阶段漏掉正确工具时,后续再强的模型也选不到,因此需单独测量候选召回率,并允许安全地扩大候选范围。
没有适用于所有模型和业务的固定最佳工具数量。数量、描述长度、工具重叠和任务复杂度都要纳入测试。只传少数候选却把正确工具筛掉,同样会降低成功率。
决策依据可以围绕目标推进、待补信息、成本、延迟和副作用。信息增益是一种选择思路,但“减少不确定性”不应变成无限检索:缺少的信息必须影响当前成功标准,才值得继续获取。
7. 执行前再次检查
模型知道一个工具存在,不代表这一轮允许调用它。执行网关必须核对本轮候选资格,再检查参数、权限、前置条件和版本。
execute(proposal, state, candidates):
require proposal.action in candidates
validate_schema(proposal.params)
check_permission(user, proposal.action, proposal.params)
check_preconditions(state, proposal)
require state.version == proposal.expected_version
reserve_execution_budget(proposal)
return dispatch_with_audit_and_idempotency(proposal)
授权还需要记录范围和时效:用户允许查询订单,并不等于允许退款;一次审批也不应自动覆盖新对象或更高金额。候选筛选后权限仍可能变化,因此执行时复查不可省略。
工具内部可以封装限次重试、熔断和降级,但应向运行时返回实际尝试次数和降级状态。使用旧缓存时标明数据时间;写操作超时后先确认结果,避免内层重试三次、外层再重试三次造成重复副作用。
跨工具失败和路径变化交由重规划与恢复机制处理。业务写入的幂等与补偿依赖底层服务,不能由模型一句“可以回滚”代替。
8. 明确六类出口,阻止无效循环
| 出口 | 触发依据 |
|---|---|
| Continue | 有必要缺口,且存在能推进任务的合格动作 |
| Finish | 成功标准有证据支持,关键校验已经通过 |
| Clarify | 必要信息无法从现有证据获得,继续猜测会改变结果或授权范围 |
| Retry | 原路径有效,当前失败符合可重试条件 |
| Replan | 路径、关键假设或约束发生实质变化 |
| Interrupt | 无可行路径、任务取消、授权不足或预算耗尽 |
循环控制至少应包括次数、总时间、工具预算和无进展检测。可以记录动作名、规范化参数及相关状态版本的指纹,识别相同条件下的重复调用;但不能一律禁止重复,实时数据到期或失败依赖恢复后,重查可能合理。
停止不应只依赖模型自报“完成”。例如生成了三个候选,还需要核验它们是否满足约束;如果只完成部分工作,返回阶段性结果及缺口,不要把预算耗尽包装成成功。
长任务可以增加外层监督,在里程碑或异常信号出现时检查目标、约束和状态。异步监督要使用版本化结果,避免与主循环并发修改同一状态;它能辅助发现偏差,不能保证自动消除漂移。
9. 分开评估选择、执行和解释
一个失败任务可能是选错工具、参数错误、工具本身失败,也可能是工具成功后被错误解释。评测需沿这三个边界拆开,避免一律归因于模型。
- 选择:在给定状态下,所选动作是否属于可接受集合?不是每个任务都只有一个标准动作。
- 参数与权限:参数是否正确,前置条件是否满足,越权提案是否被执行器阻止?
- 执行:响应时间、超时、部分成功、重试与降级是否符合契约?
- 观察:是否正确提取事实、绑定证据、发现空结果和剩余缺口?
- 整体:最终任务是否成功,约束有无违规,付出的轮数、时间和成本是否合理?
可为每个离线状态标注一个可接受动作集合,结合真实结果检查任务推进。语义评价可使用人工或模型评审,但确定性结果优先用代码验证;模型评审也需要抽样校准,不能作为唯一真值。
重点回归场景包括:正确工具不在候选中、相近工具职责混淆、参数缺失、权限在执行前撤销、工具返回空数据、重复调用没有进展,以及外部内容试图改变任务指令。执行循环只有在这些失败场景里也能保持状态清楚、动作受控,才有稳定交付的基础。