让 AI Agent 更可靠:Harness Engineering 与多 Agent 系统工程实践

我们遇到了什么问题

如果你做过 AI 辅助分析工具,大概率踩过这两个坑:

坑一:AI 结论忽好忽坏。任务流程一长,AI 就开始"飘"------用词精准、语气自信,但结论经不起推敲。更坑的是,你问它"你确定吗",它会更加笃定地告诉你"是的,完全正确"。

坑二:Token 越烧越多。上下文越堆越厚,每次启动都要把历史上下文全部重新喂给模型,Token 消耗线性增长,但分析质量不升反降。

这正是我们团队在开发 CarPlay bug 分析工具时遇到的真实困境。AI 在多项目、长链路的 bug 分析中,分析报告质量严重不稳定;引入多 Agent 架构后,Token 消耗和运行时间又大幅增加。

这两个问题,促使我们去找一套系统性的解决方案。


一、Harness Engineering:给 AI 套上"缰绳"

问题:不确定性是 Agent 的原罪

大模型天生有随机性。在单轮对话里,这点随机性是创意的来源;但在长链路任务里,它是灾难的根源。

一个典型的失控场景:你让 Agent 完成一个分 10 步的开发任务。前 7 步一切正常,第 8 步 Agent 稍微偏了一下,第 9 步继续往偏了的方向走,第 10 步你收到了一个看起来完整、实则驴唇不对马嘴的结果。你还没意识到问题,因为 Agent 写了一段很有说服力的总结。

当 AI 开始连续执行时,如何监督并及时纠正,成了核心工程问题

方案:Agent = Model + Harness

2026 年 2 月,Martin Fowler 团队(作者 Birgitta Böckeler)提出了 Harness Engineering 这个概念:

ini 复制代码
Agent = Model(模型)+ Harness(约束框架)

Harness 是 Agent 里除了模型之外的一切东西------提示词、工具定义、规则约束、上下文管理、校验机制、反馈循环,全部统称为 Harness。

这个定义乍看平淡,但背后有个重要的思维转变:要提升 Agent 的稳定性,不是换更好的模型,而是设计更好的 Harness

Harness 由两部分组成:

  • Guides(前馈):在 AI 行动前给它正确的输入------清晰的指令、相关的上下文、结构化的任务描述
  • Sensors(反馈):在 AI 行动后检验输出------独立的验证器、质量评估、异常检测

LangChain 团队的实验很直观:在不换底层模型的情况下,仅靠 Harness Engineering,他们的 Agent 排名从 30 名以外提升到了前五名。

解决:在问题到达人眼之前自动修正

一句话概括 Harness Engineering 的目标:

要让 AI Agent 在更少人工监督下工作,需要系统化地构建一套"外部控制框架"------Harness。它由前馈的 Guides 和反馈的 Sensors 组成,目标是在问题到达人眼之前就自动修正


二、单 Agent 的两个致命失败模式

有了框架方向,我们来看单 Agent 具体会在哪里失控。Anthropic 在《Harness design for long-running application development》中识别了两类核心失败模式:

失败模式一:上下文焦虑(Context Anxiety)

任务太长,Agent 接近上下文窗口上限时会"焦虑",开始草草收尾------把没完成的工作标记为完成,把模糊的分析写成确定的结论。

这不是模型的 bug,是它在用"自信的收尾"来应对"不确定的延续"。

解决方案 :不是 Compact(压缩上下文),而是 Context Reset------完全清空上下文,带结构化的交接文件启动新 Agent,让新 Agent 接棒继续工作。

失败模式二:自我评估失灵

让 Agent 评估自己的输出,它会"病态乐观"------即使结果很糟糕,它也会自我点赞,因为它的评估基于生成该结果时的同一套认知框架。

就像让一个人同时做卷子又改自己的卷子,几乎必然高分。

解决方案 :引入独立的 Evaluator Agent,专门调教成"严格挑剔模式",与 Generator Agent 完全隔离。

这两个发现,直接引出了多 Agent 架构的第一个也是最核心的模式。


三、多 Agent 架构:五种协作模式

有些团队选模式时,依据的是听起来是否高深,而不是是否适合手头的问题。建议从可能奏效的最简单模式开始,观察它在哪里遇到困难,然后逐步演进。

模式一:生成-验证(Generator-Validator)

适合什么问题:输出质量至关重要,且评估标准能明确表述。

工作原理:Generator 生成输出 → Validator 按明确标准评估 → 不通过则附带具体反馈退回 → 循环直到通过或达到最大迭代次数。

