Harness Engineering

1、什么是 Harness

AI 圈最近又造了一个词,Harness Engineering,这也是目前 AI 圈的风向转变:从「比拼模型智商」变成了「比拼系统稳定」。

Harness Engineering

Harness 本义是马具(缰绳、马鞍等),作用是套在马上,控制马的方向、力量,让马既能全力奔跑,又不跑偏、不闯祸。Agent 就像「动力十足但不守规矩的野马」:大模型 / Agent 能力极强,但容易出现幻觉、跑偏、失控;而 Harness Engineering(马具工程),就是给这匹「AI 野马」套上专业的马具,让它既能发挥 AI 的强大能力(跑得快),又能被精准控制方向、全程管控,最终输出可靠、安全、合规的结果。

Harness Engineering 并不是突然出现的,而是经历了3 个阶段:

  • 阶段 1:Prompt Engineering(提示词工程)
    核心关注点:「怎么跟 AI 说话」。精心设计提示词引导 AI 完成任务,是 AI 早期的「入门驾驭法」。但很多时候不是说清楚就行了,而是 AI 必须真的知道。所以提示词解决的是表达问题,但没解决信息问题。
  • 阶段 2:Context Engineering(上下文工程)
    核心关注点:「给 AI 什么信息」。给 AI 搭建 Memory 记忆、Tool Call 工具调用,把正确的信息传递给模型,解决提示词工程「信息不足」的问题,而当信息太多时,注意力就会涣散,这时可以通过 skill 渐进式披露,把信息按需分配给大模型。但即使信息给对了,大模型仍可能在中途跑偏了,提示词和上下文都只能约束输入,没有执行过程中的纠偏。
  • 阶段 3:Harness Engineering(马具工程)
    核心关注点:「构建什么环境让 AI 工作,如何保证 AI 产出可靠」。比 Context Engineering 更进一步,不仅管理 AI 的输入信息,还管控模型之外的整个执行环境,让模型别跑偏,验证结果是否正确。

Agent 的核心是一个「感知-决策-行动」的自主循环。给它一个目标,它会自己决定先读哪个文件、再跑什么命令、然后改哪行代码,整个过程可能循环几十轮,直到任务完成。

那么 Harness 到底是什么,与 agent 之间又是什么关系呢?简单的说,agent = model + harness。

通过小学数学变形一下,那么 harness = agent - model。

也就是说,在一个 agent 系统里,除了模型本身以外,几乎所有决定 agent 能否稳定交付的东西,都是 harness。

前段时间泄露的 51 万行的 Claude Code 源码,简直就是 Harness Engineering 的最佳教科书,其 80% 的代码不是在搞什么黑科技让 AI 更聪明,而是在死磕 Agent「可靠性」。

2、ReAct 模式的问题

Agent 的核心是 ReAct(Reasoning + Acting)。它是 2022 年提出的一种 Agent 范式,核心思路是把 Agent 的每一步拆成三个阶段:

具体来说,模型在每一轮都会先输出一段「思考」Thought,比如「需要先读取 config.ts 文件来了解数据库连接配置」;然后选择一个工具调用 Action;最后拿到工具结果 Observation。这三步不断循环,直到模型认为任务完成。

但 ReAct 有几个问题:

  • Token 浪费。 每一轮都要输出一段 Thought 文本,这些文本要作为上下文的一部分发给 API。
  • 应用层代码太复杂。 需要解析模型的输出,区分「哪部分是 Thought、哪部分是 Action」,然后提取 Action 调用工具,再把 Observation 拼回去。
  • ReAct 是为「弱模型」设计的。 当大模型的推理能力不够强时,用显式的 Thought 来「强迫」它一步步思考是有意义的。

3、Tool-Use Loop

Claude Code 没有采用 ReAct 的 Thought-Action-Observation 三步循环,而是用了一个更简洁的模式,叫做 Tool-Use Loop。

其核心在于没有 Thought 步骤。模型在内部完成推理(通过 Extended Thinking,不占用上下文空间),然后返回两种结果之一:

  • tool_use:「工具使用」,应用层执行工具,把结果拼入消息列表,继续循环;
  • end_turn:「结束轮次」,跳出循环,把最终结果返回给用户。

这个设计的核心是:「大道至简」,信任模型的推理能力,保持应用层框架尽可能简单

但是 ReAct 的设计哲学是「帮模型思考」,用显式的 Thought 步骤引导模型一步步推理。这在弱模型时代是必要的。

