Prompt、Context、Harness、Agentic:LLM 应用四层嵌套结构,搞清自己卡在哪一层

最近几个月,关于”LLM 应用应该怎么搭”的讨论里,四个词反复出现:prompt engineering、context engineering、harness engineering、agentic engineering。每个词后面都跟着一群人喊”另一个已经过时”——Karpathy 公开站队 context engineering,认为这个叫法比 prompt engineering 更准确地描述了工业级 LLM 应用的实际工作;做 agent 框架的人说”光会 context 没用,harness 才是真正的护城河”;研究 multi-agent 的人又说”前面那些都是底层细节,真正的工程是 agentic 系统设计”。

听多了会以为这是四个不同的工种在抢饭碗。但实际跑过几个 LLM 项目以后,我的感觉是:它们根本不在打架,是同一件事的四层嵌套——从最内层”一句话”到最外层”一整个自主系统”,关注点逐层放大。每一层在前一层的基础上多包一圈控制权。

这篇拿 Claude Code 这套我每天都在用的 harness 当例子,把这四层拆开看一遍。重点不是”该叫自己什么工程师”,而是当某次跑通不顺、效果差、agent 卡死时,你能快速判断:我现在到底卡在哪一层?应该往哪个方向调?

一张嵌套图先放在这里

┌─────────────────────────────────────────────────────┐
│ Agentic 工程:一个能自主追求目标的系统               │
│  ┌─────────────────────────────────────────────┐    │
│  │ Harness 工程:模型外面的代码骨架/运行时       │    │
│  │  ┌─────────────────────────────────────┐    │    │
│  │  │ Context 工程:窗口里放什么、怎么组装  │    │    │
│  │  │  ┌─────────────────────────────┐    │    │    │
│  │  │  │ Prompt 工程:单次输入的措辞   │    │    │    │
│  │  │  └─────────────────────────────┘    │    │    │
│  │  └─────────────────────────────────────┘    │    │
│  └─────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────┘

越往里越具体(一段话),越往外越宏观(整套系统)。外层包含内层,但解决的问题不一样

第一层:Prompt 工程——一句话的优化

最内层,工作单元是一段提示词

关心的问题:

  • 怎么措辞这条指令最不容易被误解?
  • 要不要给 few-shot 例子?给几个?
  • 要不要让模型先想(chain-of-thought)再答?
  • 怎么强制输出固定格式(JSON、XML、Markdown)?
  • 怎么设定角色让回答风格稳定?
  • 怎么写 system prompt 才能压住模型瞎发挥?

这是 2022–2023 年 LLM 应用的核心技能。那时候模型能力还弱、上下文窗口小(4K、8K 算大)、tool use 还不靠谱——能不能让模型干对一件事,几乎完全取决于这一段提示词怎么写。

放到 Claude Code 的语境里,CLAUDE.md 和各种 skill 的 SKILL.md 顶部那段 system prompt 就是典型的 prompt 工程产物:你在用文字把模型的行为往你要的方向拧。

Prompt 工程的天花板

它的局限也在这一层就显现:

  • 单次输入再精心,也只是一次输入——下一轮对话、跨任务复用、动态信息注入它管不到
  • 窗口里其他东西它管不了——RAG 检索结果、对话历史、工具返回的数据,这些塞进来的内容如果质量差,再好的提示词也救不回来
  • 模型自身的能力没有提升——prompt 工程把模型现有能力榨干,但榨不出它没有的能力

当你发现”提示词怎么改都没用了”,那不是 prompt 工程没做好,是该往外一层走了。

第二层:Context 工程——窗口里放什么

往外一圈,工作单元变成整个上下文窗口里的全部内容及其组装逻辑

Prompt 只是窗口里的一块。其他还有:

  • RAG 检索来的文档片段(向量召回、BM25、混合检索)
  • 对话历史(要不要全保留?怎么压缩?什么时候摘要?)
  • 工具调用结果(一个 ls 命令返回 500 行怎么办?)
  • 记忆 / 摘要(短期窗口塞不下的旧信息往哪存?)
  • 结构化背景(用户偏好、当前项目状态、时间日期)

核心问题是:在有限的 token 预算里,怎么动态地塞进”恰好够用”的信息?该放的放进来、该压缩的压缩、该剔除的剔除,还要管好顺序和相关性。

Karpathy 之所以把 context engineering 摆到 prompt engineering 前面,讲的就是这件事——一旦模型要持续地干活、跨多轮、调工具,单次提示词怎么写已经不是瓶颈了,瓶颈是这一次模型看到的窗口里到底装了什么。他原话大意是:“在每一个工业级 LLM 应用里,context engineering 都是一门精细的艺术与科学:把恰好够用的信息填进窗口,给到下一步。“

