从一次 API 调用到完整 Agent Loop:上下文到底如何流动

从一次 API 调用到完整 Agent Loop:上下文到底如何流动

摘要

Agent Loop 常被简化成"模型返回工具调用就执行,否则结束"的 while True。这个 Demo 能解释主干,却省略了生产最关键的部分:供应商消息协议并不相同,工具调用与结果必须正确关联,最终文本不一定代表任务完成,错误需要分类恢复,循环还要受轮次、时间、token 和费用约束。本文从消息角色差异出发,建立供应商无关的内部事件模型,再给出包含校验、观测、恢复与安全停止的 Loop 状态机。

关键词

上下文工程、消息角色、工具调用、Agent Loop、调用轨迹、终止条件、max iterations、错误恢复

CSDN 分类建议:人工智能 / 大模型应用

推荐标签:AI Agent、LLM、智能体、大模型、Agent Engineering

本文知识地图

我们先拆"消息是什么",再看一次工具调用怎样往返,最后把这个往返放进状态机。两张图分别回答:谁产生什么消息,以及循环在什么时候继续、恢复、完成或安全停止。

图 1:Agent 工具调用消息时序。来源:作者依据 OpenAI 与 Anthropic 官方工具调用文档整理。

读图重点是 call_42:模型输出的调用请求、执行器结果和下一轮上下文必须保持关联。由图可得的工程结论是,工具结果不能作为一段无来源普通文本塞回模型;否则并行调用、重试和审计都可能串线。

先纠正"消息有四种角色"

源稿以 OpenAI Chat Completions 风格说明 system、user、assistant、tool 四种角色。这对理解特定接口有用,却不是跨供应商标准。

Anthropic Messages API 的官方参考明确说明:系统提示通过顶层 system 参数提供,常规输入消息可用 user 与 assistant,并不存在把系统提示作为输入消息 role: "system" 的通用做法。事实;Anthropic Messages API 工具调用则出现在内容块里:模型返回 tool_use,应用执行客户端工具,再用 tool_result 回传。事实;Handle Tool Calls

OpenAI Chat Completions、Responses API 和 Agents SDK 又有各自的消息或 Item 结构。工程结论不是发明一个"万能 role",而是在应用内部规范化少量语义事件,再由适配器转换:

text 复制代码
Instruction     开发者/系统约束
UserInput       用户或外部事件
ModelOutput     文本、结构化输出或调用请求
ToolCall        call_id + tool + args
ToolResult      call_id + result/error
StateUpdate     任务进度、预算、环境状态

这样业务状态机不依赖某家字段名。适配器负责遵守供应商的顺序、内容块、签名或调用 ID 规则;日志层保存规范化事件与原始响应引用。

上下文不是"消息列表"这么简单

不论状态存在哪里,模型在某个决策点实际可见的内容仍是关键。Anthropic 把上下文描述为采样时包含的 token 集合,并强调它有限且需要策展。事实;Effective Context Engineering 生产系统还要保存模型看不见但 Harness 必须知道的控制状态,例如租户、授权票据、幂等键、剩余预算和审计元数据。这些不应全塞进 prompt。

因此建议分成三层:

  1. 模型上下文:模型决策需要的最小信息;
  2. 运行状态:循环、预算、权限、取消信号、幂等和恢复点;
  3. 审计记录:原始请求响应、策略判定、版本和环境证据。

一次工具调用怎样完整往返

以客户端工具为例,通用时序是:

  1. Harness 组装当前模型上下文和工具定义;
  2. 模型返回文本、工具调用,或两者按协议允许的组合;
  3. Harness 解析调用,验证 Schema、业务语义、权限和预算;
  4. 执行器在受控环境运行工具,记录耗时与副作用;
  5. 将结果或错误与原调用 ID 关联,追加到下一轮上下文;
  6. 模型依据新观测给出最终输出或继续调用。

Anthropic 官方工具文档区分客户端与服务端工具:客户端工具由应用执行,服务端工具由 Anthropic 基础设施执行。事实;Tool Use Overview 所以"模型不执行工具"只对客户端工具这一层成立,文章和代码应写清执行位置。

OpenAI Function Calling 的 Structured Outputs 在 strict: true 时可保证参数匹配所给 JSON Schema。事实;OpenAI Function Calling 但 Harness 仍必须验证:订单属于当前用户吗?金额在余额内吗?此动作需要确认吗?工具参数结构正确不等于动作安全。

