人工智能理论知识 - 智能体
这一篇处理模型之外的系统层问题,包括上下文工程、Harness Engineering、检索增强生成(RAG)与智能体。前一篇讲的是模型本体及其训练和推理,这一篇转向“模型如何被放进真实系统里工作”:上下文如何组织,工具与知识库如何接入,验证闭环如何建立,以及多步推理与多智能体协作如何落地。
提示词工程(Prompt Engineering)最早强调的是“怎么写一句更有效的话”,关注点集中在措辞、顺序、示例和限制条件。随着大模型应用从单轮问答扩展到智能体(AI Agent)、RAG、多工具调用与长会话系统,工程重点逐渐转向上下文工程(Context Engineering):真正决定效果的,不再只是某一句提示词本身,而是系统提示、用户输入、示例、检索结果、对话历史、工具返回、结构化状态与输出约束如何被整体组织成一次模型调用。
因此,上下文工程可以看作比提示词工程更大的外层概念。提示词仍然重要,但它只是上下文中的一个组件;在生产系统里,更关键的问题通常是“哪些信息应该进入上下文、以什么顺序进入、保留多久、如何压缩、何时替换、如何约束输出”。这一变化反映的不是术语时尚,而是应用形态已经从“写一句 prompt”演进为“设计一套输入装配系统”。
上下文学习(In-context Learning)指模型在不更新参数的前提下,仅凭当前输入中的任务说明、示例与约束完成新任务。它依赖的是上下文中的条件信息,而不是额外微调。
零样本(Zero-shot)是在不给示例的情况下,直接通过任务描述让模型完成目标。例如“判断以下影评是正面还是负面,只输出标签”。它的优点是成本低、迁移快;缺点是任务边界一旦含糊,模型更容易自由发挥。
少样本(Few-shot)是在提示词中附带少量示例,让模型在当前上下文里归纳输入输出模式。它特别适合标签定义不够直观、格式要求严格或任务带有领域习惯的场景。示例的价值不只是“给答案”,更是显式定义任务边界、异常情况与输出风格。
一个可维护的提示词通常由若干功能块组合而成,而不是一段散乱文本。把这些块拆开,能够显著提高复用性、可调试性与一致性。
角色定位(Role)定义模型在本次任务中的身份与职责边界,例如“你是严谨的法律信息抽取器”或“你是面向儿童解释科学概念的讲解者”。它的作用是设定默认行为策略,而不是替代具体任务指令。
指令(Instruction)直接说明模型要完成什么任务,是提示词中最核心的控制块。好的指令应当明确目标、操作步骤、禁止事项与完成标准,避免把多个含糊目标混在同一层表达里。
上下文(Context)提供完成任务所需的背景信息,例如产品文档、会话历史、用户约束、检索片段或前一步工具返回。它回答的是“模型基于什么信息工作”,而不是“模型该怎么工作”。
输出格式(Output Format)规定结果应该长什么样,例如纯文本、项目符号、JSON、表格或固定字段。格式要求越明确,后续系统越容易解析、验证与链接到其它模块。
受众(Audience)决定解释深度、术语密度与默认背景知识。例如 ELI5(Explain Like I'm 5)指面向完全没有背景知识的读者,需要更浅白的表达;面向资深工程师时,则应保留专业术语、边界条件与实现细节。
语气(Tone)控制表达风格,例如正式、简洁、鼓励式、审慎式或客服式。它影响的是话语风格和风险表达方式,但不应改变事实本身或任务判断标准。
数据(Data)指与任务本身直接相关的材料,例如待分类文本、待总结文档、用户表单、日志片段、表格记录或检索回来的证据。很多提示词失败,根源在于真正决定任务结果的数据并没有进入上下文。
系统提示(System Prompt)是整个上下文的最高层行为约束,通常用于定义角色、原则、边界和长期稳定规则。它应该稳定、简短且高信号,承载通用策略,而不适合塞入频繁变化的任务细节。
多数大模型 API 是无状态(Stateless)的:模型在一次调用中只“看到”你发送的输入(Prompt),不会自动记住上一次调用的对话内容。因此对话应用通常需要把对话历史(Conversation History)连同当前用户输入一起发给模型。
这会带来两个直接后果:
- token 占用会随着历史增长而上升(直到触达上下文窗口上限)。
- 并非“发得越多越好”:冗余历史会稀释注意力、提高成本,并可能引入过时或冲突信息。
工程上常见的记忆(Memory)分层是:
- 短期记忆(Short-term Memory):保留最近 N 轮原文对话,确保局部连贯。
- 工作记忆(Working Memory):把对话状态压缩成结构化摘要,例如用户偏好、已确认事实与当前任务约束。
- 长期记忆(Long-term Memory):把历史片段写入外部存储(向量库/数据库),需要时检索回填。
工具调用上下文(Tool Context)指模型在调用搜索、数据库、代码执行器或业务 API 后得到的中间结果。它的关键不只是“把结果贴回模型”,而是把工具返回整理成模型真正可用的状态:保留必要字段、去掉噪声、标明来源与时间,并避免把原始日志整段塞进上下文。
渐进式披露(Progressive Disclosure)强调:不要在一开始把所有文档、规则、工具说明和历史对话一次性塞进上下文,而应只注入当前步骤真正需要的那一层信息。模型先看到最小可行上下文,只有当任务推进到下一层时,才继续展开更具体的约束、领域知识或执行细节。
这样做的原因不只是节省 token,更是为了保持推理质量。多组工程实践都观察到,上下文利用率一旦超过大约 40%,模型就可能从“聚焦求解”进入“信息过载”状态,开始出现幻觉、循环、格式错误或低质量实现。渐进式披露的目标,就是让 Agent 长时间停留在这个甜蜜区,而不是被无关材料拖进噪声区。
Token 预算(Token Budget)是把上下文窗口(Context Window)当作一种稀缺资源来管理:一次请求的输入 token 与输出 token 都要计入模型的最大长度限制,并直接影响延迟与成本。
经验做法是把 prompt 切成可控的几块:系统提示尽量短且稳定;对话历史只保留近期原文;把长期信息通过检索(Retrieval)按需注入。
压缩与摘要(Compression & Summarization)的核心不是把文本“变短”,而是把信息从逐字转录(Transcript)变成可被模型继续使用的状态(State)。常见策略:
- 滚动摘要(Rolling Summary):每轮对话后更新一段固定长度的当前状态。
- 层级摘要(Hierarchical Summarization):长文先分块总结,再总结摘要。
- 结构化记忆(Structured Memory):用 JSON 或表格保存关键字段(偏好、约束、已决策项),避免自然语言摘要漂移。
摘要要可验证:优先保留可操作事实(约束、数值、名称、决策),少写主观评价。
当最新一次对话依赖很久以前的信息时,最可靠的方法不是无限追加历史,而是检索增强:把历史切成片段并建立索引(向量索引、关键词索引、主题标签),在每次请求前先检索与当前问题最相关的片段,再把这些片段注入上下文。
在当前智能体开发里,最主流的组合通常是:滑动窗口 + 滚动摘要 + 向量检索(RAG)。早期的外部记忆网络(Memory Networks / Neural Turing Machine)更多是研究范式,工程落地上更常见的是向量数据库与检索管线。
JSON Schema 约束把“输出应该长什么样”前置为机器可验证的结构定义,例如字段名、字段类型、必填项、枚举值与嵌套关系。它的价值在于把格式控制从“模型尽量照做”提升到“系统可以检查对不对”,从而显著降低后处理复杂度。
函数调用(Function Calling)把模型输出从自由文本转成“选择哪个工具、填写哪些参数”的结构化决策。它的工作方式是让模型先生成一个可被程序消费的调用意图,再由外部系统负责权限校验、真实执行与结果回填。
这里讨论的高级提示词策略,指的是仅通过提示词设计改变模型求解过程,而不借助额外框架、搜索控制器或推理编排器。它们本质上仍属于上下文工程:通过改变输入结构,让模型在一次或少数几次调用中显式展开中间推理步骤。
思维链(Chain-of-Thought, CoT)的核心做法是:在提示词中明确要求模型先分步分析,再给出最终答案。例如,可以把任务写成“先列出关键事实,再逐步推理,最后只输出结论”。若任务本身较复杂,也可以在 few-shot 示例里直接展示“问题 ➡ 分步推理 ➡ 最终答案”的格式,让模型在上下文中模仿这种求解模式。
在纯提示词使用方式下,CoT 的关键不是一句固定咒语,而是把推理过程结构化地写进输出要求。例如,可以把输出格式限定为“步骤 1 / 步骤 2 / 结论”,或要求模型先检查条件、再排除候选、最后汇总结论。这样做通常有利于多步算术、条件判断、规则推导与长链依赖任务;但对简单任务、严格结构化输出任务或成本敏感场景,强行要求展开思维链反而会增加 token 开销与噪声。
思维树(Tree of Thoughts, ToT)可以看作思维链的分支化版本:提示词不只要求模型给出一条线性推理路径,而是要求它先生成多个候选思路,再比较这些思路,最后选择更优的一条继续展开。在不借助框架的前提下,这种策略仍可以通过提示词实现,例如要求模型“先给出三个可能方案,分别说明优缺点,再选择最合理的方案给出最终答案”。
纯提示词版 ToT 的本质,是把“分支生成 + 分支比较 + 继续展开”都压进一次或少数几次模型调用里。它适合开放式规划、方案比较、复杂写作提纲和策略搜索这类任务,因为这类任务往往不存在唯一直接路径。代价同样明显:提示词更长,输出更长,模型也更容易在分支之间漂移。因此,ToT 更适合高价值、需要比较多个候选方案的任务,而不适合作为所有请求的默认模式。
Harness Engineering(驾驭工程)研究的是:当模型推理与生成能力已经足够强时,决定 Agent 能否稳定完成复杂任务的,往往是模型外围的整套工作系统。Harness 指模型之外的所有代码、配置与执行逻辑——工具接口、状态管理、上下文装配、架构约束、验证机制、回滚策略与持续清理,全部属于这一层。裸模型只能接收输入、输出文本;只有当 Harness 为它提供状态、工具、约束和反馈回路后,它才能成为一个持续干活的 Agent。
目前 Harness Engineering 落地最广、讨论最充分的场景仍然是 Coding Agent,因此本章中的很多方法首先来自代码生成、调试、验证、跨会话交接和多 Agent 编排的工程实践。但它并不局限于写代码。凡是 Agent 需要长期持有状态、调用外部工具、在约束下执行任务、接受反馈并持续纠偏的场景,都可以应用同样的方法论,例如研究 Agent、数据分析 Agent、运维自动化 Agent、业务流程 Agent 以及多模态交互系统。随着 Agent 从“生成回答”走向“持续执行任务”,Harness Engineering 也会从 Coding Agent 的经验集合,扩展为更一般的 Agent 系统工程。
下文将沿着“为什么 Agent 会失效 ➡ 如何搭建控制面 ➡ 如何长期治理系统 ➡ 工程师角色如何变化”这条主线展开。
Prompt Engineering(提示词工程)、Context Engineering(上下文工程)与 Harness Engineering 构成了层层外扩的系统模型:前者决定如何表达任务,中间层决定模型能看到什么,最外层决定整个系统如何执行、纠偏与长期维持质量。
提示词工程回答的是“如何把任务说清楚”。它关注指令措辞、角色设定、Few-shot 示例、输出格式和推理引导,目标是在单次调用里把任务表达得足够明确,让模型更容易走向期望行为。
上下文工程回答的是“模型应该看到什么”。它关注记忆注入、检索回填、窗口压缩、状态摘要和工具返回整理,目标是控制输入信息的相关性与密度,使模型在有限上下文里获得完成当前任务所需的关键材料。
Harness Engineering 回答的是“模型在什么系统里工作”。它处理的不再只是输入文本,而是工具接口、状态持久化、架构边界、验证回路、错误恢复、执行顺序与持续清理。到了这一层,关注点已经从“如何让模型回答得更好”转向“如何让 Agent 在真实系统中稳定完成工作”。
Harness 并不等同于某一句系统提示,也不等同于某个框架的名称。框架(Framework)、运行时(Runtime)和工具链都可以参与实现 Harness,但 Harness 这个词强调的是模型外围整套工作系统,而不是其中任何一个单独组件。
从系统设计视角,一个可用的 harness 通常由五类承重件组成:上下文管理(Context Management)、工具编排(Tool Orchestration)、安全护栏(Safety Guardrails)、反馈回路(Feedback Loops)与可读性/可观测性(Legibility / Observability)。前两者解决“Agent 知道什么、能做什么”,中间两者解决“何时纠偏、如何避免越界”,最后一类解决“系统当前到底发生了什么”。
上下文管理决定 Agent 在每一步究竟能看到什么信息。它的目标不是堆砌更多材料,而是把系统提示、短期记忆、长期知识、工具返回和任务状态按层组织,让模型始终工作在信息足够但不过载的区间。
工具编排决定 Agent 能做什么,以及如何把动作接回推理链路。搜索、数据库、代码执行器、浏览器自动化和业务 API 只有在权限、输入输出格式、调用顺序与结果回填都被设计清楚后,才会从“外挂能力”变成稳定的执行系统。
安全护栏负责限制 Agent 的越界空间。它包括写权限边界、架构约束、审批节点、沙箱、敏感操作限制与结构化状态约束,作用是把“模型可能做错事”转化为“系统不允许它在关键位置随意犯错”。
反馈回路负责告诉 Agent 当前结果究竟对不对。测试、lint、evaluator、Sprint Contract、健康检查和人工验收都属于这一层。没有反馈回路,Agent 只能凭语言流畅性误判成功;有了反馈回路,系统才能把错误重新送回执行链路中修复。
可读性与可观测性负责让 Agent 看见系统真实状态。UI、日志、指标、追踪、截图、DOM 快照和运行时事件,都是 Agent 判断“系统发生了什么”的依据。若系统对 Agent 不可见,很多问题即使存在,也只能靠盲目试错去碰。
Harness 的成熟度,本质上就是这五类控制面被工程化到什么程度。后文的各个部分,基本都可以看作对这五类支柱的展开:先看 Agent 为什么会系统性失效,再分别讨论上下文、编排、知识、约束、可读性、验证与熵控制如何把这些失效压回系统边界之内。
长运行 Agent(Long-Running Agent)必须跨多个上下文窗口持续工作,每个新会话在启动时对前一会话发生的事情没有任何记忆。即使使用最强的前沿模型,如果只给一个高级别的提示词,Agent 也无法稳定构建出生产质量的复杂系统。实践观察到四类典型失效:
- 过早宣告完成(Premature Victory Declaration):在项目进行到一定阶段后,Agent 环视已完成的工作,宣告整个项目已经完成,忽略仍未实现的功能。
- 脏状态遗留(Dirty State Handoff):会话结束时遗留未修复的 bug 或未记录的进度,下一个会话必须先花大量 token 恢复工作环境,而不是推进新功能。
- 伪完成标记(False Completion):Agent 完成代码改动并运行单元测试或 curl 命令后,在没有进行端到端验证的情况下把功能标记为已完成,而该功能实际上并不能正常工作。
- 上下文焦虑(Context Anxiety):部分模型在上下文窗口填充到一定程度后,会主动收尾、提前结束任务——即便任务尚未完成,这种过早的"善后行为"会导致中途截断的工作状态。
这四类失效都不能靠"换一个更好的模型"自动解决。它们是系统性问题,需要 Harness 层面的工程设计来对抗。
Harness 是通过失败持续生长的控制层。一个重要的工程判断是:当 Agent 在某类任务上反复失败时,应先把失败当作 Harness 缺口的定位信号。失败可能意味着工具接口缺失、文档不可达、架构边界不清、状态交接不足,或验收标准仍停留在模糊自然语言层面。
因此,Harness Engineering 的关键动作是把失败外化成新的系统组件:增加脚本、补充文档、收紧 lint 规则、拆出更明确的 Contract、补上 evaluator 或可观测性接入。每次失败若都能回写为新的约束与支撑物,Agent 系统就会逐步从“靠经验驱动”演化为“靠机制驱动”。
上下文焦虑(Context Anxiety)是指模型在感知到上下文窗口即将耗尽时,主动把任务包装成"已完成"状态——即便还有大量工作未做。Anthropic 在 Claude Sonnet 4.5 上观察到这一现象尤为明显。
应对上下文耗尽有两种互相对立的策略:
| 策略 | 机制 | 保留连续性 | 消除上下文焦虑 | 代价 |
| 压缩(Compaction) | 将早期对话摘要替换原文,同一 Agent 继续运行 | 是 | 否(焦虑可能持续) | 摘要信息损失 |
| 重置(Context Reset) | 清空上下文,新 Agent 从结构化交接物(Handoff Artifact)重启 | 否(全新起点) | 是 | 需要构造高质量交接物;增加编排复杂度与延迟 |
对于 Sonnet 4.5,仅靠 Compaction 不足以支撑长任务,Context Reset 成为 Harness 设计的必要组件。随着 Opus 4.6 的推出,其长上下文检索能力显著提升、上下文焦虑基本消除,Context Reset 可以从 Harness 中移除——这正是 Harness 组件应随模型能力动态调整的典型示例。
一个很有价值的经验规律是:上下文窗口并不是“越满越好”。多组实践都观察到,随着无关文档、工具说明和历史对话不断堆积,Agent 的推理质量会先升后降。工程上可以把这理解为上下文利用率的“甜蜜区间”:模型需要足够信息才能稳定工作,但一旦被冗余材料淹没,就会出现幻觉、循环、格式错误或低质量实现。Harness 的任务不是把更多 token 塞进去,而是让 Agent 在任意时刻只看到当前步骤真正需要的信息。
长运行 Agent 在会话之间传递状态,不能依赖模型的内部记忆,必须依靠外化的持久化制品(Persistent Artifacts)。实践中形成了一套固定的状态传递套件:
- 进度文件(Progress File):纯文本日志,记录每个会话完成了什么、遇到了什么问题、下一步是什么。每个会话开始时读取,结束时更新。
- 功能列表文件(Feature List):结构化的功能需求清单,初始全部标记为未完成,Agent 逐项实现并通过测试后方可标记通过。使用 JSON 而非 Markdown——实验发现模型不当覆写或修改 JSON 文件的概率远低于 Markdown 文件。
- 启动脚本(init.sh):由初始化代理预先写好的环境恢复入口,负责安装依赖、启动必要服务并打印访问入口。后续 fresh session 不再重新猜测项目如何运行,而是把它作为标准恢复脚本,在需要时检查并调用。
- Git 历史:每个会话以描述性的 commit message 结束。Git 历史既是进度时间线,也是恢复机制——Agent 可以通过 git revert 从错误改动中恢复。
这套设计借鉴的是人类软件工程师的轮班交接实践:进度文件对应交班笔记,git commit 对应有记录的工作移交,init.sh 对应标准化的环境搭建步骤,功能列表对应待办看板。
当单个 Agent 已经能够跨会话持续推进后,下一个问题就不再是“如何记住过去”,而是“如何把复杂任务拆给更合适的执行者”。这正是多 Agent 架构出现的背景。
让单个 Agent 对自己的输出进行评估会产生自评偏差(Self-Evaluation Bias):即使输出质量明显一般,模型也倾向于给出积极评价。这一问题在主观任务上尤为突出,在可验证任务上同样存在。
一个有效的应对结构来自生成对抗网络(Generative Adversarial Network, GAN)的启发:将生成者和评估者分离成两个独立 Agent。
|
1 2 3 |
[Generator Agent] ←── feedback ──[Evaluator Agent] │ │ └──────── output artifact ────────┘ |
关键发现:调教一个独立的评估者使其保持怀疑态度,远比让生成者对自己的输出保持批判性更为可行。评估者仍然是 LLM,仍然有宽容倾向,但针对评估者进行专项提示调优的效果可以稳定收敛,而自评调优往往无效。
在 Generator–Evaluator 基础上增加一个 Planner Agent,构成完整的三 Agent 架构:
| Agent | 输入 | 输出 | 设计要点 |
| Planner | 1–4 句用户提示 | 完整产品规格书 | 只关注产品上下文与高层技术设计,不指定实现细节(过度具体的规格会将错误级联到下游);被提示在规格中寻找机会融入 AI 功能 |
| Generator | 产品规格 + Sprint Contract | 可运行代码 | 按 Sprint 增量构建(早期模型)或持续运行(强模型);完成 Sprint 后先自评,再交 Evaluator 审查;拥有版本控制权限 |
| Evaluator | 运行中的应用 + Sprint Contract 验收标准 | 通过/失败判定 + 具体可行的问题报告 | 通过 Playwright MCP 实际操作运行中的应用;设有硬性阈值,任一标准未达到则 Sprint 失败并返回修复 |
Agent 之间的通信完全基于文件:一个 Agent 写文件,另一个读文件并响应。这种方式简单、可追溯、不依赖框架内部状态。
对于需要跨多个上下文窗口持续工作的场景,一种实用模式是将第一次会话与后续会话用不同的提示驱动:
- 初始化 Agent(Initializer Agent):仅在第一个会话运行,负责构建整套脚手架:根据项目规格生成 init.sh、功能列表 JSON、初始 git commit 和进度文件,把“项目如何启动、功能如何追踪、状态如何恢复”一次性外化成可执行制品。
- 编码 Agent(Coding Agent):从第二个会话起运行,先读取进度文件、功能列表和最近的 git 历史,再按需调用 init.sh 恢复环境,每次只实现一个功能,并以"干净状态(Clean State)"结束会话。
两个"Agent"在技术上是同一套系统提示和工具集,区别仅在于初始用户提示不同——这是一种提示策略,而非架构分离。
这种设计的关键,不是简单多了一个 shell 脚本,而是把“如何把项目跑起来”从高 token 成本的推断问题,转成低成本、可重复、可审计的脚本执行问题。后续每个 fresh session 的标准启动序列因此可以稳定下来:先用 pwd 与最近的 git log 确认当前工作状态,读取进度文件和功能列表定位下一项任务,再检查并在需要时调用 init.sh 恢复依赖、服务和访问入口。模型不再反复猜测包管理器、启动顺序、端口和运行命令,上下文预算因此可以集中到真正的实现与验证上。
Sprint Contract 是 Generator 与 Evaluator 在任何代码被写下之前,对"这一阶段完成的标准"达成共识的协议制品:Generator 提出将要构建什么以及如何验证成功,Evaluator 审查并确认,双方迭代直到达成一致。其目的是弥合高层用户故事与可测试实现之间的鸿沟,防止模糊需求在实现阶段演变为争议。
任务拆分解决了“谁来做”,但还没有解决“知识从哪里来、如何保持最新”。一旦 Agent 工作跨越多个会话、多个角色和多个代码域,知识组织方式本身就会成为 Harness 的一部分。
“给 Agent 地图而非手册”讨论的是知识入口(Knowledge Entry Point)的设计原则:在大型、持续演化的代码库中,Agent 需要的是一套能够把它稳定引导到正确信息源的导航结构,而不是一份试图囊括所有细节的单体说明书。知识库工程的关键目标是让上下文可定位、可更新、可裁剪,而不是一次性塞满。
因此,这里的首要挑战是"如何让 Agent 在需要时找到正确信息"。"一个巨型 AGENTS.md 文件"的方案会失败,原因是多方面的:
- 上下文是稀缺资源。一个巨大的指令文件会挤占任务本身、代码和相关文档的空间,导致 Agent 要么遗漏关键约束,要么对错误的目标进行优化。
- 过多的指导等于没有指导。当所有内容都被标记为"重要"时,Agent 会退化成局部模式匹配,而不是有目的地导航。
- 单体文档会迅速腐烂。人类停止维护,Agent 无法分辨哪些规则仍然有效,文件变成一个充满过期规则的吸引力陷阱。
有效的替代方案是:AGENTS.md 充当目录(Table of Contents),而非百科全书。一份约 100 行的精简 AGENTS.md 作为上下文的入口,通过指针将 Agent 引导至结构化 docs/ 目录中的具体知识源。
AGENTS.md 还有一个更重要的角色:它不应是一次写完后长期冻结的静态文档,而应是失败驱动的活反馈循环。每当 Agent 因为命令使用错误、目录理解偏差、架构约束遗漏或工具接入方式不清而出错,最直接的修复方式往往就是把这类经验回写进 AGENTS.md 或其指向文档。这样,文档不再只是说明书,而是把历史失败压缩成未来会话可直接继承的系统记忆。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
AGENTS.md ← 约100行,地图角色 ARCHITECTURE.md docs/ ├── design-docs/ │ ├── index.md │ └── core-beliefs.md ├── exec-plans/ │ ├── active/ │ └── completed/ ├── generated/ │ └── db-schema.md ├── product-specs/ │ └── index.md ├── references/ │ ├── design-system-reference-llms.txt │ └── ... ├── DESIGN.md ├── FRONTEND.md ├── PLANS.md └── QUALITY_SCORE.md |
这种结构实现了渐进披露(Progressive Disclosure):Agent 从一个小而稳定的入口开始,被引导到它需要的具体知识,而不是在启动时被所有信息淹没。
当团队反复构建相似类型的系统时,Harness 不应只停留在单项目经验,而应上升为组织级的服务模板(Service Template)或黄金路径(Golden Path)。现实中的软件形态并不是无限多样的,常见项目通常集中在少数几类技术拓扑:前端应用、后端服务、数据流水线、内部工具。若能把每类拓扑常用的目录结构、启动脚本、验证流水线、可观测性接入、架构约束和 Agent 指令打包成模板,新项目就不必从零设计 Harness。
这类模板的价值不只是“脚手架复用”,更在于组织把高频工程判断沉淀成标准化控制面。团队成员在真实项目中学到的约束、回滚经验和验证方法,可以持续回流到模板;模板更新后,又会反过来提升后续所有项目的默认质量。Harness 一旦进入这个阶段,便不再只是某个工程师的个人技巧,而是组织级生产力资产。
从 Agent 的视角来看,任何它在运行时无法在上下文中访问的知识,实际上不存在。存在于 Google Docs、Slack 线程或人脑中的决策,对 Agent 来说与从未发生过没有区别。唯一对 Agent 有效的知识是代码库中版本化的制品:代码、Markdown、Schema、可执行计划。
这一约束倒逼团队把越来越多的上下文推入代码库:对齐团队架构决策的 Slack 讨论、产品原则、工程规范,都需要以 Agent 可读的形式在仓库中存在。这不仅是文档实践,更是系统设计约束。
知识库的有效性需要机械化强制执行,而不能依靠人工自律。专用的 linter 和 CI 任务验证知识库是否最新、交叉引用是否完整、结构是否正确。一个周期性运行的"文档园丁 Agent(doc-gardening agent)"扫描文档与实际代码行为之间的偏差,发现过期或不一致的内容后自动开启修复 Pull Request。
知识工程解决的是“找得到信息”,架构约束工程解决的是“即使知道该做什么,也不能随意乱做”。两者结合,Agent 才既有方向感,也有边界感。
Agent 在具有严格边界和可预测结构的环境中工作效果最好。在全 Agent 生成的代码库中,这一原则需要在工程层面提前落地:等到有数百名工程师时再引入架构规则,通常已经太晚了——而在 Agent 驱动的代码库中,混乱会以比人类团队快得多的速度蔓延。
一种行之有效的结构是分层领域架构(Layered Domain Architecture):每个业务域被划分为固定的层集合,依赖方向被严格验证,仅允许有限的跨层边。例如,在一个业务域内部,代码只能沿固定顺序向前依赖(Types → Config → Repo → Service → Runtime → UI);跨切面关注点(认证、连接器、遥测、特性标志)通过单一显式接口进入。其他所有依赖方向都被机械地禁止。
架构规则通过定制 linter 和结构测试强制执行,而不是依赖文档和代码审查中的人工判断。关键实践:
- linter 的错误信息被设计成直接包含修复指令,从而将约束违反转化为 Agent 可消费的上下文。
- 在对人类团队而言显得迂腐的细粒度规则,对 Agent 来说是乘数效应:一旦编码,立即在所有代码上生效,无需逐一审查。
- 约束划定边界,边界内部的实现方式允许 Agent 自由选择——这类似于大型平台工程组织的管理模式:集中强制边界,局部授权自治。
这套约束还包括"品味不变量(Taste Invariants)":结构化日志、Schema 与类型命名规范、文件大小限制、平台特定的可靠性要求。这些规则用静态分析强制执行,将人类工程师的审美判断固化成可机器检查的规则。
对 Agent 可以修改的内容施加精确的写权限,是防止状态腐蚀的重要手段。典型模式:功能列表文件中,Agent 只允许修改 passes 字段,不得删除或改写任何测试条目。这种狭义写权限用强措辞的指令约束来传达:"删除或编辑测试是不可接受的行为,这会导致功能遗漏或引入 bug。"
此外,在数据边界处解析数据形状(而不是 YOLO 式地推断数据结构),使用类型化 SDK 或 Schema 验证库,是保持 Agent 可以安全推理的代码库形态的基础约束。
边界清晰之后,系统仍然需要对 Agent “可见”。否则即使约束被写得很严,Agent 也只能在黑箱里试错,无法高效定位运行时问题。
Agent 可读性(Agent Legibility)指的是:系统的 UI、日志、状态和指标对 Agent 来说是否足够可见、可解析、可操作,从而使模型能够直接观察应用行为、复现问题并验证修复结果。它关注的是系统是否为推理提供了足够清晰的外部反馈面。
随着代码吞吐量提升,人工 QA 容量会成为瓶颈。此时,关键路径不再是增加人力,而是让应用自身的 UI、日志和指标对 Agent 直接可读,使 Agent 能够自主复现 bug、验证修复并对应用行为进行推理。
使应用对 Agent 可读的关键手段:
- 每个 git worktree 独立启动一个应用实例:Agent 可以针对自己的变更启动隔离的应用版本,互不干扰。
- Chrome DevTools Protocol(CDP)接入:将 CDP 接入 Agent 运行时,并封装操作 DOM 快照、截图和页面导航的技能,使 Agent 能够驱动浏览器、复现 bug 并验证修复,而不依赖人工截图传递。
- Playwright/Puppeteer MCP:在多 Agent 架构中,评估 Agent 使用浏览器自动化工具实际操作运行中的应用,而不是静态分析代码。这使得"应用看起来工作"与"应用实际可用"之间的差距得以被发现。需注意:浏览器原生弹窗(alert modal)对这类工具不可见,这是已知盲区。
将完整的可观测性栈暴露给 Agent,使其可以查询日志、指标和追踪数据,是将模糊性能目标转化为 Agent 可执行任务的关键。每个 worktree 配备临时的本地可观测性栈(完成后自动销毁),Agent 可通过 LogQL 查询日志、PromQL 查询指标、TraceQL 查询链路追踪。
有了这种接入能力,"确保服务启动在 800ms 以内完成"或"这四条关键用户路径中没有 span 超过两秒"这类提示就变得可执行——Agent 可以直接查询数据、定位问题根源并实施修复,而不需要人工解读日志然后描述问题。
不过,看得见系统状态还不等于能正确判断任务是否完成。可读性回答的是“发生了什么”,验证闭环回答的是“这样是否算成功”。
对于没有二元正确性检验的任务(如界面设计、用户体验),需要将主观判断转化为具体的、可评分的标准,才能构建有效的验证闭环。一套已验证有效的前端设计评分框架包含四个维度:
| 维度 | 评估内容 | 权重 |
| Design Quality(设计质量) | 配色、字体、布局、视觉意象是否融合为一个有清晰气质和独特身份的整体,而非各部分的简单堆砌 | 高 |
| Originality(原创性) | 设计决策是否经过定制,还是使用了模板布局、库默认值、AI 生成惯例模式(紫色渐变白色卡片、未经修改的 stock 组件) | 高 |
| Craft(工艺) | 字体层级、间距一致性、颜色对比度等技术执行质量 | 低(模型默认已做得较好) |
| Functionality(功能性) | 用户能否理解界面功能、找到主要操作、完成任务而无需猜测 | 低(模型默认已做得较好) |
重要发现:评估者提示中的措辞本身(如"最好的设计是博物馆级别的")会直接影响生成器的输出风格——不仅仅在评估反馈阶段生效,在第一次生成时就已经开始引导模型远离通用默认值。评估者需通过 Few-shot 示例加详细评分解析进行校准,以保持判断一致性并减少分数漂移。
单元测试和 curl 命令验证的是代码片段,而不是用户体验。端到端测试的原则是:像人类用户一样测试——通过浏览器自动化工具实际操作运行中的应用,才能发现"代码逻辑看似正确但功能整体不可用"的问题。
实施健康检查门控(Health-Check Gate):在每个会话开始时,Agent 必须先运行基础端到端功能测试,确认应用处于正常工作状态,再开始实现新功能。如果发现应用处于损坏状态,应先修复,否则新功能会在损坏的基础上叠加,问题会更难追溯。
干净状态(Clean State)的定义:每个会话结束时,代码库应处于可合并到主分支的状态——无重大 bug,代码有序且有文档,后续开发者(或 Agent)可以直接开始新功能,而无需先清理遗留的乱局。
Harness 案例里常见一个容易被忽略的盲点:系统也许已经很好地约束了内部质量,却未必充分验证了外部行为是否真的符合产品意图。目录结构、架构 lint、单元测试、Clean State 和持续回收都很重要,但这些机制首先保证的是内部一致性,而不是最终功能一定可用。
因此,成熟的 Harness 必须把功能验证(Functionality Verification)视为独立承重件,而不是默认附属物。真正可靠的系统需要对“用户是否真的能完成任务”建立单独的验证回路,例如任务级验收标准、浏览器自动化、独立评估 Agent、人工 spot check,或基于运行时信号的行为检查。能持续写代码只是起点;能持续验证行为,才是 Harness 真正闭环的标志。
即使单次任务已经具备了约束、可读性和验证,长期运行后的系统仍会累积漂移。Harness 因此不仅要管每一轮执行是否正确,还要管整个代码库是否在时间尺度上持续失真。
Agent 会复制代码库中已存在的模式——即使这些模式并不理想。随着时间推移,全 Agent 生成的代码库会发生不可避免的漂移:重复工具函数扩散、文档与代码行为不同步、架构规则被逐渐侵蚀。早期的应对方式是每周花费 20% 的团队时间手动清理,但这完全不可扩展。
有效的替代方案是将"黄金原则(Golden Principles)"直接编码进代码库,并建立周期性的自动化垃圾回收流程:
- 在代码库中明确记录有主见的、机械可检查的原则(如:优先使用共享工具包而非手写 helper;必须在边界处解析数据形状,不得基于猜测的结构构建逻辑)。
- 周期性运行后台 Agent 任务,扫描原则违反、更新质量评分、开启针对性重构 Pull Request。
- 大多数这类 PR 可以在一分钟内完成审查并自动合并。
技术债务与高息贷款相似:持续小额偿还几乎总是优于积累后集中清算。人类工程师的品味判断被捕获一次,随后在每一行代码上持续强制执行——这是 Agent 驱动开发模式下特有的杠杆效应。
但这些组件本身并不是一成不变的。任何垃圾回收策略、验证门控或多 Agent 编排,背后都隐含着对当前模型能力的判断;一旦模型变化,Harness 的承重结构也需要重新评估。
Harness 中的每一个组件都编码了一个假设:模型目前无法独立完成这件事,所以需要这层脚手架。这些假设有两个失效原因:
- 假设从一开始就是错的——模型其实能做到,但工程师没有测试验证就加了脚手架。
- 假设因模型能力提升而过时——昨天需要 Sprint 分解的任务,今天的模型可以持续完成而不失去连贯性。
因此,评估哪些 Harness 组件是真正的承重结构(Load-Bearing Components)——每当新模型发布时,剥除不再有效的部分,添加利用新能力的新部分——是 Harness 工程师持续的工作职责。
一个典型的演化轨迹:Claude Sonnet 4.5 需要 Context Reset + Sprint 分解 + 完整三 Agent 架构;Opus 4.5 在三 Agent 架构下表现更好,Sprint 结构依然必要;Opus 4.6 消除了上下文焦虑,Generator 可以持续运行超过两小时而无需 Sprint 分解,Evaluator 从"始终必要"变为"在任务超出模型原生能力时才有价值"。这套 Harness 对于 Sonnet 4.5 来说恰到好处,对于 Opus 4.6 来说则是过度设计。
一个重要的元原则:随着模型能力提升,有趣的 Harness 组合空间不会缩小,而是移动。工程师的工作不是等待模型强大到不需要 Harness,而是持续找到下一个新颖的组合。
一旦系统的主要难点从“写出代码”转移到“设计并维护这套控制面”,工程师的职责也会随之改变。
在 Harness Engineering 语境下,工程师的工作重心发生了系统性上移。原本直接产出代码的工作,转变为设计 Agent 工作的环境、指定意图与验收标准、构建使 Agent 能可靠工作的反馈闭环,以及将人类判断和品味持续编码进系统。
核心原则可以概括为一句话:Humans steer, agents execute。这意味着人类在更高的抽象层次上工作:确定优先级、将用户反馈转化为验收标准、验证结果。当 Agent 遇到障碍时,工程师更应追问"缺少什么能力?如何让这个需求变得对 Agent 可理解且可强制执行?"
随着代码吞吐量的提升,许多传统工程规范变得适得其反。PR 在高吞吐系统中应该是短命的;测试 flakiness 有时更适合通过后续补丁修复而非阻塞合并;纠错的成本极低,等待的成本极高。这与低吞吐人工团队的工作假设完全相反。
不过,这些方法目前验证得最充分的,仍然主要是绿地项目或受控实验环境。一旦进入历史包袱深重的老系统,Harness 的建设顺序与成本结构都会发生变化。
当前公开的成功 Harness 案例大多发生在绿地项目、受控实验或可以从零搭脚手架的环境中。真正更难的问题,是如何把 Harness Engineering 引入一个已经运行多年、缺少架构边界、测试质量不稳定、文档残缺且历史包袱沉重的棕地代码库。这里最大的风险不是 Agent 不会写代码,而是现有系统本身已经缺乏足够清晰的控制面,Agent 一旦接手,只会更快复制并放大原有混乱。
因此,棕地改造不能照搬绿地模板,通常需要渐进式引入:先补最关键的边界约束,再建立最小可用的知识入口、验证门控和可观测性接入,最后才考虑多 Agent 编排或更高自治级别。换言之,Harness 在棕地场景里的首要任务不是提升速度,而是先把代码库变成一个对 Agent 可理解、可约束、可验证的环境。
OpenAI Codex 内部实验(2026 年 2 月):三名工程师在约五个月内,通过零人工手写代码的流程,构建了一个拥有内部日常用户和外部 alpha 测试用户的内部 beta 产品。代码库规模约一百万行,覆盖应用逻辑、测试、CI 配置、文档、可观测性和内部工具。约 1500 个 PR 被合并,平均吞吐为每名工程师每天 3.5 个 PR,且随团队扩张吞吐还在提升。核心投入集中在:精简的 AGENTS.md 目录结构、分层领域架构 + 机械化 linter、应用 + 可观测性对 Agent 的完整可读性、黄金原则与周期性垃圾回收 Agent。
Anthropic 复古游戏编辑器对比实验(2026 年):使用 Claude Opus 4.5,对同一个 prompt "构建一个 2D 复古游戏制作工具"进行两种模式的比较。单 Agent 单次运行:20 分钟,花费 9 美元,结果是布局浪费空间、核心玩法无法运行。完整三 Agent Harness(Planner + Generator + Evaluator,含 Sprint Contract):6 小时,花费 200 美元,结果是 Planner 将一句 prompt 扩展为横跨 10 个 Sprint 的 16 项功能规格,游戏核心机制正常运行,并额外实现了精灵动画、AI 辅助关卡设计等超出原始 prompt 的功能。成本约为单次运行的 22 倍,但输出质量远超。
Anthropic 浏览器 DAW 实验(2026 年):使用 Claude Opus 4.6(已移除 Sprint 分解),通过 prompt "构建一个基于 Web Audio API 的全功能浏览器 DAW",三轮构建 + QA 循环总计 3 小时 50 分钟,花费 124.70 美元。最终产物包含可用的编排视图、混音台和传输控制;内置 AI Agent 可通过自然语言提示设置节拍/调性、演奏旋律、建立鼓轨、调节混音和添加混响,完成一段完整的短曲创作。
检索增强生成(Retrieval-Augmented Generation, RAG)把“外部知识”通过检索在推理时注入到上下文里:先检索,再生成。它解决的不是模型能力问题,而是信息可得性与可控性问题:把知识放在可更新的外部存储里,而不是指望模型参数记住一切。
真正落地到生产后,RAG 很快会从“模型 + 向量库”的玩具结构,变成一套完整的知识处理系统。一个更接近现实的抽象是:知识源接入、文档获取、分块、增强、索引、召回、融合、重排、上下文回拼、生成。其中任何一步做得粗糙,最终回答质量都会明显退化。
从工程视角看,RAG 的核心是把知识库建成一个可持续演化的外部记忆系统,而不是简单把文本切块后丢进向量数据库。这里通常至少会区分三层对象:知识库(Base)负责来源配置、召回策略与索引策略;文档(Document)负责内容文件、语言、状态与分块配置;块(Chunk)负责可检索的最小语义单元及其摘要、问题、向量、命中统计等元数据。再往上,很多系统还会加一个目录(Catalog)层,把知识按业务树、产品线、权限域或租户边界组织起来。这种分层的意义在于:RAG 检索的不是“一个文本文件夹”,而是一个带治理、带生命周期、带配置继承的知识对象系统。
一个成熟的知识库系统通常会显式区分知识源(Source)与检索目标(Target)。知识源回答“内容从哪里来”,例如上传文件、网页抓取、代码仓库、目录扫描;检索目标回答“内容最终由谁提供召回能力”,可以是系统自建索引,也可以是外部知识平台。这样设计的好处是把“接入来源”与“服务出口”解耦:同一套文档采集和治理流程,可以接到不同的检索后端,而不用把采集逻辑和向量库实现绑死。
另一个关键决策是把知识处理做成异步流水线,而不是同步上传即就绪。现实中的知识库往往需要经历扫描、下载、解析、分块、摘要生成、问题生成、向量化、索引构建等多个阶段。把这些阶段拆开,一方面是因为它们耗时、依赖不同资源且失败模式不同;另一方面是为了支持恢复、重试、并发控制与增量更新。于是,生产 RAG 往往天然带有一个状态机:知识库有自己的状态,文档有自己的状态,块也有自己的状态。这个状态机的作用是把长链路处理过程显式化,使每个阶段都能被观察、重跑和局部修复。
教程中的“上传文档 ➡ embedding ➡ 检索 ➡ 回答”只覆盖了最小闭环。真实系统里的知识库会持续新增、修改、下线、重建索引,并不断调整切分方式和召回参数。因此,RAG 更接近“搜索系统 + 知识处理中台 + 生成模型”的组合,而不是一次性的离线脚本。
分块(Chunking)决定了“检索的最小单位”。块太大:召回相关信息但携带大量噪声;块太小:召回片段零散,缺上下文导致生成不稳。分块应与文档结构、问题类型、上下文窗口预算一起设计。
固定大小分块(Fixed-size Chunking)按 token/字符数切片,简单稳定,适合结构较弱的纯文本与大规模离线构建。常配合重叠窗口(Overlap)避免跨边界信息断裂。
语义分块(Semantic Chunking)用段落/标题/语义边界切分,目标是让一个 chunk 自洽(Self-contained)。它通常更适合技术文档与带层级结构的内容,但需要更复杂的解析与规则。
递归分块(Recursive Chunking)先按大结构切(章节/标题),再对子块继续切(段落/句子/固定大小),兼顾结构与长度约束,是很多工程实现的折中方案。
生产系统里的分块通常远比这三类更细。除了固定大小、递归和语义切分,还会按 Markdown、HTML、PDF、代码、表格、JSON、LaTeX、句子、段落、滑动窗口等内容类型选择不同 chunker。这背后的设计判断非常重要:分块不是一个通用算法参数,而是内容理解策略的一部分。代码和 API 文档更适合按语法结构或标题层级切;表格和 PDF 更需要保留版面边界;Markdown/HTML 则需要保留层次结构,甚至形成父子 chunk 树。
这类设计会直接改变召回质量。若把所有内容都按固定长度切块,标题、层级、页面边界、代码块和表格结构都会被抹平;若系统保存 chunk 的父子关系、边界分隔符、正文起止位置、重叠前后文与结构元数据,那么检索命中的就不再只是孤立片段,而是文档结构中的一个明确位置。此时的 RAG 更接近结构化文档检索。
Agentic Chunking 进一步把 LLM 引入切分阶段,由模型判断哪些内容应属于同一语义单元。它在复杂文档上可能带来更强的语义完整性,但代价同样明显:构建成本高、可重复性差、调试难度大,提示词质量会直接影响索引结果。因此它更适合作为高价值内容的增强型切分,而不适合作为默认的全量基础设施。
向量数据库(Vector Database)存储每个 chunk 的向量表示(Embedding Vector)及其元数据(Metadata),支持近似最近邻(Approximate Nearest Neighbor, ANN)检索。向量并不“包含全文”,它是语义相似度的索引键;检索结果仍然需要回源拿到原文片段。
工程上需要区分“向量索引(Vector Index)”与“向量数据库(Vector Database)”:前者强调 ANN 检索算法与数据结构;后者强调持久化、增量更新、元数据过滤(Metadata Filtering)、分片/副本与多租户(Multi-tenancy)等系统能力。
生产知识库通常会同时维护多个索引平面:chunk 正文索引、chunk 摘要索引、chunk 问题索引,必要时还有文档摘要索引。它们对应的是不同的检索语义:正文索引擅长直接召回原文;摘要索引更适合长文压缩后的主题级匹配;问题索引则把 chunk 改写成更贴近用户查询的可检索意图。因此,生产 RAG 的索引设计本质上是“同一内容的多种检索视图”。
双后端架构也是常见现实。高质量知识库常把 Milvus/Qdrant 一类向量系统与 Elasticsearch/OpenSearch 一类全文检索系统并行使用:前者负责稠密向量、稀疏向量与 ANN 检索,后者负责 BM25、字段过滤和业务搜索。这种组合对应的是信号分工:向量擅长语义匹配,词项系统擅长精确关键词与过滤。真正的难点随之转移到一致性和融合上:索引命名要对齐,更新要同步,删除要清理,跨系统分数不能直接比较。
向量检索组件通常有三种部署形态:向量索引库(如 FAISS/ScaNN)偏“库”;向量数据库(如 Milvus/Qdrant/Weaviate)偏“服务”;全文检索引擎(如 Elasticsearch/OpenSearch)则以 BM25 为核心并逐步补齐向量检索能力。许多生产系统采用“双引擎”组合:向量库负责高性能 ANN,全文检索负责复杂过滤与关键词召回,最终在融合/重排阶段统一排序。
| 形态 | 代表实现 | 优势 | 局限 | 适用场景 |
| 向量索引库(In-process Vector Index) | FAISS / ScaNN | 单机性能极强;集成简单;易做离线批构建 | 分布式/多租户/权限/运维能力弱;元数据过滤能力有限 | 原型验证;单机检索;离线候选生成 |
| 向量数据库(Vector Database Service) | Milvus / Qdrant / Weaviate | 持久化 + CRUD;支持元数据过滤;更易做水平扩展 | 需要运维;延迟/吞吐取决于索引与集群配置 | 生产 RAG;增量更新频繁;需要过滤/权限 |
| 全文检索 + 向量检索(Hybrid Search Engine) | Elasticsearch / OpenSearch | BM25 + 过滤能力强;生态成熟;适合业务检索 | 向量能力与性能细节高度依赖具体版本/配置;向量索引形态可选项较少 | 强关键词依赖;复杂过滤/字段检索;混合检索一体化 |
| 组合架构(Vector DB + Search Engine) | Milvus/Qdrant + ES | 各取所长;向量与词项召回分别优化;融合/重排可控 | 系统更复杂;需要去重、打分对齐与一致性策略 | 对检索质量要求高,且有复杂过滤/排序逻辑 |
| 托管服务(Managed Service) | Pinecone / 各云厂商向量服务 | 运维成本低;弹性扩缩容;通常带权限与监控 | 成本较高;可控性与部署形态受限 | 快速上线;团队缺乏检索基础设施经验 |
ANN 索引(ANN Index)在“速度、召回率(Recall)与内存”之间权衡。检索侧常见痛点是“向量相似度可算,但业务过滤很难做快”:元数据过滤会破坏 ANN 的近邻结构,使得系统需要在“先过滤再向量检索”和“先向量检索再过滤”之间做策略选择。
在生产知识库里,过滤通常不是可选项,而是第一等公民。目录树(Catalog Tree)、启用状态、文档类型、租户边界、语言、内容类型、业务域前缀,都可能成为过滤条件。也正因为如此,许多系统会把 catalog 前缀过滤、enabled 标志、source_type/source_id 等字段同时写入 Milvus 和 ES,两边都能先做过滤再做召回。否则,召回质量再高,也可能把“本不该返回的内容”混进上下文。
| 索引/策略 | 核心思路 | 优点 | 代价 |
| Flat(Exact) | 全量计算相似度 | 精确;实现最简单 | 规模上去后延迟/成本不可接受 |
| HNSW | 分层小世界图近邻搜索 | 高召回、低延迟;对在线增量友好 | 内存占用较高;过滤条件复杂时性能波动 |
| IVF / IVF-PQ | 先粗聚类(倒排),再在桶内搜索;PQ 进一步压缩 | 更省内存;适合大规模离线构建 | 更新成本高;召回/延迟依赖参数调优 |
| DiskANN / Hybrid Memory | 把索引/向量放到 SSD,内存放导航结构 | 降低内存压力;可支持更大规模 | I/O 成为瓶颈;工程复杂度更高 |
稠密检索(Dense Retrieval)用向量相似度(如余弦相似度或内积)做 top-k 召回,擅长语义匹配与同义改写,但可能漏掉精确关键词(如错误码、版本号)。
它还有一个常被低估的前提:embedding 模型的训练分布必须与目标领域足够接近。若把主要基于互联网通用语料训练出来的嵌入模型,直接拿去检索法律、医疗、专利或企业内部术语密集的文本,向量空间中的“相似”往往就不再等于业务上的“相关”,召回质量会明显下降。此时更稳妥的做法通常是引入领域微调 embedding、混合检索,或让 sparse / full-text 路径共同兜底。
全文检索(Lexical Retrieval)以 BM25 等词项匹配为核心,擅长精确匹配与关键词召回。它对拼写、专有名词、数字更敏感,但对语义改写不够鲁棒。
稀疏检索(Sparse Retrieval)用“稀疏向量”表示文本:向量维度对应词项(或子词),权重表示该词项对匹配的贡献。与 BM25 相比,稀疏检索的权重来自模型学习而非纯统计;与稠密检索相比,它保留了词项级可解释性与对罕见词/数字的敏感性。
典型路线包括 SPLADE(Sparse Lexical and Expansion Model):通过学习得到“词项扩展(Lexical Expansion)”,让语义相关但不共词的文本仍能在词项空间相遇。工程上,稀疏检索常作为混合检索的一路召回信号,而不是单独替代 BM25。
混合检索(Hybrid Retrieval)把稠密检索与全文检索结合:先分别召回,再融合排序(如加权、去重、学习排序)。这是目前最稳健的通用策略之一。
在更完整的知识库系统里,混合检索不只是“dense + BM25”两路,而可能是 chunk / summary / question 三类检索目标与 dense / sparse / fulltext 三类检索路径的组合矩阵。换句话说,生产 RAG 召回的是多个“信号通道”,而不是单一相似度函数。它的优势是覆盖面更强:原文命中、主题命中、问句改写命中可以互补;但代价也很直接:路径暴涨、分数更不可比、日志更难读、回归测试更复杂。
这类系统往往还会按知识库能力做“有效方法裁剪”。例如,用户请求 fullhybrid,但某个知识库只建了 dense 和 sparse 索引,那么实际就只能退化成 hybrid;某个库没有开启 question recall,就不该在该路径上浪费资源。这个细节反映出一个成熟的 RAG 判断:检索策略不是全局写死的,而是知识库级配置与请求级策略共同决定的。
混合检索的难点不在“多路召回”,而在“分数不可比(Incomparable Scores)”:BM25 分数、余弦相似度/内积分数、稀疏向量分数往往不在同一尺度,不能直接相加。常见融合策略:
- 归一化后加权:对各路分数做 min-max / z-score 等归一化,再做加权求和或加权乘积。
- 基于排序的融合:不依赖原始分数尺度,例如 RRF(Reciprocal Rank Fusion):\(\mathrm{score}(d)=\sum_{s}\frac{1}{k+\mathrm{rank}_s(d)}\)。
- 学习排序(Learning to Rank):把各路分数与特征(BM25、embedding sim、字段匹配、长度等)作为特征,训练一个排序模型做融合。
生产系统通常更偏爱基于排序的融合,而不是直接拼原始分数。这是因为 ES 的 \(_score\)、Milvus 稠密距离、Milvus 稀疏 BM25 分数往往来自完全不同的评分体系。RRF 或加权 RRF 的价值就在于鲁棒:它不要求各后端分数可比,只要求各路径给出相对顺序。若再往上追求精度,则会在粗召回后接一个模型重排器,对融合后的候选做统一判断。
相关性阈值(Relevance Threshold)决定的是:召回结果里哪些片段值得继续送给模型,哪些片段应该被直接丢弃。很多 RAG 系统的问题并不是“完全没召回到东西”,而是把大量边缘相关、低置信度甚至明显错误的片段一并塞进上下文,结果让生成阶段被噪声牵着走。
因此,top-k 本身通常不够;工程上还需要结合相似度阈值、分数差值阈值或最小证据数量规则共同判断。阈值设得过低,会把噪声片段混进上下文;阈值设得过高,又可能让系统在真实有答案时错误地进入“未检索到结果”分支。成熟系统往往会把阈值当作知识库级和请求级都可调的参数,并配合离线标注集或在线反馈持续校准。
查询改写(Query Rewriting)解决的问题是:用户真正表达的检索意图,经常并不等于用户字面上输入的那句话。尤其当用户提问冗长、上下文依赖强、代词很多、问题里混有解释性语句而不是检索关键词时,直接拿原问题去召回,往往不如先把问题改写成更适合检索的形式。
查询改写的核心是把问题重新组织成更适合索引命中的检索表达,例如补全省略主语、显式写出实体名、拆开复合问题、提取关键词、或把对话上下文中的隐含约束展开成可检索文本。
多查询 RAG(Multi-Query RAG)会先把一个原始问题改写成多个语义相近但表述不同的检索查询,再分别召回并合并结果。它的动机很直接:单一路径的 query 很容易受措辞影响,而多个改写版本可以覆盖不同的关键词、别名、问题角度与表达方式,从而提高召回覆盖率。
多跳 RAG(Multi-hop RAG)适合那些答案依赖多段证据链的查询。它通常不会指望一次检索就拿到最终答案,而是先检索第一跳证据,再根据第一跳结果生成下一跳 query,继续检索后续证据。于是,检索过程本身就变成了一条“检索 ➡ 读证据 ➡ 改写下一问 ➡ 再检索”的链式推理流程。
智能体 RAG(Agentic RAG)则把查询改写提升为一个可反复决策的过程:模型不只改写一次 query,而是根据当前召回质量、证据缺口、工具反馈与上下文状态,决定是否继续搜索、换一种问法、切换知识库、触发重排,或干脆停止检索进入回答阶段。它的重点已经不只是“改写 query”,而是让检索成为 Agent 控制流的一部分。
重排序(Reranking)在“召回”(Recall)之后提升“相关性排序”(Precision@k):用更强但更慢的模型对候选片段重新打分。
成熟 RAG 系统里的 rerank 还常分成两层。第一层是每个知识库内部的局部重排:对该库自己的候选做加权、RRF 或模型精排。第二层是多知识库结果合并后的全局重排:当查询同时打到多个知识库时,再在总候选集合上做一次统一排序。这样做的动机很现实:单库内部的分数可比较,并不代表跨库结果也天然可比较;若不做第二层,全局 top-k 往往会被某个打分体系更“激进”的知识库垄断。
Cross-Encoder Reranker 把 query 与候选 chunk 拼接后输入同一个编码器,用注意力做细粒度匹配,相关性通常更高,但计算更慢,适合对 top-k(例如 50→10)做精排。
典型输入形式是 [CLS] query [SEP] doc [SEP](或对应模型的特殊 token)。在 BERT 类模型中,token type embeddings(也称 segment embeddings)可用于区分两段文本;随后 Transformer 的全连接自注意力允许 query token 与 doc token 在每一层发生深度交互,这正是 cross-encoder “cross” 的本质。
打分通常取 \([\mathrm{CLS}]\) 位置的最终隐向量 \(h_{\mathrm{CLS}}\) 过一个线性层得到相关性分数(或二分类 logits)。与双编码器(Bi-Encoder / Dual Encoder)相比,cross-encoder 更准但无法离线预计算候选向量,因此在线成本更高。
LLM Reranker 用大模型直接判断相关性或做对比选择,能融合更复杂的语义与任务约束,但成本更高且需要防止“自信乱判”。工程上常用它做少量候选的最终筛选。
生成式重排序(Generative Reranking)把“相关性打分”转写为生成任务:把 query 与 doc 拼接输入解码器(Decoder-only)或编码器-解码器(Encoder–Decoder),让模型生成一个标签 token(例如 Yes/No)或一个短评分文本,并用生成概率作为分数。
常见的点式打分形式是二分类 log-odds:令 \(y\in\{0,1\}\) 表示是否相关,则
\[\mathrm{score}(q,d)=\log p_\theta(y=1\mid q,d)-\log p_\theta(y=0\mid q,d)\]相比传统 BERT 类 cross-encoder,生成式 reranker 往往更擅长处理长文本匹配、复杂约束与隐含推理;工程上常用“轻量级 LLM + 领域数据微调”来获得显著增益。
列表式重排序(Listwise Reranking)把多个候选 doc 一次性送入模型,在同一个上下文窗口中共同建模“相对顺序”,而不是对每个(query, doc)独立跑一次 forward。直觉上,它让候选之间在 self-attention 中“同台竞争”,从而提升排序一致性,并降低多次推理带来的总开销。
实现上常见做法是:把候选 doc 按截断长度拼接成一个 list,要求模型输出每个 doc 的分数或名次;也有实现会在末尾使用一个专门的“汇聚 token”对每个 doc 读取表示。Listwise 方法的工程约束更强:候选数、每段 doc 的截断长度与模型上下文窗口会直接决定可吞吐的 top-k。
精排训练的难点是“区分相似但不相关”:需要硬负样本(Hard Negatives)来逼迫模型学习细粒度差异。硬负样本通常来自第一阶段召回:对同一 query,取检索 top-k 中不相关的候选作为 negatives(也可混入 BM25 negatives、in-batch negatives、或对抗式 negatives)。
| 目标 | 形式 | 直觉 | 常见风险 |
| 点式(Pointwise) | 学习 \(s(q,d)\) 或 \(p(y=1\mid q,d)\) | 把相关性当作二分类/回归 | 分数标定(Calibration)难;对“相对顺序”监督较弱 |
| 对式(Pairwise) | 学习 \(s(q,d^+)>s(q,d^-)\) | 直接优化排序边际(Margin) | 负样本质量决定上限;采样偏差可能放大 |
| 列表式(Listwise) | 对候选列表联合优化(如 softmax over list) | 更贴近 NDCG/MRR 等排序指标 | 计算与实现复杂;受上下文窗口约束 |
蒸馏(Knowledge Distillation)把一个强但慢的教师模型(Teacher)产生的打分/偏好,转移给一个更快的学生模型(Student)。在重排序里,蒸馏最常见的目标不是“压缩参数”,而是把 LLM 级别的相关性判断能力下放到可规模化的 reranker,使线上能承载更大的 top-k、更高的 QPS 或更低的 P99。
| Teacher → Student | 监督信号 | 常见损失 | 收益 | 主要风险 |
| LLM / 生成式 reranker → Cross-Encoder | 软分数(log-odds / graded)或偏好对 | 回归(MSE)/ 对式(pairwise logistic) | 显著降成本;保留较强语义与推理能力 | 学生上限受教师约束;教师偏差会被复制 |
| Cross-Encoder → Bi-Encoder | 相对顺序/分数 | 对比学习(InfoNCE)/ 蒸馏排序边际 | 把精排能力“下放”到召回,提高召回质量 | 需要大量 hard negatives;对领域漂移敏感 |
| LLM → 数据标注(作为训练集构造器) | 弱标注标签 + 解释/证据 | 按目标任务训练(点式/对式/列表式) | 快速构造大规模领域数据;迭代快 | 噪声标注;需抽样人工复核与在线 A/B 验证 |
RAG 检索阶段的最终产物并不一定只是“命中的那一小段 chunk”。很多高质量系统会把返回内容模式做成显式策略:只返回命中块正文、返回去掉 overlap 的核心正文、返回命中块加邻近上下文、或按文档中的位置范围把相关块递归拼回更完整的片段。这样做的原因是:模型生成真正需要的是足够完整且边界清晰的证据上下文,而不是孤立句子。
这里的关键判断是:检索命中的是索引单元,但喂给模型的应是生成单元。索引单元倾向短小、便于召回;生成单元则要兼顾上下文完整性、token 预算和可引用性。若两者完全绑定,系统通常会在召回精度与生成可读性之间来回拉扯。
第一,RAG 的上限不只由 embedding 模型决定,而是由“分块质量、索引视图、融合策略、回拼策略、状态治理”共同决定。把注意力只放在换一个更强 embedding 上,通常抓不住主矛盾。
第二,知识库不是静态文件集合,而是带状态机的外部知识资产。只有显式区分 base、document、chunk,并让它们有自己的生命周期,系统才可能支持增量更新、失败恢复、重建和审计。
第三,生产 RAG 常常天然走向双后端和多路径召回。这个方向的收益是更稳健的覆盖率,代价是系统复杂度、索引一致性成本和观测难度都会明显上升。因此它适合高价值知识库,不一定适合所有团队的第一版系统。
第四,把摘要和问题也视作可检索对象,是一个非常务实的设计。它等于承认“原文表述”与“用户提问方式”经常不一致,于是用知识增强知识本身的可检索性。但它也会带来额外索引、额外 embedding 成本与额外一致性问题,因此只有在召回质量确实成为瓶颈时,这种多视图索引才值得引入。
第五,外部知识平台同步并不等于“复制一份数据就结束”。一旦系统允许一部分知识由外部平台托管、另一部分知识由内部系统自建索引,那么“谁是事实源、谁负责更新、谁负责删除、谁负责召回”就必须在架构上说清楚。否则最容易出现的不是召回不到,而是召回出重复、过期或跨系统不一致的内容。
| 阶段 | 常见架构 | 代表实现 | 核心逻辑 | 速度 | 精度 |
| 召回 | 双编码器(Bi-Encoder) | BGE-Embedding text-embedding-3 |
向量相似度 | 极快 | 中 |
| 精排(稳健基线) | 交叉编码器(Cross-Encoder) | BAAI bge-reranker-v2-m3 |
\([q;d]\) 深度交互 | 中 | 高 |
| 精排(顶配) | 生成式 / 列表式(LLM-based) | BGE-Reranker-v2-Gemma Jina-Reranker-v3 |
生成式打分或 listwise 竞争 | 较慢 | 极高 |
生成与融合(Generation & Fusion)的关键在于:把检索到的证据(Evidence)以可控格式注入 prompt,并要求模型“基于证据回答”。常见做法包括:
- Stuffing:把 top-k 片段直接拼接进上下文(最简单,最易超预算)。
- Map-Reduce:先对各片段分别提炼要点,再汇总生成最终答案(更稳,成本更高)。
- Refine:先用少量证据生成初稿,再逐片段增量修订(适合长证据链)。
检索增强生成(RAG)解决的是“模型缺少外部知识”的问题;智能体(Agent)解决的是“模型如何在真实环境中持续完成任务”的问题。一个真正可用的 Agent 不再是单次 prompt 的包装,而是一个带有状态(State)、工具(Tools)、记忆(Memory)与控制流(Control Flow)的运行时系统。它能够观察环境、决定下一步动作、调用外部能力、根据反馈修正策略,并在多轮交互中维持任务连续性。
从工程视角看,Agent 的本质是“以大模型为决策核心的软件系统”。模型负责理解、推理与生成;外层系统负责注入上下文、执行动作、保存状态、施加约束,并把环境反馈重新送回模型。只有这几层协同起来,模型才会从一次性回答器变成可持续工作的执行体。
计划-执行(Plan-Execute)是智能体最常见的控制流之一:先把“用户目标”分解为一组可操作步骤(计划),再逐步调用工具/模型完成这些步骤(执行),并把中间结果写回状态(State)。当环境反馈与计划假设不一致时,触发再计划(Replan)。工程上,它的价值是把一次长输出变成可观测(Observable)、可重试(Retryable)、可中断(Interruptible)的多步过程。
感知-推理-行动(Perception-Reasoning-Action)循环是 Agent 的基本闭环。感知阶段读取环境状态,例如用户输入、网页 DOM、数据库返回值、日志、文件内容或工具回执;推理阶段根据当前目标、约束和历史状态决定下一步策略;行动阶段把决策落实为具体操作,例如搜索、调用 API、写文件、点击界面或向下游智能体发消息;随后再读取新反馈,进入下一轮循环。这个闭环的关键不在“会不会思考”,而在“每一轮是否拿到了正确观测、是否执行了正确动作、是否把结果正确写回状态”。
因此,Agent 设计首先是状态机(State Machine)设计。很多失败并不是模型推理能力不足,而是观测不完整、动作不可验证、状态写回混乱,导致下一轮推理建立在错误世界模型之上。一个好的 Agent runtime 会显式记录当前目标、最近动作、动作结果、异常信息与下一步计划,从而让每一轮循环都建立在稳定状态上。
工具使用(Tool Use)让语言模型突破“只会生成文本”的边界,把外部系统接成自己的感官与执行器。工具既可以是只读型能力,例如搜索、数据库查询、文件读取;也可以是动作型能力,例如发送请求、执行 shell、操作浏览器、写入代码仓库。模型本身不直接执行这些动作,而是输出结构化调用意图,再由外层系统负责真正执行、捕获结果并返回。
工程上,Tool Use 的难点不在“把工具接上”,而在“把工具定义清楚”。一个好的工具接口需要明确输入 schema、输出 schema、权限边界、失败语义和重试策略。工具定义越模糊,模型越容易产生参数幻觉(Argument Hallucination)、错误调用和无效循环;工具定义越稳定,模型越容易学会把工具当作程序原语来组合。
记忆系统(Memory System)负责解决跨步骤与跨会话连续性问题。没有记忆的模型每次调用都像“重新开机”;有记忆的 Agent 才能累积上下文、复用历史决策、根据过去错误调整行为。记忆并不等同于“把更多 token 塞进上下文窗口”,而是要把不同时间尺度、不同重要性的状态放进不同存储层,再按需检索。
短期记忆(Short-term Memory)通常由上下文窗口(Context Window)承载,保存当前任务最活跃的信息:系统指令、最近几轮对话、正在执行的计划、刚拿到的工具结果、当前工作草稿等。它的优势是读取成本低、和当前推理绑定最紧;它的限制也同样明显:容量昂贵、注意力会稀释、信息越多不代表效果越好。
因此,短期记忆的核心工作不是“堆满”,而是“裁剪”。优秀的 Agent 会把原始轨迹压缩成摘要(Summary)、状态(State)和待办项(Next Actions),只保留当前决策真正需要的变量。短期记忆承担的是工作记忆(Working Memory)的职责:它服务当前这一轮推理,而不是承担长期知识库的角色。
长期记忆(Long-term Memory)存放在上下文窗口之外,常见载体包括向量数据库、关系数据库、对象存储、文档库、日志系统、代码仓库、任务看板与事件流。它保存的是“现在不必全部加载,但未来可能需要回忆”的信息,例如用户偏好、历史案例、项目规范、过去失败总结、已验证的事实与中间产物。
长期记忆要解决三个问题:写什么、怎么检索、何时遗忘。写入过多会让存储退化为噪声池;只做向量相似度检索又容易漏掉结构化约束与时间关系。成熟做法通常会把结构化状态、全文检索、向量召回与人工定义的索引结合起来,让 Agent 既能“语义回忆”,也能“精确定位”。
目前主流 Agent 设计常借用认知科学中的三类记忆划分:情景记忆(Episodic Memory)、语义记忆(Semantic Memory)与程序记忆(Procedural Memory)。这三类记忆对应的是“发生过什么”“知道什么”“怎么做”。把它们混在一个存储里,检索和写入策略很快就会失控;分层建模则更容易设计稳定的读写规则。
| 记忆类型 | 保存内容 | 典型载体 | 工程价值 |
| 情景记忆(Episodic) | 具体事件、行动轨迹、失败案例、会话历史 | 任务日志、轨迹摘要、审计记录 | 支持回放、复盘、反思与重试 |
| 语义记忆(Semantic) | 稳定知识、规则、事实、领域概念 | 知识库、文档索引、结构化事实表 | 支持检索、问答、约束判断 |
| 程序记忆(Procedural) | 工作流程、技能脚本、工具使用模式 | 系统提示、工具说明、可复用 playbook | 把“会做事”沉淀为稳定操作习惯 |
其中,程序记忆对工程系统尤其关键。很多所谓“Agent 经验”最终都会沉淀成程序记忆,例如某个 API 的调用顺序、某类错误的排查流程、某个项目的提交流程。Harness Engineering 本质上就是把这些隐性经验逐步外化成可持续复用的程序记忆。
推理(Reasoning)解决的是“当前这一步怎么想”;规划(Planning)解决的是“整个任务怎么走”。现代 Agent 往往同时需要二者:局部步骤要有足够的推理精度,长期任务要有阶段化计划与中途重规划能力。近两年的研究基本沿着四条路线收敛:交错式思考与行动、反思式自我修正、显式规划后求解,以及基于搜索的多路径探索。
ReAct(Reason + Act)是当前 Agent 范式最有影响力的起点之一。它把“思考轨迹”和“动作轨迹”交错起来:模型先给出一小步 reasoning,再发起 action,读取 observation 后继续下一步 reasoning。与只做链式思维(Chain-of-Thought)的做法相比,ReAct 的优势在于每一步都能接触外部环境,因此能在事实不确定、需要探索、需要工具辅助的任务上持续修正路径。
ReAct 的核心价值并不是让模型“想得更多”,而是让推理过程与环境反馈形成闭环。它也有明显代价:若没有停机条件、步数上限和工具约束,轨迹很容易冗长、循环或过度调用工具。因此,ReAct 更像 Agent 控制流的原型范式,生产系统通常会在其外层再加计划、验证、预算控制与错误恢复机制。
Reflection(自我反思)把“错误”变成下一轮决策的输入。其基本思想是:一次执行失败后,不只返回原始错误信号,还额外生成一段高信息密度的经验总结,说明失败原因、已验证无效的路径、下一次应当修改的策略。这样,模型获得的不是一个抽象的 reward,而是一段可以直接进入上下文的文字化梯度。
从研究谱系看,Reflexion 将这种思路系统化为 verbal reinforcement learning:把环境反馈转写成文本反思,并存入 episodic memory,供后续回合检索。工程上,这类方法通常以“执行后 Critic”“失败总结卡片”“经验回放摘要”等形式落地。它最适合高代价试错任务,例如代码修复、网页操作、长任务代理;前提是系统能可靠地区分“失败是策略问题”还是“失败只是偶然噪声”。
Plan-and-Solve 的思想很直接:先显式列出求解计划,再根据计划执行。它针对的是零样本链式思维常见的 missing-step 问题,即模型直接开始求解时容易跳步骤、漏约束或在中途漂移。把“先规划、后执行”做成两个阶段后,模型的注意力会先聚焦在任务分解,再聚焦在逐步完成,从而显著降低长任务中的结构性遗漏。
这一思路在工程系统里几乎已经成为默认模式。很多 Coding Agent、Research Agent 与 Workflow Agent 都把 planner 和 executor 拆成不同阶段,甚至拆成不同角色。原因很简单:计划是一种低成本、高杠杆的中间产物。它既能让人类在写代码前审查方向,也能让系统在执行中持续对照“当前动作是否仍服务于原始目标”。
MCTS(Monte Carlo Tree Search,蒙特卡洛树搜索)把 Agent 的决策过程从“单路径生成”升级为“多路径探索”。系统不再只让模型给出一个下一步动作,而是展开多个候选分支,对不同轨迹进行模拟、评估和回传分值,再把计算预算集中到更有希望的分支上。对于需要长程依赖、路径选择、试探性探索的任务,这种显式搜索比单次贪心生成更稳健。
Language Agent Tree Search(LATS)是这一路线的代表性工作,它把 MCTS 与语言模型结合,让模型同时承担候选动作生成、状态评估和自我反思等角色。代价同样明确:搜索带来更高 token 成本、更复杂的状态管理和更重的工程编排。因此,MCTS 更适合高价值、高不确定性任务,例如复杂推理、博弈式决策、困难编程与网页任务,而不是每个简单问答都默认启用的通用套路。
如果说推理模块决定“应该做什么”,那么工具层决定“究竟能做到什么”。当前主流 Agent 平台基本收敛出几类高频动作接口:结构化函数调用、受控代码执行、Web 检索、图形界面操作,以及把外部工具和资源标准化接入的协议层。它们共同构成了 Agent 的执行面。
Function Calling(函数调用)是最基础、最通用的 Tool Use 形式。模型输出的不再是自然语言描述,而是一个满足 schema 的调用请求,例如函数名、参数对象、调用意图;应用侧接收到请求后真正执行代码,并把结果作为 tool result 返回。这样,模型负责“决定调用什么”,应用负责“保证执行正确”。
Function Calling 的真正意义是把自由文本接口收窄为结构化程序接口。只要参数 schema 足够清晰,模型就能稳定学会把外部系统当成可组合原语。这也是今天大部分 Agent 框架的底层抽象:上层看起来是“智能体会用工具”,底层通常仍是“模型在做结构化函数选择与参数填充”。
Code Interpreter(代码解释器)让模型在受控沙箱中执行代码,从而把“语言推理”转换为“可验证计算”。它特别适合数据清洗、表格处理、统计分析、绘图、文件转换、轻量脚本自动化与需要精确数值结果的任务。与纯文本推理相比,Code Interpreter 的优势在于中间状态可执行、可复现、可检查。
这类能力本质上是把 Python 或其他运行时变成模型的外部工作台。模型负责提出程序,沙箱负责执行,系统再把 stdout、文件产物、异常栈和图像反馈给模型。只要隔离、资源限制和文件边界设置得当,Code Interpreter 往往是让 Agent “从会解释变成会计算”的最直接跃迁。
Web 搜索(Web Search)解决的是模型知识静态化问题。基础模型参数中固化的是训练时刻之前的分布,而 Agent 经常需要回答最新价格、最新政策、最新产品文档、最新论文或当前网页状态。把搜索能力接入后,模型可以先检索,再基于来源生成回答,并在必要时附带引用。
工程上,Web 搜索不是“把搜索结果贴给模型”这么简单。系统还需要处理查询重写、来源筛选、去重、可信度排序、片段抽取与多源融合。对于需要最新信息的任务,搜索应当被视为一等能力,而不是可有可无的外挂;否则 Agent 的错误会表现为“推理看起来正确,但事实已经过时”。
Computer Use(计算机使用)让 Agent 直接在图形界面层面操作软件与网页,例如看截图、定位元素、移动鼠标、键入内容、滚动页面与读取屏幕变化。它的价值在于:当目标系统没有现成 API,或者真正业务流程本来就发生在浏览器/桌面界面中时,Agent 仍然可以像人类操作员一样完成任务。
这类能力也是最脆弱的一类动作接口。界面结构变化、网络延迟、弹窗遮挡、验证码、权限确认和安全风险都会放大失败概率。因此,Computer Use 应被视为“最后一层兼容性接口”:没有 API 时才使用,并始终运行在隔离环境中,为高风险动作保留人工确认与回滚机制。
MCP(Model Context Protocol,模型上下文协议)试图把“给模型接工具与上下文”这件事标准化。它定义了一套客户端-服务端协议,让宿主应用可以连接多个 MCP server,并以统一方式暴露工具(Tools)、资源(Resources)与提示模板(Prompts)。这样,模型不必为每个外部系统重新学习私有接线方式,应用也不必为每种模型重复造一套集成层。
在工程语义上,MCP 解决的是“工具可移植性”和“上下文供给标准化”。一个搜索 server、一个数据库 server、一个设计文档 server,只要遵循同一协议,就能被不同 Agent host 复用。当前生态已经把 MCP 从“工具协议”扩展成“上下文协议”:除了调用动作,也强调让模型按需读取结构化资源,而不是把所有材料一次性塞进 prompt。
截至 2026 年 3 月,MCP 官方稳定协议版本为 2025-11-25,2026 路线图正在推进会话扩展(session handling)、Server Cards、Registry 与 agent-to-agent 协作能力。对应用开发者而言,更重要的不是版本号本身,而是它标志着一件事:Agent 运行时正在从各家私有 Tool API,逐步走向可协商、可复用、可观测的开放接口层。
多智能体系统(Multi-agent System)指的是:把一个复杂任务分解给多个具有不同职责或不同上下文边界的 agent,由它们通过委派、协作、验证和状态传递共同完成目标。它关注的核心是如何把规划、执行、审查和并行探索写成一个可控的协作结构。
是否拆成多个 agent,取决于任务是否存在天然的角色分工、上下文隔离需求、并行空间与独立验证价值。很多简单任务用一个强单体 agent 加好工具即可;只有当单一上下文开始拥塞、单角色难以兼顾规划与执行、或多个分支可以并行推进时,多智能体系统才真正体现优势。
角色分工(Role Decomposition)指的是:在多智能体系统中,为不同 agent 分配稳定且边界清晰的职责,使每个 agent 只处理自己最应该承担的那一类决策与操作。它的作用是把复杂任务拆成多个可管理的视角与责任域,降低单一上下文同时兼顾规划、执行和审查的负担。
最常见的基本三角是 Planner、Executor 与 Critic:Planner 负责分解目标,Executor 负责实际操作,Critic 负责验证与挑错。这个结构的本质是在系统内部显式制造不同视角,避免同一个上下文同时承担规划、执行与审查,最终让错误在更早阶段暴露出来。
Planner 负责把模糊目标转成结构化任务图,例如目标拆解、依赖关系、优先级、完成标准与失败回退条件。一个好的 Planner 不直接沉迷于实现细节,而是尽快产出可被执行层消费的中间表示,例如任务列表、阶段计划、验收清单或执行 DAG。这样,后续 agent 的上下文会更短、更稳定。
Executor 负责把计划变成具体动作:调用 API、写代码、运行测试、检索资料、修改文件、操作界面。它通常需要最严格的权限控制,因为真正改变外部世界的是执行层,而不是规划层。把 Executor 的工具范围、写入范围和预算边界限定清楚,往往比继续优化模型 prompt 更能提升整体可靠性。
Critic 负责验证“结果是否正确”,而不是复述“过程看起来合理”。它可以检查事实一致性、运行测试、比对输出格式、审查架构约束、回放浏览器流程,或要求执行层补充证据。Critic 的价值在于给系统引入独立的否决权:没有独立验证的多智能体系统,本质上仍然只是把同一种错误复制了几遍。
角色定义清楚之后,下一步是决定这些角色如何协作。常见模式主要有顺序执行、并行执行与层级委派。三者区别不在名称,而在状态如何传递、谁拥有控制权、失败后如何收敛,以及系统是否允许多个 agent 同时写入同一世界状态。
顺序执行(Sequential Execution)是最稳的模式:上一步完成并产出明确结果后,下一步才开始。它最适合依赖链强、可验证点清晰的流程,例如“先规划,再实现,再审查,再修复”。优点是状态简单、问题定位容易;缺点是吞吐量受限,前一环的错误会整体阻塞后续流程。
并行执行(Parallel Execution)用于把独立子任务同时推进,例如多个资料检索、多个候选方案探索、多个代码模块并行实现。它能显著提高吞吐,但前提是任务切分足够干净,或者系统拥有足够好的合并策略。并行化的真正难点在于如何避免它们争抢同一上下文、重复劳动或互相覆盖结果。
层级委派(Hierarchical Delegation)由一个上层 supervisor 或 manager 统一掌控目标和全局状态,再把子任务委派给不同 specialist。它适合长任务和复杂流程,因为全局控制权集中在上层,局部上下文压力则下沉到子 agent。代价是 supervisor 很容易成为瓶颈,因此需要明确委派粒度、回收机制与升级路径,避免系统退化成“一个总管在不停转述消息”。
Agent Framework 解决的是“如何把模型能力组织成长期可运行的软件系统”。主流框架的差异主要体现在三个层面:控制流表达方式、状态管理方式,以及多智能体协作的原生支持程度。选型时最重要的是它是否契合你的系统拓扑:你需要图式工作流、事件驱动编排、还是平台托管的工具执行与追踪能力。
| 框架/形态 | 控制流模型 | 强项 | 代价 | 适用 |
| LangChain / LangGraph | 链式/图式(Graph) | 组件化;易组合 RAG、工具与记忆;LangGraph 适合复杂状态机 | 抽象层较多;需要明确工程边界 | 生产 RAG/Agent pipeline |
| AutoGen | 事件驱动多智能体(Event-driven) | 消息传递清晰;适合团队式协作与研究 | 系统设计自由度高;需要自定治理边界 | 多智能体实验;复杂协作流程 |
| CrewAI | 角色 + 任务流水线 | 任务编排直观;适合“岗位分工”式流程 | 可控性取决于框架提供的扩展点 | 面向业务流程的多角色 Agent |
| OpenClaw | 自托管 Gateway + Agent runtime | 多渠道接入、会话路由、插件与设备节点整合强 | 更像入口与运行时基础设施,不是最轻量的 Python 编排库 | 本地优先、多渠道助手、长期在线 Agent 网关 |
| Hermes Agent | 自治运行时(Autonomous Runtime) | 内建 learning loop、skills、memory、profiles 与 delegation | 系统较重;要真正发挥优势需要接受其运行时哲学 | 长期运行、自我积累、强工具使用的个人/团队 Agent |
| OpenAI Responses API / Agents SDK | 平台托管(Managed) | 内建工具、Tracing、Handoff 与托管能力完善 | 更依赖平台抽象;深度定制时需额外设计 runtime | 快速构建生产 Agent;希望复用官方工具栈 |
LangChain 偏组件化抽象,LangGraph 偏图式控制流。前者适合把模型、检索器、工具、记忆等模块快速拼接起来;后者适合把复杂 Agent 流程显式建模为图(Graph),把循环、分支、检查点和人机介入点写成状态转移。对于生产系统,LangGraph 的意义尤其明显:它让“Agent 不是一段 prompt,而是一个状态机”这件事可以被直接编码。
在多智能体方面,LangGraph 当前更强调基于工具调用(tool-calling)的 supervisor 模式,而不是把所有 agent 都包装成自由对话体。原因很实际:当协作关系被写成显式图结构后,上下文边界、路由条件和失败恢复都会更好控制。
AutoGen 的长处在于把多智能体协作建模为显式消息系统。不同 agent 可以作为独立节点收发消息、触发工具、交换中间状态,因此很适合研究“团队式智能体”以及需要复杂路由的实验性系统。新版 AutoGen 也更强调事件驱动(Event-driven)与可扩展运行时,而不只是几个人工角色互相聊天。
它的代价也非常明确:自由度越高,系统边界越需要开发者自己画清楚。权限、可观测性、记忆持久化与异常恢复如果没有在框架外补齐,多智能体对话很容易演化成难以调试的消息洪流。
CrewAI 把多智能体系统表达为“角色(Role)+ 任务(Task)+ 工具(Tool)”的业务编排语言,适合把组织分工直接映射到系统设计中。它的上手成本较低,尤其适合内容生成、运营流程、分析流水线这类天然按岗位拆分的任务。
这类框架的优势是表达直观,代价是底层控制流往往被隐藏得更深。只要任务依赖、重试策略、共享状态和权限边界开始复杂化,就需要确认框架是否允许你把隐含运行时重新显式化。
从当前官方工具栈看,OpenAI 已经把 Responses API 作为构建 agent-like application 的统一接口,并以 Agents SDK 提供更轻量的编排、handoff、guardrail 与 tracing 能力。这一路线的核心价值是把常见基础设施平台化:函数调用、Web 搜索、Computer Use、Code Interpreter、Tracing 与多智能体 handoff 都可以沿着同一套接口组织。
托管式能力的优点是默认路径短、集成成本低、官方工具之间协同更顺滑;缺点是当业务开始需要深度定制的状态机、自定义持久化策略或异构执行环境时,应用仍然需要在 SDK 之上补一层自己的 runtime。换句话说,托管平台减少的是“起步成本”,而不是彻底消灭 Agent 工程本身。
OpenClaw 更适合理解为本地优先的 Agent Gateway 与运行时基础设施,而不是单纯的 prompt 编排库。它的核心不是“怎样写一条 Agent workflow”,而是“怎样把一个长期在线的 Agent 安全地接到 Discord、Slack、Telegram、WhatsApp、iMessage 这类渠道上,并用统一 Gateway 管理会话、路由、插件、节点设备和工具能力”。
这一路线的长处在于入口治理和系统完整性。若需求是“我需要一个可长期运行、跨多个聊天入口、会话持续存在、支持插件和设备节点的个人或团队助手”,OpenClaw 的抽象更贴近真实系统边界。它的重心不是研究型多智能体消息编排,而是把渠道、会话、路由、插件和运行时做成一个统一控制平面。
Hermes Agent 则更像学习型 Agent Runtime。它不是简单包装单一模型 API 的聊天壳,而是试图把长期记忆(Memory)、技能(Skills)、子 Agent 委派(Delegation)、工具调用、批处理、浏览器自动化、语音模式和消息网关放进一个统一自治运行时里。其最鲜明的卖点,是官方强调的 built-in learning loop:Agent 会把经验沉淀成可复用技能,并跨会话持续积累。
因此,Hermes 更适合那类“希望 Agent 长期运行、逐步形成操作习惯、沉淀程序性知识并持续复用”的场景。它的重点不是先把多渠道入口打通,而是让 Agent 在运行中越来越像一个有历史、有技能库、有工作记忆的长期执行体。
OpenClaw 与 Hermes 对比:
| 维度 | OpenClaw | Hermes Agent |
| 核心定位 | 自托管 Gateway / 渠道路由 / Agent 接入层 | 长期运行、自我积累的自治 Agent 运行时 |
| 更强的一侧 | 多渠道入口、会话与路由治理、插件与节点生态 | 记忆、技能沉淀、学习闭环、工具执行与多 profile 隔离 |
| 抽象重心 | “把 Agent 接到哪里、如何长期在线、如何统一调度” | “让 Agent 如何长期工作、持续复用经验、并逐步变强” |
| 更像什么 | Agent 基础设施与控制平面 | Agent 大脑与执行运行时 |
| 典型适用 | 个人 AI 助手、多聊天平台入口、设备联动 | 编码助手、研究助手、长期自动化执行体 |
这两者并不是简单替代关系。一个偏“入口与治理”,一个偏“执行与成长”。如果系统目标是搭建长期在线、多入口、可治理的助手平台,OpenClaw 更贴近问题本身;如果目标是让 Agent 在长期运行中积累技能、形成风格、复用经验,Hermes 的抽象更自然。现实工程里,两类能力往往最终会逐步靠拢,但在当前阶段,它们仍代表了两条不同的主线。
Leave a Reply