从 Prompt 到 Harness:Agent 到底是什么,以及它如何真正做事
把 Agent 相关的概念梳理总结一下:Prompt、Context、Tool、Skill、MCP、Harness、Sub-agent、Workflow、Loop。这些词已经出现很久了,经常一起出现,却不在同一个层次上,结果是大家讨论 Agent 时,容易把“模型会不会思考”“产品给了哪些工具”“系统怎样运行”混成一件事。
我更喜欢从一个具体问题开始:
如果我只对一个 LLM 说“帮我修好这个 bug”,它为什么只能给建议;而 Claude Code、Codex 或 Pi 却能读代码、改文件、运行测试,最后把一个可工作的结果交给我?
答案不是多写几句 Prompt,而是给模型接上了一套可以观察、行动、获得反馈并继续行动的运行环境。
Prompt:这次想完成什么?
Context:模型现在知道什么?
Harness:模型能看见什么、能做什么、边界在哪里?
Loop:做完一步后,谁把结果送回来并决定是否继续?
这篇文章不试图给 Agent 下一个唯一的学术定义,而是从工程实现出发,建立一套足以阅读和设计 Agent 的心智模型。先给出一个足够实用的工程定义:
Agent = Model + Context + Actions + Execution Loop

1. 先把四个词放回各自的位置
Prompt:告诉模型目标和约束
Prompt 是发送给模型的指令与输入。它可以包含:
- 用户的目标:修复一个 bug、实现一个 API、分析一份数据;
- 约束:不要修改接口、遵守项目风格、不能访问生产环境;
- 输出格式:给出计划、返回 JSON、修改代码并报告测试结果;
- 当前对话:用户和模型之前说过的话。
如果只使用一次模型调用,Prompt 往往就是整个交互的中心:模型读完输入,生成一段文本,任务结束。
但 Agent 任务通常不是一次回答就能完成的。模型不知道仓库当前有哪些文件,不知道测试命令是否成功,也不能凭空修改电脑。Prompt 只表达“想要什么”,并不自动提供“做什么”的能力。
Context:模型这一次究竟看到了什么
Context 是某一次模型调用真正收到的上下文。它不等于用户输入,而是由多种信息拼出来的:
Context
├── system prompt:身份、基本规则、工具协议
├── developer / project instructions:仓库规范、团队约定
├── user prompt:这次任务
├── conversation history:之前的对话和工具结果
├── tool schemas:可以调用哪些工具、参数是什么
└── retrieved state:文件内容、测试输出、数据库结果、网页片段
同一个 Prompt,放在不同 Context 里,结果可能完全不同。让模型知道“这是一个 Go 项目,测试命令是 go test ./...”,和只告诉它“修好 bug”,不是同一个任务。
Context 也不是越多越好。无关的 README、过期规则和重复的工具描述会挤占窗口,稀释真正重要的约束。一个好的 Agent 会把信息分层:稳定规则常驻,任务相关知识按需加载,工具结果只保留对下一步有用的部分。
Harness:包住模型的运行时
Harness 可以直译成“马具”,在这里更接近 Agent 的运行时或控制层。它连接四样东西:
用户 / 上层应用
│
▼
Harness ─── 模型 API
│ │ │
│ │ └── 状态:会话、文件、任务、权限、成本
│ └───── 工具:read / edit / bash / browser / MCP
└──────── 控制:循环、压缩、重试、审批、停止条件
│
▼
真实环境:文件系统、shell、网络、数据库、CI
Harness 决定模型看到哪些信息、可以调用哪些工具、工具在哪里执行、结果如何返回、什么时候需要人批准,以及任务什么时候算完成。Claude Code、Codex CLI 和 Pi 都不只是“给模型发 Prompt 的脚本”,而是不同取舍的 Harness。
Loop:让一次回答变成持续行动
最小的 Agent Loop 大致是:
用户目标
↓
组装 Context
↓
调用模型
↓
模型返回文本,或一个 Tool Call
↓
执行工具,获得 Observation
↓
把 Observation 放回 Context
↓
继续调用模型,直到完成、失败或被停止
模型并没有在一次调用里“偷偷操作电脑”。它每次提出一个动作,Harness 执行动作,再把真实结果交还给模型。所谓 Agent 的自主性,主要来自这个循环能够持续运行,而不是模型突然获得了人类意义上的意志。
2. 一个修 bug 的请求,实际经过了什么
假设用户说:
修复登录接口偶发返回 500 的问题,并补上测试。
一个简单的聊天模型可能直接猜测原因,给出一段代码。一个 coding agent 则更可能经历下面的过程:
1. 读取项目说明和目录
2. 搜索登录接口、错误日志和相关测试
3. 打开关键文件
4. 推断可能的失败路径
5. 修改实现
6. 运行针对性测试
7. 看到失败输出后继续修改
8. 运行完整测试或 lint
9. 检查 diff,向用户报告事实
这里每一步都需要不同的能力:
| 行为 | 所需能力 |
|---|---|
| 读取目录和文件 | 文件系统工具、当前工作目录 |
| 搜索代码 | shell 或专门的搜索工具 |
| 修改实现 | 精确编辑/写文件工具 |
| 运行测试 | shell 执行器、超时与输出截断 |
| 根据失败继续 | Loop、状态持久化、错误作为反馈 |
| 安全执行 | 沙箱、权限、审批、网络策略 |
| 最终报告 | 读取真实 diff 和测试结果 |
这张表很重要:模型负责提出下一步,Harness 负责让下一步真的发生,并把结果带回来。模型再聪明,如果工具不可用、结果没有回到 Context,或者 Harness 在第一次回答后就退出,系统仍然不是一个能完成任务的 Agent。
3. Agent 不只是“更好的 Prompt”
Prompt engineering 关注的是:怎样描述任务,模型更容易给出正确答案。Agent engineering 还要问:
- 模型如何看到环境事实?
- 它如何改变环境?
- 改变之后如何验证?
- 失败时如何恢复?
- 哪些动作需要人批准?
- 运行多久、花多少钱、何时停止?
可以把一次 Agent 任务的质量粗略写成:
结果质量
≈ 模型推理能力
× Context 质量
× 工具可用性
× Loop 的反馈质量
× 验证与安全边界
这不是数学公式,而是一个提醒:任意一项接近零,整体效果都会很差。一个强模型拿不到代码,无法修 bug;一个工具很多但没有测试反馈的 Agent,可能会自信地宣布“已经修好”;一个循环没有停止条件的 Agent,则可能不断重复同一件事。
4. Boris 的观点:Agent 更像给 LLM 做事的能力
你提到的 Boris Cherny 的那种说法,我认为可以归纳为:Prompt 更像是在告诉模型做什么,Harness 则是在给模型做事的能力。
这句话的重点不在于 Prompt 不重要,而在于两者解决的是不同问题。
“把这个函数改成异步”
│
├── Prompt:目标、约束、验收标准
│
└── Harness:读文件、搜引用、编辑、编译、测试、查看 diff
如果只有 Prompt,模型最多能描述修改方案;有了工具和循环,它才有机会验证方案、面对错误,并把修改落到真实文件中。
这也解释了一个常见现象:同一个模型放进不同 Agent 产品,体验差异可能非常大。差异未必来自模型权重,可能来自:
- 一个产品默认把哪些项目文件放进 Context;
- 工具返回的是完整输出还是经过整理的摘要;
- 是否自动读取测试失败日志;
- 是否有权限审批和沙箱;
- 是否会在上下文过长时压缩历史;
- 是否有停止钩子、后台任务和验证阶段。
不过,“给能力”不等于“把所有能力都打开”。能力必须和边界一起设计:可以读整个仓库,不代表可以删除整个磁盘;可以运行测试,不代表可以把生产凭据放进环境变量;可以访问网络,不代表应该允许任意外发数据。
我更愿意把 Boris 的观点理解成一种工程重心的变化,而不是一句“Prompt 已经不重要”:当模型已经能够理解自然语言和代码时,瓶颈会越来越多地转移到环境、工具、反馈、权限和验证上。
5. 从 Pi 出发:一个 Agent 最小需要什么
Pi 很适合用来讨论“Agent 的最小能力”。它的设计方向不是预装尽可能多的产品功能,而是提供一个很小的核心:模型、上下文、工具调用和循环,再通过扩展增加能力。Pi 的 coding agent 默认提供 read、write、edit、bash 四类基本工具,并支持通过 extensions、skills、prompt templates 和 packages 扩展。
把最小 coding agent 抽象成伪代码,大概是:
const tools = [read, write, edit, bash];
const messages = [systemPrompt, userPrompt];
while (true) {
const response = await model.complete(messages, tools);
messages.push(response);
if (response.type === "text") {
return response.text;
}
for (const call of response.toolCalls) {
const observation = await execute(call);
messages.push(observation);
}
}
这段代码看起来很朴素,但已经包含 Agent 的核心闭环:
- 模型接口:能返回普通文本,也能返回结构化 Tool Call。
- 工具注册:模型知道有哪些工具、参数如何填写。
- 工具执行:Harness 把 Tool Call 变成真实环境中的动作。
- 结果回传:工具结果成为下一次推理的上下文。
- 状态保存:至少保存当前对话和工具结果,必要时支持恢复。
- 停止机制:模型完成、出错、超时或用户中止时退出。
缺少其中任何一项,系统都会退化:
没有工具 → 只能回答,不能行动
没有结果回传 → 只能盲猜,不能根据现实修正
没有状态 → 每一步都像失忆
没有停止机制 → 可能无限循环或失控
没有边界 → 能做事,但不敢让它做
为什么四个工具就能做很多事
read 让模型获得事实,write 和 edit 让它改变代码,bash 让它运行搜索、测试、编译和自定义脚本。工具数量不多,但组合空间很大:
read → 理解现状
edit → 改变实现
bash → 观察反馈
loop → 根据反馈继续
这是一种很有启发性的设计:工具不需要替模型预先实现每一种工作流。只要环境提供足够通用、可组合、反馈清晰的原语,模型就能在循环中临时组织出工作流。
Bash 为什么接近“万能 Primitive”
如果 Agent 拥有一个受控的 bash(command),它理论上就能调用 git、grep、find、pytest、go、psql、kubectl 和各种项目脚本。甚至 read、write、edit 都可以用 cat、shell redirection、sed 或脚本间接完成。
LLM + bash + loop
↓
搜索、读取、修改、编译、测试、部署脚本
但“理论上能做”不等于“适合直接暴露”。专用的 read(path, offset, limit) 比任意 shell 更容易限制路径、限制输出、记录行为和返回结构化结果;edit 也比让模型拼接复杂 sed 命令更容易验证失败原因。因此 Primitive 的目标不是追求数学意义上的最小,而是追求:
少量、正交、可组合、可观察、容易授权的基本能力。
这也是为什么一个只有几个工具的 Agent,反而可能比拥有几百个语义重叠 Tool 的 Agent 更稳定。search、find、lookup、fetch 如果职责和描述差不多,模型先要解决 Tool Selection Ambiguity;而 read、edit、bash 的边界更清楚,复杂行为由组合产生。
当然,最小能力不等于生产能力。真正的产品还需要权限、沙箱、上下文压缩、并行任务、子 Agent、日志、恢复、成本控制和可观测性。Pi 的价值正在于把“核心闭环”和“产品层功能”分开,让使用者看得见两者的边界。
6. Skill 和 MCP:一个教方法,一个接能力
Skill:按需加载的做事方法
Skill 通常是一组可复用的任务知识:说明、规范、脚本、模板、示例和资源。它回答的是:
面对某类任务,应该采用什么流程、遵守什么规则、使用哪些辅助材料?
例如一个 PDF skill 可以告诉 Agent:先识别文档结构,再提取表格,最后用指定脚本检查输出;一个数据库迁移 skill 可以规定:先生成 migration,再运行测试,禁止直接修改生产库。
Skill 不一定提供新的底层能力。它更像操作手册或领域 playbook:模型本来就能调用 bash,Skill 告诉它什么时候运行哪个脚本、如何判断结果、失败后怎么办。
一个典型 Skill 可以这样组织:
pdf-processing/
├── SKILL.md ← 入口:何时使用、流程和约束
├── references/ ← 需要时读取的详细说明
├── scripts/ ← 可执行的确定性工具
└── templates/ ← 输出模板
Skill 最重要的设计原则是按需加载。所有领域知识一开始都塞进 system prompt,会造成 Context 膨胀;先让 Agent 发现有哪些 Skill,再只加载当前任务需要的那一个,通常更经济,也更容易维护。
MCP:把外部能力接入统一协议
MCP(Model Context Protocol)解决的是另一个问题:
外部系统如何以统一方式向 Agent 暴露工具、资源和提示模板?
Agent Harness(MCP Client)
│ MCP
├──────── 文件系统服务器
├──────── GitHub 服务器
├──────── 数据库服务器
└──────── 浏览器 / SaaS / 内部系统服务器
MCP Server 可以暴露:
- Tools:模型可以调用的动作,例如查询 issue、创建文档、执行受限数据库操作;
- Resources:客户端或模型可以读取的上下文,例如某个文档、schema 或配置;
- Prompts:可复用的提示模板。
因此,Skill 和 MCP 的关系可以简单记为:
Skill:怎样完成一类任务?
MCP:怎样连接一个外部能力?
两者经常组合使用。比如“发布周报”这个 Skill 规定流程:读取数据、生成摘要、人工确认、发布;MCP 提供读取数据库、访问文档系统和发消息的工具。
MCP 不是 Agent Loop,也不是安全边界本身。它定义了能力如何被发现和调用,但真正的权限审批、凭据管理、超时、审计和沙箱,仍然需要 Harness 或 MCP Server 自己负责。
CLI-first 与 MCP-first
Pi 这类 Agent 很容易采用 CLI-first 的组合方式:
Agent → bash → gh / kubectl / psql / curl → 外部系统
它的优点是成熟、透明、容易让人和 Agent 共用,也方便在终端复现问题。MCP 则更偏 Protocol-first:
Agent → MCP Client → MCP Server → 外部系统
它带来工具发现、结构化 schema、统一调用格式和跨 Agent Host 复用。两者不是替代关系:一个内部服务和一个 Agent 可能直接用 Native Tool 最简单;当多个 Agent 都要连接 GitHub、数据库或内部系统时,MCP 的标准化价值才会明显。
无论使用 CLI 还是 MCP,都要遵守同一条边界:
LLM 提议动作
↓
Schema 校验
↓
权限与策略判断
↓
确定性执行器执行
Tool description 是给模型看的 API 文档,但它不能替代 Authorization。Schema 可以把 environment 限制为 dev、staging,却不能单独决定当前用户是否有权访问 staging;危险动作还需要 allowlist、dry-run、人工确认和审计。
7. Harness 应该承担哪些责任
当一个 Agent 从 demo 走向日常工作,Harness 的价值通常集中在下面几层。
Context 管理
Harness 要决定什么进入上下文、什么延迟加载、什么被压缩或丢弃:
常驻:身份、核心安全规则、项目入口
按需:Skill、参考文档、MCP 资源
即时:当前文件片段、命令输出、测试失败信息
可丢弃:已经解决的中间过程、重复日志、旧计划
上下文压缩不是简单截断字符串。好的压缩会保留目标、已完成修改、未解决问题、关键错误和下一步约束,否则模型可能在压缩后忘记自己为什么改某个文件。
工具执行与 Observation
工具执行结果是 Agent 的“感官”。一个好的 Observation 应该:
- 真实:明确命令是否执行、退出码是什么;
- 有用:突出错误位置和关键输出;
- 可继续:让模型知道下一步能做什么;
- 可控:限制输出大小、超时和敏感信息泄露。
如果测试失败只返回“command failed”,模型没有足够信息修复;如果把几万行日志原样塞进 Context,又会淹没真正错误。
权限与安全
Agent 的风险来自“模型能做什么”和“模型被什么输入影响”。除了工具权限,还要考虑 prompt injection:仓库里的 README、issue、网页内容都可能包含诱导模型执行危险操作的文本。
常见的边界包括:
- 文件系统允许读写范围;
- shell 命令审批和危险命令拦截;
- 网络是否开放、允许哪些域名;
- 是否能读取凭据和环境变量;
- 修改是否必须经过人工确认;
- 每步、每个任务和整个会话的预算。
“模型决定调用什么工具”和“系统允许它调用什么工具”应该是两层判断。MCP 暴露了一个工具,不等于当前任务就有权使用它。
Subagent:扩展并行性,不是最小能力
Subagent 不是最小 Agent 必需的 Primitive。一个 Model + Context + read/edit/bash + Loop 已经可以完成大量编码任务。Subagent 主要解决三件事:并行执行、专业化分工和 Context Isolation。
Parent Agent
/ | \
▼ ▼ ▼
Security Database Performance
Agent Agent Agent
\ | /
└── summaries ──┘
↓
Parent merge
子 Agent 不需要看到父 Agent 的全部历史,只需要收到目标、相关文件和约束,最后返回摘要、证据和待处理问题。这种隔离能降低上下文噪声;但一旦引入多 Agent,系统就开始面对调度、超时、重试、任务归属、共享文件冲突和结果合并等分布式系统问题。
因此,Multi-Agent 不天然优于 Single-Agent。只有当并行性、专业化或上下文隔离确实带来收益时,才值得支付额外的协调成本。
验证与停止
Agent 不应把“模型说完成了”当成完成。完成最好由外部证据定义:测试通过、lint 通过、diff 符合预期、文件存在、API 返回正确结果。
模型:我认为已经修好了
↓
Harness:运行测试、检查 diff、收集退出码
↓
证据:测试通过 / 仍有失败
↓
Loop:结束,或继续修复
停止条件同样重要:成功条件、最大步数、超时、预算、重复动作检测、用户中止和不可恢复错误都应该明确。
8. Claude Code、Codex、Pi 与 DeepSeek Harness 怎么比较
这里把 Harness 当作 Agent Runtime 来讨论。它有时也指评测脚手架、工作流编排器或产品中的 Agent 控制层,语境不同,不能把这些含义混在一起。DeepSeek Harness(DSH)则是 DeepSeek 推出的、以插件为核心的开源 Agent Harness:模型、工具、Skill、会话、沙箱、存储、循环、调度和 UI 都可以作为插件替换或重新组合,目前仍处于 developer preview 阶段。
更有意义的比较维度不是“谁的模型更聪明”,因为产品使用的模型、版本、权限和任务都可能不同,而是:谁负责循环,工具多大,默认上下文多少,安全边界在哪里,扩展成本如何。
| 维度 | Claude Code | Codex | Pi | DeepSeek Harness |
|---|---|---|---|---|
| 定位 | 面向软件工程的完整 coding agent | 面向编码任务的 Agent 产品与运行时 | 极简、可改造的 terminal coding harness | 插件优先、可组合的 Agent Harness |
| 核心取舍 | 开箱即用、工作流完整 | 模型、沙箱、审批和多客户端能力结合 | 小核心、低预设、强可塑性 | 把 Harness 本身拆成可替换插件,换取组合能力与更高系统复杂度 |
| 工具与环境 | 文件、shell、项目指令、扩展等 | 文件和 shell 能力,并强调沙箱、审批、客户端集成 | 默认 read/write/edit/bash | 由设计者决定 |
| 扩展方式 | Skills、hooks、plugins、MCP 等 | Skills、MCP、应用/协议层扩展 | TypeScript extensions、Skills、packages | 任意代码、协议和工作流 |
| 编排能力 | 产品内置较多工作流能力 | 支持线程、持久化和多种客户端形态 | 核心保持简单,更多能力交给扩展 | Standard、Code Mode、Minimal、Creator 等预设,能力也可由插件重组 |
| 适合谁 | 想直接在代码库中工作的人 | 想要受控、可集成的编码 Agent 的团队 | 想理解、改造和自定义 Agent 的工程师 | 想研究 Harness、开发插件或用 DeepSeek 模型构建 Agent 的工程师 |
| 主要代价 | 默认行为和上下文较复杂,需要理解其约定 | 平台、权限和运行环境需要配置 | 许多高级能力需要自己搭建 | 生态和 API 仍在演进,插件组合、兼容性和安全需要自己判断 |
Claude Code:能力密度高的产品化 Agent
Claude Code 把项目指令、文件操作、shell、权限、hooks、skills、MCP 等组合成一个面向软件工程的完整体验。它的优势是把大量常见工作流预先产品化:用户可以直接在仓库中描述目标,让 Agent 自己搜索、编辑、运行验证。
它的代价是“默认世界”比较大:系统提示、工具协议、项目规则和扩展都可能参与一次调用。对于希望少操心基础设施的人,这种默认值很有价值;对于想精确控制 Token、上下文和循环的人,则需要理解并调整这些层。
Codex:把 Agent 作为可受控的运行时
Codex 可以从 CLI、应用和其他客户端使用。它的关键不只是“会写代码”,而是把 thread 生命周期、配置认证、工具执行、沙箱、MCP、Skills 和客户端集成放进一个可持续演进的运行时。这样,终端、IDE 和桌面应用可以共享同一类 Agent 核心,而不必各自重写循环。
它代表一种产品化方向:Agent 不再只是一个命令行 UI,而是一个可以被多个界面驱动、能够持久化和审计的服务/运行时。相应地,用户需要更多理解权限、沙箱、网络访问和线程状态。
Pi:把“Agent 是什么”缩到最小
Pi 的有趣之处在于它刻意不替用户预装所有复杂性。最小的四工具闭环已经能完成很多 coding task,其他能力可以通过扩展和 packages 逐步加入。
它更像一个可编程材料:你可以从一个小核心开始,自己决定是否需要 MCP、子 Agent、计划模式、主题、RPC 或 SDK。这个取舍让 Pi 特别适合研究 Agent 原理、适配不同模型、构建自己的工作流;但它也要求使用者承担更多设计工作。
DeepSeek Harness:把“Everything is a Plugin”贯彻到底
DeepSeek Harness 的核心取舍不是只提供一个更轻的 coding agent,而是把 Harness 的组成部分都放进插件模型:模型 provider、工具、Skill、session、sandbox、filesystem、loop、scheduler 甚至 UI 都可以被替换和组合。它更像一个可以装配 Agent 的运行时,而不是一个固定功能的客户端。
它还提供不同的运行预设:标准模式提供完整能力,Code Mode 让模型通过 SDK 把多步操作组合成程序,Minimal 模式只保留持久化 bash 和编辑器,Creator 模式则帮助开发者检查运行时、实验插件并创建自己的 preset。对想研究 Harness 的工程师来说,这种“把脚手架本身暴露出来”的设计很有意思;对只想马上完成任务的用户来说,插件和预设也意味着更多需要理解的配置。
自定义 Harness:当工作流本身就是产品
如果任务有强业务约束,例如处理生产事故、审批金融操作、运行长时间数据管道,通用 coding agent 可能不够。这时可以自己构建 Harness:
任务状态机
↓
模型负责局部判断
↓
确定性工具负责关键动作
↓
策略引擎负责审批和权限
↓
验证器负责验收
↓
事件日志和可恢复状态
自定义 Harness 的优势是可以把不可违反的规则写成代码,把 Agent 放在适合它的模糊判断环节;缺点是你需要自己维护模型适配、上下文策略、错误恢复、观测、成本和安全。
9. 模型越强,Harness 是否应该越轻
你的这个感觉是成立的,但需要加一个限定:随着模型的工具使用、规划和自我修正能力增强,过重的 Harness 确实可能从“脚手架”变成“限制器”;但安全、验证和状态管理这些确定性能力不会因为模型变强而自动消失。
可以把 Harness 看成模型和环境之间的一层接口。如果模型还不擅长使用工具,Harness 需要提供更多流程引导;如果模型已经能自己决定先搜索、再修改、再测试,那么过多的固定步骤、重复提示和封闭工具会限制它的行动空间。
弱模型 + 重 Harness
→ 需要更多流程、示例、专用工具和强约束
强模型 + 轻 Harness
→ 只提供清晰的 Primitive、真实反馈和安全边界
强模型 + 过重 Harness
→ 可能被固定流程、提示噪声和工具选择限制
过重 Harness 常见的限制方式包括:
- Prompt tax:每次调用都附带大量静态规则和工具描述,真正的任务反而被挤到 Context 边缘;
- 流程锁定:强制模型先规划、再分解、再执行固定步骤,模型无法根据任务简单程度选择更短路径;
- 工具替代判断:为每种场景制作一个高级工具,模型被迫在大量近似 Tool 中选择,而不是组合少量正交 Primitive;
- 反馈失真:Harness 只返回摘要或预设状态,模型看不到足够的原始事实,无法自行诊断;
- 能力封顶:系统只允许产品设计者预想过的动作,模型即使知道更好的 CLI 或脚本路径,也无法尝试。
这也是 Pi 的最小主义和 DeepSeek Harness 的插件化值得研究的原因:它们把更多控制权交还给模型或使用者,让 Harness 不必替模型预先写完所有工作流。对于能力很强的模型,一个清晰的 bash、文件工具、测试反馈和可控环境,可能比十个“智能助手”式的高级 API 更能发挥能力。
但轻并不等于裸奔。以下能力最好仍由 Harness 用确定性代码负责:
模型可以决定:下一步读哪个文件、运行哪个测试、是否需要继续
Harness 必须决定:能不能访问、是否需要批准、最多运行多久、结果如何验证
换句话说,应该减少的是替模型做认知决策的部分,而不是减少安全边界、验证器、状态持久化和故障恢复。理想状态不是“没有 Harness”,而是一个薄而透明、可替换、可观察、会随模型能力变化而收缩或扩展的 Harness。
这会带来一个新的设计问题:Harness 不应该只有一个固定档位。简单任务可以走 Minimal Loop;复杂任务再按需启用 Skill、MCP、Subagent、Compaction 和审批。让能力渐进式出现,通常比一开始把整个系统的复杂性都暴露给模型更好。
10. 不要只比较 Agent,要比较 Model × Harness
“哪个 Agent 最强”通常不是一个稳定问题。更合理的单位是:
一次真实结果 = Model × Harness × Context × Environment × Human policy
同一个模型在四个 Harness 中可能表现不同:
- Harness A 自动读取正确的文件,并在每次修改后运行测试;
- Harness B 把整个仓库塞进 Context,却不告诉模型测试结果;
- Harness C 工具权限太少,模型只能输出建议;
- Harness D 权限太大,但没有验证和停止条件。
如果要做公平比较,至少应该固定:模型版本、任务、仓库状态、工具权限、网络条件、上下文预算、是否允许人工干预、成功标准和总成本。否则比较出来的往往不是 Agent 能力,而是默认配置差异。
对日常使用者,可以用下面的问题选择:
| 你的问题 | 更可能适合 |
|---|---|
| 我只想在仓库里直接完成开发任务 | Claude Code / Codex |
| 我想把 Agent 接到 IDE、服务或自己的产品 | Codex 或自定义 Harness |
| 我想理解 Agent 最小闭环并自己改造 | Pi |
| 我有严格审批、审计、状态机和长任务需求 | 自定义 Harness,必要时组合现成 Agent |
11. Agent 最容易失败的地方
把计划当成进展
模型说“我会修改 A、运行 B、检查 C”,不代表这些事已经发生。Harness 应该把计划和实际 Tool Call、退出码、diff 分开记录。
把工具数量当成能力
工具越多,Context 和权限复杂度越高。一个清晰的 bash 加文件工具,可能比十几个边界模糊的工具更容易让模型正确使用。工具描述必须准确,错误的 schema 会直接变成模型的错误行动。
把上下文越长越好
上下文的价值取决于相关性和时效性。旧日志、重复文件和过期规则会降低信噪比。Context engineering 的目标不是装满窗口,而是让下一次决策拥有足够事实。
让 Agent 自己宣布成功
“看起来应该可以”不是证据。测试、lint、类型检查、diff、部署预检和业务查询,应该尽量由 Harness 自动运行。
在事务或高权限环境里无限循环
长任务一定会遇到超时、上下文耗尽、网络失败、工具异常和模型重复。没有预算、checkpoint、重试上限和人工接管,Agent 的自主性就会变成不可控性。
12. 一个 Agent System 的分层模型
把前面的概念放在一起,可以得到一个由下而上的分层:
Layer 4:Coordination
Subagent / Delegation / Communication
Layer 3:Knowledge & Integration
Skill / Memory / MCP
Layer 2:Runtime
Context / Loop / Compaction / Permission / Verification
Layer 1:Action Primitives
read / write / edit / bash
每一层回答的问题不同:
- Layer 1:我如何观察和改变环境?
- Layer 2:我如何持续、可靠、受控地运行?
- Layer 3:我知道什么,以及如何连接外部能力?
- Layer 4:我如何把工作拆分给其他 Agent,并合并结果?
设计时最好从下往上增加能力。一个简单任务先用 Primitive 和 Single-Agent Loop;遇到上下文过长,再加 Compaction 或 Subagent Isolation;遇到外部系统复用,再考虑 MCP;遇到严格业务流程,才引入更复杂的协调和状态机。
总结:Prompt 是意图,Harness 是能力,Loop 是行动
可以用下面这张图记住全文:
用户意图
↓ Prompt
模型当前知道什么
↓ Context
模型能够做什么
↓ Harness + Tools + Skills + MCP
做了一步后现实发生了什么
↓ Observation
是否继续、修正、请求批准或结束
↓ Loop + Verification + Policy
最终结果
Agent 的核心不在于给 LLM 换一个更神秘的名字,而在于把它从“一次性文本生成器”放进一个能够观察环境、采取行动、获得反馈、持续运行并接受约束的闭环里。
Pi 展示了这个闭环可以小到四个工具和一个循环;Claude Code 和 Codex 展示了它如何被做成面向真实工程的产品;DeepSeek Harness 则展示了如何把模型、工具、循环和 UI 都拆成可替换的插件;自定义 Harness 进一步展示了当工作流、权限和验收本身成为业务时,Agent 需要怎样嵌入更大的系统。
所以,与其问“应该给 LLM 写什么 Prompt”,不如同时问四个问题:
它应该知道什么?能够做什么?每一步如何获得真实反馈?什么证据能证明它完成了?
这四个问题,才是从 Prompt 走向 Agent 的起点。