并行调用的关联规则

模型可能一次请求多个无依赖工具。执行器可并行运行,但结果返回顺序可能不同。不要按数组位置猜对应关系,应以调用 ID 关联。上下文适配器还要遵守供应商对调用与结果相邻、顺序和内容块的要求。

工具输出不要无限回灌

网页、日志或数据库结果可能非常大,也可能包含提示注入。工具层先做长度限制、结构化提取、来源标记和敏感信息处理;原始结果保存到外部制品存储,给模型的是任务所需摘要与可追溯引用。摘要是有损的,涉及证据核验时允许模型按需读取原文片段。

核心循环:从 while 变成状态机

图 2:Agent Loop 状态机。来源:作者依据 OpenAI Agents SDK 生命周期与生产错误处理模式整理。

读图重点是两个出口:完成与安全停止。由图可得的工程结论是,"模型没有返回工具调用"最多表示一个最终输出候选,不能自动证明外部任务完成;相反,预算耗尽时即使任务未完成,也必须退出并报告可恢复状态。

OpenAI Agents SDK 的官方运行文档说明,Runner 会在模型输出最终结果时结束,在产生工具调用时执行并追加结果后重跑;超过 max_turns 会抛出 MaxTurnsExceeded。事实;Running Agents 这验证了轮次上限是当前生产 SDK 的一等概念,但具体默认值与异常类型属于 SDK,实现自己的 Loop 时不能照搬字段名。

供应商无关的伪代码可以写成:

python 复制代码
state = load_or_create_run()
while True:
    enforce_deadline_budget_and_max_turns(state)
    response = model(generate_context(state), available_tools(state))
    events = adapter.normalize(response)

    if events.final_candidate:
        verdict = verify_completion(events.final_candidate, state)
        if verdict.accepted:
            return finalize(verdict, state)
        state.observe(verdict.as_error())

    for call in events.tool_calls:
        verdict = policy.validate(call, state)
        result = executor.run(call) if verdict.allowed else verdict.as_error()
        state.observe(link(call.id, result))

伪代码省略了并发、流式、取消和持久化,却保留五个硬点:每轮检查预算;供应商响应先规范化;最终输出独立验证;调用先过策略;成功与错误都成为观测。

终止条件应该是组合条件

只用 if not tool_calls: break 会产生两类错误:模型过早给出文本,或用文本询问澄清却被当作完成。生产 Loop 常组合以下条件:

  • 完成信号 :模型返回指定结构、调用 submit_result,或工作流到达终态;
  • 环境验证:文件存在且测试通过、交易状态已提交、引用可访问;
  • 用户交互:需要澄清或审批时进入暂停,而非完成;
  • 安全停止 :达到 max_turns、deadline、token、金额或调用预算;
  • 不可恢复错误:权限永久拒绝、资源不存在且无替代路径、策略禁止。

完成信号是候选,环境验证才决定能否交付。安全停止要返回当前状态、已发生副作用、未完成事项和恢复标识,方便之后续跑。

max iterations 不是随手填一个数字

轮次上限过低会截断正常任务,过高会放大循环成本和风险。工程经验是从任务族统计分布出发:记录成功任务所需轮数、长尾失败和每轮成本,为不同工具风险设置差异化预算。例如只读检索可以给更多轮,高风险写操作不仅轮次更低,还应限制每类工具次数。

除了总轮次,还要检测"无进展循环":同一工具与同一参数重复、错误签名重复、状态哈希不变、计划反复切换。检测到后可注入明确观测、切换策略、请求用户信息或停止。不要让模型自己数历史调用次数;Harness 应用代码维护计数。

错误恢复:先分类,再决定动作

错误类别 例子 合理动作
瞬时基础设施 429、短暂超时、连接重置 指数退避、抖动、遵守 Retry-After
参数/格式 Schema 失败、枚举值错误 把精确错误送回模型,限制纠参次数
业务拒绝 余额不足、状态不允许 不盲目重试,换方案或询问用户
权限/策略 越权、缺审批、高风险禁止 停止执行,走授权或人工路径
部分成功 邮件已发但数据库更新失败 查幂等状态,补偿或人工处置
模型协议 调用 ID 丢失、内容块非法 适配器拒绝,保存原始响应并回退

恢复必须知道副作用是否已经发生。超时不等于失败:支付请求可能服务端已成功,只是客户端没收到响应。执行器应使用幂等键并先查询状态,避免重复执行。