javascript 复制代码
Generator → 输出 → Validator ──通过──→ 完成
                        │
                   不通过 + 反馈
                        │
                        └─→ Generator(下一轮)

典型场景

  • 代码生成(Generator 写代码,Validator 写并运行测试)
  • 客服回复(Validator 检查准确性、语气、完整性)
  • 合规性审查(Validator 按规则逐条核查)

关键注意 :Validator 必须有具体的评估标准,而不是"检查是否良好"。没有标准的 Validator 只会走形式盖章。另外要设置最大迭代次数上限,防止 Generator 和 Validator 陷入无限来回振荡。


模式二:编排器-子智能体(Orchestrator-Subagent)

适合什么问题:任务可以清晰分解为相互独立的子任务。

工作原理:Orchestrator 负责全局规划和任务分配,Subagents 各自处理具体职责并返回结果,Orchestrator 整合后输出。

css 复制代码
Orchestrator ──分配任务──→ Subagent A(安全检查)
             ──分配任务──→ Subagent B(代码风格)
             ──分配任务──→ Subagent C(测试覆盖率)
                   ←─── 收集所有结果 ───
                   → 整合输出最终报告

Claude Code 就用了这个模式:主 Agent 处理主流程,同时派发子 Agent 在后台搜索代码库或研究独立问题,让 Orchestrator 的上下文始终聚焦在主任务上

局限:Orchestrator 是信息瓶颈------子 Agent 之间的关联信息必须经 Orchestrator 中转,多次传递后细节容易丢失。串行执行时也享受不到速度收益。


模式三:智能体团队(Agent Team)

适合什么问题:任务可以分解为长时间运行的独立子任务,且每个子任务能从持续积累的上下文中获益。

工作原理 :Coordinator 分发工作,多个 Worker 从共享队列领取任务,各自持续运行完成多步工作,完成后发出信号。与模式二的关键区别:Worker 跨任务持续存在,不断积累领域上下文。

css 复制代码
Coordinator ──→ 任务队列
Worker A ←── 领取任务 ──→ 完成 ──→ 发信号
Worker B ←── 领取任务 ──→ 完成 ──→ 发信号
Worker C ←── 领取任务 ──→ 完成 ──→ 发信号
                           ↓
              Coordinator 收集结果 → 集成测试

典型场景:将大型代码库从一个框架迁移到另一个框架,每个 Worker 独立迁移一项服务。

局限:独立性是前提,Worker 之间无法轻松共享中间结果,需要仔细划分任务边界和设计冲突解决机制。


模式四:消息总线(Message Bus)

适合什么问题:事件驱动的流水线,且 Agent 生态在不断扩展。

工作原理:Agent 通过发布/订阅事件进行解耦通信,路由器负责分发匹配消息,新 Agent 可以随时加入订阅而无需修改已有连接。

markdown 复制代码
警报来源 → 分类 Agent → 路由器
                          ├──→ 网络调查 Agent
                          ├──→ 身份分析 Agent
                          └──→ 上下文收集 Agent
                                    ↓
                          响应协调 Agent → 处置动作

适用条件:工作流源于事件本身而非预定顺序,且团队需要独立开发和部署各个 Agent。

局限:事件链路越长,追踪和调试越困难。路由器分类错误会导致系统静默失效。


模式五:共享状态(Shared State)

适合什么问题:Agent 需要基于彼此的发现进行协同构建,且无需中央协调器。

工作原理:Agent 自主运行,通过共享的持久化存储(数据库/文件系统)相互协调。没有中央 Orchestrator,每个 Agent 读取共享存储中的发现,基于此继续工作,并将自己的发现写回。

css 复制代码
Agent A(学术文献)─┐
Agent B(行业报告)─┤──→ 共享知识库 ──→ 各 Agent 读取彼此发现
Agent C(专利文件)─┘                 → 不断迭代深化

局限 :缺乏显式协调,Agent 可能重复劳动,甚至陷入"反应式循环"(A 写 → B 回应 → A 继续回应...无限循环消耗 Token)。必须设计一等公民级别的终止条件:时间预算、收敛阈值(N 个周期无新发现),或专门的判断 Agent。


四、解决"扭头就忘":Claude Code 记忆机制

问题:上下文税

Claude Code 有个致命缺陷:无状态。关掉对话窗口,记忆清零。

