读完 LangChain 的 The Anatomy of an Agent Harness 后,我对 Agent 的判断发生了一个变化:真正决定 Agent 能不能落地的,不只是模型本身,而是模型外部那套让它进入工作现场的系统层。
LangChain 用一个很简洁的公式描述这件事:
Agent = Model + Harness
模型提供理解、推理、规划和生成能力;Harness 负责把这些能力接到真实环境里,让模型能读取上下文、调用工具、保留状态、执行动作、观察结果,并通过验证回路修正自己。没有 Harness,模型更像一个会回答问题的大脑;有了 Harness,它才可能成为一个能持续完成任务的工作系统。
为什么 Agent 不能只看模型能力
讨论 Agent 时,我们很容易把问题收缩成模型能力:推理强不强、上下文长不长、工具调用准不准、代码生成好不好。这些当然重要,但它们不足以解释 Agent 在真实任务中的表现。
一个简单例子:用户说“帮我修复这个项目的构建问题”。模型如果只是给出一段分析,任务并没有完成。它需要读取仓库、理解依赖、运行构建命令、观察错误、修改文件、再次构建、确认通过,还要避免误删用户已有改动。
这条链路里,模型负责判断,但大部分行动能力都来自模型外部:
Goal
→ Context
→ Tools
→ State
→ Execution
→ Observation
→ Verification
→ Iteration
如果缺少文件系统,模型无法稳定读取项目现场;如果缺少命令行,它无法验证构建结果;如果缺少状态管理,它很难跨多轮任务保持进度;如果缺少权限和回滚机制,它的行动能力越强,风险越大。
所以同一个模型放在不同 Agent 产品里,表现可能差很多。差异不只来自提示词,而来自 Harness 是否提供了合适的上下文、工具、执行环境、状态管理和验证机制。
Harness 是什么:模型之外的运行系统
LangChain 对 Harness 的定义很宽:只要不是模型本身,却参与 Agent 行为的代码、配置和执行逻辑,都属于 Harness。
它可以包括:
- System Prompt
- Tools、Skills、MCP 以及它们的描述
- 文件系统、沙箱、浏览器等基础设施
- 子 Agent 编排、任务交接、模型路由
- Hooks、Middleware、压缩、继续执行、lint 检查
- 状态管理、记忆、搜索、验证和观测机制
这个定义的关键不是把所有组件列全,而是改变我们理解 Agent 的方式。Agent 不是“模型加几个工具”,而是一个围绕模型构建的运行系统。
一个最小的 Harness 可以只是聊天应用里的消息循环:保存历史消息,把用户输入追加到上下文,再调用模型生成回复。一个复杂的 Harness 则会提供工作区、命令行、沙箱、浏览器、Git、测试命令、计划文件、权限边界和上下文压缩。两者都在包裹模型,但能完成的任务层级完全不同。
因此,判断一个 Harness,不能只问“接了哪些工具”,而要问:
模型看到什么上下文?
模型能采取什么动作?
动作在哪里执行?
状态如何跨步骤保留?
结果如何被观察?
失败如何被纠正?
完成如何被验证?
这些问题比工具数量更接近 Agent 工程的本质。
Harness 在 Agent 链路中负责什么
Harness 的价值最好放到任务链路里理解,而不是放到组件清单里理解。
一个可用的 Agent 系统通常可以拆成几层:
Model
→ Context
→ Tools
→ State
→ Execution Environment
→ Observation
→ Verification
→ Agent Runtime
Model 是智能核心,负责理解任务、生成计划、选择动作和解释结果。但模型只能基于它看到的上下文做判断。
Context 决定模型能看见什么。项目规则、用户需求、文件内容、历史操作、工具返回结果,都需要被组织成对模型有用的信息。上下文不是越多越好,噪音越多,模型越容易偏离重点。
Tools 决定模型能做什么。搜索、文件读写、代码执行、浏览器、数据库查询、MCP 服务,本质上都是让模型把判断转成动作的接口。工具设计的难点不只是提供能力,还包括描述清楚、调用稳定、结果可观察。
State 决定任务能否跨步骤延续。文件系统、计划文件、缓存、记忆和 Git 历史,都能让 Agent 把进度保留下来,而不是每一轮都从上下文窗口重新开始。
Execution Environment 决定动作在哪里发生。沙箱、容器、远程工作区、本地仓库、浏览器环境,都决定了 Agent 能访问什么、能安装什么、能执行什么,以及执行失败时如何恢复。
Observation 和 Verification 决定 Agent 是否能修正自己。日志、截图、测试、构建结果、CI 状态和人工审查,都是把结果反馈给模型的信号。如果 Agent 只能行动,不能观察和验证,它很容易交付“看起来完成”的结果。
最后,Agent Runtime 把这些部分串起来:什么时候调用模型、什么时候调用工具、什么时候压缩上下文、什么时候继续执行、什么时候停止。这一层决定 Agent 是一次性响应,还是一个可持续工作的系统。
什么时候需要设计 Harness,而不是继续优化 Prompt
不是所有 AI 任务都需要复杂 Harness。简单问答、一次性总结、轻量文案生成,很多时候只需要把输入说清楚。继续堆工具和流程,反而会增加成本。
但当任务开始接触真实环境,Prompt 的边际收益会下降,Harness 的重要性会上升。
几个明显信号是:
- 任务需要跨多轮、多文件、多步骤推进。
- 任务需要读取或修改真实项目。
- 任务需要运行代码、安装依赖或调用外部工具。
- 任务需要访问实时信息,而不是只依赖模型训练时知识。
- 任务需要保留长期状态或在中断后继续。
- 任务需要测试、构建、日志或浏览器预览来验证结果。
- 任务涉及权限、安全、可回滚和审计。
比如“解释一下 Astro 是什么”主要是模型能力问题;“帮我把 Astro 博客改成新的内容结构,跑构建,确认页面生成,再提交部署”就是 Harness 问题。
前者更依赖表达质量,后者更依赖工作链路。只优化 Prompt 可以让模型回答得更好,但不能自动提供文件系统、构建命令、Git diff、浏览器预览和 CI 反馈。
如何设计一个可用的 Harness
Harness 设计不应该从“我要接哪些工具”开始,而应该从“我要让 Agent 完成什么真实任务”开始。
更好的设计路径是:
Goal
→ Context Design
→ Tool Design
→ State Design
→ Execution Design
→ Verification Design
→ Feedback Loop
Goal 先定义任务边界。Agent 是要写文章、修 Bug、分析数据,还是执行部署?不同目标需要完全不同的上下文和工具。目标不清楚时,Harness 越复杂,越容易把模型推向错误方向。
Context Design 解决模型应该看什么。稳定规则应该进入项目文件,例如 AGENTS.md;重复流程可以做成 Skill;长日志和大文件不应该全部塞进上下文,而应该通过摘要、索引或按需读取提供。
Tool Design 解决模型能做什么。工具不是越多越好。一个好工具应该有明确用途、清晰输入、可解释输出和失败反馈。工具描述含糊时,模型会猜;工具输出太长时,模型会被噪音淹没。
State Design 解决任务如何延续。长任务需要计划文件、检查点、Git 历史或其他状态载体。否则一旦上下文压缩、会话中断或换一个 Agent 接手,任务就会失去连续性。
Execution Design 解决动作在哪里发生。代码执行最好在隔离环境里进行,危险命令需要权限边界,网络访问和敏感数据也需要明确控制。Harness 不是只让 Agent 更能干,也要让它更可控。
Verification Design 解决结果如何被证明。构建、测试、lint、浏览器检查、日志读取、CI 状态,都应该成为 Harness 的一部分。验证不是交付后的人工补救,而是 Agent 行动链路里的反馈信号。
最后是 Feedback Loop。Agent 的价值不在于一次生成正确答案,而在于能根据观察结果持续修正:
Act
→ Observe
→ Diagnose
→ Fix
→ Verify
没有这个闭环,Agent 只是一个会调用工具的模型;有了这个闭环,它才开始接近一个能完成工作的系统。
如何评估 Harness 是否真的有效
好的 Harness 不只是让 Agent 能行动,还要让行动可验证、可控、可复现。
评估 Harness 可以看七个维度。
成功率:Agent 是否真的完成了任务,而不是只产出了一段看似合理的回答。对于工程任务,成功率应该尽量绑定测试、构建、部署或明确验收条件。
验证证据:Agent 是否能提供可审查的结果。比如测试输出、构建日志、Git diff、截图、CI 链接,都比“我已经完成”更可靠。
成本:Harness 会消耗 token、时间、工具调用和沙箱资源。一个复杂 Harness 如果只能提升很少成功率,可能不值得。好的设计应该把复杂度放在高价值任务上。
稳定性:换一个任务、换一个模型、换一个仓库后,Harness 是否仍然有效。如果 Harness 只在某个 demo 场景里表现好,就很难变成长期能力。
安全性:Agent 能访问什么、能执行什么、能修改什么,都需要边界。权限过宽时,Agent 的错误会直接变成系统风险。
可维护性:Prompt、Skill、工具描述、状态文件和验证命令都需要维护。Harness 一旦变成没人敢改的隐形流程,长期效果会下降。
可迁移性:一个好 Harness 应该沉淀出可复用模式,而不是只服务一次任务。例如“读取上下文、修改文件、运行验证、检查 diff、再提交”就是可以迁移到很多 Codex 任务中的链路。
评估 Harness 的重点不是它看起来多复杂,而是它是否稳定提升了任务完成质量,并让失败更容易定位。
实践框架:把 Harness 思维迁移到 Codex 工作流
对个人开发者来说,Codex 本身就是一种轻量 Agent Harness。模型负责理解和生成,Codex 提供文件系统、终端、编辑器、Git、浏览器、工具调用和权限边界。真正影响效果的,不只是“让 Codex 写什么”,而是你是否把任务组织成一条可执行、可观察、可验证的工作流。
一个通用 Codex 工作流可以拆成八步:
Project Rules
→ Task Definition
→ Context Loading
→ Plan / Decomposition
→ File Editing
→ Verification
→ Git Diff
→ Delivery
Project Rules 是工作流的底座。把稳定规则写进 AGENTS.md 或项目文档,例如代码风格、目录约定、测试命令、提交边界、语言偏好和禁止操作。这样 Codex 每次进入项目时,不需要靠临时提示词重新理解基本约束。
Task Definition 决定任务能不能被执行。一个好的任务描述至少要包含目标、范围、约束和验收方式。比如“修复登录报错”不如“修复登录页提交后 500 的问题,不改接口协议,完成后运行单测和登录 smoke test”。任务越接近可验证状态,Codex 越容易形成闭环。
Context Loading 是把上下文从“全部给模型”改成“按任务读取”。先让 Codex 查看项目结构、相关文件、错误日志和最近变更,再决定下一步。不要一次性塞入大量无关背景;更好的方式是让模型通过搜索、文件读取和命令输出逐步建立上下文。
Plan / Decomposition 用来降低长任务风险。对简单修改,Codex 可以直接执行;对跨模块、多文件、涉及部署或数据迁移的任务,应该先拆成步骤,并明确每一步的验证点。计划不是形式主义,它是让 Agent 在长任务里保留方向的状态载体。
File Editing 是 Codex 的主要行动层。这里最重要的是控制修改边界:只改和当前任务有关的文件;遇到已有未提交改动时,先识别哪些属于用户、哪些属于当前任务;不要用大范围重构掩盖局部问题。
Verification 是 Codex 工作流里最关键的 Harness 能力。不同项目的验证命令不同,可能是 npm run build、npm test、pytest、go test、lint、类型检查、浏览器预览或接口 smoke test。没有验证,Codex 只是生成了修改;通过验证,修改才变成可交付结果。
Git Diff 是人工审查和机器行动之间的边界。每次完成修改后,都应该看 diff:确认有没有无关文件、有没有意外删除、有没有格式化噪音、有没有把本地配置或敏感信息带进去。Codex 的行动能力越强,diff 审查越重要。
Delivery 是交付动作,可以是给出补丁说明、提交 commit、推送远程、打开 PR 或部署。交付前应该说明做了什么、验证了什么、还有什么风险。对于高风险任务,Delivery 之前还应该有人类确认。
这个通用框架可以迁移到大多数 Codex 场景:
- 写博客时,Verification 是构建、预览和链接检查。
- 写代码时,Verification 是测试、类型检查和关键路径 smoke test。
- 做重构时,Git Diff 用来确认行为边界没有被扩大。
- 修 CI 时,Delivery 应该包括失败原因、修复点和重新运行结果。
这就是 Harness 思维对 Codex 的意义:不要只把它当成更会写答案的模型,而要把它放进一条有规则、有上下文、有计划、有验证、有审查的工程链路里。Prompt 让模型理解任务,工作流让模型把任务做完。