
搞懂 Harness、Context、Memory 三件套,告别"调包侠"人生

现在做 AI 应用的兄弟们,画风都差不多:
掏出 API Key,敲一行 claude-sonnet,再不济换成 gpt-5.5,回车,收工,下班,吹牛。
但兄弟,模型只是发动机,你交付的可是一整辆车啊。
真正把"能跑的 Demo"和"能打的系统"区分开来的,是三门被严重低估的工程学:
这篇就把这三兄弟拆开揉碎讲清楚,并用一个真实案例让它们同台飙戏。
Harness(外壳/挽具),是你围绕模型搭建的一切外围设施。它决定:
模型是发动机,Harness 是车上除了发动机以外的所有东西。
没有 Harness,你那玩意儿不叫 Agent,叫高级版自动补全。用户说一句,模型回一句,散会。
有了 Harness,你才进入所谓的 Agentic Loop(智能体循环):
用户输入
↓
[ Harness ] ──── 调用 ────→ Model
↓
产出一个动作
↓
[ Harness ] ──── 执行工具 ────→ 工具结果
↓
把结果再喂回模型
↓
... 循环继续 ...
↓
最终答案 → 用户
Harness 到底干了些啥?给你列个清单:
职责 | 说明 |
|---|---|
工具注册 | 告诉模型它能调哪些手艺,比如 RunQuery、ReadFile |
工具执行 | 真把那些工具跑起来,并把结果拿回来 |
循环控制 | N 轮之后强制刹车,或者模型说"我搞定了"就退出 |
错误恢复 | 失败重试、把异常翻译给模型听 |
编排调度 | 把子任务路由给不同的子 Agent |
重点划一下:模型本身是无状态的,它压根不知道有个循环在转。它收到消息就吐响应,然后立刻装死。**是 Harness 在背后疯狂"call back"**,像极了一个不肯放过你的甲方。
模型唯一能看到的,就是上下文窗口(Context Window)。
你塞进去的每一个 token 都是一次决策,你没塞进去的每一个 token 也是一次决策。
Context Engineering 就是研究:什么内容、按什么顺序、用什么格式塞进窗口。这不是写 Prompt 那种小儿科,而是全景拼图:
┌─────────────────────────────────────────┐
│ System Prompt │ ← 你是谁,规矩是啥
│ ───────────────────────────────────── │
│ Tool Definitions │ ← 你能调哪些工具
│ ───────────────────────────────────── │
│ Retrieved Documents (RAG) │ ← 相关知识检索结果
│ ───────────────────────────────────── │
│ Conversation History │ ← 之前聊了啥
│ ───────────────────────────────────── │
│ Current User Message │ ← 用户当下这句话
└─────────────────────────────────────────┘
模型对开头和结尾最上心,埋在中间的内容基本就是"已读不回"。
错!错!错! 塞一堆无关信息进去叫做 Context Pollution(上下文污染),模型会被你噪到怀疑人生。
举个栗子 🌰:Postgres 里有 200 张表,用户只问发票相关的事,你就该精准注入 3 张相关 Schema,而不是把 200 张表一股脑全甩进去——那叫送命,不叫送料。
同样的信息,结构化数据(表格、JSON) 永远比散文式描述更让模型读得舒服。一张干净的发票表 vs. 一段絮絮叨叨的文字描述,模型表演给你看的是两个段位。
记住一句话:模型从不决定上下文长什么样,它只能读你递给它的东西。这事 100% 是工程师的锅。
模型是无状态的渣男。会话一断,窗口一关,你们聊过的一切,它全忘。
Memory Engineering 就是给它装一颗"外挂硬盘",让记忆能跨会话存活。
记忆分四种:
类型 | 含义 | 例子 |
|---|---|---|
情景记忆 | 具体发生过的事 | "上周二我们修了 OrderService 的 N+1 问题" |
语义记忆 | 事实和知识 | "本项目用 EF Core + 仓储模式" |
程序记忆 | 怎么操作 | "跑迁移命令:dotnet ef database update" |
工作记忆 | 当前正在用的上下文 | 这一轮对话本身 |
工作记忆 = 上下文窗口本体,其他三种都得靠工程师手搓。
方案一:基于文件把事实写进 Markdown,会话开始时读出来、塞进 System Prompt。简单、可视、易调试。Claude Code 就是这么干的。
方案二:向量数据库把事实变成 Embedding 存进 pgvector(或同类产品)。用户提问时,先把 query 向量化,再做相似度检索,把最相关的几条记忆注入上下文。可以扛百万级事实。
存储不难,衰减(Decay)才是地狱模式。
举个扎心场景:记忆里写着"我们每周五发布",结果团队改成持续部署了——这条记忆瞬间从助手变成杀手 🔪。
Memory Engineering 还得回答这些灵魂拷问:
坦白讲:这事行业里也没解透,谁先解出来谁封神。
来,关掉抽象层,上真材实料。
某周一早晨,你团队的内部 AI 助手收到一条提问:
"为啥我们的报表模块把 Dapper 换成了 EF Core?高并发下我要不要慌?"
表面上一句话,实际上是三连击:过去发生了什么 / 现在代码长啥样 / 撑得住未来流量吗。
裸模型怎么答?大概率给你抛一篇《Dapper vs EF Core 全方位评测》——正确,且废话。
下面看三剑客如何出招 👇
模型还没被叫醒,Harness 已经把问题向量化,去记忆库做相似度检索,捞回来三条团队亲身经历:
[2025年9月] 把 Dapper 换成 EF Core。原本 40+ 条原始 SQL,
没人维护,逻辑悄悄飘了。选 EF Core 是为了可维护性,不是性能。
[2025年10月] 仪表盘查询:常规负载下 ~800ms。产品同意上线。
[2025年11月] 全局禁用了懒加载。生产事故:一个页面触发 2400 次额外查询。
从此所有 Include 必须显式声明。
模型这时候还没说话,但它马上要带着团队"三个月的血泪经验"进场。这就是记忆的价值。
Context Engineering 接力,把窗口精心摆好:
为啥这样排?因为模型注意力是 U 型曲线:头尾最亮,中间昏暗。所以重要信息上下夹击,参考资料丢中间。 这不是巧合,是设计。
模型看完一圈,发现还差点料,于是:
GetQueryPlan → Harness 老老实实跑了一次 EXPLAIN ANALYZEreporting_events 表 420 万行,全表扫描,无覆盖索引 😱GetTableIndexes → Harness 把索引定义捞回来用户只敲了一句话,Harness 默默替它跑了两次数据库操作,全程没人吩咐。 这就是外壳工程的体面。
Dapper 迁到 EF Core 是为可维护性,EF Core 这层从来没为吞吐量调优过——这是关键背景。 短期风险点是
reporting_events(420 万行)的全表扫描,缺覆盖索引。你那 800ms 基线会随表线性恶化,真上量就崩。 懒加载已全局禁用,N+1 不是问题。一个针对性索引就能解决,不用动迁移决策。
精准、贴脸、可执行。对比一下三件套缺席的后果:
很多人以为三件套是平铺的,其实它们是一个循环闭环:
┌─────────────────────┐
│ MEMORY │
│ (学到的东西) │
└────────┬────────────┘
│
检索相关事实
│
▼
┌─────────────────────┐
│ CONTEXT │◄──────────────────┐
│ (模型看到的) │ │
└────────┬────────────┘ │
│ │
决定开放哪些 │ 工具结果回流
工具 │ 成新的上下文
▼ │
┌─────────────────────┐ │
│ HARNESS │───────────────────┘
│ (实际执行的) │
└─────────────────────┘
│
会话结束后,模型产出
再回写进 Memory
│
▼
┌─────────────────────┐
│ MEMORY │
│ (已更新) │
└─────────────────────┘
这是个飞轮。转得越久,越聪明。 这种复利,才是 AI 系统真正的护城河。
下次再有人跟你吹他做了个 AI Agent,记得灵魂三问:
你的 Harness 长啥样? 你的 Context 是怎么组织的? 你的 Memory 怎么衰减?
如果对方眼神开始闪躲——恭喜,你又识破了一个"调包侠"。😎
#AI #AGI #AIAgent #Harness