每次开新对话,你都要把历史背景重新塞进去------上次的分析结论、项目架构、踩过的坑、沟通风格偏好......全部重新传一遍。

更糟的是,这些重复传输是按 Token 计费的。为了唤醒 AI 的记忆,你在持续缴纳"上下文税"。

方案一:Claude Code 原生记忆(CLAUDE.md + Auto Memory)

Claude Code 提供两种跨会话传递知识的机制:

CLAUDE.md 文件 Auto Memory
由谁编写 Claude 自动
包含内容 指令和规则 学习到的规律
适用场景 编码规范、架构约定、工作流 构建命令、调试发现、行为偏好
加载方式 每次会话加载前 200 行 每次会话加载前 200 行

CLAUDE.md 的位置决定作用范围,优先级从高到低:

  • .claude/CLAUDE.md(项目级,通过版本控制共享)
  • ~/.claude/CLAUDE.md(用户级,跨所有项目生效)

对于大型项目,可以用 .claude/rules/ 目录按主题拆分规则文件,还可以用 YAML 前置信息将规则路径绑定到特定文件:

yaml 复制代码
---
paths:
  - "src/api/**/*.ts"
---
# API 开发规则
- 所有 API 端点必须包含输入验证
- 使用标准错误响应格式

路径绑定的好处:只在处理匹配文件时加载相关规则,减少上下文噪音。

Auto Memory 是 Claude 自动积累的笔记,存储在 ~/.claude/projects/<project>/memory/ 下:

bash 复制代码
memory/
├── MEMORY.md          # 索引文件,每次会话加载
├── debugging.md       # 调试规律详细笔记
├── api-conventions.md # API 设计决策
└── ...

运行 /init 可以自动生成初始 CLAUDE.md;Claude 后续会根据纠正和偏好自动更新 Auto Memory。

方案二:claude-mem ------ 社区的"上下文税反制方案"

官方方案偏被动(你纠正 → Claude 更新)。社区开源项目 claude-mem 则更激进:

bash 复制代码
npx claude-mem install

核心机制:在 Claude Code 外部挂载本地记忆库,利用 Hooks 机制截获每次工具调用,自动压缩成摘要存入 SQLite 数据库,下次会话按需语义检索注入,而不是全量加载。

数据流:

markdown 复制代码
工具调用 → PostToolUse Hook 捕获
       → 调用 Claude API(Observer 角色)
       → 压缩为 XML 格式 observation
       → 存入 SQLite + Chroma 向量库
       ↓
新会话 SessionStart
       → 查询最近 50 条 observation + 10 个摘要
       → 注入 Claude 上下文
       ↓
用户提交 prompt(UserPromptSubmit)
       → 语义搜索最相关的 5 条 observation
       → 精准注入相关历史

效果:95% 的 Token 节省(基于该项目自身数据:6 条 observation 读取了 2,911 Token,完成了原本需要 56,291 Token 的工作)。

claude-mem 的 Observer 使用专门设计的 prompt,格式化输出可解析的 XML:

xml 复制代码
<observation>
  <type>bugfix</type>
  <title>CarPlay 启动时断连根因定位</title>
  <narrative>排查发现是 IOKit 初始化时序问题,修复方案是...</narrative>
  <facts>
    <fact>连接断开发生在 kIOMessageServiceIsTerminated 事件后 200ms</fact>
    <fact>根因:驱动初始化完成前 CarPlay 框架已开始握手</fact>
  </facts>
</observation>

五、让 AI 从你身上学习:持续学习架构

问题:AI 没有"肌肉记忆"

你用了 Claude Code 三个月,它对你的编码风格一无所知。每次开新对话,它都是个对你一无所知的新员工------不知道你偏好函数式还是面向对象,不知道你的项目有什么奇怪的约定,不记得你上次是怎么解决同类问题的。

方案:Hooks + Instinct 系统

这套架构来自 claude-code-everything 项目,由两个独立子系统组成:

arduino 复制代码
子系统 A:会话记忆(Memory Persistence)
  → 解决"上次做了什么"------短期记忆,跨会话恢复工作状态

子系统 B:Instinct 学习(Continuous Learning)
  → 解决"用户有什么习惯"------长期学习,积累行为偏好

两者都通过 Hook 机制触发,都在会话开始时将结果注入 Claude 上下文。

Hook 是什么?

Hook 是 Claude Code 工具执行前后的事件驱动钩子

复制代码
用户请求 → Claude 选择工具 → PreToolUse hook → 工具执行 → PostToolUse hook

