收藏必备!小白程序员轻松掌握Context Engineering,让你的AI Agent智能翻倍!
本文深入浅出地介绍了2025年AI工程圈最热的概念——Context Engineering通过实战代码和五个实用技巧帮助程序员解决AI Agent在运行中出现的“失忆”和答非所问等问题。文章强调了上下文质量对Agent性能的重要性并提出了结构化Prompt、对话历史压缩、记忆注入、工具输出格式化和上下文预算管理等关键策略旨在提升AI 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 anthropic client anthropic.Anthropic(api_keyAPI_KEY) # ✅ 用 XML 标签结构化 System Prompt # 为什么用 XMLClaude 的训练数据里大量使用 XML识别效果最好 SYSTEM_PROMPT role 你是一个专业的 RAG 技术顾问帮助开发者解决检索增强生成相关问题。 /role rules - 只回答 RAG、向量数据库、LLM 应用相关的技术问题 - 代码示例必须可以直接运行不允许使用占位符 - 如果不确定明确说我不确定不要编造答案 /rules context 当前用户是一名有 Python 基础的 AI 应用开发工程师正在学习 RAG 技术。 /context output_format 回答分三部分核心答案1-2句→ 原理解释 → 代码示例 /output_format response client.messages.create( modelclaude-sonnet-4-6, max_tokens1024, systemSYSTEM_PROMPT, # 结构化的 System Prompt messages[{role: user, content: FAISS 和 Milvus 该选哪个}] ) print(response.content[0].text)# 运行结果示例 核心答案本地开发用 FAISS生产环境用 Milvus。 原理解释FAISS 是内存索引库轻量快速但无法持久化和水平扩展 Milvus 是完整的向量数据库支持分布式部署、数据持久化和实时更新...技巧二对话历史压缩防止上下文溢出Agent 跑多轮之后历史记录越来越长Token 消耗爆炸。解法是定期把历史总结成摘要替换掉原始记录。from langchain_anthropic import ChatAnthropic from langchain_core.messages import HumanMessage, AIMessage, SystemMessage # ----------------------------------------------- # 【按你的环境修改这里】 # ----------------------------------------------- # Anthropic API Key API_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)# 运行结果 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 FAISS from langchain_huggingface import HuggingFaceEmbeddings from langchain_core.documents import Document embeddings 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})# 运行结果✅ 记忆已保存用户偏好使用 FAISS 而不是 Milvus因为他的项目是单... ✅ 记忆已保存用户的技术栈Python3.11 LangChain0.3 FastAPI ✅ 记忆已保存用户正在做一个内部知识库 RAG 系统文档量约1000篇 注入的记忆relevant_memory- 用户偏好使用 FAISS 而不是 Milvus因为他的项目是单机部署 - 用户正在做一个内部知识库 RAG 系统文档量约1000篇/relevant_memory技巧四工具输出格式化别把垃圾喂给模型Agent 调用工具之后返回值可能又长又乱——SQL 查询返回了几百行数据、API 返回了一大堆嵌套 JSON。直接塞进上下文模型会被噎住。现在想想当时我们组有个系统工具返回值直接原样传给模型——一次工具调用产生 3000 个 Token 的返回值调三次工具上下文就撑爆了。踩过才知道这个坑有多深。正确做法工具结果先提炼再注入。import json from typing import Any def 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) ool_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)} 字符)# 运行结果 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.0 CONTEXT_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_tokens def 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)} 字符)# 运行结果 ⚠️ [retrieved_docs] 超出预算估算 14000 tokens预算 11200 tokens 原始42000 字符 → 截断后33605 字符五、总结Context Engineering 的三条铁律说到这里核心就一句话上下文的质量决定了 Agent 的上限。三条铁律✅ 放什么宁缺毋滥只放跟当前任务直接相关的内容✅ 怎么放结构化优先用 XML 标签告诉模型每段是什么✅ 管多少预算意识给每部分分配合理的 Token 配额技术选型快速参考你的场景推荐方案单轮问答上下文简单不用专门做 CE把 Prompt 写清楚就够多轮对话 Agent对话历史压缩 记忆注入技巧二 三调用多个外部工具工具输出格式化技巧四复杂 RAG 系统上下文预算管理 结构化 System Prompt技巧一 五生产级 Agent以上全部配合 Prompt Caching 降成本现在就可以做的三件事1. 检查你的 System Prompt加上 XML 标签分区5 分钟的改动效果立竿见影2. 加一个压缩机制超过 10 轮对话触发摘要压缩防止上下文溢出3. 格式化工具输出别把原始返回值直接喂给模型先提炼关键信息进阶学习路线阶段掌握内容参考资料入门结构化 Prompt 对话历史管理本文代码进阶记忆系统设计 Token 预算管理mem0 文档、LangChain Memory高级Multi-Agent 上下文共享 Prompt CachingAnthropic API 文档如何学习大模型 AI 由于新岗位的生产效率要优于被取代岗位的生产效率所以实际上整个社会的生产效率是提升的。但是具体到个人只能说是“最先掌握AI的人将会比较晚掌握AI的人有竞争优势”。这句话放在计算机、互联网、移动互联网的开局时期都是一样的道理。我在一线科技企业深耕十二载见证过太多因技术卡位而跃迁的案例。那些率先拥抱 AI 的同事早已在效率与薪资上形成代际优势我意识到有很多经验和知识值得分享给大家也可以通过我们的能力和经验解答大家在大模型的学习中的很多困惑。我们整理出这套AI 大模型突围资料包✅ 从零到一的 AI 学习路径图✅ 大模型调优实战手册附医疗/金融等大厂真实案例✅ 百度/阿里专家闭门录播课✅ 大模型当下最新行业报告✅ 真实大厂面试真题✅ 2026 最新岗位需求图谱所有资料 ⚡️ 朋友们如果有需要《AI大模型入门进阶学习资源包》下方扫码获取~① 全套AI大模型应用开发视频教程包含提示工程、RAG、LangChain、Agent、模型微调与部署、DeepSeek等技术点② 大模型系统化学习路线作为学习AI大模型技术的新手方向至关重要。 正确的学习路线可以为你节省时间少走弯路方向不对努力白费。这里我给大家准备了一份最科学最系统的学习成长路线图和学习规划带你从零基础入门到精通③ 大模型学习书籍文档学习AI大模型离不开书籍文档我精选了一系列大模型技术的书籍和学习文档电子版它们由领域内的顶尖专家撰写内容全面、深入、详尽为你学习大模型提供坚实的理论基础。④ AI大模型最新行业报告2025最新行业报告针对不同行业的现状、趋势、问题、机会等进行系统地调研和评估以了解哪些行业更适合引入大模型的技术和应用以及在哪些方面可以发挥大模型的优势。⑤ 大模型项目实战配套源码学以致用在项目实战中检验和巩固你所学到的知识同时为你找工作就业和职业发展打下坚实的基础。⑥ 大模型大厂面试真题面试不仅是技术的较量更需要充分的准备。在你已经掌握了大模型技术之后就需要开始准备面试我精心整理了一份大模型面试题库涵盖当前面试中可能遇到的各种技术问题让你在面试中游刃有余。以上资料如何领取为什么大家都在学大模型最近科技巨头英特尔宣布裁员2万人传统岗位不断缩减但AI相关技术岗疯狂扩招有3-5年经验大厂薪资就能给到50K*20薪不出1年“有AI项目经验”将成为投递简历的门槛。风口之下与其像“温水煮青蛙”一样坐等被行业淘汰不如先人一步掌握AI大模型原理应用技术项目实操经验“顺风”翻盘这些资料真的有用吗这份资料由我和鲁为民博士(北京清华大学学士和美国加州理工学院博士)共同整理现任上海殷泊信息科技CEO其创立的MoPaaS云平台获Forrester全球’强劲表现者’认证服务航天科工、国家电网等1000企业以第一作者在IEEE Transactions发表论文50篇获NASA JPL火星探测系统强化学习专利等35项中美专利。本套AI大模型课程由清华大学-加州理工双料博士、吴文俊人工智能奖得主鲁为民教授领衔研发。资料内容涵盖了从入门到进阶的各类视频教程和实战项目无论你是小白还是有些技术基础的技术人员这份资料都绝对能帮助你提升薪资待遇转行大模型岗位。以上全套大模型资料如何领取