4、Plan Mode

Claude Code 不仅有 Tool-Use Loop 这种「边想边做」模式,还有 Plan Mode,一个更精细的两阶段工作流:先规划、再执行。

Plan Mode 的核心思想是:复杂任务应该先规划再执行,避免方向跑偏、浪费精力。它并不是一个独立的框架,而是在同一个 Tool-Use Loop 中通过 EnterPlanMode 和 ExitPlanMode 两个工具实现的:

整个流程分三步:

  1. 模型自主进入或用户手动触发。 当模型判断「这是一个复杂任务」时,它会调用 EnterPlanMode 工具。对于简单任务,则不进入。
  2. 只读探索 + 设计方案。 进入 Plan Mode 后,权限降为只读,模型只能用 Read、Grep、Glob 这些工具去探索代码库,不能写文件、不能改代码、不能跑命令。探索完后,把计划写入 .claude/plans/ 目录。每 5 轮对话,系统会偷偷给模型塞一张「小纸条」,提醒它「你现在还在 Plan Mode」,防止模型在长对话中「走神」。
  3. 用户审批后实施。 模型调用 ExitPlanMode,此时需要用户确认。用户批准后,权限恢复为之前的模式,模型开始自由执行读写操作,按计划实施。

Plan Mode 最值得学习的设计是「工具即能力」。对模型来说,Plan Mode 不是一种特殊的「模式切换」,而只是调用了 EnterPlanMode 和 ExitPlanMode 这两个工具。

5、System Prompt

先看一段组装后的 System Prompt 长什么样(简化版):

┌──────────────────────────────────────────────┐
│ [角色定义] 你是交互式代理,帮助用户完成软件工程任务。│  ← 所有用户完全一样
│ [安全红线] 重要:允许协助已授权的安全测试...       │  ← 所有用户完全一样
│ [行为准则] 不要对你没有阅读过的代码提出修改建议。   │  ← 所有用户完全一样
│ [操作安全] 仔细考虑操作的可逆性...               │  ← 所有用户完全一样
│ [工具使用] 当有专用工具可用时,不要用 Bash 执行命令 │  ← 所有用户完全一样
│ [Git 安全] 绝不修改 git config...              │  ← 所有用户完全一样
│ [输出风格] 直奔重点,要极度简洁...               │  ← 所有用户完全一样
├───── __SYSTEM_PROMPT_DYNAMIC_BOUNDARY__ ─────┤
│ [环境信息] 主工作目录: /Users/you/my-project    │  ← 每个用户不一样
│ [CLAUDE.md] 本项目使用 TypeScript + Jest...    │  ← 每个项目不一样
│ [记忆指令] 你有一个持久记忆系统...                │  ← 每次对话可能不一样
│ [MCP 指令] 你已连接 GitHub MCP server...        │  ← 每个用户不一样
└───────────────────────────────────────────────┘

System Prompt 就是 Claude Code 的灵魂,它定义了 Agent 的身份、行为规范、可用工具、安全约束……

5.1、角色定义与安全红线

每个 Agent 的 System Prompt 都要回答一个根本问题:你是谁?Claude Code 的开场是这样的:

你是一个交互式代理(interactive agent),帮助用户完成软件工程任务。
请使用下面的指令和可用的工具来协助用户。
重要:你绝对不能为用户生成或猜测 URL,除非你确信这些 URL
是为了帮助用户完成编程任务。你可以使用用户在消息或本地文件中
提供的 URL。

注意两个关键点。第一,它把自己定位为「interactive agent」,而不是「assistant」或「chatbot」,这从一开始就暗示了模型应该主动采取行动,而不是被动回答。第二,立刻划了安全红线:不能乱编 URL。这看起来是个小事,但对编程 Agent 非常重要,如果模型瞎编一个 npm 包的 URL,用户执行了就可能中招。

紧接着是一段安全约束指令,这段话非常值得每个 Agent 开发者抄作业:

重要:允许协助已授权的安全测试、防御性安全研究、CTF 挑战赛
和教育场景。拒绝涉及破坏性技术、DoS 攻击、大规模目标扫描、
供应链攻击或用于恶意目的的检测规避请求。

这种「先肯定再约束」的写法,比纯禁止清单效果好得多,它给了模型清晰的判断依据,而不是一堆模糊的红线。

5.2、行为准则

