Agent Harness架构拆解:为什么同一个模型在不同运行时里表现差3倍
"openclaw harness"最近在技术社区热度很高。但大部分讨论停留在"OpenClaw 好用"的层面,没有拆到架构里面去。这篇从工程角度分析 Agent Harness 的 5 层架构设计,以及每一层对模型表现的影响有多大。
先定义清楚:Harness 是什么
一个类比:模型是 CPU,Harness 是整台电脑。
CPU 再强,没有内存、没有硬盘、没有操作系统,它什么都做不了。同一颗 CPU 装在不同的主板上,配不同的内存和散热,性能表现完全不同。
Agent Harness 就是模型的"整台电脑"。它包含模型运行所需要的一切上下文环境:
Agent Harness 的组成(5 层):
┌─ 第5层:输出通道层 ─────────────────────────────┐
│ 消息推送(飞书/Discord/Slack/iMessage) │
│ PR 提交、文件写入、Webhook 触发 │
├─ 第4层:工具执行层 ─────────────────────────────┤
│ MCP Server 调用、Shell 命令、API 请求 │
│ 沙箱隔离、权限控制、超时管理 │
├─ 第3层:记忆层 ──────────────────────────────────┤
│ 短期记忆(当前会话上下文) │
│ 长期记忆(跨 session 持久化知识) │
│ 工作记忆(当前任务的中间状态) │
├─ 第2层:上下文管理层 ────────────────────────────┤
│ CLAUDE.md/AGENTS.md 注入、滚动窗口、历史压缩 │
│ 工具输出摘要、错误回答清理 │
├─ 第1层:会话控制层 ──────────────────────────────┤
│ Session 创建/销毁、连接管理、心跳探测 │
│ 触发机制(消息/定时/事件/API) │
└──────────────────────────────────────────────────┘
↕ 模型 API 调用 ↕
┌──────────────────────────┐
│ LLM(Claude/GPT/DeepSeek)│
└──────────────────────────┘
模型本身只是最底下那个框。上面 5 层的设计质量决定了模型能发挥几成实力。
第 1 层:会话控制——决定 Agent 能不能"活着"
这一层解决的问题:Agent 什么时候启动、怎么和外部通信、断了怎么恢复。
看起来很基础,但这是生产环境里出问题最多的一层。根据我跑了两个月 Agent 的经验,3 次严重故障里有 2 次出在这一层(WebSocket 竞态条件、进程 OOM)。
设计决策 1:连接模式
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| WebSocket 长连接 | 低延迟,实时响应 | 要处理断连重连、竞态 | 飞书、Discord |
| HTTP Webhook | 无状态,简单稳定 | 延迟略高,需要公网 URL | Slack、GitHub |
| 轮询 | 最简单,无需服务端推送 | 延迟高,浪费资源 | 测试/开发环境 |
OpenClaw 用 WebSocket 接飞书,HTTP 接 Slack。关键设计:每个连接分配唯一 ID,旧连接的关闭事件不能干掉新连接——不这样做,竞态条件会让你的 Agent 静默断连,健康检查还显示正常。
// 防竞态的连接管理(核心模式)
let activeConnectionId = 0;
function reconnect() {
const myId = ++activeConnectionId;
const ws = new WebSocket(url);
ws.on("close", () => {
// 只有当前活跃连接断了才触发重连
if (myId === activeConnectionId) {
setTimeout(reconnect, 3000);
}
// 旧连接的 close 事件直接忽略
});
}
设计决策 2:触发机制
| 触发方式 | 延迟 | 复杂度 | 适用场景 |
|---|---|---|---|
| 消息触发 | <1s | 低 | 聊天机器人 |
| 定时触发(Cron) | 秒级精度 | 中 | 定时报告、巡检 |
| 事件触发(Webhook) | <1s | 中 | PR 创建、CI 失败 |
| API 触发 | <1s | 低 | 外部系统集成 |
一个 Harness 通常需要同时支持多种触发方式。OpenClaw 的设计是把触发逻辑和 Agent 逻辑解耦——触发器只负责创建 session 和传入初始消息,不参与 Agent 的执行过程。
第 2 层:上下文管理——决定 Agent “看到什么”
这一层的设计直接决定模型的输出质量。据 Anthropic 官方指南,长文档放在 prompt 开头可以提升回答质量 30%。 同理,上下文管理做得好不好,影响幅度在 20-40% 之间。
设计决策 3:项目规范注入
模型裸跑时不知道你的项目用什么代码风格、什么架构模式。CLAUDE.md 或 AGENTS.md 就是告诉它"你在这个项目里应该怎么做"的文件。
据之前的消融实验分析(引用 Morph 的公开报告),CLAUDE.md 是影响最大的单一 Harness 组件——有没有这个文件,代码风格一致性差距可达 3-4 倍。
设计决策 4:上下文窗口策略
| 策略 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| 全量保留 | 所有历史对话都发给模型 | 不丢信息 | 上下文爆炸,质量衰减 |
| 固定窗口 | 只保留最近 N 轮 | 简单 | 会丢早期关键信息 |
| 滚动窗口+摘要 | 近期完整保留,远期做摘要 | 兼顾精度和长度 | 摘要可能丢细节 |
| 动态加载 | 按当前任务拉取相关上下文 | 最精准 | 实现复杂 |
大部分 Agent Harness 用的是"滚动窗口+摘要"——最近 3 轮完整保留,更早的压缩成一段摘要。OpenClaw 和 Claude Code 都是这个思路。
但有一个被忽视的细节:工具调用的返回值也要摘要。 一次 Web 搜索可能返回 3000 token 的原始内容,有用的可能只有 100 token。不做摘要就直接塞进上下文,等于注入了 2900 token 的噪音。
def build_context(messages, tools_results, current_turn):
context = []
context.append(system_prompt) # CLAUDE.md 内容
# 远期对话 → 压缩成摘要
if current_turn > 3:
old = messages[1:current_turn-3]
context.append({"role": "system",
"content": f"[之前的对话摘要] {summarize(old)}"})
# 近期对话 → 完整保留
context.extend(messages[max(1, current_turn-3):])
# 工具输出 → 摘要后注入(不是原始内容)
for result in tools_results:
context.append({"role": "tool",
"content": summarize_tool_output(result)})
return context
第 3 层:记忆——决定 Agent “记得什么”
上下文管理处理的是当前 session 内的信息。记忆层处理的是跨 session 的知识持久化。
设计决策 5:记忆架构
| 记忆类型 | 存什么 | 存多久 | 存在哪 |
|---|---|---|---|
| 短期记忆 | 当前对话历史 | 当前 session | 内存 |
| 工作记忆 | 当前任务的中间状态 | 任务完成即清 | 内存+文件 |
| 长期记忆 | 用户偏好、项目知识、历史决策 | 永久 | SQLite/向量库 |
| 情景记忆 | 特定事件的完整记录 | 按需保留 | 日志/归档 |
大部分 Agent 框架只做了短期记忆(对话历史)。OpenClaw 额外做了长期记忆——它能记住"上周你说项目代号叫 Phoenix",跨 session、跨渠道(飞书说的话在 Discord 也记得)。
长期记忆的核心难题是"记忆衰减"。 存太多记忆,检索效率下降。存太少,关键信息丢失。实践中需要做定期的记忆整合——把碎片信息合并成结构化知识。
但要注意:内存里的完整历史和发给模型的上下文是两个东西。 内存里可以保留全量日志做分析用,但发给模型的必须经过裁剪。之前有过进程因为内存里的历史消息无限增长导致 OOM 的案例——内存管理是这一层容易忽视的坑。
第 4 层:工具执行——决定 Agent “能做什么”
这一层通过 MCP 协议把模型连接到外部世界。
设计决策 6:工具数量和组织
据公开的实测报告,模型的工具选择准确率随工具数量增加而下降:
| 工具数 | 选择准确率(参考值) |
|---|---|
| 5 | ~95% |
| 12 | ~85%(拐点) |
| 20 | ~72% |
| 30 | ~53% |
拐点在 12 个工具左右。 超过之后准确率开始断崖式下降。
工程对策:不要把所有工具注册到一个 MCP Server。 按领域拆分成多个 Server(每个 8-12 个工具),或者用动态加载——按当前任务的关键词只加载相关工具。
设计决策 7:工具安全
模型决定调什么工具、传什么参数——这个过程没有独立的安全审计。
生产级 Harness 需要在工具执行层做四道防护:
安全防护栈:
├── 参数级白名单(不是语句级——SQL 的 UNION 绕得过 SELECT 白名单)
├── 结果脱敏(敏感字段在返回给模型前做遮蔽)
├── 频率限制(防止批量数据窃取)
└── 审计日志(每次工具调用记录完整参数和结果行数)
第 5 层:输出通道——决定 Agent “怎么交付”
最后一层:Agent 的结果怎么送到用户手里。
| 通道 | 延迟 | 格式支持 | 适用场景 |
|---|---|---|---|
| 飞书消息 | <1s | 文本 + 卡片 | 团队日常 |
| Discord 消息 | <1s | 文本 + Embed | 社区/个人 |
| PR 提交 | 秒级 | 代码 + 描述 | 自主编程 |
| 文件输出 | 即时 | 任意格式 | 报告/数据 |
| Webhook 回调 | <1s | JSON | 系统集成 |
一个 Harness 通常需要支持多通道输出。OpenClaw 的设计是在 cron job 配置里指定 delivery.channel——同一个 Agent 的输出可以根据任务类型推送到不同渠道。
5 层之间的依赖关系
这些层不是独立的——它们之间有关键的依赖:
层级依赖图:
第1层(会话控制)→ 如果连接断了,上面4层全停
第2层(上下文管理)→ 直接决定模型推理质量
第3层(记忆)→ 跨 session 的信息靠这层传递
第4层(工具执行)→ Agent 能力边界由这层决定
第5层(输出通道)→ 用户体验的最后一环
生产环境里最常出问题的是第 1 层和第 4 层。 第 1 层出问题 Agent 直接挂;第 4 层出问题 Agent 调错工具或者超时。中间三层出问题通常不会导致服务中断,只是质量下降——更隐蔽,更难排查。
对架构选型的影响
如果你正在选 Agent 框架(或者自己搭 Harness),按这 5 层来评估:
| 层 | 要问的问题 |
|---|---|
| 会话控制 | 支持哪些触发方式?断连恢复机制是什么? |
| 上下文管理 | 支持 CLAUDE.md/AGENTS.md 吗?有滚动窗口吗? |
| 记忆 | 有跨 session 的持久化记忆吗?记忆检索方式? |
| 工具执行 | 支持 MCP 吗?工具数量怎么管理?安全怎么做? |
| 输出通道 | 支持哪些渠道?能多通道输出吗? |
第 2 层(上下文管理)对质量影响最大,第 1 层(会话控制)对可靠性影响最大。 选框架时优先看这两层的实现质量。
多模型支持也在这个评估框架里——Harness 应该允许不同的 Agent 用不同的模型。简单任务用便宜模型,复杂任务用旗舰模型。通过 API 网关统一管理模型调用是最省心的做法——Harness 层不用关心每个模型厂商的 SDK 差异。
常见问题
Q: Harness Engineering 和 Prompt Engineering 的关系?
A: Prompt Engineering 优化的是第 2 层的一个子集(系统提示词的写法)。Harness Engineering 优化的是全部 5 层。2026 年的共识是:只优化 Prompt 远远不够,因为 Prompt 只覆盖了影响因素的 20-30%。
Q: 自己从零搭 Harness 还是用现成框架?
A: 取决于你的定制需求。如果你只需要标准的对话 Agent,用 OpenClaw 或 LangChain 开箱即用。如果你需要深度定制某一层(比如特殊的记忆系统或工具安全策略),从零搭可能更高效——现成框架的抽象层反而会成为限制。
Q: 5 层里哪一层最值得投入精力?
A: 短期看第 2 层(上下文管理)——ROI 最高,一个 CLAUDE.md 文件就能带来巨大提升。长期看第 3 层(记忆)——记忆系统是 Agent 从"工具"进化到"助手"的关键分界线。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)