- Published on
Agent Harness:AI Agent 可靠性的真正瓶颈在哪里?
- Authors

- Name
- Yuga Sun
为什么写这篇文章
OpenAI Codex 团队有一句话在 AI 圈广泛流传:
"Agents aren't hard; the Harness is hard."
这句话在 2026 年被反复引用,原因是它准确命中了一个反直觉的现象:即使在模型推理能力持续飞速提升的今天,AI Agent 在生产环境中的可靠性问题依然普遍存在。大量 Agent 项目失败,不是因为模型不够聪明,而是因为包裹模型的执行环境不够稳健。
这篇文章想回答的问题是:Agent Harness 的核心支柱是什么,每个支柱解决了哪些真实的工程问题,以及主流系统是如何设计这些支柱的?
同一个模型,两种截然不同的结果
给同一个 GPT-4.5 模型完全相同的任务:"重构这个 10 万行的遗留 Python 项目,采用领域驱动设计。"
- Agent A(无专业 harness):产出 40% 可用代码,陷入死循环 3 次,产生 23 个冲突修改,5 小时后任务失败
- Agent B(专业 harness):产出 92% 可用代码,2 小时内完成,零冲突,全程没有人工干预
同一个模型,为什么结果天差地别?因为 Agent B 的 harness 提供了四件事:
- 结构化任务分解:把"重构 10 万行代码"拆解成可以逐步完成的子任务
- 上下文管理:避免 agent 在某个细节上花太多 context,忘记全局目标
- 增量验证:每个子任务完成后运行测试,确认进度方向正确
- 状态回滚:某个子任务失败时,恢复到上一个已知良好状态,而不是继续构建在错误上
核心结论:模型的推理能力不是瓶颈,支撑模型在长任务中可靠运行的基础设施才是。
什么是 Agent Harness?
如果把 AI 模型比作"大脑",Agent Harness 就是这个大脑的颅骨、神经系统和工作记忆的结合体。它不是模型本身,但它决定了模型如何感知世界、如何采取行动、如何保持跨轮次的一致性。
Agent Harness = 模型之外的一切
= 意图捕捉 → 规范编译 → 工具执行 → 验证 → 状态持久化
Harness vs Prompt Engineering vs Context Engineering
这三个概念经常被混淆,但它们处于不同的抽象层次:
| 维度 | Prompt Engineering | Context Engineering | Agent Harness |
|---|---|---|---|
| 关注点 | 提示词措辞 | 上下文内容选择 | 整个执行系统 |
| 抽象层级 | 微观(单次交互) | 中观(单次会话) | 宏观(系统架构) |
| 核心问题 | 怎么表达更清晰 | 传什么进 context | 如何可靠运行 |
| 影响范围 | 单次 LLM 调用 | 单次会话质量 | 长期可靠性 |
三者是包含关系:Prompt 和 Context Engineering 是 Harness 内部的两个子问题,Harness 是整体架构。Harness Engineering 正是 2026 年兴起的新学科,它不是要取代前两者,而是为它们提供系统性的运行环境。
五大支柱:每个设计决策背后的原因
支柱一:工具调用系统 — Agent 与外部世界的唯一通道
工具调用是 Agent 能力的边界。没有工具,Agent 只能聊天;有了工具,Agent 才能真正执行操作。
工具系统设计的核心决策是:声明式规范 vs 动态发现。
声明式(主流选择):预先定义所有工具的名称、参数、权限需求、描述。模型调用时行为确定可预测。
ToolSpec(
name="bash",
description="在 shell 中执行命令,支持 timeout",
input_schema={
"command": "string",
"timeout": "integer (optional, default: 30s)"
},
required_permission="DangerFullAccess"
)
ToolSpec(
name="read_file",
description="读取文件内容,支持行范围",
input_schema={
"path": "string",
"offset": "integer (optional)",
"limit": "integer (optional)"
},
required_permission="ReadOnly"
)
动态发现:运行时发现可用工具,看似灵活。实际问题:不可预测性、安全风险、难以测试。
工具规范采用声明式的收益是:工具列表可版本化、可 code review、可测试,模型的行为空间有明确边界。
Claude Code 的 Deferred Loading:减少 context 开销
声明式工具规范有一个潜在问题:复杂 Agent 可能定义几十个工具,全量传入 schema 会大量消耗 context token,而单次任务实际只会用到其中几个。
Claude Code 的 Deferred Loading 机制解决了这个问题:
实际工程意义:一个拥有 50 个工具的 Agent,如果全量 eager loading,初始 context 开销可能达 10,000+ tokens。Deferred Loading 把这个开销摊薄到首次使用时,大幅降低了工具丰富 Agent 的运行成本。
支柱二:上下文管理系统 — 有限 window 里的无限任务
上下文管理的失败是 Agent 系统最常见的故障模式。核心矛盾:context window 再大(当前主流 200K tokens),真实的长时间任务也可能持续数天、数百轮交互。
最常见的错误处理方式:等到 context 满了才截断。这会导致信息骤降,Agent 突然"忘记"之前的上下文,用户体验崩溃。
正确的做法:渐进式、主动压缩。 压缩应该在 context 还没满时就开始,且对用户完全透明。
| 压缩层级 | 触发条件 | 压缩策略 | 关键目标 |
|---|---|---|---|
| Micro-compact | 单条消息 > 2KB | 手术式删减:移除重复信息、verbose 日志 | 保留完整语义 |
| Auto-compact | 70% window 使用率 | 生成结构化摘要 + 保留最近 N 条消息 | 保留行动痕迹 |
| Session-memory | 90% window 使用率 | 生成持久化会话记忆文件 | 跨会话连贯性 |
| Reactive | 最后 10% 空间 | 紧急压缩,可能降低质量 | 防止崩溃 |
关键工程细节是 Instant Compaction:在 Auto-compact 阶段(70% 时)就启动后台线程提前生成摘要,当 Session-memory 阶段触发时,摘要已经就绪,压缩对用户完全无感:
def _background_compaction_worker(self):
while True:
if self.context_usage > 0.7 and self.session_memory is None:
# 在用户无感知时提前生成摘要
self.session_memory = self._generate_session_summary()
def _generate_session_summary(self) -> str:
# 压缩时的优先级:
# 必须保留:工具调用记录、错误记录、关键决策、用户明确意图
# 可以删减:冗长中间讨论、已执行的计划草稿、重复确认信息
return self.model.generate(SESSION_MEMORY_PROMPT)
压缩时保留什么的判断标准:Agent 做了什么比说了什么更重要。
支柱三:错误恢复系统 — 区分概念验证和生产系统的关键
错误处理是最容易被忽视、却最能区分生产级 Agent 和 demo 级 Agent 的组件。在 Agent 系统中,错误处理不只是 try-catch,而是整个执行流程的容错设计。
错误类型分类:
| 错误类型 | 示例 | 处理策略 |
|---|---|---|
| 瞬时错误 | 网络超时、API 限流 | 指数退避重试(最多 3 次) |
| 工具错误 | bash 命令失败、文件不存在 | 向模型报告错误,让模型调整策略 |
| 语义错误 | 模型误解了目标,方向错误 | 回滚到最近检查点 |
| 权限错误 | 操作超出当前权限级别 | 拦截 + 提示升级权限或拒绝 |
| 不可恢复 | 文件系统损坏、外部服务宕机 | 保存状态,优雅退出 |
Checkpoint + Rollback 机制是错误恢复的核心。每完成一个有意义的工作单元,就保存一个检查点:
checkpoint = {
"turn": 47,
"context_summary": "已完成模块 A 的重构,测试通过",
"verified_artifacts": [
"src/auth/__init__.py",
"tests/test_auth.py",
],
"pending_operations": [], # 回滚时丢弃
"git_commit": "abc123", # 可以 git reset 到这个状态
}
关键设计原则:Agent 应该"保守地前进,激进地回退"。当不确定当前操作是否正确时,宁可回到已知的良好状态,也不要在错误基础上继续叠加修改。这与人类工程师的直觉相反,这正是 Agent 系统需要显式设计回退机制的原因。
支柱四:状态持久化系统 — 让 Agent 具备跨会话连续性
真实任务跨会话是常态:用户周一开始的重构任务,周五还需要继续。如果每次启动 Agent 都是空白大脑,所有上下文都需要重新建立,生产效率大幅下降。
一个结构化的跨会话记忆模板(比原始对话摘要价值高得多):
## 跨会话记忆 — user-service 重构 — 2026-04-09
### 项目目标
重构 user-service,从单体迁移到 DDD 架构,目标完成日期:本周五
### 已完成工作
- [周一] auth 模块重构完成,12 个文件,所有测试通过
- [周二] user profile 模块重构,引入 Value Object 模式
- [周三] 集成测试发现 auth × profile 的依赖问题,已修复
### 当前状态
- 正在处理:payment 模块,已完成 50%
- 遇到问题:外键约束冲突,PostgreSQL 迁移脚本需要调整
- 下一步:修复迁移脚本,运行完整集成测试
### 关键技术决策
- 采用事件溯源模式处理用户状态变更
- PostgreSQL 替代 MongoDB(性能和事务需求)
- 服务间通信统一走 gRPC
### 已知风险
- payment 模块的外键约束问题可能影响数据迁移时间线
为什么结构化记忆比摘要更有价值:摘要记录的是"说了什么",而上面这个模板记录的是"做了什么、决策了什么、遇到了什么问题"。后者才是 Agent 恢复工作状态真正需要的信息。
支柱五:权限与安全系统 — 可用性与安全性的精确平衡
Agent 可以在真实环境执行操作这一事实,使其成为一个潜在的高风险系统。
两种错误设计:
- 过于严格:每一步都询问用户,效率低到无法接受
- 过于宽松:Agent 可能执行灾难性操作,如
rm -rf /或覆写生产配置
正确的设计是分级权限 + 默认拒绝:
| 级别 | 能力范围 | 推荐场景 | 为什么设计这一级 |
|---|---|---|---|
| ReadOnly | 仅读取文件和目录 | 生产环境、代码 review | 最安全的默认值 |
| WorkspaceWrite | 读写指定工作区 | 受控开发环境 | 限制影响范围 |
| DangerFullAccess | 完全访问含危险命令 | 本地开发 | 最高效率模式 |
| Prompt | 每次危险操作前询问 | 审计环境 | 人在环路的安全阀 |
权限检查流程:
核心设计原则:"默认拒绝,显式允许"。DangerFullAccess 应该是用户主动选择的模式,而不是最省事的默认值。在安全系统设计中,永远不应该让高权限变成阻力最小的选项。
Hook 系统:Harness 的中间件层
Hook 系统是 Agent Harness 可扩展性的核心机制。它允许在不修改任何核心代码的情况下,在工具调用前后插入自定义逻辑。这是**控制反转(IoC)**思想在 Agent 系统中的应用。
Hook 的强大在于组合性:每个 Hook 专注单一职责,通过链式组合实现复杂治理逻辑。
场景 1:自动代码质量检查
每次修改 Python 文件后自动运行 ruff,无需 Agent 主动触发:
{
"hooks": {
"PostToolUse": [
{
"match": { "tool": "Write", "path": "**/*.py" },
"type": "command",
"command": "ruff check {path} --fix && ruff format {path}"
}
]
}
}
场景 2:危险命令安全拦截
#!/bin/bash
# pre_security_check.sh
DANGEROUS_PATTERNS=("rm -rf /" "curl.*\|.*sh" ":()\{:|:&\};")
for pattern in "${DANGEROUS_PATTERNS[@]}"; do
if echo "$CLAW_TOOL_INPUT" | grep -qE "$pattern"; then
echo "SECURITY: Dangerous pattern blocked" >&2
exit 1 # 非零退出码 = 阻止执行
fi
done
exit 0
场景 3:架构合规检查
每次修改领域层代码时,触发另一个 Agent 进行架构 review:
{
"hooks": {
"PostToolUse": [
{
"match": { "tool": "Edit", "path": "**/domain/*.py" },
"type": "agent",
"agent": "architect-reviewer",
"prompt": "检查以下修改是否违反 DDD 分层原则:{diff}"
}
]
}
}
三个场景覆盖了三个不同的关切点:代码质量、安全防护、架构治理。它们相互独立,通过 Hook 组合而非硬编码实现,治理策略可以独立演化和测试。
Subagent:解决 Context 爆炸的关键策略
当主 Agent 的 context 接近饱和,同时需要并行探索多个子任务时,将子任务委托给 Subagent 是最优解。
假设要分析一个有 20 个模块的大型代码库。主 Agent 顺序探索,每个模块都会消耗 context,很快就会因 context 不足而无法继续。Subagent 的解法:
Subagent 配置的关键点是最小权限原则:
AgentConfig(
description="模块架构分析",
prompt="分析指定模块的代码结构,输出:1)职责 2)依赖 3)重构建议",
tools=["Read", "Grep", "Glob"], # 只读工具
disallowed_tools=["Bash", "Write"], # 明确禁止修改
permission_mode="ReadOnly", # 权限最小化
max_turns=30, # 避免无限循环
)
缓存优化:多个 Subagent 往往共享相同的 system prompt。这部分内容的 prompt cache 只计算一次,后续所有 Subagent 实例共享,大幅降低 token 成本。
这本质上是 map-reduce 模式:任务分解(map)→ 独立执行 → 结果聚合(reduce)。取舍标准:当主 Agent 的 context 成为瓶颈时,Subagent 协调成本是值得的。
MCP:工具发现的标准化协议
MCP(Model Context Protocol)解决了 AI 模型与工具之间缺乏标准化连接协议的问题。在 MCP 出现之前,每个 Agent 框架都需要为每个工具编写定制集成:
- 连接 GitHub 需要 GitHub API SDK 的专用适配代码
- 连接数据库需要数据库 SDK 的专用适配代码
- 这些集成不可移植,切换 Agent 框架时需要全部重写
MCP 的架构实现了"一次编写,到处使用":
{
"mcpServers": {
"filesystem": {
"type": "stdio",
"command": "npx @modelcontextprotocol/server-filesystem",
"args": ["/path/to/workspace"]
},
"enterprise-api": {
"type": "sse",
"url": "https://api.internal.company.com/mcp",
"headers": { "Authorization": "Bearer ${TOKEN}" }
}
}
}
MCP 的核心价值是工具的可移植性:一个符合 MCP 规范的工具服务,可以被任何支持 MCP 的 Agent 框架使用,无需重写集成代码。
主流实现对比
| 特性 | Claude Code | Cursor | SWE-Agent | Devin |
|---|---|---|---|---|
| 工具加载 | Deferred Loading | Eager Loading | Eager Loading | 未知 |
| 上下文压缩 | 四级自动渐进 | 基础压缩 | 简单截断 | 未知 |
| 权限模型 | 五级分权 | 固定模式 | 无 | 未知 |
| Hook 系统 | 完整 Pre/Post | 部分 | 无 | 未知 |
| Subagent | 原生支持 | 通过 Composer | 支持 | 未知 |
| 会话持久化 | Session Memory | Project Memory | 无 | 未知 |
| MCP 支持 | 原生 | 插件 | 无 | 未知 |
| 错误回滚 | Checkpoint 机制 | 基础 | 无 | 未知 |
Claude Code 在 Harness 层面目前设计最完整,特别是 Deferred Loading 和四级渐进压缩体系,是其他系统尚未充分解决的难题。这不是偶然的——它反映了对 Agent 系统可靠性更深的系统性理解。
核心设计模式总结
| 模式 | 解决的问题 |
|---|---|
| Deferred Tool Loading | 大量工具定义导致的 context 初始开销 |
| Progressive Compaction | context 满了才压缩导致的体验崩溃 |
| Checkpoint + Rollback | 错误后无法恢复,在错误上继续构建 |
| Permission Pipeline | 权限粒度粗,无法精细治理危险操作 |
| Hook Chain | 治理逻辑硬编码进核心,难以扩展和测试 |
| Subagent Fork | 主 Agent context 爆炸,无法并行处理子任务 |
| Session Memory | 重启后需要重建所有上下文,降低效率 |
| MCP Integration | 每个工具需要定制集成代码,不可移植 |
总结
Agent Harness 是五大支柱组成的执行环境。每个支柱的设计都有明确的工程动机:
- 工具调用系统:决定 Agent 能干什么,以及能干到什么边界
- 上下文管理:决定 Agent 能持续工作多久,不会因 context 耗尽崩溃
- 错误恢复:决定 Agent 在真实环境中是否可靠,而不只是在 demo 里
- 状态持久化:决定 Agent 是否有连续性记忆,而不是每次从零开始
- 权限安全:决定 Agent 能否在非受控环境中安全部署
核心判断:Harness 工程是 AI Agent 系统最重要的工程学科,比模型选型更影响长期可靠性。
实践建议:
- 先设计 Harness 架构,再选模型。Harness 是基础设施,模型是可替换的组件
- 上下文压缩应该是渐进的,70% 时就要开始,不要等到满了
- 错误处理要分类:瞬时错误重试,语义错误回滚,权限错误拒绝
- 权限遵循"默认拒绝,显式允许",DangerFullAccess 不应是默认值
- 用 Hook 系统为治理逻辑预留扩展点,避免把安全和审计逻辑硬编码进核心
- 通过 MCP 标准化工具集成,避免重复造轮子,增强工具可移植性