Context 工程的几个核心动作

1. 选择性注入

不是把所有相关文档都塞进去,而是检索后做一次质量过滤、相关性排序。塞 10 段中等相关的不如塞 3 段高度相关的——窗口里噪音越多,模型注意力越散。

2. 压缩与摘要

对话进行到第 50 轮,前 40 轮的细节不能全留。常见做法:滚动窗口(只留最近 N 轮)、分级摘要(远期高度压缩、近期保留细节)、按主题归档(把同主题的多轮合并成一段)。

3. 顺序很重要

LLM 对窗口里位置敏感——最前面的 system prompt 和最后的 user message 影响最大,中间的”迷失在中间”(lost in the middle)现象人人都遇到过。重要信息要么放头要么放尾,不要埋在中段。

4. 工具结果的”瘦身”

模型调一个 find . -name '*.ts' 返回 2000 行路径,全塞回去窗口立刻爆。要么截断(前 50 行 + ”…还有 N 行”)、要么转成结构化摘要(“找到 N 个文件,分布在以下 5 个目录”)、要么让模型自己再发一次更精确的查询。

放到 Claude Code 的语境里,设计 SKILL.md、用 MCP server 暴露记忆、控制喂进窗口的文件 / 检索结果,全是 context 工程。Claude Code 的 /compact 命令(用户手动触发)和 auto-compact(窗口快满时自动触发)更是 context 工程的教科书级例子——把历史对话压缩成摘要再继续,腾出 token 空间。

Context 工程的天花板

Context 调得再好,也只是窗口内的事情。模型一旦要循环跑(agent loop)、要调工具、要在多轮之间维持状态——那些是”窗口外面的逻辑”,context 工程管不了。

第三层:Harness 工程——模型外面的运行时

再往外一圈,关注点从”窗口里”变成”包住模型的整套代码骨架”。

如果说模型是发动机,harness 就是把发动机包起来、让它实际能干活的整台机器。Claude Code 本身就是一个典型的 harness

Harness 工程关心:

  • Agent loop 怎么转——什么时候停?怎么判断任务做完了?要不要中途让用户介入?
  • 工具怎么定义——参数 schema、文档字符串、错误处理、超时
  • 工具结果怎么回喂——结构化、截断、错误转译
  • 错误重试与降级——模型给的 JSON 不合法怎么办?工具调失败要不要换一种?连续 5 次错误要不要中断?
  • Guardrails——敏感操作要不要二次确认?破坏性命令要不要 sandbox?
  • 可观测性——每一步在干啥能看见吗?token 花在哪?哪个工具最慢?
  • 缓存与成本——prompt caching、tool result caching、流式响应

工作单元是承载模型运行的那套系统与控制流

Harness 工程做对了的样子

我在 Claude Code 里写过几个长跑任务(blog175 那个交易策略 dogfooding 就是一个)——能跑稳的原因不是我提示词写得多好,是这套 harness 在背后做了大量工作:

  • 工具调用失败会自动转译错误消息再让模型重试
  • 破坏性命令(rmgit reset --hard)会暂停等用户确认
  • token 接近上限时 auto-compact 自动启动压缩历史对话
  • 工具输出过长会自动截断并标注”…还有 N 字节未显示”
  • agent 卡住超过一定步数会主动提醒”你似乎在循环,要不要换个思路”

这些都不是模型自己会做的——是 harness 这层的代码在管。模型只负责”下一步该做什么”,harness 负责”这一步实际怎么发生、出了问题怎么收拾”。我之前写过 agent 经常无视铁律——那篇里的失效场景几乎全是 harness 没把”高优先级规则的强制 hook”做到位,模型记不住不是模型的问题,是 harness 没替它把规则压到对的位置。

Harness 工程的天花板

写好一个 harness,单 agent 能可靠地完成任务。但当任务复杂到一个 agent 装不下——需要拆解、需要多 agent 协作、需要长期记忆跨 session 持续、需要 eval 体系判断系统整体好不好——这些就是 harness 解决不了的问题。

第四层:Agentic 工程——一整个自主系统

最外层,关注点变成”这个系统能不能可靠地端到端完成目标”。