接下来是一大段关于「怎么做事」的行为指南,这部分是 Claude Code System Prompt 的精华。

关于修改代码前先阅读:

一般来说,不要对你没有阅读过的代码提出修改建议。如果用户要求你查看或修改某个文件,先读一遍它。在提出修改建议之前,先理解现有代码。

这条看起来简单,但解决了 Agent 的一个常见问题:很多 Agent 会根据用户描述直接生成代码,而不先看看现有代码是什么样的,结果经常和项目风格不一致或者引入重复实现。

关于代码风格:「少即是多」:

不要在用户要求之外添加功能、重构代码或进行"改进"。修一个 bug 不需要顺手清理周围的代码。一个简单功能不需要额外的可配置性。

不要为一次性操作创建辅助函数、工具类或抽象层。三行相似的代码比一个过早的抽象更好。

这个设计思路太重要了。如果你用过 Agent 写代码,你一定遇到过这种情况:你让它修一个 bug,它顺手把整个文件重构了,加了一堆你没要求的类型标注和错误处理。Claude Code 在 Prompt 里明确禁止了这种行为。

关于失败处理:「先诊断再换方案」:

如果某个方案失败了,先诊断原因再决定是否换方案——读报错信息、检查你的假设、尝试有针对性的修复。不要盲目重试完全相同的操作,但也不要因为一次失败就放弃一个可行的方案。

这条解决了 Agent 的另一个常见问题,「摆烂式重试」或「草率放弃」。Claude Code 要求模型先搞清楚为什么失败了,再决定是修复还是换方案,而不是两个极端。

5.3、操作安全

Claude Code 对「什么操作需要用户确认」做了非常详细的规定。

仔细考虑操作的可逆性(reversibility)和影响范围(blast radius)。
一般来说,你可以自由执行本地的、可逆的操作,比如编辑文件或运行测试。但对于难以撤销、影响共享系统或有风险的操作,请先和用户确认后再执行。

需要用户确认的高风险操作示例:
破坏性操作:删除文件/分支、删表、rm -rf
难以逆转的操作:force-push、git reset --hard、修改已发布的 commit
对他人可见的操作:推送代码、创建/关闭 PR、发送消息
上传到第三方工具:内容可能被缓存或索引,即使删除也无法撤回

这段的核心思想是用可逆性和影响范围两个维度来判断风险。读文件、改本地代码是低风险的(可逆、只影响本地),直接放行。git push、发 Slack 消息是高风险的(不可逆、影响他人),必须确认。

然后还有一句非常精妙的补充:

用户批准了某个操作(比如 git push)一次,并不意味着他在所有场景下都批准这个操作。授权仅对指定的范围有效,不能超出范围。

这解决了「权限蔓延」的问题,用户同意了一次 push 不代表以后都自动 push,授权是一次性的、有范围的。这个原则在 Agent 权限设计中非常重要。

5.4、工具使用指南

当有专用工具可用时,不要用 Bash 来执行命令。使用专用工具可以
让用户更好地理解和审查你的工作。
读取文件用 Read 工具,而不是 cat、head、tail 或 sed
编辑文件用 Edit 工具,而不是 sed 或 awk
创建文件用 Write 工具,而不是 echo 重定向
搜索文件用 Glob 工具,而不是 find 或 ls
搜索内容用 Grep 工具,而不是 grep 或 rg

这条规则的设计动机值得深思。为什么不让模型直接用 cat 读文件、用 sed 改代码?技术上完全可以。

原因是可审查性。当模型调用 Read 工具读文件时,UI 会清晰地展示「Agent 正在读取 src/index.ts」。但如果模型执行 cat src/index.ts,用户看到的只是一条 Bash 命令和一大坨输出,完全不知道 Agent 在干什么。

而且,专用工具有专用的权限检查,Read 工具会检查文件路径是否在允许范围内,而 cat 命令就没有这层保护了。所以「用专用工具而不是 Bash」不仅是体验问题,更是安全问题。

6、记忆系统

6.1 记什么:四类型分类

Claude Code 把记忆分成了四种明确的类型:

export const MEMORY_TYPES = [
  'user',      // 用户画像:角色、偏好、知识水平
  'feedback',  // 行为反馈:该做什么、不该做什么
  'project',   // 项目动态:在做什么、截止日期、协作信息
  'reference', // 外部指针:哪里能找到什么信息
] as const

限定四种类型,就是在逼 Agent 做分类决策:每存一条记忆必须想清楚「到底属于哪一类」,而不是一股脑往里塞。

