Skip to content

总体架构解剖

这是全站的枢纽页。前面三篇导读回答了「Harness 是什么」「为什么它重要」「它从哪来」,这一页做一件更具体的事:把一个生产级 Agent Harness 拆成一张可以指认的架构图,说清楚每个组件管什么、最难的设计问题是什么、和邻居之间用什么接口对话。

读完这一页,你应该能拿着任意一个 agent 产品(Claude Code、Cursor、Devin……)往这张图上一摆,说出它的设计重心落在哪个格子里。

阅读姿势

如果你还没读过 什么是 Agent Harness,建议先读那一篇建立直觉;如果你已经认同「Harness 决定 agent 能力上限」这个判断(论证见 模型 vs 骨架),直接往下读即可。

一张总图

一个 Agent Harness 可以分成四层:用户层、Harness 层、模型层、环境层。模型只做一件事——给定输入生成输出;其余所有事情都发生在 Harness 层。

text
┌─────────────────────────────────────────────────────────────────┐
│ 用户层   任务下达 · 中途反馈 · 权限审批 · 打断纠偏                 │
└──────────────────────────────┬──────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ Harness 层(本站拆解的全部对象)                                  │
│                                                                 │
│   ┌──────────── 智能体循环(agent loop,系统的跳动心脏)────────┐ │
│   │                                                           │ │
│   │   组装上下文 ─▶ 调用模型 ─▶ 解析动作 ─▶ 执行 ─▶ 观察回灌   │ │
│   │       ▲                                            │      │ │
│   │       └────────────────────────────────────────────┘      │ │
│   │            直到:任务完成 / 求助人类 / 触发熔断            │ │
│   └───────────────────────────────────────────────────────────┘ │
│                                                                 │
│   循环内组件   上下文工程 · 工具系统 · 规划分解 · 记忆系统        │
│   扩展组件     子代理编排 · 技能注入                             │
│   横切组件     权限安全 · 评测观测(每一轮循环都穿过它们)        │
└──────────────────────────────┬──────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ 模型层   LLM:系统里唯一的"思考者"                               │
│          它每一步看到什么、输出往哪去,全部由 Harness 决定        │
└──────────────────────────────┬──────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ 环境层   文件系统 · 终端 · 浏览器 · 外部 API · 代码仓库            │
│          工具执行真正作用的地方,观察结果的来源                   │
└─────────────────────────────────────────────────────────────────┘

读这张图时记住三句话:

  1. 循环是主干,组件是挂在循环上的器官。 上下文工程决定「组装上下文」这一步产出什么;工具系统决定「执行」这一步能做什么;权限系统在每个动作执行前横插一脚。
  2. 模型层的输入输出完全被 Harness 中介。 模型从不直接「看到」环境——它看到的是上下文工程组装出来的环境表征;它的「动作」也从不直接生效——要经过解析、权限检查和工具运行时。这就是 harness(挽具)这个词的字面含义。
  3. 用户不是只在开头出现。 审批、打断、中途反馈都是循环内的正常事件,而不是异常。Anthropic 在《Building effective agents》(2024 年 12 月)里把 agent 定义为「LLM 动态指挥自己的流程和工具使用、自主掌控任务完成方式」的系统——但即便是他们自家产品,也把人类检查点(human checkpoint)列为标准实践。

组件逐个解剖

下面九个小节,每个对应站内一个组件页。统一的描述格式是:职责 → 关键设计问题 → 与相邻组件的接口

智能体循环(Agent Loop)

职责: 系统的主控制流。决定何时调用模型、如何解析输出、动作按什么顺序执行、什么时候停下来。它是 Harness 里唯一「永远在跑」的部分,其余组件都是被它在特定时点调用的。

关键设计问题:

  • 单轮循环里允许模型输出几个动作?(串行一个,还是并行一批——直接影响延迟和一致性)
  • 终止条件怎么定义?模型自报完成之外,要不要外部验证(跑测试、检查 diff)?
  • 循环的异常路径:模型输出格式错误重试几次?死循环怎么熔断?成本超限怎么办?

与相邻组件的接口: 向上从用户层接任务和打断信号;向「上下文工程」要每一轮的模型输入;向「工具系统」递交解析出的动作;向「权限安全」请示高危操作;向「评测观测」暴露每一步的结构化事件。

→ 详见 智能体循环(Agent Loop)

上下文工程(Context Engineering)

职责: 每一轮循环开始时,决定模型这一次「看到什么」——系统提示词、对话历史、工具结果、检索到的代码、记忆片段、技能说明,按什么结构、什么顺序、什么篇幅拼进有限的上下文窗口。这是 2024 年以来业界公认杠杆最大的组件:模型是固定的,输入是你可以完全控制的。

