智能体核心:上下文工程,决定AI成败的关键!
本文深入探讨了智能体(Agent)开发中的一个关键问题——上下文工程。作者指出,上下文工程并非简单的Prompt Engineering升级,而是关于如何在每次模型调用前,从海量信息中挑选出真正需要的内容,并以正确的结构、顺序、粒度和证据形态呈现给模型。文章详细阐述了上下文工程的必要性、常见误区、核心组件(Router和Context Builder)、信息分类与生命周期管理、以及如何通过结构化、压缩、预算控制等手段优化上下文。作者强调,良好的上下文工程能显著提升Agent的稳定性和效率,并建议开发者重视Router、Context Builder和Context Trace的设计与实现。
前端出身,跨进智能体这个坑已经有一段时间了。写这个系列,是想把自己摸索的过程留下来。不是教程,是记录。同在学习路上的,可以看看我整理的电子书:https://book.zyh.lol,共勉(增加了面试题专栏)。
最近几篇我一直在写 RAG、工具调用、并行、MCP、Reasoning Model。写到这里,其实绕不开一个更底层的问题:
Agent 每一轮到底应该把什么交给模型?
这个问题现在经常被包装成一个新词:Context Engineering,上下文工程。
很多人第一次听到这个词,会下意识把它理解成 Prompt Engineering 的升级版:以前写 system prompt,现在写更复杂的上下文模板;以前调 instruction,现在调 message 顺序;以前塞几段示例,现在塞更多历史、更多知识、更多工具返回。
但我越做 Agent,越觉得这个理解是偏的。
上下文工程不是"更会写 prompt"。
它真正关心的是:在每一次模型调用之前,系统如何从一堆可能相关的信息里,挑出当前任务真正需要的那部分,以正确的结构、顺序、粒度和证据形态交给模型。
换句话说,Prompt Engineering 更像是在写一段话;Context Engineering 更像是在设计一个运行时系统。
这篇就专门讲这件事。
如果你正在做 Agent Runtime、Agent Orchestrator、多轮任务系统、企业知识库助手,或者正在把 RAG、memory、tools 拼到一个智能体里,这个问题迟早会撞上。
一、为什么上下文会变成 Agent 的真实瓶颈
早期做 LLM 应用时,大家最关心的是 prompt。
模型答得不好,先改 prompt:
你是一个资深专家。请一步一步思考。请基于以下资料回答。如果不知道,请说不知道。这在单轮问答里还够用。
但 Agent 不一样。Agent 是多轮的、带状态的、会调工具的、会从外部系统取数据的。它的上下文来源至少来自三个面:
- 用户侧:当前输入、历史对话、用户偏好
- 任务侧:任务状态、中间计划与检查点、上一轮模型输出
- 外部侧:RAG 检索结果、工具调用结果、可用工具说明、系统规则
这些东西一多,问题就不是"prompt 写得好不好"了,而是:
1. 哪些信息根本不该进上下文?
不是所有存下来的东西都应该喂给模型。比如长期用户偏好应该在相关时出现,不应该每轮都塞;工具原始返回可能很长,应该先结构化摘要;中间 scratchpad 可能只对当前子任务有效,过了阶段就应该丢。
2. 哪些信息必须进上下文?
任务目标、当前状态、关键约束、最近工具结果、被引用的证据,这些如果缺失,模型就会开始"自己补"。
3. 哪些信息要压缩?
历史对话、搜索结果、长文档、工具返回,直接塞会爆窗口。压缩不是简单 summarize,而是保留对当前任务有用的决策、事实、约束、未解决问题。
4. 信息之间谁优先?
用户当前指令和长期偏好冲突,听谁的?RAG 文档和历史记忆冲突,怎么处理?工具结果和模型猜测冲突,谁可信?
5. 怎么观察上下文是否组装对了?
很多 Agent 看起来是模型答错,其实是 Context Builder 给错了上下文。你如果不记录最终进入模型的 context,就没法 debug。
这些问题合在一起,就是上下文工程。
二、上下文工程不是把窗口填满
一个常见误区是:模型上下文窗口越来越大,那就尽量多塞。
128k、200k、1M token 出来以后,很多团队会自然地想:
既然窗口够大,历史、文档、工具结果、记忆都塞进去,模型自己判断不就行了吗?
Demo 阶段这确实省事。
生产里会出四类问题。
1. 噪音会稀释注意力
模型不是数据库。上下文越长,不代表有效信息越多。大量弱相关内容会把关键证据淹没。
用户问"上次我们决定 API 先做哪个版本",你把最近 50 轮对话、10 份产品文档、3 个工具返回都塞进去,模型可能反而找不到那句真正的决策。
2. 旧状态会污染新任务
Agent 最容易犯的错之一,是把上一段任务的状态带到下一段任务里。
比如上一个任务在讨论"日报生成",下一个任务开始讨论"客户合同分析",但上下文里还留着前一个任务的计划、工具结果、临时结论。模型会把它们当成仍然有效的背景。
这类错误很隐蔽,因为模型输出看起来仍然流畅。
3. 成本和延迟会失控
上下文窗口不是免费的。长上下文会增加输入成本,也会增加推理延迟。Reasoning Model 上尤其明显:你喂进去的上下文越乱,它内部要花更多 reasoning tokens 去判断哪些有用。
如果一个 Agent 每轮都带 50k tokens,跑 8 轮工具循环,很快就不是"智能"问题,而是账单问题。
顺带说一下"那直接靠长上下文不就行了吗"这个问题。Gemini、Claude 把窗口推到 1M 之后,确实很多团队会想:既然窗口够大,治理这件事是不是可以省了?
不能。长上下文降低的是"必须压缩"的物理压力,没有降低"必须分层、带来源、按生命周期治理"的工程压力。窗口越大,治理不当的代价反而越高——一是噪音稀释注意力的效应在长窗口里更严重,二是单次推理成本和延迟会放大同样的上下文设计错误。窗口扩大解决的是预算紧张,不是上下文工程本身。
4. Debug 变困难
上下文越大,越难定位错误。
模型答错了,到底是:
- RAG 证据没召回?
- 证据召回了但排得太后?
- 历史状态污染了?
- 工具结果没结构化?
- 用户约束被压缩丢了?
- system prompt 和上下文冲突?
如果所有东西都混成一大坨,基本没法查。这一节列的痛点,第十三节会用一个context_trace模块统一兜底——每轮模型实际看到的上下文都落盘,出错时直接回放。
所以,上下文工程的第一原则不是"尽量多放",而是:
每一段进入上下文的信息,都必须有明确用途、生命周期和优先级。
三、先把上下文拆成六类
做上下文工程,第一步不是选框架,也不是写模板,而是把信息类型分清楚。
我一般把 Agent 上下文拆成六类:
| 类型 | 解决的问题 | 典型内容 | 是否每轮都放 |
|---|---|---|---|
| Goal | 当前要完成什么 | 用户当前请求、任务目标、验收标准 | 是 |
| State | 任务进行到哪 | 当前步骤、已完成动作、未解决事项 | 是,但要压缩 |
| Memory | 过去发生过什么 | 用户偏好、历史决策、长期约束 | 按需放 |
| Knowledge | 外部世界有什么 | RAG 文档、手册、规范、代码片段 | 按需放,必须带来源 |
| Tool Result | 刚刚观察到了什么 | API 返回、数据库查询、搜索结果 | 当前循环内放,之后摘要 |
| Policy | 什么不能做 | 权限、安全规则、业务边界 | 关键路径必须放 |
这张表看起来简单,但很多 Agent 的问题就出在这里:把不同类型的信息混在同一个 message 里。
比如:
- 把 RAG 文档叫作 memory
- 把工具返回长期塞在历史对话里
- 把用户偏好写进 system prompt
- 把临时任务状态持久化成长期记忆
- 把安全规则和普通背景材料放在同一优先级
这些短期都能跑,长期一定会乱。
更工程化一点,可以把六类上下文对应到不同来源:
User Request → GoalTask Runtime / Checkpoint → StateMemory Store → MemoryRAG / Search / Docs → KnowledgeTool Executor → Tool ResultPolicy Engine / Permission System → Policy注意,这里不是说它们最后不能进入同一个 prompt。
最后当然都会被拼进模型输入。
关键是:在进入模型之前,它们必须先被分层治理。
四、上下文工程的核心组件:Router + Context Builder
如果只用一句话描述上下文工程的架构,我会这么说:
Router 决定去哪里拿信息,Context Builder 决定怎么把信息交给模型。
这两个组件很容易被写成一段 prompt 模板,但在生产系统里最好显式拆出来。
1. Router:判断这轮需要什么
Router 的职责不是回答用户,而是判断当前请求需要哪些上下文来源。
比如用户问:
“上次我们决定这个 Agent 先支持哪些工具?”
这更像是状态延续,需要查短期记忆或历史决策。
用户问:
“公司报销制度里差旅住宿上限是多少?”
这更像是外部知识,需要走 RAG。
用户问:
“按我们上次定的方案,把报销制度里的住宿标准整理成表格”
这就同时需要 memory 和 RAG:既要延续"上次定的方案",又要查制度原文。
一个非常粗的 Router 可以长这样:
def route_context_need(user_message, task_state): intent = classify(user_message, task_state) return { "need_goal": True, "need_state": intent in {"continue_task", "modify_previous_work"}, "need_memory": intent in {"user_preference", "past_decision", "continue_task"}, "need_knowledge": intent in {"fact_lookup", "policy_question", "doc_grounded_answer"}, "need_tools": intent in {"external_action", "fresh_data", "business_query"}, "need_policy": intent in {"write_action", "permission_sensitive", "external_action"}, }真实系统可以更复杂,但核心逻辑就这一点:先判断信息需求,再取上下文。
很多团队做反了:先统一检索一遍,再把 top-k 塞进去,让模型自己判断。这就是把 Router 的工作丢给模型。
2. Context Builder:决定怎么组装
Router 取回来的东西不能原样塞。
Context Builder 要处理几个动作:
- 去重:同一事实不要出现三遍
- 压缩:长历史变成任务状态摘要
- 排序:目标、约束、状态、证据、工具结果的顺序要稳定
- 标注来源:RAG 证据必须带 doc_id、版本、片段位置
- 冲突处理:新指令覆盖旧偏好,工具结果覆盖模型猜测
- 预算控制:不同类型上下文分配 token budget
可以把 Context Builder 想成一个"装箱器"。
它不是简单字符串拼接,而是在做一个带预算的选择题:
def build_agent_context(request, routed_items, budget): context = [] context.append(render_goal(request.goal)) context.append(render_policy(routed_items.policy)) context.append(render_state(compact_state(routed_items.state))) context.append(render_memory(select_relevant_memory(routed_items.memory))) context.append(render_evidence(rerank_evidence(routed_items.knowledge))) context.append(render_tool_results(compact_tool_results(routed_items.tool_results))) return fit_to_budget(context, budget)这里的重点不是代码,而是顺序:
目标先于材料,规则先于建议,状态先于历史,证据先于生成。
如果上下文顺序混乱,模型会把"历史里曾经说过的话"当成当前任务目标,也会把"用户偏好"误当成硬性业务规则。
五、不同上下文的生命周期不一样
上下文工程里最容易被忽略的是生命周期。
不是所有信息都应该活一样久。
| 信息 | 生命周期 | 过期方式 | 常见错误 |
|---|---|---|---|
| 当前用户输入 | 当前轮 | 下一轮变成历史 | 被摘要时丢掉关键约束 |
| 工具原始结果 | 当前工具循环 | 生成结构化摘要后丢弃原文 | 长期保留原始 JSON |
| 任务状态 | 当前任务 | 任务结束或 checkpoint 更新 | 跨任务污染 |
| 短期记忆 | 当前 session | TTL / 会话结束 | 被写入长期记忆 |
| 长期记忆 | 跨 session | 用户撤销 / 新偏好覆盖 | 每轮无条件注入 |
| RAG 证据 | 随文档版本 | 文档更新、权限变化 | 不带版本和来源 |
| Policy | 随规则配置 | 配置变更 | 和普通 prompt 混在一起 |
很多 Agent 看起来"记性不好",其实不是没记住,而是生命周期没设计。
举个例子。
用户说:
“这次先别考虑移动端。”
这句话到底是什么?
它不是长期偏好。不能写成"用户不喜欢移动端"。
它也不是企业知识。不能进 RAG。
它是当前任务的局部约束,应该进入 Task State,并且在这个任务结束后自然过期。
再比如用户说:
“以后给我技术方案都先给表格对比,再给推荐结论。”
这更像长期偏好,可以进入 Long-term Memory。但也不是每轮都要放,只有在生成技术方案时才召回。
上下文工程要做的,就是在写入那一刻先判断类型。
def place_context_item(item): if item.kind == "current_task_constraint": return ShortTermState(ttl="task") if item.kind == "user_preference" and item.confidence >= 0.8: return LongTermMemory(scope="user") if item.kind == "external_fact": return KnowledgeStore(versioned=True) if item.kind == "tool_raw_output": return ToolTrace(retention="debug_only") return Discard()关键不是这段伪代码,而是它背后的习惯:
上下文不是在召回时才治理,而是在写入时就要决定归属。
六、Placement Table:到底什么放哪里
为了避免概念混乱,我建议每个 Agent 项目都做一张 placement table。
不是为了写文档好看,而是为了让团队在开发时有共同语言。
| 信息类型 | 存哪里 | 何时召回 | 是否进入模型 | 备注 |
|---|---|---|---|---|
| 用户当前请求 | Current Turn | 每轮固定 | 必进 | 不能被摘要替代 |
| 最近 N 轮对话 | Conversation Buffer | 多轮任务中 | 选择性进入 | 超预算后压缩为状态摘要 |
| 当前任务目标 | Task State | 每轮固定 | 必进 | 用于防止任务漂移 |
| 当前任务进度 | Task State | 每轮固定 | 必进,但压缩 | 只保留已完成、待完成、阻塞点 |
| 临时约束 | Short-term Memory | 当前任务内 | 相关时进入 | 任务结束过期 |
| 用户长期偏好 | Long-term Memory | 任务类型匹配时 | 选择性进入 | 需要置信度和来源 |
| 历史决策 | Long-term / Project Memory | 用户要求延续时 | 选择性进入 | 必须带时间和来源 |
| 企业文档 | Knowledge Store | 事实问题/RAG 场景 | 以证据片段进入 | 必须带 doc_id/版本 |
| 工具 schema | Tool Registry | 模型需要决策时 | 进入工具定义 | 不要把所有工具都暴露 |
| 工具原始返回 | Tool Trace | 当前循环/调试 | 通常不原样进入 | 先结构化摘要 |
| 工具执行摘要 | Tool Result Context | 当前循环 | 必进 | 包含 status/error_type/data |
| 安全与权限规则 | Policy Store | 敏感动作前 | 必进 | 优先级高于普通上下文 |
| 中间推理草稿 | Scratchpad | 当前子任务 | 通常不进入下一任务 | 防止污染 |
这张表的价值是把"看起来都像上下文"的东西拆开。
你会发现,真正每轮必进的东西其实不多:
- 当前用户请求
- 当前任务目标
- 当前任务状态
- 当前必要规则
- 本轮相关证据或工具结果
其他内容都应该按需召回。
七、上下文不是只有内容,还有结构
同样一批信息,以不同结构交给模型,效果会差很多。
反例是这样的:
以下是历史对话、相关资料、工具结果和用户偏好:......请回答用户问题。这相当于把所有东西倒在模型面前,让它自己分拣。
更稳的结构应该是显式分区:
<goal>用户当前要完成的任务:...验收标准:...</goal><current_state>已完成:...待完成:...当前阻塞:...</current_state><constraints>- 用户本轮明确要求:...- 业务/安全规则:...</constraints><relevant_memory>- [source=memory, time=...] 用户偏好:...- [source=project_decision, time=...] 历史决策:...</relevant_memory><evidence>- [doc_id=..., version=..., chunk=...] ...- [doc_id=..., version=..., chunk=...] ...</evidence><tool_results>- [tool=..., status=ok] ...- [tool=..., status=error, error_type=permission_error] ...</tool_results>为什么要这么麻烦?
因为模型需要的不只是文本,还需要知道这些文本的"身份"。
同一句话,如果来自用户当前输入,优先级很高;如果来自长期记忆,可能只是偏好;如果来自 RAG 文档,是外部证据;如果来自工具结果,是刚刚观察到的事实;如果来自模型上一轮输出,反而可能需要谨慎对待。
上下文工程的一个重要动作,就是把信息的来源、类型、时间、置信度一起交给模型。
不要只给 content。
要给 metadata。
八、工具结果是上下文污染重灾区
做 Agent 的人都知道工具调用重要,但很多系统对工具结果的处理很粗糙。
常见写法:
messages.append({ "role": "tool", "content": json.dumps(raw_result)})工具返回小的时候没事。
一旦工具返回:
- 100 条搜索结果
- 500 行数据库记录
- 一个很长的网页
- 一段报错堆栈
- 多个并行工具结果
上下文马上被撑爆。
更糟的是,模型看不懂哪些字段重要,只能在原始 JSON 里猜。
工具结果应该分三层处理:
| 层级 | 用途 | 是否进上下文 |
|---|---|---|
| Raw Trace | 调试、审计、复现 | 默认不进 |
| Structured Result | 给 Runtime 做判断 | 选择性进 |
| Model Summary | 给模型继续推理 | 进 |
比如数据库查询返回 500 行,不应该原样塞给模型,而应该先变成:
{ "status": "ok", "row_count": 500, "summary": "共找到 500 条订单,其中 37 条逾期,逾期金额合计 128000 元。", "top_items": [ {"order_id": "A1021", "amount": 23000, "days_overdue": 18}, {"order_id": "A1088", "amount": 19000, "days_overdue": 15} ], "next_page_available": true}模型要的是"足够继续决策的信息",不是完整数据库 dump。
错误结果也一样。
不要只塞:
Error: 403更好的工具结果上下文是:
{ "status": "error", "error_type": "permission_error", "retryable": false, "message": "当前用户没有读取该客户合同的权限", "safe_next_actions": ["ask_user_for_permission", "explain_limitation"]}这和第 65 篇讲工具失败路由是同一件事的另一面:工具结果不是日志,它是下一轮模型决策的上下文输入。
九、RAG 证据进入上下文时,必须带边界
RAG 和上下文工程的关系很容易被低估。
很多系统会把检索结果直接拼成:
相关资料:chunk1...chunk2...chunk3...这在简单问答里可以用,但在 Agent 里不够。
因为 Agent 需要知道:
- 这段证据来自哪里?
- 是哪个版本?
- 相关性分数多少?
- 是原文还是摘要?
- 有没有权限限制?
- 和当前问题的关系是什么?
更稳的 evidence block 应该是:
<evidence>[E1]source: travel_policy.mdversion: 2026-03-01chunk_id: p12-c03score: 0.87type: original_textcontent: ...[E2]source: finance_faq.mdversion: 2026-01-18chunk_id: q08score: 0.74type: original_textcontent: ...</evidence>这样模型回答时才能引用证据,系统也能回溯。
如果证据是摘要,也要标出来:
type: summary_of_search_results不要让模型误以为摘要就是原文。
还有一个细节:RAG 证据不应该和长期记忆混在一起。
外部知识解决的是"世界里有什么"。
记忆解决的是"我们之间发生过什么"。
两者都可能进入上下文,但应该用不同 section,不同 metadata,不同优先级。
十、长期记忆不能每轮都塞
很多人一做 memory,就会犯一个错误:只要召回到,就塞进上下文。
比如长期记忆里有:
用户喜欢中文回答。用户喜欢表格。用户上次做过 RAG 评估。用户曾经说不想用 LangChain。用户偏好先给结论。然后每轮都放。
问题是,长期记忆不是 system prompt。它是可召回的状态。
进入上下文前至少要过三道过滤:
1. 相关性过滤
用户问天气,不需要召回"上次做过 RAG 评估"。
2. 置信度过滤
用户一次随口说"今天先别用表格",不能变成永久偏好。
3. 冲突过滤
长期偏好说"喜欢中文",但用户当前明确要求"用英文写",当前指令优先。
可以给长期记忆设计这样的结构:
{ "memory_id": "mem_1024", "type": "user_preference", "content": "用户偏好技术方案先给表格对比,再给推荐结论", "scope": "technical_design", "confidence": 0.86, "created_at": "2026-05-01", "last_used_at": "2026-05-12", "source": "user_explicit_instruction"}这比一条裸文本有用得多。
Context Builder 可以根据 scope、confidence、recency、当前任务类型决定要不要放。
长期记忆的原则是:
宁可少放,也不要把无关偏好变成模型的背景噪音。
十一、压缩不是总结,而是状态重写
上下文窗口不够时,大家都会想到 summarize。
但 Agent 里的压缩如果只是普通摘要,很容易丢关键信息。
比如一段历史对话:
用户先要求做一个企业知识库助手。中间讨论过三种方案:纯 RAG、RAG + memory、Agentic RAG。最后决定第一版只做 RAG + 工具调用,不做自主规划。用户明确要求:不要引入复杂多 Agent。普通摘要可能写成:
我们讨论了企业知识库助手的多种实现方案,包括 RAG、memory 和 Agentic RAG。这句话看起来对,但最关键的决策丢了:
- 第一版只做什么
- 不做什么
- 用户明确约束是什么
Agent 压缩应该更像状态重写:
{ "task_goal": "设计企业知识库助手 V1", "decisions": [ "V1 采用 RAG + 工具调用", "暂不做自主规划", "暂不引入多 Agent" ], "open_questions": [ "是否需要接入权限系统", "是否需要引用原文链接" ], "constraints": [ "优先保持架构简单", "不要过度设计" ]}这才是对 Agent 有用的压缩。
所以我更愿意把这件事叫做state compaction,而不是 summary。
摘要关注"这段话讲了什么"。
状态压缩关注"后续任务还需要记住什么"。
十二、上下文预算要按类型分配
如果没有预算控制,Context Builder 最后一定会退化成"谁先来谁占坑"。
更合理的是按类型分配 token budget。
比如一个 32k 输入窗口,可以粗略这样切:
| 区域 | 预算 | 说明 |
|---|---|---|
| System / Policy | 2k | 稳定规则、权限边界 |
| Goal / User Request | 2k | 当前任务与验收标准 |
| Task State | 4k | 当前进度、决策、约束 |
| Relevant Memory | 3k | 用户偏好、历史决策 |
| RAG Evidence | 12k | 原文证据,按 relevance 排序 |
| Tool Results | 6k | 当前循环工具观察 |
| Buffer | 3k | 给模型输出和不可预测增长留余量 |
注意,这张表里的"32k"是进入业务上下文的可用预算,不是窗口总量。实际项目里,system 模板、tools schema、few-shot 示例都会先吃掉一部分,常见 32k 窗口里留给 evidence/tool results 的真实空间通常比看起来少 20–30%。预算要按"扣除固定开销之后的可用窗口"来切,不要按窗口总长度切。
这个比例不是固定的。
如果是文档问答,RAG Evidence 多一些。
如果是长任务执行,Task State 多一些。
如果是工具型 Agent,Tool Results 多一些。
关键是要显式做预算,而不是让上下文自然膨胀。
CONTEXT_BUDGET = { "policy": 2000, "goal": 2000, "state": 4000, "memory": 3000, "evidence": 12000, "tool_results": 6000,}一旦某类超预算,就触发对应压缩策略。
不要所有类型共用一个 summarize。
RAG 证据超预算,应该 rerank / cut by source / 保留高分原文。
历史状态超预算,应该 state compaction。
工具结果超预算,应该结构化聚合。
长期记忆超预算,应该按 scope 和 confidence 筛。
这就是上下文工程和普通 prompt 拼接的区别。
十三、一个最小可用的上下文组装链路
如果要从零做一个 Agent Runtime,我建议先做一个最小版本,不要一开始就搞很复杂。
链路可以是:
user message ↓intent/context router ↓retrieve: - task state - relevant memory - RAG evidence - recent tool results ↓normalize metadata ↓rank / filter / compress ↓build structured context ↓LLM call ↓tool calls / final answer ↓write back state / memory / trace对应伪代码:
async def agent_turn(user_message, session_id): task_state = await state_store.get(session_id) context_need = await router.classify( user_message=user_message, task_state=task_state, ) memory_items = [] if context_need.need_memory: memory_items = await memory_store.search( query=user_message, scope=context_need.memory_scope, ) evidence_items = [] if context_need.need_knowledge: evidence_items = await rag.retrieve( query=context_need.search_query, filters=context_need.knowledge_filters, ) tool_context = await tool_trace.get_recent(session_id) context = context_builder.build( goal=user_message, state=task_state, memory=memory_items, evidence=evidence_items, tool_results=tool_context, budget=32000, ) response = await llm.call( messages=context.to_messages(), tools=tool_registry.select(context_need.tool_scope), ) await state_store.update(session_id, response.state_delta) await trace_store.save_context(session_id, context) return response注意这里有一个经常被忽略的动作:
await trace_store.save_context(session_id, context)最终进入模型的上下文必须可观测。
不然 Agent 出错时,你只看得到用户输入和模型输出,看不到中间到底塞了什么。
这就像调试 RAG 时只看 answer,不看query -> candidates -> final context -> answer,基本是在猜。
十四、上下文工程的评估,不是只看最终答案
很多团队评估 Agent,只看 final answer。
但上下文工程要单独评估。
我会拆成几个指标:
| 指标 | 问题 | 怎么看 |
|---|---|---|
| Context Precision | 放进去的内容有多少真的相关 | 人工标注 / LLM judge |
| Context Recall | 必要信息有没有漏 | 对照标准证据和任务状态 |
| Source Correctness | 信息来源是否标对 | 检查 metadata |
| Conflict Handling | 冲突时优先级是否正确 | 构造冲突用例 |
| Budget Stability | token 是否稳定 | 线上分布监控 |
| State Continuity | 多轮状态是否不断片 | 长任务回放 |
| Contamination Rate | 旧任务是否污染新任务 | session 切换测试 |
尤其建议做两类回放测试:
1. 长任务回放
给 Agent 一个 10-20 轮的任务,看它到后面是否还记得最初目标、关键约束、已完成动作。
2. 任务切换测试
连续跑两个不相关任务,看第一个任务的状态是否污染第二个。
很多上下文问题,单轮 benchmark 根本测不出来。
十五、几个常见反模式
最后把容易踩的坑集中列一下。
反模式 1:把所有历史对话都塞进去
短期最省事,长期最不稳。历史对话应该逐步压缩成 task state,而不是无限 append。
反模式 2:把 RAG、memory、tool result 混成一个"相关资料"
模型不知道谁是事实证据、谁是用户偏好、谁是临时观察。调试时也分不清是哪类上下文出错。
反模式 3:长期记忆每轮无条件注入
长期记忆应该按任务类型、相关性、置信度召回。否则就是另一种噪音。
反模式 4:工具原始返回直接进 prompt
工具返回要先结构化、摘要、标注 status/error_type。原始 trace 留给审计和 debug。
反模式 5:只压缩内容,不保留决策
Agent 需要的不是"聊过什么",而是"决定了什么、还剩什么、约束是什么"。
反模式 6:上下文随调用临时拼装,不留 trace
每轮都现场拼一段、调用完就丢,出错时只看得到 user/assistant 两端,中间到底进了什么、被谁压缩、被谁挡掉,全凭猜。Context 必须是可观测的对象,而不是函数内部的局部变量。
反模式 7:把上下文窗口当数据库
上下文窗口是模型本轮推理的工作台,不是长期存储层。该存数据库的存数据库,该进上下文的才进上下文。
十六、回到开头:上下文工程到底工程在哪里
现在再看 Context Engineering,它和 Prompt Engineering 的区别会更清楚。
| 维度 | Prompt Engineering | Context Engineering |
|---|---|---|
| 核心问题 | 怎么表达指令 | 怎么选择和组织信息 |
| 主要对象 | prompt 文本 | Runtime、Router、Memory、RAG、Tool Trace |
| 变化频率 | 相对静态 | 每轮动态变化 |
| 失败表现 | 指令不清、格式不稳 | 遗忘、污染、证据缺失、状态漂移 |
| 优化方式 | 改写提示词、加示例 | 路由、召回、压缩、排序、预算、追踪 |
| 可观测性 | 看 prompt 模板 | 看最终 assembled context |
Prompt 当然仍然重要。
但对 Agent 来说,真正决定上限的往往不是那段 system prompt,而是 system prompt 之前发生了什么:
- 哪些记忆被召回
- 哪些证据被选中
- 哪些工具结果被摘要
- 哪些历史被压缩
- 哪些旧状态被丢掉
- 哪些规则被提升优先级
- 哪些无关信息被挡在上下文外
这些事情才是上下文工程。
一句话收束:
Prompt 是模型看到的说明书;Context 是模型本轮能看到的世界。Agent 稳不稳,取决于 Runtime 有没有把这个世界整理干净。
如果你正在做一个真正要进生产的 Agent,我建议先别急着堆更多工具、更多 memory、更多 RAG 策略。
先把这三个文件或模块做出来:
context_router.pycontext_builder.pycontext_trace.pyRouter 决定拿什么。
Builder 决定怎么放。
Trace 负责让你知道这轮到底放了什么。
这三件事做好,Agent 的稳定性会比单纯调 prompt 提升得更明显。
传统产品经理,正在成为下个被淘汰的“传统岗位”。
过去画原型、写 PRD、跟进度的“传统技能包”,在AI时代正迅速贬值。63% 的企业转型做 AI 产品!当下的问题不再是“要不要学 AI ”,而是“如何构建 AI 产品”。
前段时间还跟字节、腾讯的资深 AI 产品经理沟通,他们反馈:在大量招人,只要有 AI 相关的项目经验,基本都能拿到面试机会,而且领导很舍得给钱,涨薪 40-60% 很正常!
01
接下来的产品人,得卷AI能力了!
如今AI大火,行业极速发展的背后,懂AI 产品人才却严重稀缺。这不是要你转技术岗,而是要掌握构建 AI 产品的核心方法:
- 如何将你的领域知识,转化为 AI 产品的核心竞争力?
- 如何用 AI 技术实现你的产品需求?
- 如何设计真正懂用户的 AI 交互体验?
- ……
懂AI,就是产品经理的“救命稻草”!
风口之下,与其焦虑被行业淘汰
不如先人一步享受AI技术带来的红利!
我把AI产品经理的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
(不限年龄!不限岗位!没有代码基础也能学!)
🎁现在扫码,完课还送:
《AI产品面试题库》《AI大模型应用案例集》
02
掌握技术+实战,快速转型!
想成为一名卓越的AI大模型产品经理,需要从技术、到项目实战的全方位转型指南!
**1)**AI产品应用原理解析,产品经理也能听懂!
对于产品经理来说,如果你不懂技术,做不了业务和AI大模型技术衔接、定义不了数据需求,是没法完整的落地一个产品的!
本次课程,专门面向产品经理人群,解析当下最热门的AI产品应用的必备的「大模型」、「多模态」的实际应用和算法原理!解析AI产品应用技术,积累大模型能力!简单易懂,不需要会代码,小白也能掌握!
- 大模型微调:掌握主流大模型(如DeepSeek、Qwen等)的微调技术,针对特定场景优化模型性能。学习如何利用领域数据(如制造、医药、金融等)进行模型定制
- AI Agent智能体搭建:学习如何设计和开发AI Agent,实现多任务协同、自主决策和复杂问题解决。构建垂类场景下的智能助手产品(如制造业中的设备故障诊断Agent、金融领域的投资分析Agent等)
2)超全行业案例解析!
课程详细讲解现阶段,大模型在各个行业和领域的应用现状!包括:零售与电商、教育、医疗、泛娱乐、法律等等10大行业!
详细讲解案例的思路、应用场景,以及背后的技术原理、核心技术!揭秘各个行业、场景的真实现状,和未来产品的发展与机遇!
可以说,讲解完一个案例,就能积累一个AI产品实践的经验!
课程中所涉及到的实战项目,都可以直接在自己的工作中使用,让自己的产品/项目有可借鉴的成功案例!
3)AI产品经理求职专项辅导
课程中会系统的帮助大家拆解字节、腾讯、百度等大厂AI PM岗位JD关键词,掌握AI PM高频面试题型与回答框架;展示 AI 相关能力的关键技巧:Prompt设计、模型评估、A/B测试、成本意识、与算法/工程协作经验;
- To B类AI产品经理:突出“行业理解 + 技术落地 + 商业闭环”能力的简历结构设计,展示项目成果;从客户需求洞察到技术方案设计,展现端到产品思维;如何评估To B AI产品的可行性、客户付费意愿与实施成本
- To C类AI产品经理:拆解头部公司岗位JD,将过往尽力转化为AI产品叙事逻辑;从行业趋势、产品设计题、案例分析&数据分析题、技术理解边界等全流程辅导面试;避免无效海投、锁定最适合的AI产品岗位;
03
本次课程,全程直播讲解,能直接对话大佬和专业助教,不懂就问,超详细的案例,小白也能轻松get!
完课后,还赠送《AI产品经理面试题库》、《AI大模型应用案例集》!不断更新中……
适合人群:
- 想转型AI产品经理、AI项目管理专家、AI产品解决方案等岗位
- 想进行AI产品创业的创业者
- 想成为制作AI产品的程序员
- 想利用AI解决企业问题的管理岗
- 想在AI方向寻找就业方向的毕业生
- AI方向前景广阔、待遇好!
目前,很多产品人已经通过完整学习拿到大厂高薪offer,收入嗷嗷涨!
我把AI产品经理的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~