User(用户画像)是最个人化的一类,记住用户是谁、擅长什么、知识水平如何。比如用户说「一个写了十年 Go 的后端工程师,第一次接触 React」,Agent 就应该在解释前端概念时用后端的类比,而不是从零讲起。这类记忆让 Agent 的回答因人而异。

Feedback(行为反馈)是最重要的一类,记住用户说过「不要做什么」和「做得好继续保持」。

Project(项目动态)记的是「正在发生什么」,谁在做什么、截止日期是什么、有什么重要决策。

Reference(外部指针)记的是「去哪找什么信息」,Bug 在哪个项目里追踪、Grafana 看板的地址是什么、Slack 的哪个频道能问到相关的人。这类记忆的价值在于,Agent 不需要知道外部系统的具体内容,只需要知道去哪里找。

6.2、不记什么:排除清单

Claude Code 明确规定了什么不应该存到记忆里,这个设计和「记什么」同样重要。

首先是代码模式、项目架构和文件结构这些信息,通过 grep、git、CLAUDE.md 就能获取,存在记忆里反而会导致记忆和代码实际状态不一致。

然后是 Git 历史和最近的改动,git log 和 git blame 才是权威来源,不需要记忆系统再来存一遍。调试方案和修复方法也不存,因为修复已经在代码里了,commit 消息已经记录了上下文。

CLAUDE.md 里已经写了的内容也不存,避免重复。最后是临时任务状态和当前对话上下文,这些是会话级的信息,不需要跨会话保持。

这个排除清单背后的核心原则是:可以从当前代码推导出来的信息,一律不存。

6.3、怎么存:索引 + 独立文件

搞清楚了「记什么」和「不记什么」,接下来看「怎么存」。

每条记忆存为一个独立的 .md 文件,文件开头有一段 YAML 格式的元信息(可以理解为这条记忆的「身份证」):

---
name: no-mock-database
description: 集成测试必须使用真实数据库,不能用 mock
type: feedback
---

集成测试必须使用真实数据库,不能用 mock。

**Why:** 上季度 mock 测试全部通过但生产环境迁移失败了。
**How to apply:** 在这个模块写测试时,始终连接真实数据库。

文件开头那段 YAML 格式的元信息里:name 是人类可读的标识;description 是一句话摘要,专门用于检索时的相关性匹配;type 标记四类型之一。

然后有一个 MEMORY.md 文件作为索引,它是一个不超过 200 行(25KB)的轻量目录:

- [No Mock Database](feedback_no_mock_db.md) — tests must use real DB
- [User Preferences](user_preferences.md) — prefers terse responses
- [Auth Rewrite](project_auth_rewrite.md) — driven by compliance, not tech debt

6.4、怎么召回:Sonnet 当秘书

存好了记忆,关键问题来了:每次对话时,怎么从几十条记忆里挑出最相关的那几条加载进来?

Claude Code 的做法非常巧妙,用一个廉价的小模型(Sonnet)来做记忆检索。

整个召回流程分为三步:

第一步:扫描所有记忆文件的「头部信息」。它只读每个文件的开头那段元信息里的 name、description、type,不会读取记忆的完整内容。

第二步:拼成清单,发给 Sonnet 做选择。扫描完之后,所有记忆的「头部信息」被拼成一个文本清单,把这个清单连同用户当前的输入一起发给 Sonnet

第三步:加载选中记忆的完整内容,注入上下文。
拿到文件名列表后,系统才去读取这几条记忆的完整内容,作为 <system-reminder> 注入当前对话。

回顾一下 Claude Code 的记忆系统,它的核心设计哲学可以用三句话概括。

第一句是「记该记的,不记能推导的」。
第二句是「存索引,按需加载详情」。哪些记忆可用,又不会撑爆上下文。
第三句是「用小模型做秘书,大模型做决策」。

最后

Claude Code 源码里有太多优秀的 Agent 技术落地方案。

比如压缩上下文要分五步走、记忆要分四种类型存、System Prompt 设计……

每一件事单拿出来都算不上黑科技,但全串在一起,就是一套能把一匹野马驯成耕牛的缰绳系统。

一个很大的启发:做 Agent,别总盯着模型发呆。模型是发动机,但一辆车能不能安全上路,靠的是刹车、方向盘、安全带。这些「不起眼」的东西,才是真正决定成败的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容