关键设计问题:

  • 上下文预算是多少?超出后是截断、摘要压缩,还是卸载到外部存储按需取回?
  • 工具结果要不要做降噪?(一次 grep 可能返回几千行)
  • 哪些信息放系统提示词(稳定、可缓存),哪些放对话流(动态)?缓存命中直接决定成本和首 token 延迟。

与相邻组件的接口: 输入来自「记忆系统」(取什么)、「技能注入」(挂什么)、「工具系统」(刚返回的观察)、「规划」(当前计划状态);输出只有一个——交给循环传给 LLM 的那份消息列表。

→ 详见 上下文工程

工具系统(Tools & MCP)

职责: 定义模型能对环境做什么:工具清单、每个工具的 schema 和描述、执行运行时(沙箱、超时、资源限制)、结果的序列化格式。工具描述本身就是给模型读的文档,写法好坏直接改变模型行为。

关键设计问题:

  • 给通用工具(bash、文件读写)还是领域专用工具(apply_patchsearch_symbol)?SWE-agent 的论文(NeurIPS 2024)把这个问题命名为**智能体-计算机接口(agent-computer interface, ACI)**设计,并证明同一模型仅因接口设计不同,在 SWE-bench 上从 3.8% 跳到 12.5% pass@1。
  • 工具粒度:一个大而全的 edit_file,还是一组小工具?粒度影响模型的选择困难和错误恢复成本。
  • 要不要接入 MCP(Model Context Protocol)这类标准化协议,换取工具生态?

与相邻组件的接口: schema 交给「上下文工程」拼进提示词;执行请求来自循环;执行前过「权限安全」;执行结果经降噪后回流上下文;调用日志全部进入「评测观测」。

→ 详见 工具系统与 MCP

规划与任务分解(Planning)

职责: 把「做不完一整轮的大任务」变成可追踪的步骤序列。形态跨度很大:从让模型在思考中自由规划(ReAct 式,Yao et al., ICLR 2023),到显式的 TODO 列表工具,再到独立的规划器-执行器(planner-executor)分层架构。

关键设计问题:

  • 显式还是隐式?显式计划可检查、可纠偏、可展示给用户,但多一层开销,且计划会随环境反馈过期——多久重规划一次?
  • 计划存放在哪?放上下文里(模型每轮可见但占预算)还是放外部状态里(需主动注入提醒)?
  • 谁来验证计划进度——模型自评,还是循环用确定性检查(测试通过数、子任务勾选数)?

与相邻组件的接口: 计划状态是「上下文工程」的重要输入源;分解出的子任务可能派发給「子代理」;计划的持久化交给「记忆系统」。

→ 详见 规划与任务分解

记忆系统(Memory)

职责: 对抗上下文窗口的有涯。分两个时间尺度:会话内——历史太长时如何压缩、摘要、筛选;跨会话——用户偏好、项目约定、踩过的坑,以什么形式存下来、下次如何被想起来。

关键设计问题:

  • 写入时机:每条都记(噪音爆炸)还是显式触发(模型或用户决定「这值得记」)?
  • 召回方式:全量注入、关键词匹配、向量检索,还是让模型用工具主动查?召回错了比不召回更糟——过时记忆会稳定地误导模型。
  • 记忆谁可写?模型自动写入的记忆文件是一种需要审计的攻击面。

与相邻组件的接口: 读侧挂在「上下文工程」的组装流水线上;写侧通常暴露为「工具系统」里的一个工具;持久化内容属于「权限安全」的审计范围。

→ 详见 记忆系统

子代理与多智能体编排(Subagents)

职责: 把任务的一部分连同一个干净的上下文一起委派出去。子代理最重要的价值不是「 parallelism(并行)」,而是上下文隔离——主代理的上下文不被几十次试探性搜索污染,只收到提炼后的结论。

关键设计问题:

  • 委派边界:什么任务值得拆出去?拆出去的通信成本(任务描述必须自包含)经常大于收益。
  • 子代理和主代理共享什么?工具集、文件系统、记忆——共享越多越省事,隔离越多越安全。
  • 层级深度:允许子代理再派生子代理吗?失控的递归委派是成本和延迟的黑洞。

与相邻组件的接口: 子任务是「规划」的输出;每个子代理内部跑一个完整的「智能体循环」,有自己的「上下文工程」和受限的「工具系统」「权限」配置;返回结果是主代理上下文里的一条观察。

→ 详见 子代理与多智能体编排

权限、安全与人类在环(Permissions & Safety)

职责: 在每个动作真正生效之前回答「这允许吗」。包括:工具分级(只读 / 可逆写 / 不可逆写 / 对外副作用)、审批交互(每次问 / 记住选择 / 预授权规则)、沙箱隔离,以及把「何时停下来问人」变成一等公民的协议。

