先约定一个最朴素的说法:本文中的 Agent,是“模型加上外层程序和工具”组成的工作系统。模型负责判断下一步,外层程序负责准备材料、执行真实动作并保存结果,工具则让它能够读文件、改代码和运行测试。
读完这篇,你应该能回答:模型需要知道什么?谁真正执行动作?为什么要重复多轮?一次运行结束后谁接手?谁确认工作已经完成?改动某一层后,又怎样证明系统真的变好?
资料说明:本文结合 OpenAI 与 Anthropic 的官方材料,以及 Codex 的固定源码快照。六类工程职责是学习和设计用的划分,并非每个产品都有六个独立模块。图与教学 JSON 表示建议设计;具体源码行为另行注明。运行结束、检查通过与任务交付是三个不同判断。
一、先沿一项任务建立完整直觉
1.1 跟着 Agent 完成一次任务
假设支付模块有一个测试失败了。我们给 Agent 的任务是:“找出原因,做最小修改,运行支付测试,并留下可审查的结果。”一条带有独立验收的目标路径是:
- 系统先把任务要求交给模型。
- 系统再准备失败日志、相关代码和项目规则,让模型看到当前事实。
- 模型判断应该先读取哪个文件,或者提出运行哪条测试命令。
- 外层程序检查这个动作是否存在、参数是否有效、权限是否允许,然后才真正执行。
- 文件内容或测试结果返回给模型,成为它判断下一步的新依据。
- 模型继续读取、修改和验证,直到完成,或者明确说明为什么不能继续。
- 最后由测试、静态检查或 reviewer 独立确认结果,而不是只相信模型说“修好了”。

1.2 给沿途的六类问题命名
AI Engineering 不是先背一组英文名词,而是反复解决六个普通问题。每个问题都来自刚才那条任务路径。
1.2.1 怎样把要求说清楚?
目标是什么、不能改什么、什么结果才算完成、最后怎样报告——把这些默认期待写成清楚的工作说明,就是本系列所说的 Prompt engineering。
1.2.2 这一步应该让模型看到什么?
调查时需要失败日志,修改时需要相关代码,验证时需要当前 diff 和最新测试输出。为模型的下一次判断挑选材料,就是 Context engineering。
1.2.3 模型提出的动作怎样真正发生?
模型说“运行测试”只是一项建议。负责检查参数和权限、隔离执行环境、运行工具、保存日志的外层软件,就是 runtime harness。
1.2.4 为什么 Agent 能做一步再看一步?
外层程序不断让模型判断、执行动作、接收结果,再决定继续或停止。一次运行里的这段反复过程叫 Agent Loop。
1.2.5 一次运行结束后,任务怎样继续?
任务可能因为时间、预算或等待人工而中断。负责保存进度、安排下一次运行、控制重试并防止重复工作的外层流程叫 Outer Loop。
1.2.6 谁来证明系统真的做对了?
测试、规则、模型评审或人工评审组成可重复的“考试”,用外部证据判断结果。这类机制统称 Evals。
如果只想建立入门地图,到这里已经掌握主线。后半篇把同一条故事换成工程设计语言,供需要评审系统边界、API 和故障归因的读者继续深入。
二、再把故事压缩成工程地图
2.1 把六类工作放回各自的时间尺度
把刚才的故事拉远看,会发现这些工作持续的时间并不相同:模型每次只判断一个下一步;读取、修改和测试会在一次运行里往返多轮;同一张任务卡可能经历多次运行;Evals 还要比较多个任务和不同系统版本。
工程上常给这些尺度起名字:一次模型调用叫 inference;一次“模型判断—工具执行—结果返回”叫 tool cycle;从 Agent 启动到完成或中止叫一次 run;跨多个 run 仍然存在的任务卡叫 work item。下面的表只是把已经讲过的六类工作压缩到这些尺度里。

