【AI Engineering · Harness 系列】01 Agent = Model + Harness:为什么你的 Demo 活不过一周
文章摘要:本文揭示了AI Agent产品在真实场景中失效的核心原因——仅靠精心设计的Prompt无法应对复杂现实问题。通过作者亲身经历的运维事故案例,说明Prompt在模拟测试中表现优异,却在真实故障诊断时给出错误建议导致损失扩大的问题。文章提出"Harness"概念作为解决方案,将其类比为操作系统,包含上下文管理、任务调度、检查点等确定性外壳层,包裹非确定性的LLM内核。作者

系列导读:这是《AI Agent 的操作系统:Harness Engineering 深度拆解》的第 1 篇(共 8 篇)。本篇讲清楚一个问题:为什么 Prompt 写得再漂亮,你的 Agent 产品还是撑不过一周真实使用。这背后不是模型不够强,是你少了一层叫 Harness 的东西。
一、一个让我破防的真实场景
2025 年 10 月,我第一次装上 CodeBuddy,兴冲冲给团队的 on-call 值班群搭了一个"线上故障根因诊断 Agent"——把 Grafana 告警、容器日志、最近发布记录丢给它,让它自动给出初步诊断结论:
你是一个 SRE 故障诊断助手。
给你下列信息:
1. 告警内容与指标曲线(JSON)
2. 最近 5 分钟的 Pod 日志(tail 200 行)
3. 最近 1 小时的发布记录
请输出:
1. 最可能的根因(一句话)
2. 证据链(引用日志/指标/发布记录)
3. 建议的止血动作
格式用 Markdown,尽量简洁。
当天跑了 3 次模拟故障演练,效果惊艳——定位精准、证据齐全、建议合理。我截图发朋友圈,配文"AI 时代终于来了"。
第 4 天,真实翻车。
凌晨 2 点 47 分,某核心服务 P99 飙到 8 秒。值班同事把告警 + 日志丢给 Agent,Agent 给出的结论是:
根因:Pod 内存泄漏导致 OOM,建议立即扩容 2 倍并重启所有实例。
证据列得头头是道——引用了几条 OOMKilled 事件、几段 JVM GC 日志、最近一次镜像发布记录。值班同事扫了一眼,觉得"有理有据",按建议扩容 + 重启。
扩容之后,问题暂时缓解了 10 分钟,然后卷土重来,而且更严重。
等我早上爬起来一查才发现——OOM 只是结果,不是根因。真正的根因是前一天上线的一段缓存刷新逻辑里藏了个死循环,每次触发都会无限创建线程。Agent 拿到的日志里其实有一条关键的 Thread count: 12000+ 线索,它没看。它只挑了最醒目的 OOMKilled 关键词,然后用训练数据里"OOM 就扩容"的套路编了一条自信满满的结论。
扩容让死循环跑得更快,故障直接放大 3 倍。
事后复盘,我们浪费了 4700 块钱的云资源、2 小时 P99 抖动、以及——值班同事对这个 Agent 的全部信任。
那天晚上我盯着那段 Prompt 看了很久。它没有任何问题。它简洁、清晰、指令明确。如果这是一道"大学期末考题",它能拿满分。
问题是,真实工作不是期末考题。
真实工作是:
- 日志有 3 种采集路径(stdout / filebeat / 自建探针),格式各异、时序还经常乱
- 故障场景有 7 种大类(资源耗尽 / 依赖抖动 / 配置错误 / 代码缺陷 / 流量突增 / 数据倾斜 / 外部攻击),每种的诊断路径完全不同
- 建议会被直接执行,错了要烧真金白银,还要背 P0 事故
- Agent 的自信度不等于正确度——它说得越笃定的时候,往往是它越不该被相信的时候
单独的 Prompt 解决不了这些。你需要的是一套东西在 Prompt 周围——那就是 Harness。
二、调研追溯:Harness 这个词是怎么来的
我最早听到 “Harness Engineering” 这个说法是在 2026 年 2 月初,Anthropic 的一篇研究博文里:Building Effective Agents。但那篇里 Harness 只是一个半生不熟的术语,没有展开。
真正把这个概念打透的是 2026 年 3 月份的两篇:
- Stripe 工程博客《Agents in Production》——提出了 “Model is the engine, Harness is the chassis” 的类比
- Cursor 团队的《What makes an AI coding agent actually work》——把 Harness 拆成了 5 个子系统
我对比了这两篇 + 我自己跑了 6 个月的两个项目(OpenClaw / DocCenter),以及我精读过的三套开源代码(Hermes Agent / Claude Design / Warp 源码),抽象出一个判断:
Harness 不是一个新名词,是过去两年散落各处的 Prompt Engineering、Context Engineering、Tool Use、Agent Loop、Evaluation、Memory Management……这些实践的集合体,现在有一个统一的名字了。
就像 2015 年我们叫 “运维”、“部署”、“监控”、“持续集成”,2018 年我们统一叫 “DevOps”。名字只是捕捉到了一个已经在发生的事实。
三、Harness 的定义:操作系统类比
如果只能用一句话讲清楚 Harness,我会说:
Harness 是让非确定性的 LLM 在确定性的工程系统里可靠跑起来的那一套外壳。
把它翻译成工程师能秒懂的版本:
┌─────────────────────────────────────────────────────────┐
│ 用户意图 │
└──────────────────────┬──────────────────────────────────┘
│
┌──────────────────────▼──────────────────────────────────┐
│ Harness(外壳层):确定性 │
│ ├─ Context Management (内存管理 + 虚拟内存) │
│ ├─ Task Loop (进程调度 + 中断) │
│ ├─ Checkpoint (文件系统 + fsync) │
│ ├─ Tool Routing (系统调用) │
│ ├─ Evaluator (单元测试 + 健康检查) │
│ └─ Guardrails (权限系统 + SELinux) │
└──────────────────────┬──────────────────────────────────┘
│
┌──────────────────────▼──────────────────────────────────┐
│ Model(内核层):非确定性 │
│ LLM 推理引擎(Claude / GPT / Gemini / 本地模型) │
└─────────────────────────────────────────────────────────┘
读到这里你可能在想:“不就是给 LLM 加一堆中间件吗,有这么神秘?”
对,就是加中间件。但你加的那堆中间件没有名字、没有规范、没有参考架构、没有哪怕一篇系统性的教程——于是每家都在重新发明轮子,而且发明出来的轮子互相还不兼容。
Harness 这个统一称呼解决的就是这个问题。它让我们终于可以说:
“这家团队的 Harness 做得好” / “那个开源项目的 Harness 是 shit”
——而不是泛泛地讲 “他们的 AI 产品体验好”。
四、三阶段演进:你现在处在哪个阶段
我观察过近百个 AI 产品(从朋友的副业到上市公司的主打功能),几乎所有团队都在走同一条路径:
阶段一:Prompt Engineering 时代(2022-2023)
特征:把所有希望寄托在一段 Prompt 上。
# 典型的 Prompt-Only 代码
def diagnose_incident(alert, logs, releases):
prompt = f"""你是 SRE 故障诊断助手。
请根据以下信息给出根因判断与止血建议:
告警: {alert}
日志: {logs}
发布记录: {releases}
"""
return llm.call(prompt)
信奉的信条:“只要 Prompt 写得够好,模型就能搞定一切。”
翻车方式:
- 遇到 Prompt 里没覆盖过的故障类型 → 幻觉根因
- 日志格式稍微变形(新版本 JSON Schema / 不同采集器)→ 解析崩溃
- 多轮追问排查路径 → 失忆,反复让你提供已经给过的信息
我在这个阶段踩过的坑:就是开头那个凌晨 2:47 的误扩容事故。
阶段二:Context Engineering 时代(2024-2025)
特征:意识到 Prompt 只是冰山一角,重心转向"给模型塞什么上下文"。
# 典型的 Context-Aware 代码
def diagnose_incident(alert, service, env, timeline):
context = build_context(
role_card=ROLE_CARDS[service.tier], # 核心服务 vs 边缘服务,判断口径不同
runbook=retrieve_relevant_runbook(alert), # 召回历史相似告警的处置手册
topology=load_service_topology(service), # 上下游依赖、数据库、缓存
recent_changes=recent_deploys_and_configs(env, window="1h"),
metrics=pull_metrics_around(alert.timestamp, window="15min"),
logs=pull_logs_smart_sampled(service, alert.timestamp),
constraints=DIAGNOSIS_RULES, # "不要建议扩容除非排除了代码问题"
)
return llm.call(context)
信奉的信条:“模型是诊断医生,上下文是化验单。化验单齐,诊断才准。”
翻车方式:
- 上下文堆得太长 → Token 爆炸 / Lost in the Middle(关键线索被埋在中间段落)
- 相似 runbook 检索不准 → 带偏方向(拿 A 服务的套路去治 B 服务)
- 多轮排查后 Context 漂移 → 越查越跑题,忘了最初的告警是什么
大多数团队目前卡在这一阶段——包括我 2025 年底的状态。
阶段三:Harness Engineering 时代(2026 起)
特征:Prompt 和 Context 都只是外壳的两个子部件,真正重要的是整个系统怎么运转。
# 典型的 Harness-Aware 代码
class IncidentDiagnoser(Harness):
context_engine = HierarchicalContext(budget=30_000)
evaluator = IndependentCritic(model="gpt-4o")
checkpoint = FileSystemCheckpoint(path="./checkpoints/")
guardrails = [
NoFabricationRule(), # 证据链必须来自真实日志/指标,不能编
EvidenceMustCiteRawLine(), # 每条结论必须引用原始日志行号
NoScaleUpBeforeCodeCheck(), # 禁止在未排除代码问题前建议扩容
ConfidenceMustMatchEvidence(), # 证据弱时不允许输出"确定""必然"等强断言
]
async def diagnose(self, alert):
async with self.checkpoint.session() as ckpt:
ctx = self.context_engine.build(alert, ckpt.history)
draft = await self.model.generate(ctx)
critique = await self.evaluator.review(draft, alert)
if critique.has_issues():
draft = await self.model.revise(draft, critique)
for rule in self.guardrails:
rule.check_or_raise(draft)
ckpt.save(draft)
return draft
信奉的信条:“模型是 CPU,Harness 是整台计算机。”
这个阶段的 Agent 才能在真实生产环境活下来。
五、实例拆解:我从 Prompt 到 Harness 的真实进化
理论说完,讲我自己的故事。这是本篇最硬的部分,也是整个系列所有实例的起点。
阶段一:养虾系列第一篇的"Prompt 崇拜期"
2025 年 10 月,我写养虾系列第一篇《CodeBuddy 初体验》,核心内容是:“装完 CodeBuddy,一段好 Prompt 就能出奇迹”。
那会儿我的工作流长这样:
打开 CodeBuddy
→ 粘贴精心打磨的 Prompt(我自己都改过十几版)
→ 得到漂亮的输出
→ 截图发朋友圈
→ 第二天重复
问题暴露得很快:
- 第 3 天:同一个 Prompt,昨天给出的代码今天跑不通
- 第 5 天:AI 忘了昨天我们定的命名规范
- 第 7 天:AI 自信地引用了一个根本不存在的 API
核心问题:我只有 Prompt,没有 Harness。每次对话都是从零开始,AI 没有记忆、没有规范、没有检查。
阶段二:CLAUDE.md 时代(Context Engineering)
2025 年 12 月,我开始意识到"记忆"的重要性。建立了第一版 CLAUDE.md:
# 项目上下文
## 命名规范
- Python: snake_case
- TypeScript: camelCase
- 文件名: kebab-case
## 代码风格
- 不写注释除非真的必要
- 函数超过 50 行必须拆分
- 禁止 any 类型
## 我讨厌的
- 过度抽象
- 函数式一把梭
- README.md 写一堆废话
这已经是 Context Engineering 了。每次对话自动加载这份规范,AI 的输出一致性显著提升。
但新问题出现了:
CLAUDE.md越写越长(最后到了 400 行)- Token 每次对话都被它吃掉 20%
- 很多规则一辈子用不上一次,但一直占位
我进入了 Context 过载的典型困境——堆得越多,模型越累。
阶段三:Harness 时代(OpenClaw)
2026 年 3 月,我开始重构。这次不是优化 Prompt,也不是优化 Context,而是把整个协作关系重新设计成一个操作系统。
核心架构:
┌─────────────────────────────────────────────────────────┐
│ 用户说一句话 │
└────────────────────┬────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────┐
│ CLAUDE.md(内核启动文件,<10KB,每次对话注入) │
│ ├─ @./IDENTITY.md (我是谁) │
│ ├─ @./USER.md (用户是谁) │
│ └─ @./MEMORY.md (精炼后的长期记忆,~80 行) │
└────────────────────┬────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────┐
│ Skills(用户态程序,按需加载) │
│ ├─ classroom-article-writer-v2 │
│ ├─ mck-ppt-design │
│ ├─ drawio-swimlane-collab │
│ └─ ... │
└────────────────────┬────────────────────────────────────┘
│
┌────────────────────▼────────────────────────────────────┐
│ 心跳系统(后台守护进程) │
│ ├─ 哨兵心跳(launchd 4h/次) │
│ ├─ 每日学习(crontab 9:00) │
│ └─ 每日做梦(crontab 0:00) │
└─────────────────────────────────────────────────────────┘
让我解释每一层在做什么:
启动层:CLAUDE.md
这不是 Prompt,这是内核启动文件,每次会话开始时自动注入(这个机制对应后面第 05 篇要讲的 Hierarchical Context)。
关键设计:
# CLAUDE.md
@./IDENTITY.md # 我是"路易乔布斯",不是 CodeBuddy
@./USER.md # 用户是 Louis,决策风格是...
@./MEMORY.md # 长期精炼记忆(~80 行)
## 快速路由
- 问"代码风格" → 查 skills/code-style.md
- 问"最近做了什么" → 查 ./daily-reports/
- 问"川哥要什么" → 查 memories/chuange-profile.md
对比第二阶段:
- 第二阶段:400 行全塞进去
- 第三阶段:10KB 核心 + 按需跳转
这不就是操作系统吗——内核常驻 + 用户程序按需加载。
应用层:Skills
每个 Skill 是一个"用户态程序",有自己的 SKILL.md(类似 manifest.json),触发条件、流程、脚本、校验规则一应俱全。
例如 classroom-article-writer-v2:
skills/classroom-article-writer-v2/
├── SKILL.md # 技能说明 + 触发关键词
├── style-dna.md # 基础风格基因
├── cover-template.html # 封面模板
├── article-template.html # 正文模板
├── ai-slop-checker.md # AI 糟粕反清单(禁止项)
└── scripts/
├── generate-cover.py
└── check-quality.py
用户态程序 vs Prompt 的本质区别:
- Prompt 是 “你照我说的做”
- Skill 是 “你按我这套 SOP 走”,SOP 本身有版本管理、有测试、有迭代
守护进程层:心跳系统
这是最能体现"操作系统"类比的部分——AI 助手不是请求-响应式的无状态函数,它是个有自己心跳的进程。
三层心跳各司其职(后面第 04 篇会完整拆开讲):
| 层级 | 触发器 | 周期 | 职责 |
|---|---|---|---|
| 哨兵心跳 | launchd | 4 小时 | 健康检查,纯文件操作,不烧 Token |
| 每日学习 | crontab | 每天 9:00 | 搜索新信息,回写 Wiki |
| 每日做梦 | crontab | 每天 0:00 | 记忆精炼,原则进化,清理冗余 |
为什么要拆三层? 因为不同频率的事情,成本结构完全不同。4 小时一次的健康检查如果也跑 LLM,一个月光心跳就要几百块。拆开之后,每层只做最必要的事,成本降到原来的 1/8。
这就是 Harness——不是加功能,是把正确的能力放在正确的位置。
三阶段效果对比(真实数据)
从 2025 年 10 月到 2026 年 5 月,我用同样的任务(写一篇养虾系列文章)测试了三种模式的效果:
| 指标 | 阶段一(纯 Prompt) | 阶段二(CLAUDE.md) | 阶段三(Harness) |
|---|---|---|---|
| 首稿可用率 | 20% | 55% | 85% |
| 平均来回轮次 | 8–12 | 4–6 | 2–3 |
| 单篇 Token 消耗 | ~30K | ~80K | ~50K |
| 风格一致性 | 差 | 中 | 好 |
| 遗忘历史约定 | 每次都忘 | 偶尔忘 | 几乎不忘 |
| 生产耗时 | 3–5 小时 | 2 小时 | 40 分钟 |
注意一个反直觉的点:阶段三的 Token 消耗反而比阶段二更少。
原因:阶段二的长 CLAUDE.md 每次都全量注入,白白烧钱。阶段三的核心文件精简到 80 行,具体规则按需从 Skills 加载,省掉了大量"可能用不到的上下文税"。
Harness 不是加负担,是把负担放对地方。
六、启发与方法论:四条可迁移原则
理论 + 实例讲完,我尝试抽象出一些不依赖具体技术栈的原则。
原则一:工具箱 ≠ 边界
这是我最底层的信念。
大多数 AI 工程师一开始会把 “模型能做什么” 等同于 “产品能做什么”。于是:
- 模型不会写代码 → 我们不做代码助手
- 模型会幻觉 → 我们不做严肃场景
- 模型上下文窗口小 → 我们不做长文档场景
这是工具决定论。但工具不是边界,问题才是边界。
当你把问题定义清楚,发现工具不够时,你应该造 Harness 补足,而不是缩小问题。
举例:
- 模型会幻觉 → 你加一个独立 Evaluator(第 06 篇)
- 上下文窗口小 → 你加 Hierarchical Context + Handoff(第 05 篇)
- 模型失忆 → 你加 Memory Management + Checkpoint(第 03 篇)
Harness 的本质是:用工程手段补足模型能力边界。
原则二:区分确定性与非确定性
工程师的肌肉记忆是"所有东西都要可预测"。放 LLM 进来之后,这条经验被颠覆了。
但颠覆不意味着全盘接受不确定。更好的姿势是:
- 需要创造力的部分 → 非确定性(模型)
- 需要保底的部分 → 确定性(Harness)
就像双引擎飞机,一个是喷气引擎(推力大但可能失速),一个是螺旋桨(推力小但稳)。Harness 是那个螺旋桨。
具体落地:
- 生成内容用模型,格式校验用正则
- 决策用模型,执行用脚本
- 分析用模型,汇总用 SQL
- 写 PPT 用模型,画图用 matplotlib
把"非确定性"关进一个个"确定性"的笼子里,才能真正上生产。
原则三:每次失败都是 Harness 升级的邀请函
这是我过去 6 个月最重要的心态转变。
以前看到 AI 翻车,我会想:“这模型怎么这么蠢。”
现在看到 AI 翻车,我会想:“我的 Harness 少了一道什么校验?”
具体练习:每次翻车后写一份 3 行复盘:
- 现象:AI 做错了什么
- 根因:Harness 里少了哪道保险
- 加固:我加了什么规则/脚本/校验
这份复盘以后会变成你的 Skill 库、Guardrails、Evaluator 规则集。
Harness 不是一次性设计的,是每次翻车后长出来的。
原则四:把正确的能力放在正确的位置
这是 Harness 架构的灵魂。
同一个需求,有多种落地方式:
- 用 Prompt 写规则 → 便宜,但每次调用都重复消耗 Token
- 用 Context 塞规则 → 中等,但上下文会污染
- 用 Skill 装规则 → 结构化,但加载有延迟
- 用脚本执行规则 → 零成本,但失去灵活性
没有哪个最优。重要的是根据规则的使用频率、变化频率、严重性,放到合适的层。
高频 + 不变 + 严重 → 脚本(硬编码)
高频 + 不变 + 一般 → CLAUDE.md(启动即加载)
低频 + 常变 + 一般 → Skill(按需加载)
低频 + 不变 + 边角 → 文档(Agent 自己去查)
这个决策矩阵直接决定了你 Harness 的架构质量。
七、反驳性思考:如果我错了会怎样
反驳一:“Harness 只是把复杂度从 Prompt 推到了工程侧,总复杂度没降”
部分成立。总复杂度确实没降——但可维护性、可测试性、可协作性大幅提升。
Prompt 是一坨字符串,改一行要整串回归。Harness 是一个架构,每层独立测试、独立升级。
类比:单体 vs 微服务。微服务的总复杂度不低于单体,但复杂度被关进了盒子里,团队可以分工、组件可以独立演化。
反驳二:“这套只适合长期项目,做临时 Demo 过度工程”
完全成立。如果你要做的东西生命周期 <2 周,别搞 Harness,直接 Prompt 一把梭。
我的经验阈值:
- 1 周内的一次性任务 → 纯 Prompt
- 1–4 周的迭代项目 → Prompt + CLAUDE.md
- 1 个月以上的产品 → 完整 Harness
Harness 的 ROI 在时间维度上才能显现。短期看不到收益。
反驳三:“上下文窗口会涨到 10M,Harness 就不需要了”
这是 Big Model 派的核心论点,我会在第 08 篇专门反驳。
简短版答案:上下文窗口变大解决不了 注意力分配 问题。10M Token 的窗口 ≠ 10M Token 的有效利用。Lost in the Middle 现象在 10M 只会更严重。
Harness 解决的不是"装不下",是"装进去也找不到"。
八、收官与预告
这一篇你应该带走的三件事
- Agent = Model × Harness——你从来买的不是模型,你需要的是整个操作系统
- 三阶段演进:Prompt Engineering → Context Engineering → Harness Engineering,识别自己在哪个阶段是第一步
- 工具箱 ≠ 边界——当工具不够时,造 Harness 补足,而不是缩小问题
全系列地图提醒
| # | 标题 | 进度 |
|---|---|---|
| 01 | Agent = Model + Harness(本篇) | ✅ |
| 02 | 确定性外壳 × 非确定性内核 | 下一篇 |
| 03 | Checkpoint 不是为了续跑 | 硬货篇 |
| 04 | Task Loop:三层心跳架构 | 硬货篇 |
| 05 | 上下文不是内存,是注意力预算 | |
| 06 | 独立 Evaluator | |
| 07 | 五大反模式:我踩过的坑 | 硬货篇 |
| 08 | Big Model vs Big Harness |
下一篇预告:确定性外壳 × 非确定性内核
第 02 篇我会讲 Guardrails(护栏)系统,核心话题:
- 为什么"护栏"不是限制,是加速器
- 我凌晨 3 点补的那道
git push红线——那次差点把私有 Skill 推到公网 - 硬规则 / 软规则 / 检测-纠正三层护栏架构
- 反面教材:过度护栏如何把 AI 变成一个什么都不敢做的怂货
如果这一篇对你有启发,点个收藏,系列更新不迷路。
配套代码
- 本篇涉及的 CLAUDE.md 模板:OpenClaw Workspace(即将开源)
- 养虾系列文章集合:公众号菜单
作者其他 AI Engineering 深度系列
- Warp 源码深度解析(7 篇) —— GPU 终端 + AI Agent 架构拆解
- DocCenter 从 0 到 1 深度剖析(8 篇) —— 本地文档中心的 v1.0 到 v1.3 迭代史
路易乔布斯 © 2026 · AI Engineering 系列
xx号:一深思AI · 养虾系列 S4
CSDN:Harness Engineering 专栏
更多推荐



所有评论(0)