不同 Hook 的触发时机和输入数据:

Hook 类型 触发时机 关键输入
PreToolUse 工具执行前 tool_name、tool_input
PostToolUse 工具执行后 tool_name、tool_input、tool_output
Stop 每次 Claude 响应后 transcript_path(完整会话 JSONL)
SessionStart 会话开始 session_id、cwd(可注入 additionalContext)
SessionEnd 会话结束 session_id

PreToolUse 可以通过退出码控制工具是否执行:exit 0 继续,exit 2 中止并把错误展示给 Claude。

Instinct(本能)是什么样的?

一个 Instinct 就是一条原子化的行为偏好,存成 YAML 文件:

yaml 复制代码
---
id: grep-before-edit
trigger: "when modifying existing code"
confidence: 0.7
domain: workflow
scope: project
---

# Grep Before Edit

## Action
Use Grep to locate code before Edit to confirm exact location.

## Evidence
- Observed 8 times across sessions
- Pattern: Grep → Read → Edit sequence repeated consistently
  • confidence:0.3~0.9,越高越确定,控制是否注入到下次会话(阈值 ≥ 0.7)
  • scopeproject(本项目生效)或 global(所有项目生效)
  • trigger + action:这是注入时 Claude 实际看到的内容

完整学习流程

markdown 复制代码
工具调用
  → observe.sh(异步,不阻塞)
      → 写入 observations.jsonl
      → 计数器 +1,每 20 次发 SIGUSR1

observer-loop.sh(后台常驻进程)
  → 收到 SIGUSR1
  → 取最近 500 条 observations
  → 启动 Claude Haiku 分析(claude --model haiku --print)
      → Haiku 识别行为模式
      → 按规则写 instinct YAML:
          3~5 次  → confidence 0.5
          6~10 次 → confidence 0.7
          11+ 次  → confidence 0.85
  → 归档已分析的 observations

新会话 SessionStart
  → session-start.js 读取 instinct YAML
  → 过滤 confidence ≥ 0.7,取前 6 个
  → 注入 additionalContext:

"Active instincts:
- [project 70%] Use Grep to locate code before Edit
- [global 85%] Grep before Edit, Read before Write"

用 Haiku 而不是 Sonnet 做分析,是因为模式识别任务不需要最强的模型,而控制成本很重要------这个过程每 20 次工具调用就触发一次。


总结

这四套机制,对应着 AI Agent 工程化落地的四个层次:

层次 问题 方案
稳定性 AI 在长链路任务中偏轨 Harness Engineering(Guides + Sensors)
可靠性 单 Agent 失控、自我评估失灵 多 Agent 架构(按场景选模式)
连续性 每次对话从零开始 CLAUDE.md + Auto Memory + claude-mem
成长性 AI 无法积累行为习惯 Hooks + Instinct 持续学习

从"每次都要从头教"到"越用越懂你",是 AI Agent 工程化的核心演进方向。上面这些方案,都不是新奇的技术噱头,而是在实际项目中摸索出来的、真正能解决问题的工程实践。


本文整理自手车互联团队 CarPlay bug 分析工具的开发经验,内容用于交流学习。

相关推荐
放下华子我只抽RuiKe51 小时前
React 从入门到生产(四):自定义 Hook
前端·javascript·人工智能·深度学习·react.js·自然语言处理·前端框架
想你依然心痛1 小时前
HarmonyOS 6(API 23)实战:基于悬浮导航、沉浸光感与HMAF的“文思智脑“——PC端AI智能体沉浸式智能写作工作台
人工智能·ar·harmonyos·ai写作
冬奇Lab1 小时前
一天一个开源项目(第108篇):Andrej Karpathy Skills - 用一个 CLAUDE.md 文件修复 LLM 编码的四个顽疾
人工智能·开源·资讯
涛声依旧-底层原理研究所1 小时前
残差连接与层归一化通俗易懂的详解
人工智能·python·神经网络·transformer
fantasy_arch2 小时前
pytorch人脸匹配模型
人工智能·pytorch·python
科技那些事儿2 小时前
实时洞察,视觉赋能:国内情绪识别API公司推荐及计算机视觉流派深度解析
人工智能·计算机视觉
德思特2 小时前
从 Dify 配置页理解 RAG 的重要参数
java·人工智能·llm·dify·rag
火山引擎开发者社区2 小时前
ArkClaw AI 盯盘管家 —— 从手动口令到自动推送,4 套预置定时任务模版一键启用
人工智能