光会写 Prompt 不够用了——AI Agent 时代,你需要懂 Context Engineering

光会写 Prompt 不够用了——AI Agent 时代,你需要懂 Context Engineering 导读你有没有发现明明 Prompt 写得很认真AI Agent 跑着跑着就失忆了或者答非所问问题不在 Prompt在Context上下文。本文带你搞清楚 2025 年 AI 工程圈最热的概念——Context Engineering以及怎么用它让你的 Agent 聪明一倍。零基础友好附实战代码。一、那些年Agent 给我整的笑话说个真实场景。你花了两周搭了一个客服 Agent测试的时候表现完美——回答准确、有条理、语气友好。上线第一天用户问了一个稍微复杂点的问题Agent 开始正常回答。然后用户追问了三四轮……Agent 的回答开始变味了。先是忘了自己是客服助手的身份开始自由发挥。然后忘了用户前面说过的信息开始重复问。最后干脆给出了一个跟实际产品文档完全矛盾的答案。你盯着日志百思不得其解——Prompt 我没动啊怎么就翻车了“RAG 80% 的问题出在切文档那一步。Agent 80% 的问题出在上下文管理那一步。”哎这就是 Context Engineering 要解决的核心问题。二、Context Engineering 是什么跟 Prompt Engineering 有什么区别先说清楚这两个概念很多人混着用其实差得远。一句话定义Prompt Engineering 是如何问一个好问题Context Engineering 是如何把整个对话现场布置好让 AI 一直保持最佳状态。用装修来类比——Prompt Engineering 像是怎么跟装修工人沟通需求你要说清楚风格、预算、要求。Context Engineering 像是设计整个施工现场工人在哪、图纸放哪、工具摆哪、今天干什么、昨天干了啥、下一步计划是什么。现场设计好了工人自然干得好现场一团乱沟通再清楚也没用。这个概念在 2025 年被 AI 圈广泛采用Andrej Karpathy前 OpenAI 研究员、特斯拉 AI 负责人明确表达过这个观点“The bottleneck is not the model. The bottleneck is context.”瓶颈不是模型瓶颈是上下文。上下文窗口里到底装了什么很多人以为上下文就是聊天记录。其实一个 Agent 运行时上下文窗口里塞满了各种东西内容类型说明举例System PromptAgent 的身份、规则、行为约束“你是一个客服助手不得讨论竞品”对话历史用户和 AI 的来回前 N 轮问答检索结果RAG 拉回来的文档片段产品手册第 3-5 页工具调用记录调用了什么工具、返回了什么查了数据库结果是 xxx记忆注入从长期记忆里提取的相关历史这个用户上次说他是 VIP用户当前输入这一轮的问题“我的订单在哪里”这些东西加在一起很容易就把上下文窗口撑满。而模型处理上下文的能力跟塞了多少有用信息直接相关。三、为什么现在特别重要选型前先搞清楚这件事你品你细品——同样是 Claude 3.6 Sonnet为什么有人用得飞起有人用得一塌糊涂差别就在 Context 的质量。3.1 Agent 把 Context 问题放大了 10 倍单轮问答时代Context Engineering 还不紧迫——一个问题进去一个答案出来上下文本来就简单。但 Agent 不一样• 它要多轮对话历史越来越长• 它要调用工具工具返回值也要塞进去• 它要自主规划中间的推理步骤也占位置• 它可能要并行处理多个任务上下文更复杂不管好 ContextAgent 跑几步就失忆跑更多步就人格分裂。3.2 三种典型失败模式我总结了工程实践中最常见的三种 Context 翻车场景失败模式表现根本原因上下文溢出Agent 突然忘记了早期的关键指令对话太长早期内容被挤出窗口上下文污染Agent 被不相关的工具输出或检索结果带偏往上下文里塞了太多低质量信息上下文割裂Agent 无法把多轮信息联系起来缺乏有效的记忆管理和信息压缩3.3 Context Engineering 的四个核心维度说白了Context Engineering 就是回答四个问题1. 放什么进去 → 内容选择相关性过滤2. 怎么组织 → 结构设计格式、顺序、标记3. 放多少 → 预算管理Token 分配4. 什么时候更新 → 动态维护压缩、遗忘、注入决策流程动图四、实战五个让 Agent 不再失忆的 Context 管理技巧好原理讲完进入实战环节。下面这五个技巧是我认为性价比最高的 Context Engineering 手段。代码用 Python LangChain / 原生 API你可以直接跑。技巧一结构化 System Prompt用 XML 标签分区很多人的 System Prompt 是一大坨纯文本。模型理解起来其实挺费劲的——它得自己猜哪段是规则、哪段是背景、哪段是约束。给它分好区效果立竿见影。# -----------------------------------------------# 【按你的环境修改这里】# -----------------------------------------------# 把 YOUR_API_KEY 换成你的 Anthropic API Key# 在 https://console.anthropic.com 获取API_KEY YOUR_ANTHROPIC_API_KEY# -----------------------------------------------import anthropicclient anthropic.Anthropic(api_keyAPI_KEY)# ✅ 用 XML 标签结构化 System Prompt# 为什么用 XMLClaude 的训练数据里大量使用 XML识别效果最好SYSTEM_PROMPT role你是一个专业的 RAG 技术顾问帮助开发者解决检索增强生成相关问题。/rolerules- 只回答 RAG、向量数据库、LLM 应用相关的技术问题- 代码示例必须可以直接运行不允许使用占位符- 如果不确定明确说我不确定不要编造答案/rulescontext当前用户是一名有 Python 基础的 AI 应用开发工程师正在学习 RAG 技术。/contextoutput_format回答分三部分核心答案1-2句→ 原理解释 → 代码示例/output_formatresponse client.messages.create( modelclaude-sonnet-4-6, max_tokens1024, systemSYSTEM_PROMPT, # 结构化的 System Prompt messages[{role: user, content: FAISS 和 Milvus 该选哪个}])print(response.content[0].text) plaintext # 运行结果示例核心答案本地开发用 FAISS生产环境用 Milvus。原理解释FAISS 是内存索引库轻量快速但无法持久化和水平扩展Milvus 是完整的向量数据库支持分布式部署、数据持久化和实时更新...技巧二对话历史压缩防止上下文溢出Agent 跑多轮之后历史记录越来越长Token 消耗爆炸。解法是定期把历史总结成摘要替换掉原始记录。from langchain_anthropic import ChatAnthropicfrom langchain_core.messages import HumanMessage, AIMessage, SystemMessage# -----------------------------------------------# 【按你的环境修改这里】# -----------------------------------------------# Anthropic API KeyAPI_KEY YOUR_ANTHROPIC_API_KEY# 触发压缩的消息轮数阈值超过这个就压缩COMPRESS_THRESHOLD 10# -----------------------------------------------llm ChatAnthropic(modelclaude-sonnet-4-6, api_keyAPI_KEY)def compress_history(messages: list, llm) - list: 把历史消息压缩成摘要保留最近 2 轮原始对话。 为什么保留最近 2 轮保证模型能看到最新的上下文 同时用摘要覆盖早期对话大幅减少 Token 消耗。 if len(messages) COMPRESS_THRESHOLD: return messages # 还没到阈值不用压缩 # 把早期消息除最近 4 条发给模型让它总结 old_messages messages[:-4] recent_messages messages[-4:] # 保留最近 2 轮4 条消息 # 构造压缩请求 summary_prompt f请将以下对话历史压缩成一段简洁的摘要200字以内保留所有关键信息、决策和结论{chr(10).join([f{m.type}: {m.content} for m in old_messages])} summary_response llm.invoke([HumanMessage(contentsummary_prompt)]) # 用摘要替换早期消息插回对话历史 compressed [ SystemMessage(contentf[对话历史摘要]\n{summary_response.content}) ] recent_messages print(f✅ 压缩完成{len(messages)} 条 → {len(compressed)} 条) return compressed# 模拟一个多轮对话conversation_history []questions [ RAG 是什么, 向量数据库怎么选, FAISS 怎么安装, chunk_size 设多少合适, 怎么评估 RAG 效果,]for question in questions: conversation_history.append(HumanMessage(contentquestion)) # 每次对话前检查是否需要压缩 conversation_history compress_history(conversation_history, llm) response llm.invoke(conversation_history) conversation_history.append(AIMessage(contentresponse.content)) print(fQ: {question}) print(fA: {response.content[:100]}...\n) plaintext # 运行结果Q: RAG 是什么A: RAG检索增强生成是一种将外部知识库与大语言模型结合的技术框架...Q: 向量数据库怎么选A: 根据规模选择本地开发用 FAISS中等规模用 Chroma生产环境用 Milvus...✅ 压缩完成12 条 → 5 条 ← 触发压缩历史从 12 条压到 5 条Q: 怎么评估 RAG 效果A: 推荐用 RAGAS 框架核心指标包括 faithfulness、answer_relevancy...技巧三动态记忆注入让 Agent 记住重要的事不是所有信息都值得永远留在上下文里。重要的是在需要的时候把相关的记忆注入进来。# -----------------------------------------------# 【按你的环境修改这里】# -----------------------------------------------# 向量库保存路径改成你本地的目录MEMORY_STORE_PATH ./agent_memory# 嵌入模型不用改用免费的本地模型EMBED_MODEL BAAI/bge-small-zh-v1.5# 检索记忆时返回最相关的 K 条MEMORY_TOP_K 3# -----------------------------------------------from langchain_community.vectorstores import FAISSfrom langchain_huggingface import HuggingFaceEmbeddingsfrom langchain_core.documents import Documentembeddings HuggingFaceEmbeddings(model_nameEMBED_MODEL)def save_memory(content: str, metadata: dict None): 把重要信息存进记忆向量库 doc Document(page_contentcontent, metadatametadata or {}) try: # 已有记忆库则追加 store FAISS.load_local( MEMORY_STORE_PATH, embeddings, allow_dangerous_deserializationTrue # 本地文件安全 ) store.add_documents([doc]) except Exception: # 第一次运行创建新的记忆库 store FAISS.from_documents([doc], embeddings) store.save_local(MEMORY_STORE_PATH) print(f✅ 记忆已保存{content[:50]}...)def retrieve_memory(query: str) - str: 根据当前问题检索最相关的历史记忆 try: store FAISS.load_local( MEMORY_STORE_PATH, embeddings, allow_dangerous_deserializationTrue ) docs store.similarity_search(query, kMEMORY_TOP_K) if not docs: return # 把检索到的记忆拼成字符串注入到 System Prompt memories \n.join([f- {d.page_content} for d in docs]) return frelevant_memory\n{memories}\n/relevant_memory except Exception: return # 没有记忆库时静默返回空# 使用示例保存用户偏好save_memory(用户偏好使用 FAISS 而不是 Milvus因为他的项目是单机部署)save_memory(用户的技术栈Python 3.11 LangChain 0.3 FastAPI)save_memory(用户正在做一个内部知识库 RAG 系统文档量约 1000 篇)# 下次对话时动态注入相关记忆query 向量库应该用哪个memory_context retrieve_memory(query) # 自动检索相关记忆print(f注入的记忆\n{memory_context}) plaintext # 运行结果✅ 记忆已保存用户偏好使用 FAISS 而不是 Milvus因为他的项目是单...✅ 记忆已保存用户的技术栈Python 3.11 LangChain 0.3 FastAPI✅ 记忆已保存用户正在做一个内部知识库 RAG 系统文档量约 1000 篇注入的记忆relevant_memory- 用户偏好使用 FAISS 而不是 Milvus因为他的项目是单机部署- 用户正在做一个内部知识库 RAG 系统文档量约 1000 篇/relevant_memory技巧四工具输出格式化别把垃圾喂给模型Agent 调用工具之后返回值可能又长又乱——SQL 查询返回了几百行数据、API 返回了一大堆嵌套 JSON。直接塞进上下文模型会被噎住。现在想想当时我们组有个系统工具返回值直接原样传给模型——一次工具调用产生 3000 个 Token 的返回值调三次工具上下文就撑爆了。踩过才知道这个坑有多深。正确做法工具结果先提炼再注入。import jsonfrom typing import Anydef format_tool_output(tool_name: str, raw_output: Any, max_tokens: int 500) - str: 把工具返回值格式化成上下文友好的格式。 核心思路只保留模型决策所需的信息其余截断或摘要。 if tool_name database_query: # 数据库查询结果只保留前 N 行附上总行数 rows raw_output.get(rows, []) total raw_output.get(total_count, len(rows)) preview rows[:5] # 只给模型看前 5 行 return ( ftool_result namedatabase_query\n f查询成功共 {total} 条结果展示前 {len(preview)} 条\n f{json.dumps(preview, ensure_asciiFalse, indent2)}\n f{已截断仅展示前5条 if total 5 else }\n f/tool_result ) elif tool_name web_search: # 网页搜索结果每条结果只保留标题 摘要去掉正文 results raw_output.get(results, []) formatted [] for i, r in enumerate(results[:3]): # 最多用前 3 条结果 formatted.append(f{i1}. 【{r[title]}】\n {r[snippet]}) return ( ftool_result nameweb_search\n \n.join(formatted) \n/tool_result ) else: # 其他工具把结果转成字符串硬截断 result_str str(raw_output) if len(result_str) max_tokens * 4: # 粗略估算 Token 数 result_str result_str[:max_tokens * 4] \n...[已截断] return ftool_result name{tool_name}\n{result_str}\n/tool_result# 使用示例raw_db_result { rows: [{id: i, content: f文档{i}的内容...} for i in range(100)], total_count: 100}formatted format_tool_output(database_query, raw_db_result)print(formatted)print(f\n原始长度{len(str(raw_db_result))} 字符)print(f格式化后{len(formatted)} 字符) plaintext # 运行结果tool_result namedatabase_query查询成功共 100 条结果展示前 5 条[ {id: 0, content: 文档0的内容...}, {id: 1, content: 文档1的内容...}, ...]已截断仅展示前5条/tool_result原始长度2847 字符格式化后312 字符 ← 压缩了 89%且保留了所有关键信息技巧五上下文预算管理给不同内容分配 Token 配额这是稍微进阶一点的技巧。说白了就是事先规划好上下文窗口里各部分的 Token 占比防止某一部分无限膨胀把其他部分挤掉。# -----------------------------------------------# 【按你的环境修改这里】# -----------------------------------------------# 模型的总上下文窗口大小Token 数# claude-sonnet-4-6 最大 200k这里保守设 32k 用于实验TOTAL_CONTEXT_BUDGET 32000# -----------------------------------------------# 上下文预算分配方案比例之和为 1.0CONTEXT_BUDGET { system_prompt: 0.10, # 10% 给系统提示词约 3200 tokens memory: 0.15, # 15% 给长期记忆注入约 4800 tokens retrieved_docs: 0.35, # 35% 给 RAG 检索结果约 11200 tokens最大头 tool_outputs: 0.20, # 20% 给工具调用返回值约 6400 tokens chat_history: 0.15, # 15% 给对话历史约 4800 tokens user_input: 0.05, # 5% 给用户当前输入约 1600 tokens}def check_budget(content: str, budget_key: str) - tuple[bool, int, int]: 检查某部分内容是否超出预算。 返回(是否超标, 实际token数估算, 预算token数) # 用字符数 / 4 粗略估算 Token 数英文约 4字符/token中文约 2字符/token estimated_tokens len(content) // 3 budget_tokens int(TOTAL_CONTEXT_BUDGET * CONTEXT_BUDGET[budget_key]) over_budget estimated_tokens budget_tokens if over_budget: print(f⚠️ [{budget_key}] 超出预算 f估算 {estimated_tokens} tokens预算 {budget_tokens} tokens) return over_budget, estimated_tokens, budget_tokensdef truncate_to_budget(content: str, budget_key: str) - str: 把内容截断到预算以内 _, estimated, budget check_budget(content, budget_key) if estimated budget: return content # 按预算比例截断token * 3 还原成大约的字符数 max_chars budget * 3 return content[:max_chars] f\n...[已截断超出 {budget_key} 预算]# 使用示例retrieved_docs 这是从向量库里检索出来的超长文档内容... * 200 # 模拟超长检索结果truncated truncate_to_budget(retrieved_docs, retrieved_docs)print(f原始{len(retrieved_docs)} 字符 → 截断后{len(truncated)} 字符) plaintext # 运行结果⚠️ [retrieved_docs] 超出预算估算 14000 tokens预算 11200 tokens原始42000 字符 → 截断后33605 字符五、总结Context Engineering 的三条铁律说到这里核心就一句话上下文的质量决定了 Agent 的上限。三条铁律• ✅放什么宁缺毋滥只放跟当前任务直接相关的内容• ✅怎么放结构化优先用 XML 标签告诉模型每段是什么• ✅管多少预算意识给每部分分配合理的 Token 配额技术选型快速参考你的场景推荐方案单轮问答上下文简单不用专门做 CE把 Prompt 写清楚就够多轮对话 Agent对话历史压缩 记忆注入技巧二 三调用多个外部工具工具输出格式化技巧四复杂 RAG 系统上下文预算管理 结构化 System Prompt技巧一 五生产级 Agent以上全部配合 Prompt Caching 降成本学AI大模型的正确顺序千万不要搞错了2026年AI风口已来各行各业的AI渗透肉眼可见超多公司要么转型做AI相关产品要么高薪挖AI技术人才机遇直接摆在眼前有往AI方向发展或者本身有后端编程基础的朋友直接冲AI大模型应用开发转岗超合适就算暂时不打算转岗了解大模型、RAG、Prompt、Agent这些热门概念能上手做简单项目也绝对是求职加分王给大家整理了超全最新的AI大模型应用开发学习清单和资料手把手帮你快速入门学习路线:✅大模型基础认知—大模型核心原理、发展历程、主流模型GPT、文心一言等特点解析✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑✅开发基础能力—Python进阶、API接口调用、大模型开发框架LangChain等实操✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经以上6大模块看似清晰好上手实则每个部分都有扎实的核心内容需要吃透我把大模型的学习全流程已经整理好了抓住AI时代风口轻松解锁职业新可能希望大家都能把握机遇实现薪资/职业跃迁这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】