上下文增长与恢复点

长 Loop 不应只存在进程内存。每轮完成后持久化规范化事件、预算、工具副作用和可恢复游标。恢复时重建供应商上下文,但不要把所有审计字段喂给模型。对非常长的轨迹,使用结构化状态、压缩摘要与按需制品引用;第四、五篇会继续讨论缓存、压缩和隔离。

常见误区与修正

误区一:所有厂商都有四种相同角色。 修正:按官方规范实现适配器;Anthropic Messages 的系统提示在顶层,工具用内容块表达。

误区二:每次 API 调用都绝对无状态。 修正:客户端全量历史是一种方式;当前接口也可续接服务端 response、conversation 或 session 状态,权衡可编辑性与治理。

误区三:无工具调用就是完成。 修正:它只是最终输出候选;结合结构、环境证据和业务终态验证。

误区四:工具错误直接变普通文本。 修正:保留调用 ID、错误类型、是否可重试和副作用状态。

误区五:max_iterations=10 能解决循环。 修正:还要有时间、费用、工具次数和无进展检测,并按任务族校准。

生产检查清单

  • 每家模型接口有独立适配器和契约测试,不假设角色相同。
  • 内部事件区分指令、用户输入、模型输出、调用、结果和状态更新。
  • 并行工具调用以 call_id 关联,不依赖返回顺序。
  • 工具输出限制长度、标记来源、脱敏并保留原始制品引用。
  • 最终输出经过结构、业务和环境证据验证。
  • Loop 同时限制轮次、时间、token、费用和高风险工具次数。
  • 检测重复参数、重复错误和状态无进展。
  • 瞬时、业务、权限、部分成功和协议错误采用不同恢复策略。
  • 工具有超时、取消、幂等键与副作用查询接口。
  • 每轮持久化恢复点;停止时报告已完成、未完成和已发生副作用。

本文小结

Agent Loop 的本质不是一个 while,而是一套消息协议适配、运行状态、策略校验、工具执行、环境观测和终止判定。供应商 API 的角色与内容块并不通用,应用应规范化语义事件并保留原始关联。最终文本只是完成候选;环境证据、硬预算和错误分类共同决定循环是交付、继续、暂停、恢复还是安全停止。下一篇将深入循环的推理成本:Chat Template、KV Cache、跨请求 Prompt Cache 与前缀稳定性。

延伸阅读与参考资料

官方 API 与 SDK 文档

  1. Create a Message,Anthropic Messages API。(V1-R015)
  2. Tool use overview,Anthropic。(V1-R003)
  3. Handle tool calls,Anthropic。(V1-R017)
  4. Running agents,OpenAI Agents SDK。(V1-R018)
  5. Function Calling in the OpenAI API,OpenAI。(V1-R004)

官方工程文章

  1. Effective context engineering for AI agents,Anthropic。(V1-R005)

系列导航

相关推荐
Flynn Liang6 小时前
AgentScope Java 深度解析:ReActAgent、HarnessAgent 与多智能体编排——JVM 上的自治 Agent 底座
java·大模型·架构设计·ai agent·spring ai·langchain4j·agentscope
得物技术8 小时前
多 Agent 架构的三次反转:从中心调度到自驱协作|得物技术
程序员·架构·llm
吴名氏.10 小时前
Java转AI Agent教程(第九周)错误矩阵
java·人工智能·矩阵·ai agent
lucas_AI11 小时前
ToolSpace:把 804 个真实工具环境打包成 Agent 练级场,35B 小模型暴涨 18 分
llm·agent
像风一样自由20201 天前
4.DockerCompose是什么为什么算法服务需要多个容器
人工智能·rag·智能体
lyai0071 天前
读完 DeepSeek Harness 源码,我给自己画了一张「最小 CLI Agent」施工图
llm·agent
GJGCY1 天前
券商舆情智能体如何设计?事件聚类去重、主体消歧与风险事件抽取技术解析
经验分享·ai·金融·自动化·证券·智能体
goehou1 天前
缓存该删还是该改,LLM 服务里的双写问题
redis·缓存·llm·一致性·系统设计
吴名氏.2 天前
Java转AI Agent教程(第五周)Prompt工程
java·人工智能·prompt·ai agent
合天网安实验室2 天前
从压缩到泄露:KV Cache Compression 的选择性失忆与系统提示词风险
人工智能·llm