| 系统部分 | 它具体负责什么 | 主要时间尺度 | 典型失败 |
|---|---|---|---|
| Prompt | 写明模型的角色、目标、限制、指令优先级、输出格式和工具用法。 | 影响一次 inference 的行为 | 意图含糊、约束冲突、输出漂移 |
| Context | 某次模型调用实际可见、可依据的工作集。 | 每次 inference 重新装配 | 缺失、噪声、过期、位置失衡 |
| Runtime harness | 在模型之外准备请求、检查并执行工具、记录一次运行。 | 一次 run | 副作用失控、状态断裂、不可恢复 |
| Agent loop | 在一次运行内重复“推理—行动—观察”,直到满足退出条件。 | 一次 run(可含多次 inference) | 过早停止、空转、预算耗尽 |
| Outer loop | 跨运行执行触发、选工、验证、持久化、重试与升级。 | 多次 run | 重复劳动、丢状态、重试风暴 |
| Evals | 把结果质量变成可重复测量的真值与反馈机制。 | 系统生命周期 | 把“说完成了”误当成完成 |
这张表还有一个更重要的工程结论:它们不是互斥的岗位。一个人可以同时修改 prompt、context policy 和 harness;但评审改动时必须说清楚改的是哪一层,否则“效果变好”无法归因,回归也无法定位。
2.2 每一步由谁决定,结果保存在哪里
再沿七步故事问一次“谁说了算”:用户决定目标;运行时准备材料并检查工具请求;仓库和测试进程保存真实结果;持久化组件保存跨运行的进度;评估器判断检查结果是否通过。一项工作会经过多个负责方,所以模型很重要,却不能单独决定整个任务的状态。
2.2.1 用户目标先变成可验证的 done
“修一下测试”只给了方向,没有说清允许做什么。可以改生产代码还是只能改测试?必须跑哪些命令?网络是否可用?要把哪些结果交给 reviewer?Prompt 把这些要求写进工作说明;eval 再把其中可验证的要求变成机器或人工检查。两者围绕同一个目标,但承担不同工作。
2.2.2 运行时为下一次模型调用挑选材料
OpenAI 的官方 prompt engineering 指南把高层 instructions、消息角色、工具和输入都放在请求设计中讨论;Anthropic 的 context engineering 文章则强调,agent 每一步都会根据当前 context 决定下一次推理要带什么。一个便于思考的请求形状是:
{
"instructions": "Fix the failing payment test; do not change public APIs.",
"tools": ["read_file", "search", "apply_patch", "run_tests"],
"input": [
{ "type": "task", "text": "..." },
{ "type": "repo_facts", "ref": "selected working set" }
]
}仓库里可能保存了一万条事实,但只有被选择、序列化并放进当前请求的部分才属于本次 model-visible context。反过来,系统指令本身也占 context window;所以 prompt 是按职责切出的语义层,context 是按可见性切出的物理工作集,它们会重叠,却不能互换。
2.2.3 工具调用只是提案,Harness 才执行副作用
模型输出“运行测试”或一个 tool call,并没有让进程自动发生。Harness 根据具体工具校验参数与权限,选择执行环境,处理超时与取消、限制结果长度、记录事件,再把 observation 送回模型。审批与隔离是分别配置的控制:允许执行不代表没有沙箱,而没有审批提示也不能证明动作始终处于沙箱内。工具和配置决定实际经过哪些检查,第四篇会沿源码展开。
官方用法确实有宽窄差异。OpenAI 在 Harness engineering 一文里把 Codex harness 描述为核心 agent loop 和围绕它的工具/指令环境;Anthropic 在 Building and evaluating trustworthy agents 中更强调 instructions 与 guardrails 组成的 harness,在 Managed agents 又把 session、harness 和 sandbox 分开讨论。本系列采用较窄、方便设计评审的定义:runtime harness 是模型之外、单次运行之内的执行与控制面;loop 是其中驱动状态前进的控制流。
2.3 一次运行与长期任务处在不同层次
OpenAI 对 Codex agent loop 的公开拆解展示了一条单次运行主线:准备输入、调用模型、接收事件、执行工具、回填结果,直到模型完成或运行被中止。Anthropic 的 Building effective agents 也把 agent 概括为模型动态指导自己的过程和工具使用。这里说的是 inner loop。
在 Codex app-server 中,这个边界可以直接看到:turn/start 的成功响应带有 status: "inProgress",表示运行已经受理;它不是测试通过的收据。随后 run_turn 根据模型是否还需继续以及是否有待处理输入决定后续循环;没有这些工作时,还会经过可配置的 Stop hooks。这些条件控制一次 turn 的退出,并不自动证明支付测试和回归已经通过。
turn/start 成功 → inProgress:请求已受理
工具结果返回 → 模型继续判断:还在运行
turn/completed → 读取最终 status / error:本次运行结束
测试、回归、diff 范围检查通过 → 交付流程接受任务结果但生产系统还要回答另一组问题:谁触发下一次运行?从队列里选哪项工作?上次执行留下了什么可恢复状态?验证失败后是重试、换策略还是交给人?这组跨运行控制就是本系列所说的 outer loop。
| 问题 | Inner / Agent loop | Outer loop |
|---|---|---|
| 输入从哪里来 | 当前任务与 observation | 事件、计划、队列或人工触发 |
| 状态存多久 | 运行中的消息与工具结果;会话记录也可持久化 | 跨 run 的 work item、调度决策及可恢复进度 |
| 何时停止 | 完成、错误、预算或人工中止 | 目标达成、重试上限、时间窗或升级 |
| 主要风险 | 无限工具循环、错误 observation、过早 final | 重复触发、状态漂移、无人负责的失败 |
把两者揉成一个“loop”,常见后果是:inner loop 已经生成漂亮的完成报告,outer loop 却没有独立验证;或者 outer loop 不断把同一失败重新喂给 agent,却没有改变证据、策略或权限。重试只是重复,不等于学习。
三、用这张地图诊断真实系统
3.1 同一个失败,应该改哪一层
一个失败现象可能经过多个组件,但修复应该尽量落在最接近根因的地方。模型一直忽略固定约束,先查 prompt precedence;它不知道刚更新的接口,先查 context selection;它执行了越权命令,先查 harness 的权限检查;它找到正确修复却没有跑测试,查 loop termination;它声称测试通过而实际没有,查 evaluator 读取了什么结果。

