03 · 如何实现一个 Agent? - Agent Implementation
所属知识库:Agent 全栈技术地图
所属领域:02 · Agent
所属章节:03 · 如何设计、构建和测试 Agent? - Development & Practice
文档类型:技术原理与工程实践研究
版本:v2.0
更新日期:2026 年 10 月 28 日
核心问题:如何把 Agent 的任务契约和有效配置落实为可运行的软件,具体实现模型调用、结构化决策、工具执行、权限校验、状态转换、预算控制、错误处理、可观测性与测试,并在真实框架和自建运行循环之间做出有证据支持的工程选择?
一、问题定位:从设计文档到可运行的 Agent
本篇属 Development & Practice。前两篇 Design 与 Configuration 分别产出任务契约、架构方案和有效配置。Implementation 的任务是把这些声明变成可观察的执行行为:模型如何接收上下文、如何提出下一步行动,程序如何校验并执行工具,工具观察如何写入状态,任务如何在成功、失败、预算耗尽或等待人工审批时终止。
核心区分是:模型提供决策建议,Runtime 执行控制与状态管理,可信工具层实施外部动作与授权。模型生成 {"tool":"send_email"} 只是一个行动请求;只有程序完成参数校验、身份与权限检查并调用邮件系统后,外部动作才实际发生。把这三者混为一谈,是很多“能演示、难上线”Agent 的根源。
本文研究的是单 Agent 的实现边界。通用多 Agent 调度、分布式执行、持久化检查点集群、租户资源调度等归入 Agent System;平台化 Agent 创建、发布、监控与计费归入 Agent Platform。单 Agent 可以使用这些基础设施,但不必在本篇重新实现整个系统。
1.1 最小可用 Agent 与工程可用 Agent
最小可用 Agent 需要输入、模型、工具、循环与输出。工程可用 Agent 还需要严格契约、可控终止、权限、失败路径、运行记录、可重现配置、回归测试。两者之间的差距不是多写几段 Prompt,而是建立可执行的不变量。
| 工程属性 | 最小演示 | 工程实现要求 |
|---|---|---|
| 模型输出 | 直接读取自然语言 | 结构化决策及解析失败处理 |
| 工具调用 | 按工具名执行函数 | 注册表、参数验证、身份授权、超时与副作用管理 |
| 状态 | 消息列表 | 任务状态、观察证据、事件、配置摘要 |
| 终止 | 模型说“完成” | 成功契约、预算、截止时间、失败原因 |
| 错误 | 抛异常 | 分类、记录、受控重试、必要时暂停 |
| 测试 | 跑通一次 | 单元、集成、故障注入、真实任务评测 |
二、总体架构:控制流、数据流与信任边界
flowchart TD
U[TaskSpec 用户任务] --> V[任务校验]
C[EffectiveConfig 有效配置] --> R[Run Controller]
V --> R
R --> B[Context Builder]
B --> M[Model Adapter]
M --> P[Decision Parser]
P -->|tool| G[Tool Gateway]
P -->|finish / stop| F[结果验证 / 终止]
G --> A[Policy / Authorization]
A --> X[Tool Executor]
X --> O[Observation]
O --> S[State Reducer / Event Log]
S --> R
F --> S控制流由 Controller 持有:每次模型调用之前检查预算与截止时间;每次模型返回后先解析、再分派;每次工具执行后更新状态。数据流由 TaskSpec、Context、Decision、Observation 和 State 组成。信任边界出现在外部输入进入模型上下文、模型意图进入工具网关、工具返回进入证据状态三个位置。
建议将以下四种对象分离:TaskSpec 是不可随意修改的用户目标;EffectiveConfig 是运行开始时已校验的能力与约束快照;RunState 是任务执行中不断变化的事实;RunEvent 是带顺序号、时间及关联 ID 的操作记录。它们的生命周期不同,混入一个可变字典会使恢复、审计和测试复杂化。
三、执行循环的精确定义
一个受约束的 Agent 循环可抽象为状态转移:
其中 C 根据状态构建模型上下文,M 产生候选行动,validate 检查输出契约,O 是执行工具后得到的观察。对于 finish 行动没有工具观察,而应执行最终结果验证。该表达只是软件状态转移的抽象,不意味着模型决策是确定性的。
validate(task, effective_config)
state = initialize_run()
while state.status == RUNNING:
enforce_deadline_and_step_budget()
context = build_context(task, state, effective_config)
candidate = model.generate(context)
decision = parse_and_validate(candidate)
match decision:
ToolCall:
enforce_tool_budget()
authorize(identity, tool, arguments, resource)
observation = execute_with_timeout(tool, arguments)
append_event_and_reduce_state(observation)
Finish:
verify_output_contract_and_evidence(decision)
mark_completed_or_failed()
Stop:
mark_stopped_with_reason()3.1 决策协议:判别联合类型
推荐显式区分三种行动:
{"kind":"tool","name":"search_evidence","arguments":{"query":"Agent architecture"}}
{"kind":"finish","answer":"...","citations":["doc-1"]}
{"kind":"stop","reason":"INSUFFICIENT_EVIDENCE"}这不是模型提供商统一协议,而是本篇参考 Runtime 的内部契约。真实 API 的原生 function calling 结构需要由适配器转换为该内部协议。解析器必须检查字段类型、必填字段、未知字段、工具是否存在、参数是否符合 Schema。不能用正则从任意模型文本中提取 shell 命令后执行。
3.2 一次调用与一个执行步骤不一定相同
某些模型一次返回多个工具调用;一次工具调用可能产生多个事件;某些框架有 handoff、interrupt、streaming 等额外事件。max_steps 需要明确计数语义(模型决策轮次、图节点数还是工具执行数),不能假定不同框架的“step”可以直接比较。
3.3 终止条件
终止状态至少区分 COMPLETED、STOPPED、FAILED、WAITING_APPROVAL。COMPLETED 表示输出满足契约,不只是模型声称任务完成;STOPPED 可以是用户取消、预算耗尽或证据不足;FAILED 表示未能恢复的执行错误。等待审批不是失败,也不应伪装成成功。
四、模型适配器:提供商 API 与 Agent Runtime 的接口
模型适配器承担:构造请求、发送请求、处理超时与提供商错误、解析模型输出、保留用量与模型标识,并转换为 Runtime 可理解的决策。模型不应该直接持有工具执行器或数据库连接。
4.1 两条实现路线
路线 A:自行控制循环。 应用直接调用模型 API,自己解析决策、执行工具和更新状态。优势是控制流完全可见、可实现严格业务契约;代价是必须自己维护历史、重试、追踪、工具协议和升级兼容。
路线 B:使用 Agent SDK / 框架。 由框架处理循环、工具分派、状态或图执行,应用注入业务工具、策略与数据。优势是复用成熟抽象;代价是必须理解框架的生命周期、配置覆盖、异常语义与隐藏的执行行为。
OpenAI 官方文档明确区分直接使用 Responses API、自主管理循环,与使用 Agents SDK 让 Runner 管理工具、handoff、会话等运行机制。SDK 的基本循环是模型调用、检查输出、执行工具或 handoff、继续,直到产生最终结果。见文末 [S1][S2]。
4.2 最小真实 API 适配器的限制
配套 runtime.py(完整包 03-Agent-Implementation-v2.0.zip)提供可选 ResponsesModel:通过 HTTPS 向 /v1/responses 发送 instructions 与 input,读取响应的 output 内容并将 output_text 解析为 JSON 决策。它没有启用提供商原生工具调用,原因是本实验要将工具执行权明确保留在本地 Runtime。该适配器仅用于演示“真实模型可替换模拟决策器”的边界,不是完整 SDK 替代品。
重要限制:当前示例没有实现流式解析、提供商原生工具事件、结构化输出模式、速率限制重试、真实 token 计费、异步并发、长任务恢复。模型可能输出非 JSON,代码会明确失败而不是执行猜测的行动。真实模式需要 API Key、网络与支持该请求的模型;本次未实测真实模式。
4.3 使用官方 SDK 的更短路径
官方 Python Agents SDK 文档展示了 Agent(name=..., instructions=...) 与 Runner.run(agent, input) 的基本用法,并提供 run_sync、run_streamed 等形式;当前文档还描述了 RunConfig、Session、工具执行并发配置等。对需要自定义执行控制的项目,应审查 SDK 实际支持哪些 guardrail、approval 与运行边界,而不是仅凭 SDK 提供工具接口就认为权限安全。见 [S2][S3][S4]。
五、工具网关:将模型意图转为可信动作
工具调用应经过四道检查:
- 名称与注册表:模型请求的工具是否存在,是否在本 Agent 允许列表中。
- 参数与契约:字段类型、枚举、长度、资源标识与业务不变量是否正确。
- 身份与权限:当前用户、租户、任务和资源是否允许这次操作。
- 执行与副作用:是否需要审批、幂等键、事务、沙箱或速率限制。
设注册工具集合为 D,Agent 配置白名单为 C,针对主体和资源的实时授权集合为 A(p,r),真正可执行集合为 D ∩ C ∩ A(p,r)。配置白名单不等于授权:本篇最小代码仅实现静态白名单,未实现多租户身份验证或真实资源级授权,不能用于敏感生产工具。
5.1 工具返回不是天然可信事实
检索网页或文档得到的文本属于外部数据,可能包含错误信息和提示注入。Runtime 应将工具结果封装为带来源、时间、工具 ID、错误状态的 Observation;不要把网页中的“请忽略此前指令”提升为高优先级指令。引用检查应验证来源确实被检索到,而内容真实性仍需独立评价。
5.2 读操作与写操作的不同重试语义
查询类工具通常可以在超时后安全重试,但仍需考虑配额与成本。发邮件、支付、提交订单等具有副作用的工具,超时不代表操作未成功:可能是远端执行成功但本地未收到响应。必须优先使用服务端幂等键、状态查询或事务性操作记录,避免简单重试导致重复副作用。
5.3 审批位置
人工审批应在有副作用的操作真正执行之前进行。OpenAI 官方的 guardrails / human review 指南将输入、输出、工具校验与人工审批区分,并指出敏感动作应在执行前暂停等待批准。见 [S4]。审批通过后仍应重新检查实时授权与资源状态,防止审批等待期间条件变化。
六、状态、事件与上下文管理
6.1 状态与事件不是同一对象
状态是当前事实快照,例如证据列表、预算余额和任务状态;事件是发生过的动作,如 MODEL_DECISION、TOOL_RESULT、TOOL_ERROR、STOP。只存状态会失去“为什么到达此状态”的证据;只存事件则需要重放才能恢复当前状态。生产实现可使用事件日志与检查点组合,但持久化策略属于更深的 Agent System 研究。
6.2 Context Builder 的职责
模型上下文应包含:稳定任务契约、可用工具描述、当前状态摘要、必要的观察证据和输出格式要求。应避免把完整原始日志无限追加。对研究助理而言,证据 ID、来源和主题映射通常比全部聊天历史更重要。上下文压缩必须保留事实与来源之间的可追溯关系。
6.3 中断与恢复的实际语义
LangGraph 官方资料描述:interrupt() 可以在节点内暂停图执行,并依赖 checkpointer 保存状态;恢复使用 Command(resume=...) 和同一 thread ID。尤其需要注意,恢复时节点可能从头重新执行,因而中断前的副作用代码可能再次运行。这个细节直接影响审批前后的工具设计,应将副作用放在可重入安全的位置或使用幂等保障。见 [S5]。
本篇配套 Runtime 没有实现持久化恢复,不能因为记录了事件就声称支持崩溃后继续运行。
七、预算、超时与错误分类
Agent 执行存在至少四种预算:模型轮次、工具调用数、总墙钟时间、真实货币成本。它们的计数对象不同,不能互相替代。特别是并发执行时,预算检查必须在资源分配前原子预留,否则多个调用可能同时通过检查导致超限。
| 错误类型 | 典型原因 | 处理原则 |
|---|---|---|
| 模型格式错误 | 返回不符合结构化契约 | 拒绝执行,必要时受控修复 |
| 提供商超时/限流 | 网络、容量、额度 | 有界退避;尊重截止时间 |
| 工具参数错误 | 类型、缺字段、越界 | 明确失败或让模型重新规划 |
| 权限拒绝 | 工具或资源未授权 | Fail closed;不能自动升级权限 |
| 工具超时 | 外部服务不响应 | 区分只读与副作用操作 |
| 证据不足 | 检索无结果或质量不够 | 明确停止或追加受预算约束的检索 |
| 预算耗尽 | 步数、调用、时间或成本上限 | 终止并报告已完成部分 |
| 状态不一致 | 并发写入或恢复冲突 | 检测版本冲突、回滚或人工介入 |
参考代码通过 max_steps、max_tool_calls、deadline_seconds 展示三个确定性边界;它不计算真实 token 与货币成本,也没有实现跨进程原子预算预留。
八、真实框架的实现差异:三个观察尺度
8.1 自建循环(Responses API + 自有 Controller)
调用链由应用掌握:ContextBuilder → ModelAdapter → Parser → Gateway → Reducer。适用于权限、状态和终止语义需要高度定制的单 Agent;开发者承担较多基础设施责任。
8.2 OpenAI Agents SDK
官方文档说明 Runner 管理 Agent 循环,并提供工具、handoff、guardrails、sessions 与 tracing 等机制。对于单 Agent 应用,可以把业务工具作为函数工具交给 SDK,而不是重新实现整个循环。其 RunConfig 与工具执行配置会影响运行时行为,例如本地函数工具并发限制与工具名未匹配时的处理策略。具体参数应以部署时 SDK 版本文档为准。见 [S1][S2][S3]。
需要研究的代码边界是:SDK 何时调用模型、如何解析工具事件、何时执行 guardrail、如何记录 trace、何时触发最大轮次或中断。框架提供 guardrail 并不自动等同于业务授权;敏感工具仍需应用自己的身份与资源校验。
8.3 LangGraph
LangGraph 将状态与节点执行组织为图结构,适合需要显式流程节点、状态转移、分支、人工中断与检查点的应用。与“模型每次自由决定下一步”的循环不同,图的节点和边可把一部分控制权固定在程序层。官方源码与文档中可核查 StateGraph、interrupt、Command 和 checkpointer 的契约;状态 reducer、并行更新与持久化语义需要按具体版本测试。见 [S5][S6]。
| 维度 | 自建 Runtime | Agents SDK | LangGraph |
|---|---|---|---|
| 控制结构 | 自定义循环 | SDK Runner 循环 | 显式图与状态更新 |
| 工具执行 | 应用全权实现 | SDK 集成工具调用 | 由节点/工具组件实现 |
| 状态 | 应用自建 | SDK 提供会话/运行结果能力 | 图状态与检查点能力 |
| 人工介入 | 自建暂停/恢复 | 官方审批机制 | interrupt / resume |
| 主要取舍 | 灵活但维护成本高 | 集成速度与抽象约束 | 流程可见性与图设计复杂度 |
这不是基准测试排名。不同框架可以互相组合,也可以在不同层承担不同职责。是否采用某框架,应根据任务控制权、可观察性、状态恢复、工具授权、团队经验和部署环境判断。
九、完整工程实验:技术研究助理的最小 Runtime
9.1 文件与环境
本次提供配套包 03-Agent-Implementation-v2.0.zip(目录 runtime.py 等),Python 3 标准库(含 3.9)。它包含:Config、State、Event、模型协议、确定性模型、可选真实 Responses API 适配器、工具、决策解析器、Controller 与 12 项单元测试。
python3 runtime.py --test
python3 runtime.py --mode mock --question "agent architecture" --output run.json本地执行 python3 runtime.py --test:12 项确定性测试全部通过。真实 API 模式未在本次交付环境实测。
若要尝试真实 API(本次未实际验证),先在本地安全设置 OPENAI_API_KEY,再运行:
python3 runtime.py --mode real --model gpt-4.1-mini --question "agent architecture"模型名仅为示例默认值,实际可用性取决于账号、模型生命周期与 API 兼容性;如模型不支持或响应结构变化,应核对当日官方文档并修改适配器。不要把密钥写入代码、提交到仓库或附在执行日志中。
9.2 实验执行路径
以模拟模式执行 agent architecture:
- Controller 初始化任务与事件;
- 模拟模型在证据为空时提出
search_evidence请求; - Parser 验证结构;Gateway 检查工具白名单与调用预算;
- 本地工具返回
doc-agent-1;Controller 将观察写入证据状态; - 模拟模型返回
finish,引用已获取的doc-agent-1; - Controller 检查引用存在,设置
COMPLETED并写入结束事件。
这条路径说明“模型建议 - 程序验证 - 工具执行 - 状态更新 - 结果校验”的基本机制,不说明研究报告已经达到真实业务质量。
9.3 实验实际验证结果
本地执行 12 项确定性单元测试,全部通过。测试覆盖:成功路径、事件顺序、虚构引用拒绝、无效模型决策、工具白名单拒绝、工具预算、步数预算、工具超时、模型主动停止、无效配置、空输入和截止时间。
测试不能证明的内容:真实 LLM 是否遵守 JSON 协议;模型在复杂任务中的规划能力;真实网络调用与成本;租户级权限;副作用幂等;生产环境中断恢复;多轮上下文的质量。这些需要单独的集成测试、真实模型评测与安全审查。
9.4 代码中刻意保留的局限
EvidenceTool是内存中的合成证据库,不是真实检索系统。allowed_tools只实现静态允许列表,没有身份和资源级授权。- 模型适配器直接解析文本 JSON,未启用原生结构化输出或 function calling。
- 模型请求是同步 HTTP 调用;没有流式响应与异步取消。
- 截止时间在循环边界检查,无法强制中断已经阻塞的任意工具。
- 事件保存在内存;崩溃后无法恢复。
- 引用校验只检查 ID 是否出现过,不判断证据是否支持结论。
- 没有费用估算、价格版本和原子预算预留。
明确这些限制比将教学代码称为“生产级 Agent”更符合工程研究标准。
十、从教学 Runtime 走向可部署工程
建议按以下顺序扩展:
阶段 A:真实模型与工具接口。 使用官方 SDK 或直接 API,实现真实模型调用、原生工具事件解析、超时、限流、结构化输出校验和真实检索工具。建立模型/工具契约测试。
阶段 B:安全与副作用控制。 为工具网关接入用户身份、资源授权、审批与审计;为写操作引入幂等键与外部状态查询;隔离代码执行环境。不能依赖 Prompt 作为唯一防线。
阶段 C:状态与恢复。 定义持久化状态、运行 ID、配置快照、事件存储与恢复协议;验证中断前后重复执行、任务取消与状态迁移。复杂跨进程运行转入 Agent System 研究。
阶段 D:可观测性与评测。 为每次模型调用和工具执行记录关联 ID、耗时、用量、错误类型和输出版本;建立固定任务集、异常注入和真实模型重复评测。
阶段 E:灰度与回滚。 对模型、Prompt、工具和策略变更做回归,记录实际解析版本;在质量、成本或安全指标下降时恢复到已验证配置。
十一、工程选型的决策框架
| 任务条件 | 推荐优先考虑 | 必须验证 |
|---|---|---|
| 步骤稳定、动作风险高 | 确定性工作流 | 是否真的需要模型自由决策 |
| 单 Agent、工具较少、控制要求特殊 | 自建受约束循环 | 异常、权限、维护成本 |
| 需要快速构建工具型 Agent | Agent SDK | Runner 生命周期、授权和版本兼容 |
| 分支复杂、状态明确、需暂停恢复 | 状态图/图式 Runtime | checkpoint、节点重入、副作用安全 |
| 需要长时运行、多任务调度、多 Agent | Agent System 方案 | 持久化、队列、隔离与资源治理 |
设计原则是把可确定的约束留在程序层,把需要语义判断的局部问题交给模型。模型越强,并不意味着越应该将所有控制权交给模型。
十二、典型故障与调试路径
- 模型反复调用同一工具:检查任务停止条件、证据状态是否真正更新、模型是否看到工具观察,以及预算是否有效。
- 工具调用未执行却被写入成功日志:区分模型决策事件、网关授权事件、工具实际执行事件。
- 输出出现虚构引用:将最终引用与证据注册表关联,建立引用存在性与证据支持性两层验证。
- 工具超时后重复发送:审查副作用、幂等键与远端结果查询机制。
- 配置改变后行为漂移:记录有效配置、模型实际标识、Prompt 与工具版本,不只记录 Git 提交。
- 人工审批恢复后重复执行:检查框架中断恢复语义,避免在可能重入的节点中放置未受保护的副作用。
- 成本超过限制:区分模型 token、工具计费与并发预留;仅有
max_steps不构成完整成本上限。
排查顺序建议为:确认有效配置 → 确认输入与模型响应 → 确认 Parser → 确认授权与工具执行 → 确认状态更新 → 确认终止逻辑 → 再讨论模型“智能程度”。
十三、质量验收与后续研究
本篇可作为 Implementation 专题的技术机制与参考工程实现版,其质量验收应包括:
- [x] 给出完整控制流、数据流、信任边界和关键对象契约。
- [x] 实现最小运行循环、决策解析、工具白名单、状态、事件和终止。
- [x] 用确定性测试覆盖正常路径与关键失败路径。
- [x] 对比自建循环、Agents SDK 与 LangGraph 的控制方式。
- [x] 结合官方文档核对 SDK 运行循环与图式中断语义。
- [ ] 固定依赖版本并运行真实模型端到端实验。
- [ ] 对指定版本框架做逐文件源码审计与运行轨迹对照。
- [ ] 实现资源级授权、审批恢复、幂等和持久化。
- [ ] 完成真实任务数据集上的质量、成本与可靠性评测。
因此,本文不应被标记为生产工程验证完成。它完成了研究框架、关键执行语义、部分官方资料核对和最小确定性实现;下一步应通过真实集成与专题 Testing 形成更高等级的证据。随后可通过 Case Studies 对照真实开源项目的实现差异。
十四、核心结论
Agent Implementation 的关键不在于“循环调用模型直到它回答”,而在于建立模型决策与可信执行之间的严格契约。模型可以提出行动、解释证据和生成内容;程序必须负责验证行动、授权工具、维护状态、执行预算、记录事件并确定任务终止。框架能够减少基础设施开发,但不能替代业务级权限、数据质量和工程验收。
这一实现边界也构成后续 Agent System 的基础:当多个 Agent、长任务和多租户应用共享这些运行能力时,单 Agent 内部的 Controller、状态与工具网关将逐步演化为可复用的运行时服务与协作架构。
参考资料与核验记录
以下资料于 2026-10-28 检索;引用的是官方文档或项目维护者源码入口,部分文档会随版本更新。本文未固定安装并逐项验证这些框架的最新发布版本,因此涉及 API 细节时仍应以实际部署版本为准。
- [S1] OpenAI - Agents overview:Agents API、Agents SDK、Responses API 的运行边界。developers.openai.com/.../agents
- [S2] OpenAI - Running agents:Runner 循环、工具与 handoff、终止语义。developers.openai.com/.../agents/running-agents
- [S3] OpenAI Agents SDK - Running agents:
Runner.run、RunConfig、session、工具执行并发等。openai-agents-python/running_agents - [S4] OpenAI - Guardrails and human review:输入/输出/工具校验与敏感操作审批。developers.openai.com/.../agents/guardrails-approvals
- [S5] LangGraph - Interrupts(官方文档仓库):checkpoint、thread ID、
Command(resume=...)、节点恢复重入。langgraph/interrupts.mdx - [S6] LangGraph - StateGraph / state API(官方参考):图状态、更新与 reducer 语义。langgraph/graph/state
- [S7] MCP - Authorization specification(2025-11-25 版本):HTTP 传输层授权机制及适用范围。MCP authorization
研究边界声明:本篇对 [S1] - [S7] 的引用用于支持所述框架机制;自建 Runtime 的结构与工程建议是本文的参考设计,并非任何框架官方推荐的唯一实现。配套 03-Agent-Implementation-v2.0.zip 测试结果只覆盖本地模拟路径(12 项 OK);真实 API、生产权限与恢复能力仍待验证。