Chain 四兄弟 Memory 记忆体系让大模型告别单次思考和秒忘附 chatdoc 文档助手实战摘要本文基于某广告科技公司文档问答助手chatdoc的真实开发经验系统拆解 LangChain 四大内置链LLMChain、SequentialChain、RouterChain、TransformationChain与 Memory 记忆体系短时/长时/摘要/实体/知识图谱并给出 RAG Chain Memory 的融合架构与完整代码帮你解决大模型不能多步推理、记不住上下文两大工程难题。一、先说结论Chain 管多步推理Memory 管记忆大模型有两大硬伤单次调用不够智能复杂任务一步搞不定无状态上轮对话内容这轮就忘。LangChain 用两个核心组件解决Chain链把多次大模型调用编排成工作流用户只感知输入 → 输出Memory记忆给大模型外挂记忆系统。二者合起来就是 Agent 的内脑 外脑。某广告科技公司的业务场景运营每天要翻投放规则文档、出价策略、历史复盘报告。我们开发的 chatdoc 助手把 PDF/Excel/Word 文档变成可对话的知识库——这个品类的出价上限是多少直接问不用翻文件。这就是 RAGChain 编排 Memory对话记忆的典型组合。二、Chain 四兄弟每种链解决一类问题2.1 LLMChain最基础的积木所有高级链的地基封装提示词模板 大模型调用fromlangchain.chainsimportLLMChainfromlangchain.llmsimportOpenAIfromlangchain.promptsimportPromptTemplate llmOpenAI(temperature0)promptPromptTemplate.from_template(帮我给{product}想三个可以注册的域名)chainLLMChain(llmllm,promptprompt,verboseTrue)chain.run(AI研习社)verboseTrue能打印渲染后的 Prompt 和模型原始响应调试神器。2.2 SequentialChain让结果成为下一个任务的输入顺序链实现翻译 → 摘要 → 语言识别 → 用指定语言评论四步流水线。关键在output_key/input_key的显式传递fromlangchain.chainsimportSequentialChain# chain1: 翻译成中文chain_oneLLMChain(llmllm,promptPromptTemplate.from_template(把下面内容翻译成中文\n\n{Review}),output_keyChinese_Review)# chain2: 对中文做摘要input_key 是上一个 chain 的 output_keychain_twoLLMChain(llmllm,promptPromptTemplate.from_template(用一句话总结\n\n{Chinese_Review}),output_keyChinese_Summary)# chain3: 识别语言 → chain4: 用该语言回复略overallSequentialChain(chains[chain_one,chain_two],input_variables[Review],output_variables[Chinese_Review,Chinese_Summary],)避坑要点顺序链最常报错的就是input_key/output_key对不上——上一个链的输出变量名必须和下一个链的 Prompt 模板占位符完全一致包括大小写。2.3 RouterChain让大模型自己选路路由链是非确定性决策先定义多个下游链物理教授、数学教授大模型根据问题类型动态路由未命中走默认链。适合多领域分流的场景比如客服系统把问题分给不同业务线的机器人# 定义两个领域链物理 / 数学组装成路由表prompt_infos[{name:physics,description:擅长回答物理问题,prompt_template:你是一位物理教授\n{input}},{name:math,description:擅长回答数学问题,prompt_template:你是一位数学教授\n{input}},]# 未命中任何领域时走默认链ConversationChaindefault_chainConversationChain(llmllm,output_keytext)router_chainMultiRouteChain(router_chainLLMRouterChain.from_llm(llm,prompt_infos),destination_chains{...},default_chaindefault_chain)避坑要点路由表的描述字段是模型选路的唯一依据写清楚擅长什么、什么时候用它。描述模糊比如都写回答各种问题会导致路由乱跳这是路由链最常见的坑。2.4 TransformationChain预处理管道不算严格意义的 Chain是文本转换器比如把超长文本截取前三个段落再交给 LLM减少 token 消耗deftransform_func(inputs:dict)-dict:textinputs[text]return{output_text:\n\n.join(text.split(\n\n)[:3])}transform_chainTransformChain(input_variables[text],output_variables[output_text],transformtransform_func)三、自定义链内置链不够用时自己造四个内置链覆盖大部分场景但总有定制需求——比如按公司模板生成特定格式的文档。继承Chain基类重写_call方法即可fromlangchain.chains.baseimportChainclassWikiArticleChain(Chain):开发一个 wiki 文章生成器def__init__(self,llm,prompt):super().__init__()self.llmllm self.promptpromptpropertydefinput_keys(self):returnself.prompt.input_variablespropertydefoutput_keys(self):return[text]def_call(self,inputs):prompt_valueself.prompt.format_prompt(**inputs)responseself.llm.generate_prompt([prompt_value])return{text:response.generations[0][0].text}什么时候该写自定义链三个信号内置链的输出格式和业务模板对不上、需要嵌入私有校验逻辑、或者要复用一段固定的领域提示词。生产项目里自定义链是常态——框架给的是积木组装逻辑永远是你自己的。四、文档处理链长文档摘要的四种武器做 RAG 一定会碰到长文档摘要合同、研报、历史复盘。LangChain 提供了四种文档处理链选型是门学问链类型原理适用场景局限Stuff全部文档直接塞进 Prompt小文档4000 token文档一大就爆上下文Refine循环投喂逐步精炼中间答案上下文强关联的长文档不支持交叉引用逻辑易乱MapReduceMap 各自摘要 → Reduce 合并大文档高精度摘要计算量 O(N)成本高Map-Rank各块出答案并打分取最高分需要选最优答案的场景依赖打分可靠性fromlangchain.chains.summarizeimportload_summarize_chain# MapReduce先分块各自摘要再合并chainload_summarize_chain(llmllm,chain_typemap_reduce,verboseTrue)chain.run(docs)避坑要点官方预制链的默认提示词是英文的直接跑会输出英文摘要。中文场景务必自定义 prompt 模板并绑定input_variables这是教程能跑、上线水土不服的高频原因。选型决策矩阵生产经验版小文档 / 低延迟 → Stuff 长文档 / 强时序关联 → Refine 高精度 / 算力充足 → MapReduce 多方案择优 → Map-Rank五、chatdoc 实战RAG 全流程 检索优化真实项目 生产环境验证5.1 加载 → 切分 → 向量化 → 存储fromlangchain.document_loadersimportTextLoader,PyPDFLoaderfromlangchain.text_splitterimportCharacterTextSplitterfromlangchain.embeddings.openaiimportOpenAIEmbeddingsfromlangchain.vectorstoresimportChroma# 1. 加载支持 PDF/Excel/Word按文件类型选 LoaderdocsPyPDFLoader(投放规则.pdf).load()# 2. 切分chunk_size150chunk_overlap20text_splitterCharacterTextSplitter(chunk_size150,chunk_overlap20)textstext_splitter.split_documents(docs)# 3. 向量化 4. 存储Chroma 本地轻量vectorstoreChroma.from_documents(texts,OpenAIEmbeddings())5.2 检索优化三连MultiQuery、上下文压缩、MMR基础检索精度不够我们上了三招① 多重查询MultiQueryRetriever把一个问题交给大模型扩展成 3 个语义等价、角度不同的子问题公司名称“→这家公司叫什么名字”“请问这间公司的名称是什么”对子问题分别检索再取交集精准命中且零冗余fromlangchain.retrievers.multi_queryimportMultiQueryRetrieverfromlangchain.chat_modelsimportChatOpenAI retrieverMultiQueryRetriever.from_llm(retrievervectorstore.as_retriever(),llmChatOpenAI(temperature0))② 上下文压缩ContextualCompressionRetriever先检索出候选文本块再把问题 候选块交给压缩器自动剔除无关内容——问这家公司负债多少只保留含负债数据的句子删掉背景描述fromlangchain.retrieversimportContextualCompressionRetrieverfromlangchain.retrievers.document_compressorsimportLLMChainExtractor compression_retrieverContextualCompressionRetriever(base_compressorLLMChainExtractor.from_llm(ChatOpenAI(temperature0)),base_retrievervectorstore.as_retriever())③ MMR最大边际相关性在向量检索层平衡相关性与多样性避免重复片段刷屏。5.3 对话接口检索结果 用户问题拼成 Promptfromlangchain.chat_modelsimportChatOpenAIfromlangchain.promptsimportChatPromptTemplate system_template你是一个文档问答助手只能基于以下上下文回答 {context} 用户问题{question} 如果上下文中没有答案请明确说知识库中未找到相关信息。llmChatOpenAI(temperature0)promptChatPromptTemplate.from_template(system_template)defchat(question:str):contextcompression_retriever.get_relevant_documents(question)messagesprompt.format_messages(contextcontext,questionquestion)returnllm(messages).content避坑要点检索优化有精度-成本权衡多重查询一次触发 3 次 LLM 调用上下文压缩又加 1 次成本直接翻倍、延迟增加。生产环境用 A/B 双指标决策——高精度场景法务/财务上 MultiQueryCompression低延迟场景客服用 MMR相似度打分就够了。六、Memory 记忆体系从秒忘到记住你是谁6.1 短时记忆内存级ConversationBufferMemory存完整对话历史ConversationBufferWindowMemory(k2)只留最近 2 轮超出的删除fromlangchain.memoryimportConversationBufferMemory memoryConversationBufferMemory()memory.chat_memory.add_user_message(你好我是人类)memory.chat_memory.add_ai_message(你好有什么可以帮你)6.2 长对话处理摘要 Token 控制对话太长会撑爆上下文窗口两种方案ConversationSummaryMemory把历史对话总结成摘要只保留核心语义ConversationTokenBufferMemory按 token 数控制——超阈值自动对旧内容做摘要保留最近 K 条原始对话。6.3 长时记忆持久化把对话向量化存进 FAISS重启不丢fromlangchain.vectorstoresimportFAISSfromlangchain.embeddings.openaiimportOpenAIEmbeddings vectorstoreFAISS.from_texts(memory.buffer.split(\n),OpenAIEmbeddings())FAISS.save_local(vectorstore,test_faiss)# 下次 FAISS.load_local 加载即可6.4 实体记忆与知识图谱ConversationEntityMemory自动抽取实体清单——“胡八一和王胖子、雪莉杨经常一起冒险”记住这三个实体ConversationKGMemory构建知识图谱三元组——Tommy 最喜欢打游戏→(Tommy, likes, play_games)支撑深度关系推理。6.5 实战给 LLMChain 装上记忆含多记忆合并记忆不是独立组件得注入到链里才生效。最常见的是在 LLMChain 上挂ConversationBufferMemory模板里预留{chat_history}占位符fromlangchain.chainsimportLLMChainfromlangchain.memoryimportConversationBufferMemoryfromlangchain.promptsimportPromptTemplate template你是一个可以和人对话的机器人。 {chat_history} 人类{human_input} 机器人promptPromptTemplate(templatetemplate,input_variables[chat_history,human_input])memoryConversationBufferMemory(memory_keychat_history)chainLLMChain(llmllm,memorymemory,promptprompt,verboseTrue)进阶玩法是多记忆合并同时注入长期摘要记忆 当前对话缓存让模型既记得过去偏好又看得到眼前上下文fromlangchain.memoryimportCombinedMemory,ConversationSummaryMemory summaryConversationSummaryMemory(llmllm,input_keyinput)bufferConversationBufferMemory(memory_keyhistory_now,input_keyinput)memoryCombinedMemory(memories[summary,buffer])# 模板中同时用 {history}摘要和 {history_now}当前对话两个占位符避坑要点多记忆合并时 Prompt 变量一多就容易乱。铁律是每个 memory 一个专属占位符且 input_key 必须显式指定——否则模型会把记忆内容当成用户问题上下文互相污染。这也是生产环境最常见的隐蔽 bug。七、写在最后RAG 与 Chain 不是二选一而是互补RAG 解决外部知识注入外脑Chain 解决内部逻辑编排内脑。chatdoc 里 RAG 负责从文档检索知识Chain 负责把检索结果与用户问题编排成自然语言问答流——这就是生产级文档助手的完整形态。另外提醒一句LangChain 官方现在弱化了 Chain 概念转向 Agent 范式Chain Memory Tools。但 Memory 的地位反而升级了——它从对话状态缓存变成 Agent 的认知中枢要同时承载工具调用历史、用户偏好、领域知识。这是下一篇想展开的方向。最后给你一张选型速查表照着选就不会翻车问题模型一步答不了复杂任务 → SequentialChain 问题问题要分到不同领域专家 → RouterChain 问题长文档要高效摘要 → MapReduce / Refine 问题模型记不住对话上下文 → ConversationBufferMemory / SummaryMemory 问题要跨会话持久记忆 → FAISS / Redis 向量化存储如果你也在做 RAG 或 Agent 记忆系统欢迎评论区聊聊你的方案。下面几个方向想看哪个留言告诉我Agent 记忆系统的工程化实现长时记忆 情景记忆 记忆压缩多轮对话中 Memory 与 RAG 检索的上下文融合策略生产环境 RAG 的评估体系搭建RAGAS 实战