关键设计问题:

  • 权限模型的表达力:按工具一刀切,还是按「工具 × 参数模式 × 目标路径」细粒度匹配?bash rm -rf /bash ls 不该同级。
  • 审批疲劳:问得太多用户会无脑全点同意——如何用规则、白名单和风险分级减少打扰次数,是安全组件里少数纯 UX 的难题。
  • 自主性和可逆性的换算关系:操作越不可逆(发邮件、推代码、删数据),需要的人类确认越重。

与相邻组件的接口: 卡在循环的「执行」环节和「工具系统」之间;审批请求上行到用户层;所有放行/拒绝记录进「评测观测」;对「子代理」施加比主代理更严格的默认策略。

→ 详见 权限、安全与人类在环

技能与知识注入(Skills)

职责: 让通用 agent 按需获得领域专长——把「怎么做某类事」的说明书(流程、模板、脚本、检查清单)打包成可发现、可挂载的单元,在相关任务出现时注入上下文,而不是把所有知识永久塞进系统提示词。

关键设计问题:

  • 发现机制:模型怎么知道「现在该加载这个技能」?靠名称描述的自检索、关键词触发,还是路由模型?
  • 渐进披露(progressive disclosure):先给一句摘要,需要时再读全文,需要时再跑附带脚本——每深入一层才花一层的上下文。
  • 技能和普通文档、系统提示词、工具的边界在哪?(经验法则:技能 = 教模型「过程性知识」,工具 = 给模型「能力」,记忆 = 记住「事实」。)

与相邻组件的接口: 注入的内容经「上下文工程」进入提示词;技能可以声明自己需要哪些「工具」;技能包本身是「权限」意义上的供应链(第三方技能要审计)。

→ 详见 技能与知识注入

评测与可观测性(Observability & Evals)

职责: 回答两个层次的问题。运行时的可观测性:每一步循环的输入输出、工具调用、token 消耗、耗时,能否完整回放?离线的评测:改了 Harness 的任何一个组件,效果是变好还是变坏,用什么基准、什么指标判定?

关键设计问题:

  • 事件模型:把循环的每一步结构化成事件流(event stream)是现代 agent 框架的共同选择——OpenHands(前身 OpenDevin,平台论文)就把「动作 + 观察」的事件流作为整个架构的中心抽象,可观测性、回放、多代理协调全部建立在其上。
  • 评测归因:分数变化来自模型、提示词、工具还是环境抖动?没有逐组件的对照实验,Harness 迭代就是碰运气。
  • 成本观测:agent 任务的成本方差极大(同一个任务 5 轮和 50 轮都「完成」),不观测成本的评测是不完整的。

与相邻组件的接口: 它是纯消费方——订阅循环、工具、权限产生的所有事件;反过来,它的结论指导所有组件的迭代方向。

→ 详见 评测与可观测性

完整走一遍数据流

纸上得来终觉浅。用一个具体任务把整条链路走一遍:「给这个仓库的登录接口加上速率限制」

第 0 步 · 任务进入。 用户输入任务。Harness 做三件事:加载项目级约定(如 CLAUDE.md 之类的记忆文件)、匹配可能相关的技能、初始化权限会话。

第 1 步 · 组装第一轮上下文。 上下文工程产出:

text
system:    角色与行为准则 + 工具使用规范(稳定前缀,命中缓存)
context:   项目约定(记忆) + 速率限制最佳实践(技能,因关键词命中挂载)
user:      「给这个仓库的登录接口加上速率限制」
tools:     bash / read_file / edit_file / grep / todo_write 的 schema

第 2 步 · 第一次模型调用。 模型输出一个 tool call,而不是答案:

json
{ "tool": "grep", "args": { "pattern": "login", "path": "src/", "type": "py" } }

第 3 步 · 解析、鉴权、执行。 循环解析出动作 → 权限系统判断 grep 是只读操作,预授权放行 → 工具运行时执行,返回 47 个匹配。工具系统做降噪:截断到最相关的 10 条并保留文件路径清单。

第 4 步 · 观察回灌。 降噪后的结果作为一条 tool_result 消息追加进对话历史。此时上下文 = 初始上下文 + 第 2 步的工具调用 + 第 3 步的结果。注意:模型从未「看见」仓库,它看见的是 Harness 转译后的仓库。

第 5 步 · 循环继续。 模型读关键文件 → 调用 todo_write 写下三步计划(规划组件被激活)→ 读现有中间件代码 → 起草 edit_file