3.1.1 只修改真正能控制问题的组件
- 若规则对所有任务都成立,把它放进稳定 instruction,而不是每次检索出来。
- 若事实会变化,让 context policy 选择最新事实,而不是把快照永久写进 prompt。
- 若动作可能造成副作用,用权限、沙箱和确定性校验控制,而不是请求模型“千万小心”。
- 若完成条件可执行,让 loop 或 evaluator 真的执行检查,而不是让模型自我报告。
- 若失败跨运行累积,把 checkpoint、重试预算和升级责任交给 outer loop。
3.2 回到真实 Coding Agent
这套地图不是悬在具体产品之上。本系列第二至五篇用 Codex 分别检查指令、上下文、工具控制与循环,第六篇用 Symphony 检查跨运行调度,第七篇用开源 Evals 检查样本、判分和记录。它们是不同项目的实现切片,不应拼成一个现成产品。本站其他源码文章还提供更深入的阅读入口:
| 工程问题 | 可以继续看的本站材料 | 观察重点 |
|---|---|---|
| 一次任务怎样进入模型—工具循环 | Codex 运行主线、Claude Code 运行主线 | 请求装配、事件流、tool result 回填 |
| 模型每轮实际看到什么 | Codex 上下文、Claude Code 上下文 | history、投影、压缩与持久化的区别 |
| 谁在执行前检查副作用 | Codex 权限与沙箱、Claude Code 权限 | 提案、校验、审批、执行、observation |
| 长任务怎样恢复 | Transcript 与恢复、Hermes 运行过程 | 持久化事实与下一轮可见工作集 |
源码能让抽象概念落地,但不能替代系统级定义。接下来的文章采用同一套资料规则:官方文档说明产品公开承诺的行为;涉及具体实现时,再用开源或公开镜像代码展示程序怎样做到;我们自己的图只解释两者之间的机制。
3.3 修改以后,用同一个任务和同一组检查重跑
定位根因只是开始。假设支付任务因为“测试结果没有进入下一轮 Context”而失败,团队修改了 Context selection。此时不能用一句“召回率更高”宣布完成;要在相同起点重跑任务,确认新测试结果确实进入模型请求、Agent 因此选择了正确下一步,并且其他任务没有退化。
- 先执行:固定任务起点、模型、工具、权限和预算,记录旧版结果与 trace。
- 再定位:根据日志、工具结果和评估结果判断是哪一部分导致失败,而不是凭直觉改 Prompt。
- 只改一个主要组件:例如 Context 选择策略,并写下预期会改变的可观察结果。
- 在可比较条件下重跑:检查目标失败是否消失、相邻能力是否回归、成本和延迟是否仍可接受。
- 最后才采用:验证通过说明候选可发布;灰度、回滚条件和采用权限仍由交付流程决定。
因此,AI Engineering 的完整动作不是“发现问题 → 加一条规则”,而是执行 → 观察 → 找到负责组件 → 修改 → 重跑 → 只保留通过检查的改进。最后一篇会把这套过程做成可重复的 Evals。
四、复盘:用六个问题重画完整系统
| 如果你正在决定…… | 先问…… | 主要修改位置 |
|---|---|---|
| 怎样让模型稳定遵循要求 | 目标、限制、指令优先级和输出格式是否明确? | Prompt |
| 这一轮该带哪些事实 | 哪些信息相关、最新、可信且值得占预算? | Context |
| 动作能不能安全发生 | 谁校验、谁授权、在哪里执行、如何恢复? | Harness |
| 一次运行怎样收敛 | observation 是否可靠,停止与预算条件是什么? | Agent loop |
| 多次运行怎样接力 | 触发、checkpoint、验证、重试与人工升级归谁? | Outer loop |
| 我们凭什么说系统变好了 | 结果真值、失败分类与回归集在哪里? | Evals |
所以,这个系列不是宣布 prompt engineering 已经过时,而是把它放回正确位置。下一篇从最靠近模型行为的表面开始:怎样把 Prompt 从一次性话术变成版本化的行为接口。
