Harness 不是限制模型的牢笼,而是让模型能力安全释放的最薄必要层。
从 Anthropic 公开的设计理念出发,在 Claude Code 源码中找到每一条原则的具体实现。
先理解理念,再看代码。这是本文与其他分析的根本区别。
Anthropic 在多篇博文中阐述了 Agent 构建哲学。核心论点并非「如何约束模型」,而是:
"An agent is not a special architecture — it is a model that repeatedly calls tools until a task is done."
——《Building Effective Agents》, Dec 2024
"As models get more capable, harnesses should get simpler." 早期 LLM 需要复杂流水线(RAG、CoT scaffold、多步验证),因为模型不可靠。模型改进后,这些脚手架应当被移除。
"Push intelligence into the model, not into code." 如果你在写代码来验证和重试模型输出,也许应该改进 Prompt。模型应该是主要决策者,代码只是管道。
好的 Harness 像自行车 —— 放大骑手(模型)的能力,骑手控制方向。坏的 Harness 像铁轨 —— 把模型限制在预定义的轨道上。
模型改进不会让 Harness 变得不重要。补偿模型弱点的 Harness 组件会消失,但新的 Harness 能力会出现。工程师的工作是持续发现新的有价值组合。
理念 "Agent is just LLM in a loop with tools" → 源码 query.ts 的核心循环
Anthropic 明确警告不要使用复杂的 Agent 框架:"We suggest that developers first consider whether they can achieve their goals with direct API calls and simple code, before adopting an agent framework." 框架增加了抽象层,模糊了 Prompt 和 Response 的真实交互。
while (true) { // ← 无限循环。就这么简单。
// 1. 调用 Claude API
for await (const message of deps.callModel({
messages: messagesForQuery,
systemPrompt: fullSystemPrompt,
tools: toolUseContext.options.tools,
toolChoice: undefined, // ← 模型自由选择工具
})) {
// 收集流式响应 + tool_use blocks
}
// 2. 是否需要继续?
if (!needsFollowUp) {
break // ← 自然结束
}
// 3. 执行工具,把结果喂回去
yield* runTools(toolUseBlocks, ...)
// 循环回到步骤 1
}
理念 "Push intelligence into the model" → 源码 System Prompt 替代了硬编码逻辑
传统做法是在代码中写规则("如果模型调用了 cat 命令则拒绝"),Anthropic 的做法是在 Prompt 中写指导("请使用 Read 而非 cat"),让模型自己做出正确选择。
// getUsingYourToolsSection() — 工具使用优先级
"Do NOT use Bash to run commands when a relevant dedicated tool is provided.
This is CRITICAL to assisting the user:
- To read files use Read instead of cat, head, tail, or sed
- To edit files use Edit instead of sed or awk
- To create files use Write instead of cat with heredoc
- To search for files use Glob instead of find or ls
- To search content use Grep instead of grep or rg"
// getSimpleDoingTasksSection() — 代码质量规范
"Don't add features, refactor code, or make 'improvements' beyond what was asked."
"Don't add error handling for scenarios that can't happen."
"Don't create helpers or abstractions for one-time operations."
"Three similar lines of code is better than a premature abstraction."
if (command.startsWith("cat")) reject()。它在 System Prompt 中告诉模型「请用 Read 而非 cat」。模型的推理能力替代了硬编码规则。这就是「把智能推进模型」的具体实践。
// GlobTool 的 description —— 不只说「能做什么」,还说「什么时候用别的工具」
"- Fast file pattern matching tool that works with any codebase size
- When you are doing an open ended search that may require multiple
rounds of globbing and grepping, use the Agent tool instead"
// BashTool 的 description —— 嵌入了大量使用指南
"- Avoid unnecessary sleep commands
- Do not retry failing commands in a sleep loop — diagnose the root cause
- If you must poll an external process, use a check command rather than sleeping first
- NEVER skip hooks (--no-verify) unless the user explicitly asks"
每个工具的 prompt() 方法输出的不仅是参数定义,更是使用指南、最佳实践和禁止事项。模型通过阅读这些指南来做出正确决策,而非通过代码强制执行。
理念 "Give model autonomy" → 源码 toolChoice: undefined
toolChoice: undefinedfor await (const message of deps.callModel({
messages: messagesForQuery,
systemPrompt: fullSystemPrompt,
tools: toolUseContext.options.tools,
toolChoice: undefined, // ← 不强制任何工具。模型自己选。
})) { ... }
这一行 toolChoice: undefined 蕴含了整个设计哲学:
needsFollowUp 控制 — 只要模型还在调用工具,循环就继续理念 "Harness provides what model cannot" → 源码 7 个赋能系统
大多数人只关注 Harness 的「限制」功能(权限、Hook、阻止)。但 Claude Code 中,赋能代码的体量远超限制代码:
| 赋能系统 | 模型原本的限制 | Harness 如何突破 |
|---|---|---|
| 持久记忆 | 模型每次对话从零开始 | Memory 系统 + CLAUDE.md 跨会话持久化知识。Harness 预创建目录,Prompt 告知「直接写入,不用 mkdir」 |
| 上下文压缩 | 上下文窗口有限 | 自动压缩(auto compact)+ 微压缩(micro compact),让对话理论上无限长。Prompt 告知模型「上下文会自动压缩」 |
| 后台任务 | 模型一次只能做一件事 | AgentTool 可以 spawn 子代理在后台运行。15 秒自动后台化。模型可以同时推进多个工作流 |
| 工具发现 | 所有工具占用上下文空间 | ToolSearch 按需发现工具。不常用工具标记 shouldDefer,不加载到初始 Prompt |
| Prompt 缓存 | 每次调用付全额 Token 费 | 静态/动态 Prompt 分界 + CacheSafeParams 跨进程共享,大幅降低 API 成本 |
| 文件状态追踪 | 模型不知道文件是否被外部修改 | ReadFileState 缓存 + 陈旧检测,防止覆盖用户的 IDE 编辑 |
| 推测执行 | 每次写入都是不可逆的 | Speculation Overlay 沙箱让模型「先试试看」,用户确认后再提交 |
/**
* Shipped because Claude was burning turns on `ls`/`mkdir -p` before writing.
* Harness guarantees the directory exists via ensureMemoryDirExists().
*/
export const DIR_EXISTS_GUIDANCE =
'This directory already exists — write to it directly with the Write tool
(do not run mkdir or check for its existence).'
// System Prompt 明确告知模型 Harness 的赋能存在:
"The system will automatically compress prior messages in your conversation
as it approaches context limits. This means your conversation with the user
is not limited by the context window."
"Calling Agent without a subagent_type creates a fork, which runs in the
background and keeps its tool output out of your context — so you can keep
chatting with the user while it works."
模型知道自己被赋能了 —— 上下文会自动压缩,子代理可以后台运行。这种「透明协作」让模型能更好地利用 Harness 提供的能力。
理念 "Agents confidently praise mediocre work" → 源码 Verification Agent
Anthropic 的工程博客明确指出:"Self-evaluation fails. Agents confidently praise mediocre work when judging their own output. Tuning a standalone evaluator to be skeptical turns out to be far more tractable than making a generator critical of its own work."
const VERIFICATION_SYSTEM_PROMPT = `You are a verification specialist.
Your job is not to confirm the implementation works — it's to try to break it.
You have two documented failure patterns:
First, verification avoidance: when faced with a check, you find reasons
not to run it...
Second, being seduced by the first 80%: you see a polished UI or a
passing test suite and feel inclined to pass it, not noticing half the
buttons do nothing...
Your entire value is in finding the last 20%.`
Stop Hooks 实现了另一种外部验证:不依赖任何 LLM,而是运行确定性的 Shell 命令。
// Hook 返回 preventContinuation = true → 模型被阻止继续
if (result.preventContinuation) {
stopReason = result.stopReason || 'Stop hook prevented continuation'
}
一个配置了 npm test 的 Stop Hook,比任何 LLM 验证都更可靠 —— 测试要么通过,要么不通过,没有「差不多通过」。
理念 "Capability reduces complexity" → 源码 @[MODEL LAUNCH] 标记
Anthropic 说得很清楚:随着模型改进,补偿模型弱点的 Harness 组件应当被移除。你的 Harness 代码应该有「过期日期」。
@[MODEL LAUNCH] —— 显式的拆除标记// 标记 1:模型过度注释问题
// @[MODEL LAUNCH]: Update comment writing for Capybara —
// remove or soften once the model stops over-commenting by default
// 标记 2:模型不够彻底问题
// @[MODEL LAUNCH]: capy v8 thoroughness counterweight —
// un-gate once validated on external via A/B
// 标记 3:模型虚假声明问题
// @[MODEL LAUNCH]: False-claims mitigation for Capybara v8
// (29-30% FC rate vs v4's 16.7%)
@[MODEL LAUNCH] 标记意味着:「这段代码补偿了当前模型的弱点。当下一代模型不再有这个问题时,删除它。」甚至记录了具体数据(虚假声明率从 16.7% 升到 29-30%),为未来的「是否移除」决策提供量化依据。
// 正常模式:700+ 行精心编排的 System Prompt
return [
getSimpleIntroSection(), // 身份 + 风格
getSimpleSystemSection(), // 系统规则
getActionsSection(), // 安全准则
getUsingYourToolsSection(), // 工具使用
getSimpleToneAndStyleSection(), // 输出风格
getOutputEfficiencySection(), // 效率
...resolvedDynamicSections, // 记忆 + 环境
]
// SIMPLE 消融模式:一行字符串
if (isEnvTruthy(process.env.CLAUDE_CODE_SIMPLE)) {
return [`You are Claude Code, Anthropic's official CLI for Claude.
CWD: ${getCwd()}
Date: ${getSessionStartDate()}`]
}
这个消融开关回答一个关键问题:「那 700 行 Prompt 到底值多少?」 如果未来模型强到不需要详细指导就能正确行为,SIMPLE 模式就够了。这就是「模型越强,Harness 越薄」的工程准备。
理念 "Safety through alignment + defense in depth" → 源码 仅在必要处硬编码
Anthropic 的安全理念不是「用代码把模型锁死」,而是「训练模型本身可信 + 代码提供纵深防御」。Harness 中的硬限制应该只存在于模型绝对无法自我保护的场景:
// 这些文件被保护不是因为模型「不可信」
// 而是因为 Prompt Injection 可以绕过模型的判断
export const DANGEROUS_FILES = [
'.bashrc', // Shell 启动 → 命令注入载体
'.gitconfig', // Git 配置 → 可嵌入恶意 Hook
'.ssh/config', // SSH → 凭据泄露风险
]
// Harness 内部路径则自动放行 — 因为内容由 Harness 控制
// "this subtree is harness-controlled"
if (normalizedPath.startsWith(bundledSkillsRoot)) {
return { behavior: 'allow' } // ← 信任 Harness 管控的路径
}
理念 "Measure harness contribution independently" → 源码 消融基线
// Harness-science L0 ablation baseline.
// feature() gate DCEs this entire block from external builds.
if (feature('ABLATION_BASELINE') &&
process.env.CLAUDE_CODE_ABLATION_BASELINE) {
for (const k of [
'CLAUDE_CODE_SIMPLE', // System Prompt → 1行
'CLAUDE_CODE_DISABLE_THINKING', // 关闭 Thinking
'DISABLE_INTERLEAVED_THINKING', // 关闭交错思维
'DISABLE_COMPACT', // 关闭压缩
'DISABLE_AUTO_COMPACT', // 关闭自动压缩
'CLAUDE_CODE_DISABLE_AUTO_MEMORY', // 关闭记忆
'CLAUDE_CODE_DISABLE_BACKGROUND_TASKS', // 关闭后台
]) {
process.env[k] ??= '1'
}
}
注意 feature('ABLATION_BASELINE') —— 这个开关在外部构建中被 Dead Code Elimination 完全移除。只有 Anthropic 内部构建才有消融能力。普通用户永远运行完整 Harness。
理念 "Harness should be configurable" → 源码 settings.json + 10 种 Hook 事件
{
// 权限规则 = 定义模型的能力边界
"permissions": {
"allow": ["Bash(npm:*)", "Bash(git:*)"],
"deny": ["Bash(rm -rf:*)"]
},
// Hooks = 在关键节点注入确定性逻辑
"hooks": {
"PostToolUse": [{ "matcher": "Write|Edit",
"hooks": [{ "type": "command", "command": "prettier --write $FILEPATH" }]
}],
"Stop": [{ "hooks": [{ "type": "command", "command": "npm test" }] }]
}
}
前端团队添加 prettier Hook;后端团队添加 npm test Hook;安全团队添加 deny 规则。不改 Claude Code 一行代码,每个团队都有自己的 Harness 变体。
从 Anthropic 的理念到 Claude Code 的源码,一条完整的映射链
记忆系统、上下文压缩、后台任务、工具发现、Prompt 缓存、推测执行。这些让模型从「能聊天」变成「能编程」。
System Prompt、工具描述、行为规范。不是限制模型,而是用语言引导模型做出正确选择。把智能推进模型。
权限检查、路径保护、陈旧检测。只在模型绝对无法自我保护的地方介入。这是最薄的一层,但是最硬的一层。
| Anthropic 的理念 | Claude Code 的实现 | 为什么这样做 |
|---|---|---|
| "Agents are just LLMs in loops" | while(true) { callAPI → runTools },无状态机 |
简单系统更可靠、更可调试 |
| "Push intelligence into model" | 700 行 System Prompt 编码行为规范,而非代码强制 | 模型的推理能力比 if/else 更灵活 |
| "Bicycle, not railroad" | toolChoice: undefined,模型自由选择工具 |
预定义流程会限制模型的创造性解法 |
| "Harness enables, not restricts" | 7 个赋能系统(记忆/压缩/后台/发现等) | 模型的潜力需要基础设施来释放 |
| "Self-evaluation fails" | Verification Agent + Stop Hooks | 生成者不能评判自己的作品 |
| "Capability reduces complexity" | @[MODEL LAUNCH] 拆除标记 + SIMPLE 消融 |
今天的 Harness 代码可能是明天的废代码 |
| "Safety = alignment + defense-in-depth" | DANGEROUS_FILES 硬保护仅覆盖模型盲区 | 信任模型 + 纵深防御最不可控的部分 |
| "Measure harness independently" | 7 个消融开关 + Feature Gate DCE | 科学量化每个 Harness 组件的 ROI |
| "Harness space moves, not shrinks" | Auto-compact 断路器(数据驱动的 3 次上限) | 旧问题解决,新优化出现 |
一句话总结
Harness 不是牢笼,而是自行车。
它不限制模型去哪里,而是让模型骑得更远。
Claude Code 的源码证明:最好的 Harness 是你几乎感觉不到它存在的那种。
一个 while(true) 循环、一个 toolChoice: undefined、
和一份 700 行的 System Prompt —— 这就是一个世界级 AI Agent 的全部骨架。
其余的,都是为了让这个简单循环跑得更安全、更持久、更便宜。