第二篇:Prompt Engineering 已经过时了吗?从提示词到 Context Engineering
系列:《2026 可验证企业级 AI Agent 工程》
本文关键词:Context Engineering、Prompt、RAG、Memory、Tool Calling、Spring AI
文章目录
- 第二篇:Prompt Engineering 已经过时了吗?从提示词到 Context Engineering
- 《从普通 RAG 到 Agentic GraphRAG:让 AI 学会主动检索与多跳推理》
前言
早期开发大模型应用时,我们通常把精力集中在 Prompt 上:
你是一名能源管理专家,请根据以下数据分析设备异常原因……
如果回答不理想,就继续增加规则、示例和背景资料。最终,一个简单提示词可能演变成几千行难以维护的“超级 Prompt”。
这种方式在问答场景中尚可使用,但进入 AI Agent 场景后,很快会遇到问题:
- 对话历史越来越长;
- 检索文档不断增加;
- 工具返回大量数据;
- 多个任务共享同一个上下文;
- 无关信息干扰模型判断;
- Token 消耗和响应时间持续上升。
问题的关键已经不再是“提示词写得好不好”,而是:
在 Agent 执行任务的每个阶段,能否为模型提供正确、完整、最小且安全的上下文?
这就是 Context Engineering。
一、Prompt Engineering 真的过时了吗?
并没有。
Prompt Engineering 仍然负责告诉模型:
- 扮演什么角色;
- 完成什么任务;
- 遵守哪些规则;
- 按照什么格式输出。
但它只是 Context Engineering 的一个子集。
二者可以这样理解:
Prompt Engineering
= 如何写好模型指令
Context Engineering
= 如何构建模型当前决策所需的全部信息
一次完整的模型调用,实际输入可能是:
Context =
系统指令
+ 用户问题
+ 会话历史
+ 用户身份
+ 业务数据
+ RAG 检索结果
+ Agent 记忆
+ 工具定义
+ 工具执行结果
+ 当前任务状态
+ 权限规则
+ 输出格式
因此,Context Engineering 不是编写一段更长的 Prompt,而是设计一套动态上下文系统。
二、为什么上下文越多,效果不一定越好?
不少开发者存在一个误区:
模型上下文窗口足够大,就可以把所有资料全部放进去。
但上下文窗口变大,并不代表模型能够同等关注其中的所有信息。
1. 无关信息会稀释注意力
假设用户询问:
分析空压机 A 昨天能耗升高的原因。
系统一次性加载:
- 空压机 A 的实时数据;
- 全厂 300 台设备资料;
- 最近一年的所有告警;
- 完整操作手册;
- 用户半年内的对话;
- 十几个工具定义。
虽然信息非常全面,但真正与问题相关的内容可能不到 5%。
模型需要在大量噪声中寻找关键证据,反而更容易遗漏信息或者产生错误判断。
2. 信息之间可能相互冲突
例如:
旧版手册:报警阈值为 80℃
新版手册:报警阈值调整为 75℃
历史对话:用户曾临时将阈值设置为 85℃
实时配置:当前阈值为 78℃
如果系统没有标明数据来源、版本和时间,模型很难判断应该采用哪一个值。
3. 工具结果会快速消耗 Token
设备查询工具可能返回数万条时序数据:
[
{"time":"10:00:00","power":315.2},
{"time":"10:00:01","power":316.8}
]
直接将原始数据放入上下文,不仅成本高,也不利于推理。更合理的方法是先在程序中完成聚合:
{
"averagePower": 315.8,
"peakPower": 412.6,
"baselineDeviation": 0.237,
"abnormalPeriods": [
"10:15-10:28",
"14:02-14:17"
]
}
Context Engineering 的核心原则之一就是:
上下文不是越多越好,而是相关性越高越好。
三、企业级 Agent 的六层上下文模型
可以将 Agent 上下文拆分成六个层次。
1. 系统指令层
系统指令定义 Agent 的基本行为边界:
你是工业能源诊断 Agent。
你的职责:
1. 分析设备能耗异常;
2. 所有结论必须引用数据证据;
3. 不得虚构设备状态;
4. 创建工单前必须获得用户确认;
5. 数据不足时必须明确说明。
这一层应该稳定、简洁,并由系统统一管理,不能允许普通用户覆盖。
2. 用户与任务层
这一层描述当前用户和任务目标:
{
"userId": "10086",
"role": "energy_manager",
"department": "production",
"task": "分析一号车间昨日能耗异常",
"permissions": [
"energy:read",
"alarm:read"
]
}
同一个问题由不同用户提出,能够访问的数据和工具可能不同。
因此,权限控制不能只依赖 Prompt,必须在工具执行层再次校验。
3. 知识检索层
知识检索层负责提供完成当前任务所需的外部知识,包括:
- 设备手册;
- 操作规程;
- 故障案例;
- 数据库记录;
- 知识图谱;
- 实时指标。
传统 RAG 往往只执行一次向量检索,而 Agentic RAG 会根据任务动态决定:
是否需要检索?
检索哪个知识库?
使用关键词、向量还是图检索?
结果是否足以回答?
是否需要修改查询后再次检索?
检索结果还应该携带元数据:
{
"content": "空压机排气温度超过75℃时应触发高温预警",
"source": "设备维护手册",
"version": "V3.2",
"effectiveDate": "2026-06-01",
"deviceType": "screw_compressor"
}
这些信息能够帮助模型处理知识冲突,并生成可追溯答案。
4. 记忆层
记忆并不等于把所有聊天记录都交给模型。
Agent 记忆通常分为:
| 类型 | 保存内容 | 示例 |
|---|---|---|
| 工作记忆 | 当前任务临时状态 | 已完成设备查询 |
| 情景记忆 | 历史任务过程 | 上次异常如何处理 |
| 语义记忆 | 稳定事实和偏好 | 用户负责一号车间 |
| 程序记忆 | 任务执行方法 | 能耗异常分析流程 |
记忆写入前必须进行筛选,不能把模型生成的所有内容都当成事实保存。
5. 工具与环境层
工具描述同样属于上下文。
一个模糊的工具定义:
queryData:查询数据
模型很难判断应该什么时候调用,以及如何构造参数。
更合理的定义是:
工具名称:queryDeviceEnergy
用途:
查询指定设备在某个时间范围内的能耗统计。
只适用于设备级能耗查询,不用于查询告警信息。
参数:
- deviceId:设备唯一编号
- startTime:开始时间,ISO-8601格式
- endTime:结束时间,ISO-8601格式
- granularity:聚合粒度,可选 minute、hour、day
高质量的工具描述可以显著降低:
- 工具选择错误;
- 参数格式错误;
- 重复调用;
- 无意义调用。
6. 执行状态层
Agent 通常需要多轮执行:
思考 → 调用工具 → 获取结果 → 更新状态 → 再次决策
因此必须记录:
- 当前任务目标;
- 已完成步骤;
- 待执行步骤;
- 已使用工具;
- 中间结论;
- 错误和重试次数;
- 剩余 Token 与时间预算。
示例:
{
"goal": "分析空压机A能耗异常",
"completedSteps": [
"查询昨日能耗",
"查询历史基线"
],
"pendingSteps": [
"查询同期告警",
"生成异常结论"
],
"toolCallCount": 2,
"retryCount": 0
}
四、Context Engineering 的四个核心动作
面对大量上下文,可以使用四类基本操作。
1. Write:写入外部存储
将暂时不需要进入模型窗口的信息写入:
- 数据库;
- Redis;
- 向量数据库;
- 对象存储;
- Agent 状态存储。
模型上下文应该是工作区,而不是永久仓库。
2. Select:按需选择
根据当前步骤只加载相关信息。
例如:
正在判断能耗趋势
→ 加载时序聚合数据
正在分析设备故障
→ 加载告警和设备手册
正在创建工单
→ 加载诊断结论和用户权限
不同执行阶段使用不同上下文,可以减少信息干扰。
3. Compress:压缩上下文
当历史信息过长时,可以进行:
- 对话摘要;
- 工具结果聚合;
- 文档分层摘要;
- 重复信息去除;
- 结构化事实提取。
例如,将十轮对话压缩为:
{
"confirmedFacts": [
"异常设备为空压机A",
"异常时间为昨日10:15至10:28",
"用户已确认查询告警记录"
],
"unresolvedQuestions": [
"是否存在传感器故障"
]
}
压缩时必须保留关键数值、时间、实体和未解决问题,不能只生成模糊的自然语言摘要。
4. Isolate:隔离上下文
复杂任务可以拆分给不同子 Agent:
主 Agent
├── 数据分析 Agent:只接收能耗数据
├── 故障诊断 Agent:只接收告警和手册
└── 工单 Agent:只接收最终结论和用户确认
这样可以避免所有 Agent 共享一个无限膨胀的上下文窗口,同时降低敏感信息扩散风险。
五、上下文预算应该如何分配?
假设模型支持的最大上下文长度为:
Cmax = 128K Token
不能把 128K 全部用于输入,还要为模型输出预留空间:
可用输入预算 =
最大上下文
- 预期输出
- 安全余量
一种参考分配方式:
| 内容 | 预算占比 |
|---|---|
| 系统规则 | 10% |
| 当前用户任务 | 5% |
| 近期对话 | 15% |
| RAG 检索内容 | 30% |
| 工具定义 | 15% |
| 工具执行结果 | 15% |
| 输出与安全余量 | 10% |
这不是固定比例,应根据任务动态调整。
例如,知识问答应提高 RAG 预算;工具型任务应提高工具结果和执行状态预算。
六、使用 Spring AI 构建动态上下文
下面是一个简化示例,实际项目中可以把每个上下文来源封装为独立组件。
@Service
public class EnergyAgentService {
private final ChatClient chatClient;
private final ContextAssembler contextAssembler;
public EnergyAgentService(ChatClient.Builder builder,
ContextAssembler contextAssembler) {
this.chatClient = builder.build();
this.contextAssembler = contextAssembler;
}
public String analyze(String userId, String question) {
AgentContext context =
contextAssembler.assemble(userId, question);
return chatClient.prompt()
.system(context.systemInstruction())
.user(user -> user
.text("""
用户问题:
{question}
用户信息:
{userContext}
相关知识:
{knowledge}
历史记忆:
{memory}
当前任务状态:
{taskState}
""")
.param("question", question)
.param("userContext", context.userContext())
.param("knowledge", context.knowledge())
.param("memory", context.memory())
.param("taskState", context.taskState()))
.call()
.content();
}
}
真正重要的不是调用 ChatClient,而是 ContextAssembler 如何工作:
public AgentContext assemble(String userId, String question) {
UserContext userContext = loadUserContext(userId);
TaskIntent intent = classifyIntent(question);
List<Document> knowledge =
retrieveRelevantKnowledge(intent, question);
List<Memory> memories =
selectRelevantMemories(userId, intent);
TaskState taskState =
loadOrCreateTaskState(userId, intent);
return contextCompressor.compress(
userContext,
knowledge,
memories,
taskState
);
}
一个成熟的上下文组装器至少需要完成:
意图识别
→ 数据源选择
→ 权限过滤
→ 相关性排序
→ 冲突检测
→ Token 预算计算
→ 信息压缩
→ 上下文组装
七、常见的上下文工程反模式
1. 把全部对话历史直接传给模型
问题:Token 持续增长,旧指令可能干扰当前任务。
解决:保留近期对话,同时将早期内容压缩成结构化摘要。
2. 将所有工具同时暴露给 Agent
问题:模型容易选择错误工具,也增加安全风险。
解决:根据用户权限和当前任务动态加载工具。
3. 直接传递数据库原始结果
问题:上下文过大,模型难以理解大量重复记录。
解决:在 Java 服务中完成过滤、聚合和异常检测,再返回结构化结果。
4. 无条件写入长期记忆
问题:模型的错误结论可能被永久保存,并在后续任务中反复使用。
解决:只有经过验证的事实、明确的用户偏好和已完成任务结果才能进入长期记忆。
5. 只关注 Token 数量
问题:上下文长度正常,但内容可能过期、冲突或者与当前任务无关。
解决:同时评估相关性、时效性、可信度和完整性。
八、如何评估上下文质量?
可以为 Context Engineering 建立以下指标:
| 指标 | 含义 |
|---|---|
| Context Relevance | 上下文与当前问题的相关程度 |
| Context Precision | 检索内容中真正有用信息的占比 |
| Context Recall | 回答所需证据是否完整 |
| Context Freshness | 数据是否及时、版本是否最新 |
| Tool Selection Accuracy | 工具选择是否正确 |
| Token Efficiency | 每次成功任务消耗的 Token |
| Groundedness | 结论是否得到上下文证据支持 |
Context Engineering 的目标不是使用最少的 Token,而是:
在可接受的成本内,为模型提供完成当前决策所需的最小充分信息。
总结
Prompt Engineering 并没有过时,但它已经无法独立支撑复杂的 Agent 系统。
Prompt 关注的是“如何表达指令”,Context Engineering 关注的是:
- 当前应该加载什么信息;
- 哪些信息应该被过滤;
- 历史内容如何压缩;
- 工具如何动态选择;
- 多个任务之间如何隔离;
- 上下文如何控制成本和权限。
可以用一句话概括:
Prompt 决定模型怎么思考,Context 决定模型能够基于什么思考。
下一篇将进入知识检索的深水区:
《从普通 RAG 到 Agentic GraphRAG:让 AI 学会主动检索与多跳推理》
参考资料:
767



被折叠的 条评论
为什么被折叠?



