文章目录引言一、理解 LLM 的记忆机制1.1 上下文窗口模型唯一的工作记忆1.2 上下文窗口的物理限制二、方案一上下文窗口管理2.1 滑动窗口简单粗暴但有效2.2 摘要压缩用精炼代替遗忘2.3 Token 预算管理把上下文当成钱来花三、方案二RAG —— 让模型遇到问题再去查3.1 RAG 解决什么问题3.2 RAG 的核心组件3.3 RAG 的关键质量因素四、方案三长期记忆 —— 跨会话的信息持久化4.1 对话摘要 vs 长期记忆4.2 长期记忆的实现五、Context Engineer 的天花板总结本系列为《Loop Engineer 实战从提示工程到自主循环》第3篇前置条件了解 LLM 的基本工作原理知道什么是 Token、什么是上下文窗口有基本的 Python 阅读能力。引言上篇我们剖析了 Prompt Engineer 的三重天花板——无状态、无工具、无循环。今天我们来拆第一道墙无状态。想象一个场景你每天早上让 AI 助手帮你规划当天的工作。第一天你告诉它我是后端开发最近在做微服务拆分。它给了你不错的建议。第二天你再次让它规划工作——它问“请问你是做什么工作的”这很让人沮丧。不是因为它不够聪明而是因为它不记得。每次对话对它来说都是一个全新的世界。Context Engineer 要解决的核心问题就是让 AI 拥有跨越时间和会话的记忆能力。本文将沿着问题→方案→实现→边界的线索展开先讲清楚 LLM 的上下文机制为什么它会失忆再给出三大核心解决方案上下文窗口管理、RAG、长期记忆最后诚实地指出 Context Engineer 自身的天花板——它有记忆但没有手脚。一、理解 LLM 的记忆机制1.1 上下文窗口模型唯一的工作记忆LLM 本身是无状态的。它没有数据库没有变量没有任何持久化存储。它唯一能看到的东西就是你通过 API 发给它的那一串 Token——这就是上下文窗口Context Window。API 调用 System Prompt系统提示 历史消息如果开发者手动传回来 用户最新消息 → 模型生成回复关键点历史消息不会自动保留。如果你不把上一轮的对话拼回来模型就不知道上一轮发生了什么。1.2 上下文窗口的物理限制上下文窗口不是无限的。以下是几个主流模型的窗口大小模型上下文窗口大约页数中文GPT-4 (早期)8K tokens~15页GPT-4 Turbo128K tokens~240页Claude 3200K tokens~370页Gemini 1.5 Pro1M tokens~1800页看起来很大但实际使用中有三个约束让大窗口并不好用① 成本每次 API 调用输入 Token 都要计费。如果你每次都把 100K 的历史对话传回去费用会指数级增长。② 延迟输入 Token 越多模型处理时间越长。一个 100K Token 的请求可能比 5K Token 的请求慢 3-5 倍。③ 注意力衰减Lost in the Middle研究表明模型对上下文窗口中间位置的信息关注度最低。开头和结尾的信息记得最清楚中间的信息容易被忽略。窗口越大这个问题越严重。模型注意力分布示意 ████████░░░░░░░░░░░░░░░░████████ 窗口开头 中间注意力低 窗口结尾这意味着你不能无脑地把所有历史信息都塞进去——你需要管理上下文。二、方案一上下文窗口管理Context Engineer 的第一个任务就是在有限且昂贵的上下文窗口里装下最有价值的信息。2.1 滑动窗口简单粗暴但有效最直接的策略只保留最近 N 轮对话。defsliding_window(messages:list,max_turns:int10)-list:只保留最近的 max_turns 轮对话# 每条用户消息 助手回复 2 条消息returnmessages[-(max_turns*2):]适用场景对话式应用客服、闲聊历史信息价值随时间快速衰减。局限如果用户在第十一轮问你记得我第一轮说的那个需求吗——模型答不上来。2.2 摘要压缩用精炼代替遗忘与其丢掉旧对话不如把它们压缩成摘要。defsummarize_history(messages:list,llm_call)-str:将历史对话压缩为一段摘要history_text\n.join([f{m[role]}:{m[content]}forminmessages])promptf请将以下对话历史压缩为一段简洁的摘要保留关键信息 - 用户的基本信息姓名、角色、偏好 - 已完成的任务 - 正在进行中的任务 - 重要的决策和约定 对话历史{history_text}摘要returnllm_call(prompt)实际应用中通常采用分层摘要策略近期对话最近3轮→ 保留原文不压缩 中期对话4-10轮→ 保留摘要 远期对话10轮以上→ 只保留关键事实用户偏好、重要决策2.3 Token 预算管理把上下文当成钱来花一个成熟的 Context 管理系统会把 Token 当作预算来管理classTokenBudget:def__init__(self,max_tokens:int100000):self.max_tokensmax_tokens self.reserved_for_output4000# 预留给模型输出self.reserved_for_system2000# 预留给系统提示self.reserved_for_tools3000# 预留给工具定义propertydefavailable_for_context(self)-int:return(self.max_tokens-self.reserved_for_output-self.reserved_for_system-self.reserved_for_tools)defallocate(self,messages:list)-list:从最新到最旧填充消息直到预算用完budgetself.available_for_context selected[]formsginreversed(messages):costcount_tokens(msg)ifbudget-cost0:breakselected.insert(0,msg)budget-costreturnselected这保证了无论对话多长上下文都不会溢出且不会在单次请求中烧掉过多预算。三、方案二RAG —— 让模型遇到问题再去查3.1 RAG 解决什么问题上下文窗口管理解决的是对话历史怎么放的问题。但还有另一类信息外部知识。你的公司有 500 页的产品文档。你不可能每次都把它们全部塞进 Prompt——成本太高大部分内容也和当前问题无关。你需要的是按需检索只把相关的部分放进去。这就是 RAGRetrieval-Augmented Generation检索增强生成用户提问 → 向量检索 → 取 Top-K 相关文档 → 拼入 Prompt → 模型生成答案3.2 RAG 的核心组件一个完整的 RAG 系统包含以下组件┌─────────────────────────────────────────────────────────┐ │ RAG 系统架构 │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ │ │ 文档导入 │ → │ 文本分块 │ → │ 向量化 存储索引 │ │ │ │ (PDF/MD) │ │ (Chunking)│ │ (Embedding DB) │ │ │ └──────────┘ └──────────┘ └──────────────────┘ │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ │ │ 用户提问 │ → │ 向量检索 │ → │ Prompt 组装 │ │ │ │ │ │ (Top-K) │ │ LLM 生成 │ │ │ └──────────┘ └──────────┘ └──────────────────┘ │ └─────────────────────────────────────────────────────────┘① 文档分块Chunking把长文档切成小块。块太大 → 检索精度下降。块太小 → 语义不完整。常见策略固定大小分块每 500 Token 一块重叠 50 Token。语义分块按段落、章节自然边界切分。递归分块先用大分隔符章节标题如果块仍然太大再用小分隔符段落。fromlangchain.text_splitterimportRecursiveCharacterTextSplitter splitterRecursiveCharacterTextSplitter(chunk_size500,chunk_overlap50,separators[\n\n,\n,。,., ])chunkssplitter.split_text(document)② 向量化Embedding把文本转成向量。语义相似的文本向量距离近。fromopenaiimportOpenAI clientOpenAI()defembed(text:str)-list[float]:responseclient.embeddings.create(modeltext-embedding-3-small,inputtext)returnresponse.data[0].embedding③ 向量检索用户提问 → 向量化 → 在向量数据库中搜索最相似的 K 个文档块。importchromadb clientchromadb.Client()collectionclient.get_or_create_collection(knowledge_base)resultscollection.query(query_embeddings[embed(user_question)],n_results5)④ Prompt 组装把检索到的文档块拼入 Prompt作为参考资料context\n\n.join(results[documents][0])promptf请根据以下参考资料回答用户的问题。 如果参考资料中没有相关信息请如实说明。 参考资料{context}用户问题{user_question}回答3.3 RAG 的关键质量因素因素影响建议分块策略检索精度根据文档类型选择代码用小块文章用段落Embedding 模型语义匹配质量使用 text-embedding-3 或 bge-large 等高质量模型Top-K 选择信息充分性 vs 噪声一般 3-8 个根据文档密度调整检索后重排Rerank相关性排序用 Cross-Encoder 对 Top-K 结果重新打分四、方案三长期记忆 —— 跨会话的信息持久化4.1 对话摘要 vs 长期记忆上下文窗口管理和 RAG 解决的是本次对话内的信息管理。但还有一种需求跨会话的记忆。用户上周跟你说过他喜欢简洁风格这周你再推荐方案时应该优先推简洁的。这种记忆需要持久化存储。4.2 长期记忆的实现fromdatetimeimportdatetimeimportjsonclassLongTermMemory:def__init__(self,db):self.dbdb# 向量数据库 结构化存储defextract_memories(self,conversation:list)-list[dict]:从对话中提取值得记住的信息promptf从以下对话中提取值得长期记住的信息。对于每条信息 判断它属于哪种类型fact事实、preference偏好、decision决策。 对话{json.dumps(conversation,ensure_asciiFalse)}返回 JSON 数组每条格式 {{type: fact|preference|decision, content: ..., importance: 1-5}} responsellm_call(prompt)returnjson.loads(response)defsave_memories(self,memories:list[dict]):存入向量数据库formeminmemories:embeddingembed(mem[content])self.db.insert(embeddingembedding,metadata{type:mem[type],content:mem[content],importance:mem[importance],timestamp:datetime.now().isoformat()})defrecall(self,query:str,top_k:int5)-list[str]:根据当前话题检索相关记忆resultsself.db.search(embed(query),top_ktop_k)# 按 importance 排序高重要性的优先results.sort(keylambdax:x[metadata][importance],reverseTrue)return[r[metadata][content]forrinresults]使用时每次对话开始前检索相关记忆拼入 System Prompt每次对话结束后提取新记忆存入数据库。五、Context Engineer 的天花板Context Engineer 解决了记忆问题但新的天花板随之而来它有记忆但没有手脚。模型可以记住你喜欢简洁风格但它不能帮你把代码改成简洁风格。它可以检索到 Docker 部署文档但它不能帮你执行docker-compose up。它可以分析你的聊天记录总结出你的偏好但它不能帮你把偏好配置写进系统里。Context Engineer 的能力边界 ✅ 记住你是谁、你喜欢什么 ✅ 从知识库中检索相关信息 ✅ 基于历史对话理解上下文 ❌ 操作外部系统发邮件、调API、改数据库 ❌ 执行代码或命令 ❌ 自主发起行动它还是你问它答Context Engineer 给了 AI “记忆”但 AI 仍然只是一个博学的顾问不是一个能干的助手。要让 AI 从说变成做我们需要下一阶段的进化——Harness Engineer。总结Context Engineer 通过三大方案解决了 LLM 的失忆问题上下文窗口管理滑动窗口、摘要压缩、Token 预算在有限窗口中装下最有价值的信息。RAG检索增强生成让模型按需检索外部知识而非把所有知识塞进 Prompt。长期记忆跨会话持久化用户偏好、决策和关键事实。这些技术构成了 AI 应用的记忆层——没有它AI 永远是鱼的记忆七秒一轮回。但 Context Engineer 的局限同样清晰它只能说不能做。下一篇我们将进入 Harness Engineer 的世界——给 AI 装上手脚让它真正能干活的工具调用与 API 编排。
第3篇:Context Engineer:构建 AI 的长期记忆与动态知识库
发布时间:2026/6/30 23:22:05
文章目录引言一、理解 LLM 的记忆机制1.1 上下文窗口模型唯一的工作记忆1.2 上下文窗口的物理限制二、方案一上下文窗口管理2.1 滑动窗口简单粗暴但有效2.2 摘要压缩用精炼代替遗忘2.3 Token 预算管理把上下文当成钱来花三、方案二RAG —— 让模型遇到问题再去查3.1 RAG 解决什么问题3.2 RAG 的核心组件3.3 RAG 的关键质量因素四、方案三长期记忆 —— 跨会话的信息持久化4.1 对话摘要 vs 长期记忆4.2 长期记忆的实现五、Context Engineer 的天花板总结本系列为《Loop Engineer 实战从提示工程到自主循环》第3篇前置条件了解 LLM 的基本工作原理知道什么是 Token、什么是上下文窗口有基本的 Python 阅读能力。引言上篇我们剖析了 Prompt Engineer 的三重天花板——无状态、无工具、无循环。今天我们来拆第一道墙无状态。想象一个场景你每天早上让 AI 助手帮你规划当天的工作。第一天你告诉它我是后端开发最近在做微服务拆分。它给了你不错的建议。第二天你再次让它规划工作——它问“请问你是做什么工作的”这很让人沮丧。不是因为它不够聪明而是因为它不记得。每次对话对它来说都是一个全新的世界。Context Engineer 要解决的核心问题就是让 AI 拥有跨越时间和会话的记忆能力。本文将沿着问题→方案→实现→边界的线索展开先讲清楚 LLM 的上下文机制为什么它会失忆再给出三大核心解决方案上下文窗口管理、RAG、长期记忆最后诚实地指出 Context Engineer 自身的天花板——它有记忆但没有手脚。一、理解 LLM 的记忆机制1.1 上下文窗口模型唯一的工作记忆LLM 本身是无状态的。它没有数据库没有变量没有任何持久化存储。它唯一能看到的东西就是你通过 API 发给它的那一串 Token——这就是上下文窗口Context Window。API 调用 System Prompt系统提示 历史消息如果开发者手动传回来 用户最新消息 → 模型生成回复关键点历史消息不会自动保留。如果你不把上一轮的对话拼回来模型就不知道上一轮发生了什么。1.2 上下文窗口的物理限制上下文窗口不是无限的。以下是几个主流模型的窗口大小模型上下文窗口大约页数中文GPT-4 (早期)8K tokens~15页GPT-4 Turbo128K tokens~240页Claude 3200K tokens~370页Gemini 1.5 Pro1M tokens~1800页看起来很大但实际使用中有三个约束让大窗口并不好用① 成本每次 API 调用输入 Token 都要计费。如果你每次都把 100K 的历史对话传回去费用会指数级增长。② 延迟输入 Token 越多模型处理时间越长。一个 100K Token 的请求可能比 5K Token 的请求慢 3-5 倍。③ 注意力衰减Lost in the Middle研究表明模型对上下文窗口中间位置的信息关注度最低。开头和结尾的信息记得最清楚中间的信息容易被忽略。窗口越大这个问题越严重。模型注意力分布示意 ████████░░░░░░░░░░░░░░░░████████ 窗口开头 中间注意力低 窗口结尾这意味着你不能无脑地把所有历史信息都塞进去——你需要管理上下文。二、方案一上下文窗口管理Context Engineer 的第一个任务就是在有限且昂贵的上下文窗口里装下最有价值的信息。2.1 滑动窗口简单粗暴但有效最直接的策略只保留最近 N 轮对话。defsliding_window(messages:list,max_turns:int10)-list:只保留最近的 max_turns 轮对话# 每条用户消息 助手回复 2 条消息returnmessages[-(max_turns*2):]适用场景对话式应用客服、闲聊历史信息价值随时间快速衰减。局限如果用户在第十一轮问你记得我第一轮说的那个需求吗——模型答不上来。2.2 摘要压缩用精炼代替遗忘与其丢掉旧对话不如把它们压缩成摘要。defsummarize_history(messages:list,llm_call)-str:将历史对话压缩为一段摘要history_text\n.join([f{m[role]}:{m[content]}forminmessages])promptf请将以下对话历史压缩为一段简洁的摘要保留关键信息 - 用户的基本信息姓名、角色、偏好 - 已完成的任务 - 正在进行中的任务 - 重要的决策和约定 对话历史{history_text}摘要returnllm_call(prompt)实际应用中通常采用分层摘要策略近期对话最近3轮→ 保留原文不压缩 中期对话4-10轮→ 保留摘要 远期对话10轮以上→ 只保留关键事实用户偏好、重要决策2.3 Token 预算管理把上下文当成钱来花一个成熟的 Context 管理系统会把 Token 当作预算来管理classTokenBudget:def__init__(self,max_tokens:int100000):self.max_tokensmax_tokens self.reserved_for_output4000# 预留给模型输出self.reserved_for_system2000# 预留给系统提示self.reserved_for_tools3000# 预留给工具定义propertydefavailable_for_context(self)-int:return(self.max_tokens-self.reserved_for_output-self.reserved_for_system-self.reserved_for_tools)defallocate(self,messages:list)-list:从最新到最旧填充消息直到预算用完budgetself.available_for_context selected[]formsginreversed(messages):costcount_tokens(msg)ifbudget-cost0:breakselected.insert(0,msg)budget-costreturnselected这保证了无论对话多长上下文都不会溢出且不会在单次请求中烧掉过多预算。三、方案二RAG —— 让模型遇到问题再去查3.1 RAG 解决什么问题上下文窗口管理解决的是对话历史怎么放的问题。但还有另一类信息外部知识。你的公司有 500 页的产品文档。你不可能每次都把它们全部塞进 Prompt——成本太高大部分内容也和当前问题无关。你需要的是按需检索只把相关的部分放进去。这就是 RAGRetrieval-Augmented Generation检索增强生成用户提问 → 向量检索 → 取 Top-K 相关文档 → 拼入 Prompt → 模型生成答案3.2 RAG 的核心组件一个完整的 RAG 系统包含以下组件┌─────────────────────────────────────────────────────────┐ │ RAG 系统架构 │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ │ │ 文档导入 │ → │ 文本分块 │ → │ 向量化 存储索引 │ │ │ │ (PDF/MD) │ │ (Chunking)│ │ (Embedding DB) │ │ │ └──────────┘ └──────────┘ └──────────────────┘ │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ │ │ 用户提问 │ → │ 向量检索 │ → │ Prompt 组装 │ │ │ │ │ │ (Top-K) │ │ LLM 生成 │ │ │ └──────────┘ └──────────┘ └──────────────────┘ │ └─────────────────────────────────────────────────────────┘① 文档分块Chunking把长文档切成小块。块太大 → 检索精度下降。块太小 → 语义不完整。常见策略固定大小分块每 500 Token 一块重叠 50 Token。语义分块按段落、章节自然边界切分。递归分块先用大分隔符章节标题如果块仍然太大再用小分隔符段落。fromlangchain.text_splitterimportRecursiveCharacterTextSplitter splitterRecursiveCharacterTextSplitter(chunk_size500,chunk_overlap50,separators[\n\n,\n,。,., ])chunkssplitter.split_text(document)② 向量化Embedding把文本转成向量。语义相似的文本向量距离近。fromopenaiimportOpenAI clientOpenAI()defembed(text:str)-list[float]:responseclient.embeddings.create(modeltext-embedding-3-small,inputtext)returnresponse.data[0].embedding③ 向量检索用户提问 → 向量化 → 在向量数据库中搜索最相似的 K 个文档块。importchromadb clientchromadb.Client()collectionclient.get_or_create_collection(knowledge_base)resultscollection.query(query_embeddings[embed(user_question)],n_results5)④ Prompt 组装把检索到的文档块拼入 Prompt作为参考资料context\n\n.join(results[documents][0])promptf请根据以下参考资料回答用户的问题。 如果参考资料中没有相关信息请如实说明。 参考资料{context}用户问题{user_question}回答3.3 RAG 的关键质量因素因素影响建议分块策略检索精度根据文档类型选择代码用小块文章用段落Embedding 模型语义匹配质量使用 text-embedding-3 或 bge-large 等高质量模型Top-K 选择信息充分性 vs 噪声一般 3-8 个根据文档密度调整检索后重排Rerank相关性排序用 Cross-Encoder 对 Top-K 结果重新打分四、方案三长期记忆 —— 跨会话的信息持久化4.1 对话摘要 vs 长期记忆上下文窗口管理和 RAG 解决的是本次对话内的信息管理。但还有一种需求跨会话的记忆。用户上周跟你说过他喜欢简洁风格这周你再推荐方案时应该优先推简洁的。这种记忆需要持久化存储。4.2 长期记忆的实现fromdatetimeimportdatetimeimportjsonclassLongTermMemory:def__init__(self,db):self.dbdb# 向量数据库 结构化存储defextract_memories(self,conversation:list)-list[dict]:从对话中提取值得记住的信息promptf从以下对话中提取值得长期记住的信息。对于每条信息 判断它属于哪种类型fact事实、preference偏好、decision决策。 对话{json.dumps(conversation,ensure_asciiFalse)}返回 JSON 数组每条格式 {{type: fact|preference|decision, content: ..., importance: 1-5}} responsellm_call(prompt)returnjson.loads(response)defsave_memories(self,memories:list[dict]):存入向量数据库formeminmemories:embeddingembed(mem[content])self.db.insert(embeddingembedding,metadata{type:mem[type],content:mem[content],importance:mem[importance],timestamp:datetime.now().isoformat()})defrecall(self,query:str,top_k:int5)-list[str]:根据当前话题检索相关记忆resultsself.db.search(embed(query),top_ktop_k)# 按 importance 排序高重要性的优先results.sort(keylambdax:x[metadata][importance],reverseTrue)return[r[metadata][content]forrinresults]使用时每次对话开始前检索相关记忆拼入 System Prompt每次对话结束后提取新记忆存入数据库。五、Context Engineer 的天花板Context Engineer 解决了记忆问题但新的天花板随之而来它有记忆但没有手脚。模型可以记住你喜欢简洁风格但它不能帮你把代码改成简洁风格。它可以检索到 Docker 部署文档但它不能帮你执行docker-compose up。它可以分析你的聊天记录总结出你的偏好但它不能帮你把偏好配置写进系统里。Context Engineer 的能力边界 ✅ 记住你是谁、你喜欢什么 ✅ 从知识库中检索相关信息 ✅ 基于历史对话理解上下文 ❌ 操作外部系统发邮件、调API、改数据库 ❌ 执行代码或命令 ❌ 自主发起行动它还是你问它答Context Engineer 给了 AI “记忆”但 AI 仍然只是一个博学的顾问不是一个能干的助手。要让 AI 从说变成做我们需要下一阶段的进化——Harness Engineer。总结Context Engineer 通过三大方案解决了 LLM 的失忆问题上下文窗口管理滑动窗口、摘要压缩、Token 预算在有限窗口中装下最有价值的信息。RAG检索增强生成让模型按需检索外部知识而非把所有知识塞进 Prompt。长期记忆跨会话持久化用户偏好、决策和关键事实。这些技术构成了 AI 应用的记忆层——没有它AI 永远是鱼的记忆七秒一轮回。但 Context Engineer 的局限同样清晰它只能说不能做。下一篇我们将进入 Harness Engineer 的世界——给 AI 装上手脚让它真正能干活的工具调用与 API 编排。