前言:为什么现在又开始讨论 Context Engineering 和 Harness Engineering?
刚开始接触大模型开发的时候,我们经常会遇到一个问题:
这个 Prompt 到底应该怎么写?
于是我们开始研究 Prompt Engineering:
- System Prompt 怎么设计?
- Role 应该怎么定义?
- Few-shot 要不要加?
- 输出格式怎么约束?
- 怎么减少模型幻觉?
随着 Agent 应用越来越复杂,我们很快会发现:
很多问题根本不是 Prompt 写得不好。
比如:
Prompt 已经写得很清楚了,
但是模型不知道数据库里的实时数据。
Prompt 已经写得很清楚了,
但是历史对话太长,模型抓不到重点。
Prompt 已经写得很清楚了,
但是工具返回的数据太多,模型反而不知道该看什么。
于是,我们开始关注另外一个问题:
到底应该给模型什么上下文?
这就是 Context Engineering。
但是继续往前做 Agent,又会遇到更加棘手的问题:
模型知道该做什么;
也拿到了正确的信息;
但是:
工具调用失败怎么办?
任务执行到一半怎么办?
状态怎么保存?
结果怎么验证?
失败之后怎么重试?
Agent 能访问哪些资源?
这时候你会发现:
Prompt 和 Context 解决的只是 Agent 的一部分问题。
真正要让 Agent 稳定完成任务,还需要一个完整的运行环境。
于是又出现了 Harness Engineering。
所以,如果把这几个概念放到一起看,我更倾向于把它理解成一个逐渐演进的过程:
Prompt Engineering
↓
解决“模型应该怎么做”
↓
Context Engineering
↓
解决“模型需要知道什么”
↓
Harness Engineering
↓
解决“模型如何可靠地完成任务”
本文就从 Agent 开发的角度,聊聊这三个概念之间到底是什么关系。
1、Prompt Engineering:先解决“怎么告诉模型做什么”
Prompt Engineering,也就是我们最熟悉的提示词工程。
在最早的大模型应用中,系统通常非常简单:
用户输入
↓
Prompt
↓
LLM
↓
回答
例如:
你是一名发动机选型专家。
请根据用户的需求,
从候选发动机中选择最符合要求的型号。
要求:
1. 优先满足用户明确提出的条件
2. 不允许虚构不存在的配置
3. 如果条件无法满足,需要明确告诉用户
4. 最终给出推荐型号以及推荐理由
这里我们实际上是在告诉模型:
- 你是谁
- 你要做什么
- 应该遵循什么规则
- 最后应该输出什么
这就是 Prompt Engineering 最核心的工作。
可以简单理解成:
Prompt Engineering 解决的是模型的“行为规范”。
2、Prompt Engineering 为什么越来越不够用了?
假设现在我们真的做一个发动机智能选配 Agent。
用户说:
帮我选择一个功率 150kW 以上,
排量不超过 2.5L 的发动机。
Prompt 可以告诉模型:
必须满足用户提出的条件。
但是问题来了:
模型怎么知道现在有哪些发动机?
难道我们把数据库中的所有发动机都写进 Prompt?
比如:
发动机 A:
功率:120kW
排量:2.0L
价格:8000
发动机 B:
功率:150kW
排量:2.5L
价格:10000
发动机 C:
功率:180kW
排量:2.5L
价格:12000
......
如果数据量只有几十条,还可以勉强接受。
但是实际业务系统可能有:
发动机
+
零部件
+
配置参数
+
价格
+
库存
+
车型
+
客户历史选择
数据量很容易达到几万甚至几十万条。
这时候 Prompt 已经不是 Prompt 了。
而变成了一个:
巨大的数据容器。
所以问题开始发生变化:
以前:
Prompt 怎么写?
现在:
模型真正需要哪些信息?
这就是 Context Engineering 出现的原因。
3、Context Engineering:解决“模型需要知道什么”
Context Engineering 可以简单理解成:
围绕当前任务,为模型动态构建高质量上下文。
这里的关键词其实是:
动态。
不是把所有数据都提前塞给模型,而是根据当前任务,找到模型真正需要的信息。
整个过程可能是:
用户请求
↓
理解用户需求
↓
确定需要哪些信息
↓
查询数据库 / 知识库 / API
↓
筛选相关数据
↓
整理 / 压缩
↓
构建 Context
↓
发送给 LLM
比如:
用户:
我需要一个功率 150kW 以上、
排量不超过 2.5L 的发动机。
Agent 首先解析出:
power >= 150kW
displacement <= 2.5L
然后去查询数据库:
SELECT *
FROM engine
WHERE power >= 150
AND displacement <= 2.5;
数据库返回:
A:150kW / 2.5L / 10000元
B:160kW / 2.3L / 12000元
C:180kW / 2.5L / 9000元
然后把这些数据组织成模型需要的 Context:
用户需求:
功率 >= 150kW
排量 <= 2.5L
候选发动机:
A:
功率:150kW
排量:2.5L
价格:10000元
B:
功率:160kW
排量:2.3L
价格:12000元
C:
功率:180kW
排量:2.5L
价格:9000元
这时候 LLM 才真正开始发挥它擅长的能力:
基于已经获取到的信息进行理解、推理和解释。
4、Context Engineering 和 Prompt Engineering 到底有什么区别?
这两个概念其实特别容易混。
我觉得可以用一句话来区分:
Prompt Engineering 解决“怎么告诉模型做事”,Context Engineering 解决“给模型什么信息做事”。
例如:
Prompt
你是一名发动机选型专家。
请选择满足用户要求的发动机。
不得虚构数据。
这是:
模型应该怎么做
Context
用户要求:
功率 >= 150kW
候选发动机:
A:120kW
B:150kW
C:180kW
这是:
模型需要知道什么
因此二者并不是替代关系。
而是:
Prompt
+
Context
↓
LLM
Prompt 负责规则和行为。
Context 负责事实和状态。
5、Context Engineering 不等于 RAG
这里也有一个比较常见的误区:
Context Engineering = RAG?
其实不是。
RAG 只是 Context Engineering 的一种实现方式。
Context 的来源可以非常多:
Context
│
┌────────────┼────────────┐
↓ ↓ ↓
RAG Database API
│ │ │
↓ ↓ ↓
知识文档 业务数据 实时数据
┌────────────┼────────────┐
↓ ↓ ↓
Conversation Memory Tool Result
│ │ │
↓ ↓ ↓
历史对话 用户记忆 工具执行结果
所以在实际 Agent 项目中:
Context Engineering
│
├── RAG
├── Database Query
├── API
├── Tool Result
├── Conversation History
├── Memory
├── Task State
└── Runtime Information
这些都属于 Context Engineering 的范畴。
6、Context Engineering 的核心:不要什么都给模型
这里其实有一个非常重要的思想:
Context 不是越多越好。
以前我们经常有一种思维:
模型不知道?
→ 给它更多信息。
但在 Agent 中,往往不是这样。
信息太多反而会带来:
- Token 消耗增加
- 上下文噪声增加
- 模型注意力分散
- 无关信息干扰决策
- Context Window 被快速消耗
所以更合理的方式是:
不是:
把所有信息给模型
而是:
找到当前任务真正需要的信息
也就是:
Just-in-Time Context。
什么时候需要什么信息,就什么时候获取。
7、为什么 Agent 做到后面,又会出现 Harness Engineering?
假设现在 Context 已经解决了。
模型已经知道:
用户需要什么
有哪些候选发动机
当前库存是多少
价格是多少
历史对话是什么
但是 Agent 还需要完成:
查询数据库
↓
调用库存接口
↓
调用价格接口
↓
校验配置
↓
生成结果
这时候新的问题来了。
比如:
库存接口调用失败怎么办?
数据库连接超时怎么办?
模型选出的配置不符合业务规则怎么办?
工具返回的数据格式错误怎么办?
Agent 执行到一半用户退出怎么办?
任务执行到一半 Context 太长怎么办?
这些问题已经很难通过 Prompt 解决了。
因为:
它们属于系统运行问题,而不是模型指令问题。
于是,我们开始需要一个更完整的东西:
Harness。
8、Harness Engineering:给 Agent 构建一个“工作环境”
Harness 这个词本身可以理解成“驾驭、控制、约束”。
在 Agent 场景下,可以把 Harness 简单理解为:
围绕 LLM 构建的一套 Agent 运行环境。
它负责让模型不仅“会思考”,而且能够:
获取信息
↓
调用工具
↓
执行任务
↓
观察结果
↓
修改计划
↓
继续执行
↓
验证结果
↓
失败恢复
因此一个完整的 Agent 已经不再是:
Prompt
↓
LLM
↓
Answer
而更像:
Agent Harness
│
┌──────────────┼──────────────┐
↓ ↓ ↓
Context Tools State
│ │ │
└──────────────┼──────────────┘
↓
LLM
↓
Action
↓
Environment
↓
Result
↓
Context Update
↓
LLM
9、Harness Engineering 主要解决哪些问题?
如果把 Harness 拆开,其实就是我们做 Agent 时经常遇到的那些工程问题。
9.1 Tool:Agent 能做什么?
例如:
query_engine()
query_inventory()
query_price()
validate_config()
模型负责决定:
“我现在需要调用哪个工具?”
Harness 负责:
“这个工具到底怎么执行?”
9.2 State:Agent 现在做到哪里了?
例如:
{
"task": "发动机选型",
"status": "validating",
"selected_engine": "A",
"inventory_checked": true,
"price_checked": true
}
如果没有状态管理,复杂 Agent 很容易:
做过的事情重复做
↓
上下文越来越混乱
↓
Agent 开始“失忆”
所以 State Management 也是 Harness 的重要组成部分。
9.3 Execution Loop:Agent 怎么持续工作?
一个典型 Agent Loop:
Think
↓
Act
↓
Observe
↓
Think
↓
Act
↓
Observe
↓
...
也就是:
LLM
↓
Tool Call
↓
Tool Result
↓
LLM
↓
Tool Call
↓
Tool Result
Harness 负责把这个循环真正跑起来。
10、Validation:为什么 Agent 不能相信自己?
这是我认为 Harness Engineering 中非常重要的一点。
例如 Agent 修改代码后说:
代码已经修复。
这句话其实没有意义。
真正应该做的是:
修改代码
↓
运行测试
↓
测试通过?
├── 否 → 获取错误信息
│ ↓
│ 修改代码
│ ↓
│ 再次测试
│
└── 是 → 任务完成
也就是说:
Agent 负责提出行动,Harness 负责验证行动结果。
这也是为什么现在的 Coding Agent 越来越像一个完整的软件工程系统。
11、一个实际的 Coding Agent 就非常典型
比如我们让 Agent:
帮我修复这个 Bug。
一个真正能够工作的 Coding Agent,需要:
读取代码
↓
搜索相关文件
↓
理解代码
↓
修改代码
↓
执行测试
↓
读取测试结果
↓
分析错误
↓
再次修改
↓
再次测试
↓
Git Diff
↓
最终验证
这里:
Prompt Engineering
告诉 Agent:
你是一个优秀的软件工程师。
修改代码前先理解现有代码。
不要修改无关文件。
修改后必须运行测试。
解决:
应该怎么工作。
Context Engineering
给 Agent:
项目结构
相关代码
README
CLAUDE.md / AGENTS.md
历史修改
测试结果
Git Diff
解决:
应该知道什么。
Harness Engineering
提供:
File System
Shell
Git
Test Runner
Search
Sandbox
Permission
State
Retry
Validation
解决:
应该怎么真正把事情做完。
12、三者之间到底是什么关系?
现在就可以比较清晰地理解三者了。
| Prompt Engineering | Context Engineering | Harness Engineering | |
|---|---|---|---|
| 核心问题 | 怎么告诉模型? | 给模型什么信息? | 怎么让 Agent 完成任务? |
| 主要对象 | Prompt | Context | Agent Runtime |
| 关注重点 | 指令、规则、格式 | 数据、记忆、状态、检索 | 工具、执行、状态、验证 |
| 解决问题 | 行为 | 信息 | 能力与可靠性 |
| 典型手段 | System Prompt、Few-shot | RAG、DB、Memory、Tool Result | Tool、Loop、Sandbox、Retry、Validation |
| 类比 | 工作说明书 | 工作资料 | 整个工作环境 |
所以可以用三个问题快速判断:
模型不知道“应该怎么做”
↓
Prompt Engineering
模型不知道“完成任务需要什么信息”
↓
Context Engineering
模型知道怎么做,也知道需要什么,
但就是无法稳定完成任务
↓
Harness Engineering
13、为什么我认为这是 Agent 开发的一条演进路线?
回过头来看,会发现这三个概念并不是突然出现的。
它其实对应了 AI 应用开发的三个阶段。
第一阶段:Prompt Engineering
最开始:
User
↓
Prompt
↓
LLM
↓
Answer
重点是:
如何让模型回答得更好。
第二阶段:Context Engineering
后来:
User
↓
Retrieve / Query / Memory
↓
Context
↓
LLM
↓
Answer
重点变成:
如何让模型获得正确的信息。
第三阶段:Harness Engineering
再往后:
Agent
│
┌──────────┼──────────┐
↓ ↓ ↓
Context Tools State
│ │ │
└──────────┼──────────┘
↓
LLM
↓
Action
↓
Environment
↓
Observation
↓
Validation
↓
Continue
重点变成:
如何让模型在真实环境中持续完成复杂任务。
所以我更愿意把它看成:
Prompt Engineering
↓
Context Engineering
↓
Harness Engineering
↓
Agent Engineering
14、那么现在做 Agent,到底应该重点学什么?
如果是刚开始做 AI 应用,我认为 Prompt Engineering 依然值得学习。
因为:
Prompt
仍然是模型行为控制的基础。
但是如果已经进入 Agent 开发阶段,仅仅研究 Prompt 的收益就会越来越低。
这时候更应该把精力放在:
Context
├── 如何获取
├── 如何筛选
├── 如何压缩
├── 如何组织
└── 如何动态更新
Tools
├── 如何设计
├── 如何调用
├── 如何处理异常
└── 如何控制权限
State
├── Task State
├── Conversation State
└── Agent Memory
Execution
├── Agent Loop
├── Retry
├── Timeout
└── Recovery
Validation
├── Rule Validation
├── Tool Validation
└── Result Validation
也就是说:
Agent 开发正在逐渐从“Prompt 技巧”转向“系统工程能力”。
15、最后总结
如果让我用最简单的方式总结这三个概念:
Prompt Engineering
告诉模型应该怎么做。
Context Engineering
告诉模型完成任务需要知道什么。
Harness Engineering
给模型提供完成任务所需要的工具、环境和运行机制。
三者组合起来就是:
Agent
│
┌────────┼────────┐
↓ ↓ ↓
Prompt Context Harness
│ │ │
↓ ↓ ↓
怎么做 知道什么 能做什么
│ │ │
└────────┼────────┘
↓
LLM
↓
完成真实任务
所以,Agent 真正的工程能力,并不是单纯把一个 LLM API 调通,也不是把 Prompt 写得越来越长。
而是逐渐建立这样一套完整的系统:
用 Prompt 定义规则,用 Context 提供信息,用 Harness 提供能力和运行环境,再通过 Validation 保证最终结果可靠。
这也是为什么现在越来越多的 Agent 产品,看起来已经不像传统意义上的“AI 聊天机器人”,而更像一个围绕 LLM 构建的完整软件系统。
LLM 只是其中的大脑。
真正决定 Agent 能不能把事情做好的,是围绕这个“大脑”构建起来的:
Prompt
+
Context
+
Tools
+
State
+
Execution
+
Validation
+
Environment
而这可能才是 Agent Engineering 真正开始走向工程化的地方。