它把前三层全包进来,但站在更高视角问的问题不一样:

  • 任务分解与规划——一个大目标怎么拆成子目标?谁拆?拆错了怎么办?
  • 要不要 sub-agent——主 agent 调用子 agent 还是一个 agent 从头跑到尾?子 agent 之间怎么协作?
  • 多 agent 编排——一群 agent 怎么不互相打架?谁是 coordinator?
  • 工具生态设计——给 agent 多少工具?工具粒度多大?什么时候该加一个新工具而不是扩展旧工具?
  • 记忆架构——跨 session 长期记忆怎么存?记忆要不要分层(短期/中期/长期)?记忆什么时候该遗忘?(blog079 那篇专门写过
  • 评估体系(eval)——怎么知道这个 agent 整体在变好还是变差?端到端跑通率多少?回归测试怎么设计?
  • 模型路由——简单任务用便宜模型、复杂任务用强模型,路由策略谁定?
  • 失败模式分析——agent 在哪种情况下最容易翻车?怎么提前识别?

工作单元是整个 agent(或 agent 群)

放到 Claude Code 生态里,多 agent 编排(main + subagent)、整个工具链怎么可靠端到端跑、跨 session 的 memory 系统怎么设计、要不要做 routine(定时 cron agent)——这些就是 agentic 工程。

我现在自己 ai/ 目录下跑的这套 agent 系统就在这一层——blog agent、trade agent、memory agent 各司其职,cron 调度日常任务,failure 模式记在 MEMORY.md 里防止重蹈覆辙。这套系统的好坏不取决于任何一个 prompt 写得多好,取决于整个编排逻辑、记忆架构、eval 闭环、失败恢复策略这些 agentic 层面的决策。

实战:卡住时怎么判断在哪一层

四层的价值,不在于让你给自己贴一个”我是 X 工程师”的标签——实际工作里同一个人四层都在做。它真正的用处是:当你跑一个 LLM 应用发现效果不理想时,能快速定位问题在哪一层,然后往对的方向调。

我自己用的一套判断流程:

症状 1:模型答错了,但只在某种特定问法上错

怀疑:prompt 层
检查:换个措辞、加 few-shot、加 chain-of-thought、明确输出格式
判定:换措辞就好了 → prompt 问题
     换措辞还错 → 往外查 context

症状 2:模型答得很离谱,明显在”瞎编”

怀疑:context 层
检查:窗口里有没有相关信息?是不是被旧对话淹没了?RAG 召回的文档质量如何?
判定:补上正确信息就好了 → context 问题
     窗口里信息齐全还错 → 往外查 harness(工具或循环逻辑)

症状 3:agent 卡死在循环、或者中途莫名其妙停了

怀疑:harness 层
检查:agent loop 的终止条件是什么?工具失败怎么处理?有没有重试上限?
判定:调整循环逻辑或工具定义就好了 → harness 问题
     循环逻辑没问题但任务依然完不成 → 往外查 agentic

症状 4:单步都对,但端到端跑通率低;或者跨 session 表现不一致

怀疑:agentic 层
检查:任务分解合理吗?子 agent 之间有没有信息断层?长期记忆有没有衰减?
判定:调整编排结构、加强记忆架构、补 eval

误诊的代价

  • 实际是 context 问题,你在调 prompt——徒劳,因为窗口里根本没有正确答案
  • 实际是 harness 问题(agent 死循环),你在改 prompt——徒劳,因为模型每一步都做对了,是外层循环没设计好
  • 实际是 agentic 问题(任务拆错了),你在改 harness——徒劳,因为局部跑通跟整体跑通是两码事

学过四层之后,最大的变化不是技能突然变强,是面对一个”不灵”的现象时,能更快地排除掉无效方向

顺序与优先级

新建一个 LLM 应用,从内往外搭通常更稳:

  1. 先用 prompt + 简单 context 跑通最小用例——证明这件事在原理上模型能干
  2. 加 RAG / 历史 / 摘要做好 context 工程——证明信息齐全时它能稳定干
  3. 包一层 harness,把循环、工具、错误处理做好——证明它能反复干
  4. 设计 agentic 架构,多 agent / 长期记忆 / eval 都上——证明它能端到端干

反过来从最外层开始搭最容易翻车——很多 multi-agent 框架的 demo 看着惊艳,真要落地常常发现底下三层都没做好,agentic 层的编排只是把混乱放大。

结语

prompt ⊂ context ⊂ harness ⊂ agentic——这四个层次不是非此即彼的角色分工,是同一件事的不同放大倍数。

下次有人跟你说”prompt 工程已死,现在是 context 工程的时代”——你可以反过来想:它们都没死,只是关注点的相对优先级在变。模型能力越强,单次 prompt 的优化空间确实越小;但 context、harness、agentic 这几层的设计空间反而越来越大。

真正稀缺的不是任何单一层的技能,是能在四层之间自由切换、卡住时知道往哪查的人


延伸阅读