第 6 步 · 一次鉴权拦截。 edit_file 属于可逆写操作,按预设规则放行;但随后模型想跑 bash pytest 时命中了用户未预授权的模式,循环暂停,审批请求上行到用户层。用户点「允许本会话内的测试命令」——这条决定本身被权限系统记住,后续同类命令不再打扰。

第 7 步 · 验证驱动的收敛。 测试失败两轮(速率限制的计数器在并发下竞态),模型根据回灌的失败输出修正实现。第三轮测试通过。

第 8 步 · 终止与沉淀。 模型自报完成 + 循环的外部验证(测试全绿、diff 非空)确认 → 循环退出。收尾时:记忆系统把「这个项目用 pytest-xdist,测试命令要带 -n auto」写入项目记忆;评测观测组件记录本次会话共 23 轮循环、41k tokens、2 次用户审批。

text
用户任务


┌─ loop 第 n 轮 ──────────────────────────────────────────┐
│  上下文工程组装 prompt(记忆 + 技能 + 历史 + 工具结果)   │
│        │                                                │
│        ▼                                                │
│  LLM 输出:文本 or tool call                            │
│        │                                                │
│        ▼                                                │
│  权限检查 ──拒绝/需审批──▶ 用户 ──▶ 结果回灌             │
│        │ 放行                                           │
│        ▼                                                │
│  工具运行时执行(沙箱 · 超时 · 降噪)                     │
│        │                                                │
│        ▼                                                │
│  观察作为 tool_result 回灌上下文 ──▶ 进入第 n+1 轮       │
└──────────────────────────────────────────────────────────┘

   ▼  模型自报完成 ∧ 外部验证通过
记忆沉淀 · 事件归档 · 会话结束

工程上的关键认知

整条链路里,唯一不可控的环节是第 2 步的模型采样;其余每一步都是确定性代码。Harness 工程的本质,就是把所有能确定化的环节都确定化(鉴权、降噪、验证、熔断),让模型只在真正需要判断的地方做判断。

权衡与取舍

这张架构图里没有免费的设计决策。四组最核心的张力:

张力往左拉往右拉典型站位
自主 vs 可控更少审批、更长无人工循环每个写操作都要人确认按操作可逆性分级,而非全局一刀切
上下文丰富 vs 注意力稀释塞得越多,模型信息越全塞得越多,关键信号越淹没、成本越高激进降噪 + 按需取回(工具化检索)
通用工具 vs 专用接口一个 bash 走天下,迁移性强定制 ACI,错误少、轨迹短(SWE-agent 的教训)面向目标任务集做定制,保留逃生舱
单代理深钻 vs 多代理并行上下文连贯、无通信损耗上下文隔离、可并行探索默认单代理,只在上下文污染明确时委派

两条贯穿性的判断,展开论证见 Harness 设计原则

  • 简单优先。 Anthropic 在那篇被反复引用的文章里给出的第一条建议就是:先找最简单的方案,只在确有必要时增加复杂度——很多场景优化单次 LLM 调用(加检索、加示例)就够了,不需要 agent,更不需要多代理。
  • 每个组件都要能被观测、被单独替换。 把组件间接口设计成结构化数据(消息列表、事件流、工具 schema),而不是隐式约定——这是日后做归因评测和逐件迭代的前提。

按角色选路径

研究者

关心的问题是「哪些设计真正影响能力上限」。建议顺序:

  1. 模型 vs 骨架:为什么 Harness 决定上限 — 核心论点与证据
  2. 演进简史 — 从 ReAct 到今天的问题演化脉络
  3. 论文地图经典论文精读前沿进展
  4. SWE-agentOpenHands — ACI 与事件流两个研究味最浓的案例
  5. 评测与可观测性 — 做 agent 研究绕不开的实验方法论

工程师

关心的问题是「我要造一个,从哪开始、怎么避坑」。建议顺序:

  1. 本页 — 建立组件地图
  2. 智能体循环上下文工程工具系统与 MCP — 最小可用三件套
  3. 权限、安全与人类在环 — 上线前必读
  4. 从零构建一个最小 Harness — 动手把三件套跑起来
  5. 常见陷阱与反模式 + Claude Code 案例 — 对照一个成熟产品校准自己的取舍

产品经理

关心的问题是「能力边界在哪、体验差异从哪来、该怎么定需求」。建议顺序:

  1. 什么是 Agent Harness模型 vs 骨架
  2. 本页 — 重点读「权衡与取舍」一节
  3. Claude CodeCursorDevin — 三种产品形态背后的 Harness 取舍
  4. 规划与任务分解子代理 — 「 agent 到底能做多大的任务」这个问题的技术答案
  5. Harness 设计原则 — 和工程团队对话的共同语言

延伸阅读

参考资料