LangChain 1.0 入门基础教程(非常详细),RAG与Ollama实战从入门到精通,收藏这一篇就够了!
1. LangChain 1.0到底是个什么东西LangChain 1.0更接近于一个数据流/工作流它解决的问题不是“怎么和模型聊天”而是一句用户输入如何可靠地经过多个步骤产出一个结果。2. LangChain 1.0的四个核心概念首先来快速对这四个概念进行简要介绍后续通过实际例子来详细探讨这些概念的作用和实操方法。2.1 RunnableRunnable是LangChain 1.0中对“输入如何变成输出”的统一抽象是一切可组合能力的最小单元。2.2 管道符 |组合的语法管道符|用来声明数据流向把多个Runnable按输入输出关系串成一条可执行的数据流。2.3 Prompt不是字符串Prompt在1.0里是一个结构化模板from langchain_core.prompts import ChatPromptTemplateprompt ChatPromptTemplate.from_template( 回答问题{question})prompt不是字符串其真实类型是ChatPromptTemplate它是一个Runnable它接收一个输入dict输出ChatMessage结构化消息。2.4 Parser把LLM输出变成“程序能用的东西”:from langchain_core.output_parsers import StrOutputParserparser StrOutputParser()3. 第一个LangChain1.0程序不涉及RAG、不涉及Agent只是“干净的数据流”。from langchain_core.prompts import ChatPromptTemplatefrom langchain_core.output_parsers import StrOutputParser# from langchain_community.llms import Ollama# 旧时代写法已经废弃from langchain_ollama import OllamaLLMprompt ChatPromptTemplate.from_template( 用一句话解释{concept})llm OllamaLLM( modelqwen2.5-coder:7b, temperature1)chain prompt | llm | StrOutputParser()print(chain.invoke({concept: LangChain 1.0是什么}))输出LangChain 1.0 是一个用于构建语言模型应用的开源框架。在执行chain.invoke({concept: LangChain 1.0是什么}时调用的是prompt ChatPromptTemplate.from_template(用一句话解释{concept})它会执行模板填充 于是用户的输入就变成了用一句话解释LangChain 1.0是什么并将其包装成聊天消息HumanMessage(content用一句话解释LangChain 1.0)。接下来看看chain prompt | llm | StrOutputParser()的数据流向。首先将prompt模板生成的HumanMessage输入llm OllamaLLM(...)这个Runnable经过llm这个Runnable得到llm输出的AIMessage比如AIMessage(contentLangChain 1.0 是一个用于构建 LLM 应用的数据流框架。)最后将AIMessage通过StrOutputParser()这个Runnable将llm输出的内容content提取出来。4. 一个chain可以设计多条并行分支from langchain_core.prompts import ChatPromptTemplatefrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.runnables import RunnablePassthrough, RunnableParallelfrom langchain_ollama import OllamaLLMprompt ChatPromptTemplate.from_template( 请用非常非常非常简短的一句话总结下面的内容{text}。)llm OllamaLLM( modelqwen2.5-coder:7b, temperature0.0)chain RunnableParallel( originalRunnablePassthrough(), summaryprompt | llm | StrOutputParser())input_text Python是一种高级编程语言由Guido van Rossum于1991年首次发布。它是一种解释型语言具有简单易学、代码可读性高、功能强大等特点。Python广泛应用于Web开发、数据分析、人工智能、科学计算等领域。result chain.invoke({text: input_text})print(result)借助RunnableParallel对于同一个输入可以同时执行多条输出路线上述第一条输出路线是RunnablePassthrough()这意味着直接把输入进行输出不做任任何处理而第二条输出路线则执行ChatPromptTemplate定义的操作。输出结果是一个字典{original: {text: Python是一种高级编程语言由Guido van Rossum于1991年首次发布。它是一种解释型语言具有简单易学、代码可读性高、功能强大等特点。Python广泛应用于Web开发、数据分析、人工智能、科学计算等领域。}, summary: Python是一种高级、解释型编程语言由Guido van Rossum在1991年创建以其简洁语法和广泛的应用领域而闻名。}二、LangChain 1.0里的RAG1. 搭建普通RAG在LangChain 1.0里RAG 一个 Retriever Runnable 一个 Prompt 一个 LLM没错Retriever也是一个Runnable。没有Agent没有循环没有工具。现在来基于FAISS搭建一个retrieverfrom langchain_community.document_loaders import TextLoaderfrom langchain_text_splitters import RecursiveCharacterTextSplitterfrom langchain_community.vectorstores import FAISSfrom langchain_ollama import OllamaEmbeddings# 加载文档loader TextLoader(rD:\MyFile\github\AgenticRag\all2markdown\不存在的知识.md, encodingutf-8)docs loader.load()# 切分splitter RecursiveCharacterTextSplitter( chunk_size200, chunk_overlap50)splits splitter.split_documents(docs)# 向量化embeddings OllamaEmbeddings(modelnomic-embed-text)vectorstore FAISS.from_documents(splits, embeddings)# 关键Retriever 是 Runnableretriever vectorstore.as_retriever(search_kwargs{k: 2})# topk2到这里为止还没LangChain的“链”只是得到了一个retriever.invoke(什么是 Runnable)# → [Document, Document]把两个Document打印出来[Document(id086d3d39-dc15-4f12-b881-a1a3ba4f0c82, metadata{source: 不存在的知识.md}, page_content逆向熵稳定区是一个假想的系统状态区间最早出现在 **“非对称热动力学草 案”** 中。\n\n在该区间内系统表现出以下反常性质\n\n1. 局部结构复杂度随时间上升 \n2. 外部观测到的整体熵值保 持不变 \n3. 微观扰动反而提升宏观稳定性 \n\nIESZ 被认为只会在以下条件同时满足时短暂出现), Document(id710437ea-86e3-43ec-a458-0c2af164992f, metadata{source: 不存在的知识.md}, page_content拟因果残影是指在系统中**因果关系被移除后仍持续存在的解释结构**。\n\n这一概念最早出现于虚构论文《因果消退后的结构记忆》中。\n\n其主要表现包括\n\n- 系统仍能生成“看似合理”的因果叙述 \n- 不同输入 会被映射到相同的解释路径 \n- 解释结果对真实因果变化不再敏感 \n\n拟因果残影被认为是解释系统中最危险的状态之一 因为它会)]现在来把Retriever真正接进Runnable数据流from langchain_core.prompts import ChatPromptTemplateprompt ChatPromptTemplate.from_template( 你是一个严谨的技术助理只能基于给定资料回答。 资料 {context} 问题 {q} )from langchain_core.runnables import RunnablePassthroughfrom langchain_core.output_parsers import StrOutputParserfrom langchain_ollama import OllamaLLMllm OllamaLLM( modelqwen2.5-coder:7b, temperature0.0)rag_chain ( { context: retriever, # question → context q: RunnablePassthrough() # question → question } | prompt | llm | StrOutputParser())resultrag_chain.invoke(什么是逆向熵稳定区)print(result)这是一次真正的RAG操作输出逆向熵稳定区是一个假想的系统状态区间最早出现在“非对称热动力学草案”中。在该区间内系统表现出以下反常性质1. 局部结构复杂度随时间上升2. 外部观测到的整体熵值保持不变3. 微观扰动反而提升宏观稳定性调用rag_chain.invoke(什么是逆向熵稳定区)时LangChain内部做的是输入: 什么是逆向熵稳定区┌───────────────┐│ context │ ← retriever(什么是逆向熵稳定区)│ question │ ← 原样传递└───────────────┘↓ 组装 prompt↓ LLM↓ 字符串输出为什么只是写了context: retriever就“自动完成了查询”因为retriever本身就是一个Runnable它接收一个字符串输入str直接开始查询然后输出对应的查询结果。查询结果作为context的valueRunnablePassthrough()直接把输入的str原样返回作为q的value然后进入到chain的下一环节prompt。上述操作没有黑箱没有agent没有循环。2. RAG的回答靠不靠谱加一个检验的逻辑不引入Agent只在上述普通RAG基础上加一条分支让RAG在回答的同时对“自己靠不靠谱”给出一个判断。注意三点不让它解释不让它发挥输出空间被硬限制构建可控系统。confidence_prompt ChatPromptTemplate.from_template( 你是一个严格的检索结果评估器。 问题 {question} 检索到的内容 {context} 请判断这些内容是否足以回答该问题 只输出以下三个标签之一 - HIGH - LOW - NONE )from langchain_core.runnables import RunnableParallelrag_with_confidence RunnableParallel( contextretriever, questionRunnablePassthrough(), confidence( { context: retriever, question: RunnablePassthrough(), } | confidence_prompt | llm | StrOutputParser() ))result rag_with_confidence.invoke(什么是逆向熵稳定区)for k, v in result.items(): print(f{k}: {v})现在这个rag_with_confidence在一次.invoke(question)时同时并行计算三条语义不同的路径。context分支输入是问题字符串什么是逆向熵稳定区执行RAG检索后输出一个“检索结果”字符串。question分支输入是问题字符串什么是逆向熵稳定区原样输出。confidence分支又嵌套了一层又检索了一次因为retriever是“纯函数节点”重用是合法的语义是清晰的。基于confidence_prompt调用llm作答。由于整体上是3条不同的执行路线因此对应3个输出如下context: [ Document(ide4c09030-6f07-47d8-a62f-80cb8e7834de, metadata{source: 不存在的知识.md}, page_content逆向熵稳定区是一个假想的系统状态区间最早出现在 **“非对称热动力学草案”** 中。\n\n在该区间内系统表现出以下反常性质\n\n1. 局部结构复杂度随时间上升 \n2. 外部观测到的整 体熵值保持不变 \n3. 微观扰动反而提升宏观稳定性 \n\nIESZ 被认为只会在以下条件同时满足时短暂出现), Document(id5102440c-84e1-430e-97b8-58ca10ca144d, metadata{source: 不存在的知识.md}, page_content拟因果残影是指在系统中**因果关系被移除后仍持续存在的解释结构**。\n\n这一概念最早出现于虚构论文《因果消退后的结构记忆》中。\n\n其主要表现包括\n\n- 系统仍能生成“看似合理”的因果叙述 \n- 不同输入会被映射到相同的解释路径 \n- 解释结果对真实因果变化不再敏感 \n\n拟因果残影被认为是解释系统中最危险的 状态之一因为它会), ...]question: 什么是逆向熵稳定区confidence: LOW3. 根据检验结果决定是否基于知识库进行回答有些问题检索不到答案或者答案与问题本身相关性不大此时RAG要学会拒绝回答或者提示风险。基于上一节的confidence输出分支设计如下规则HIGH → 允许回答LOW → 谨慎回答 / 提示不确定NONE → 直接拒答为了实现这一目的需要引入RunnableBranchfrom langchain_core.runnables import RunnableBranch它的作用是根据输入内容选择一条Runnable执行这个不是prompt判断是代码级if/else。完整代码from langchain_core.runnables import RunnableBranchfrom langchain_core.runnables import RunnableLambdaconfidence_chain ( { context: retriever, question: RunnablePassthrough(), } | confidence_prompt | llm | StrOutputParser())answer_chain ( prompt# 之前定义好的prompt直接拿来用 | llm | StrOutputParser())refuse_chain RunnableLambda( lambda _: 检索结果不足无法可靠回答该问题。)controlled_rag ( { context: retriever, q: RunnablePassthrough(), confidence: confidence_chain } | RunnableBranch( ( lambda x: x[confidence] HIGH, answer_chain ), refuse_chain ))result controlled_rag.invoke(什么是逆向熵稳定区)print(result)输出的confidence是HIGH因此选择answe_chain执行得到如下回答逆向熵稳定区Inverse Entropy Stability Zone, IESZ是一个假想的系统状态区间最早出现在 **“非对称热动力学草案”** 中。在该区间内系统表现出以下反常性质1. 局部结构复杂度随时间上升2. 外部观测到的整体熵值保持不变3. 微观扰动反而提升宏观稳定性IESZ被认为只会在以下条件同时满足时短暂出现如果把问题改成知识库里面不存在的问题那么confidence是NONE模型拒绝回答result controlled_rag.invoke(什么是PYT)输出检索结果不足无法可靠回答该问题。4. RAG一定回答但是按照风险等级confidence走不同的prompt“回答链”不是“同一个LLM换语气”而是“不同Runnable被执行”。confidence系统行为HIGH正常、完整回答LOW回答但显式声明不确定、引用原文NONE直接拒答不调用 LLM 或最小调用本质上在模拟IF/ELSE┌─ HIGH ─→ high_answer_chainquestion → 判断 ├─ LOW ─→ low_answer_chain └─ NONE ─→ none_answer_chain代码如下# 资料充分 → 正常发挥high_answer_chain ( ChatPromptTemplate.from_template( 你是一个严谨的技术助理请基于资料回答问题。 资料 {context} 问题 {question} ) | llm | StrOutputParser())# 回答 明确风险边界low_answer_chain ( ChatPromptTemplate.from_template( 你是一个谨慎的技术助理。 以下资料可能不足以完整回答问题请 - 明确指出不确定性 - 尽量引用资料原文 - 不要做超出资料的推断 资料 {context} 问题 {question} ) | llm | StrOutputParser())from langchain_core.runnables import RunnableLambda# confidenceNONE,拒绝回答none_answer_chain RunnableLambda( lambda _: 检索资料不足无法对该问题给出可靠回答。)# 根据confidence选择不同的回答链from langchain_core.runnables import RunnableBranchmulti_strategy_rag ( { context: retriever, question: RunnablePassthrough(), confidence: confidence_chain, } | RunnableBranch( ( lambda x: x[confidence] HIGH, high_answer_chain, ), ( lambda x: x[confidence] LOW, low_answer_chain, ), none_answer_chain, # 默认分支NONE ))result controlled_rag.invoke(什么是阿尔法层级漂移定律)# confidence是HIGHprint(result)# 阿尔法层级漂移定律Alpha-Stratum Drift Law最早由虚构学者 L. K. Ardent...5. 多路查询用同一个store构造两个retriever一个精准率高(k小)一个召回率高(k大)。一次embedding多次查询是比“多次embedding”更合理的默认策略。因此输入一个问题embedding成一个向量然后执行两次查询# 精准检索更严格k 小retriever_precise vectorstore.as_retriever( search_kwargs{k: 2})# 广泛检索更宽松k 大retriever_broad vectorstore.as_retriever( search_kwargs{k: 5})from langchain_core.runnables import RunnableParallelmulti_retriever RunnableParallel( preciseretriever_precise,# 精准检索 broadretriever_broad,# 广泛检索)result multi_retriever.invoke(什么是逆向熵稳定区)print( precise )for d in result[precise]: print(d.page_content)# 把文字取出来print(\n broad )for d in result[broad]: print(d.page_content)两次查询各自的输出 precise 逆向熵稳定区是一个假想的系统状态区间最早出现在 **“非对称热动力学草案”** 中。在该区间内系统表现出以下反常性质1. 局部结构复杂度随时间上升2. 外部观测到的整体熵值保持不变3. 微观扰动反而提升宏观稳定性IESZ 被认为只会在以下条件同时满足时短暂出现拟因果残影是指在系统中**因果关系被移除后仍持续存在的解释结构**。这一概念最早出现于虚构论文《因果消退后的结构记忆》中。其主要表现包括- 系统仍能生成“看似合理”的因果叙述- 不同输入会被映射到相同的解释路径- 解释结果对真实因果变化不再敏感拟因果残影被认为是解释系统中最危险的状态之一因为它会 broad 逆向熵稳定区是一个假想的系统状态区间最早出现在 **“非对称热动力学草案”** 中。在该区间内系统表现出以下反常性质1. 局部结构复杂度随时间上升2. 外部观测到的整体熵值保持不变3. 微观扰动反而提升宏观稳定性IESZ 被认为只会在以下条件同时满足时短暂出现拟因果残影是指在系统中**因果关系被移除后仍持续存在的解释结构**。这一概念最早出现于虚构论文《因果消退后的结构记忆》中。其主要表现包括- 系统仍能生成“看似合理”的因果叙述- 不同输入会被映射到相同的解释路径- 解释结果对真实因果变化不再敏感拟因果残影被认为是解释系统中最危险的状态之一因为它会这一现象常被误认为是系统噪声或随机退化但根据阿尔法层级漂移定律其本质是一种 **结构性重心转移**。阿尔法层级漂移被认为具有以下特征- 漂移方向不可预测但一旦形成即难以回退- 在早期阶段几乎无法通过表层指标检测- 与系统规模无直接线性关系---## 2. 逆向熵稳定区Inverse Entropy Stability Zone, IESZ拟因果残影被认为是解释系统中最危险的状态之一因为它会 在完全失去真实因果基础的情况下维持高度一致的叙事输出。## 1. 阿尔法层级漂移定律Alpha-Stratum Drift Law阿尔法层级漂移定律最早由虚构学者 **L. K. Ardent** 于 1974 年提出用于描述复杂系统中“隐含决策层级”随时间发生的 不可逆偏移现象。该定律指出 当一个系统的表层行为被持续优化时其未显式建模的中间决策层会逐步偏离原始设计目标形成“层级漂移”。上述输出可以抽象为{ precise: [Document, Document], broad: [Document, Document, Document, ...]}得到上述多路输出结果后因为precise和broad里可能有重复证据也可能有只在broad里出现的内容因此需要进行处理这里做三件事去重同一段内容只算一次标注来源来自precise / broad / both分组共识证据 vs 单路证据使用如下函数进行处理from collections import defaultdictdef align_evidence(results: dict): results { precise: [Document...], broad: [Document...] } bucket defaultdict(lambda: {sources: set(), content: None}) for source, docs in results.items(): for doc in docs: key doc.page_content.strip() bucket[key][content] key bucket[key][sources].add(source) aligned [] for v in bucket.values(): aligned.append({ content: v[content], sources: sorted(v[sources]) }) return aligned然后把这个函数变成Runnablefrom langchain_core.runnables import RunnableLambdaalign_chain RunnableLambda(align_evidence)接着定义chainevidence_chain ( multi_retriever | align_chain)这一步是把多路查询结果进行对齐。现在开始执行chainevidence evidence_chain.invoke(什么是逆向熵稳定区)for e in evidence: print(item:,e)输出item: {content: 逆向熵稳定区是一个假想的系统状态区间最早出现在 **“非对称热动力学草案”** 中。\n\n在该区间内系统表现出以下反常性质\n\n1. 局部结构复杂度随时间上升 \n2. 外部观测到的整体熵值保持不变 \n3. 微观扰动反而提升宏观稳定性 \n\nIESZ 被认为只会在以下条件同时满足时短暂出现, sources: [broad, precise]}item: {content: 拟因果残影是指在系统中**因果关系被移除后仍持续存在的解释结构**。\n\n这一概念最早出现于虚构论文《因果消退后的结构记忆》中。\n\n其主要表现包括\n\n- 系统仍能生成“看似合理”的因果叙述 \n- 不同输入会被映 射到相同的解释路径 \n- 解释结果对真实因果变化不再敏感 \n\n拟因果残影被认为是解释系统中最危险的状态之一因为 它会, sources: [broad, precise]}item: {content: 这一现象常被误认为是系统噪声或随机退化但根据阿尔法层级漂移定律其本质是一种 **结构性重心 转移**。\n\n阿尔法层级漂移被认为具有以下特征\n\n- 漂移方向不可预测但一旦形成即难以回退 \n- 在早期阶段几乎 无法通过表层指标检测 \n- 与系统规模无直接线性关系\n\n---\n\n## 2. 逆向熵稳定区Inverse Entropy Stability Zone, IESZ, sources: [broad]}item: {content: 拟因果残影被认为是解释系统中最危险的状态之一因为它会\n\n 在完全失去真实因果基础的情况下维持高度一致的叙事输出。, sources: [broad]}item: {content: ## 1. 阿尔法层级漂移定律Alpha-Stratum Drift Law\n\n阿尔法层级漂移定律最早由虚构学者 **L. K. Ardent** 于 1974 年提出用于描述复杂系统中“隐含决策层级”随时间发生的不可逆偏移现象。\n\n该定律指出\n\n 当一个系统的表层行为被持续优化时其未显式建模的中间决策层会逐步偏离原始设计目标形成“层级漂移”。, sources: [broad]}多路查询结果对齐完成后开启最终的回答aligned_prompt ChatPromptTemplate.from_template( 你是一个严谨的技术助理只能基于下列证据回答。 证据列表已对齐标注来源 {evidence} 请遵守 - 优先使用被多个来源支持的内容 - 如果某结论只有单一来源请明确说明不确定性 问题 {question} )final_chain ( { evidence: evidence_chain, question: RunnablePassthrough() } | aligned_prompt | llm | StrOutputParser())result final_chain.invoke(什么是逆向熵稳定区)print(result)最终的输出如下逆向熵稳定区Inverse Entropy Stability Zone, IESZ是一个假想的系统状态区间最早出现在 **“非对称热动力学草案”** 中。在该区间内系统表现出以下反常性质1. 局部结构复杂度随时间上升2. 外部观测到的整体熵值保持不变3. 微观扰动反而提升宏观稳定性IESZ 被认为只会在以下条件同时满足时短暂出现以上只是举了一个简单的案例来演示如何使用LangChain通过一次embedding后使用多路查询并对齐再执行最终查询的过程。6. 接入LightRAGLightRAG是GraphRAG的一个轻量级实现它不是Langchain 1.0的一部分但是现在我们使用Langchain 1.0调用LightRAG实现RAG查询。首先把LightRAG包装成LangChain的Retriever接口。原本的LightRAG调用接口为from typing import Optional, List, Dict, Anyimport requestsimport uuidimport timeimport osdef query_lightrag( question: str, conversation_history: Optional[List] None, mode: str mix, user_prompt: Optional[str] None, disable_cache: bool True) - Dict[str, Any]: 调用 LightRAG Web API独立函数版不依赖 config # 基础配置函数内自洽 LIGHTRAG_URL os.getenv(LIGHTRAG_URL, http://127.0.0.1:9621/query) TIMEOUT int(os.getenv(TIMEOUT, 300)) TOP_K 40 CHUNK_TOP_K 20 MAX_ENTITY_TOKENS 2048 MAX_RELATION_TOKENS 2048 MAX_TOTAL_TOKENS 12000 DEFAULT_USER_PROMPT ( 一定要遵循知识库中的内容知识库中没有就说不知道。 请结合上下文连续回答。 如果是基于前文的问题请直接承接不要重复定义。 ) # 参数整理 if conversation_history isNone: conversation_history [] base_prompt user_prompt or DEFAULT_USER_PROMPT if disable_cache: final_user_prompt ( f{base_prompt}\n f[请求ID: {uuid.uuid4().hex[:16]}, 时间: {time.time()}] ) else: final_user_prompt base_prompt payload { query: question, mode: mode, # naive / local / global / hybrid / mix only_need_context: False, only_need_prompt: False, response_type: string, top_k: TOP_K, chunk_top_k: CHUNK_TOP_K, max_entity_tokens: MAX_ENTITY_TOKENS, max_relation_tokens: MAX_RELATION_TOKENS, max_total_tokens: MAX_TOTAL_TOKENS, conversation_history: conversation_history, user_prompt: final_user_prompt, enable_rerank: True, include_references: True, include_chunk_content: False, stream: False } # HTTP 调用 try: response requests.post( LIGHTRAG_URL, jsonpayload, timeoutTIMEOUT ) response.raise_for_status() return response.json() except requests.exceptions.RequestException as e: raise RuntimeError(fLightRAG API 调用失败: {e})对其进行封装得到Runnable版本的LightRAG Retrieverfrom langchain_core.runnables import Runnableclass LightRAGRetriever(Runnable): def __init__( self, mode: str hybrid, user_prompt: Optional[str] None, ): self.mode mode self.user_prompt user_prompt def invoke(self, query: str, configNone) - str: result query_lightrag( questionquery, modeself.mode, user_promptself.user_prompt, ) return result.get(response, )简单测试lightrag_retriever LightRAGRetriever( modehybrid, user_prompt你是一个严谨的技术助理只能基于给定资料回答。,)result lightrag_retriever.invoke(什么是逆向熵稳定区)print(lightrag_retriever result:,result)输出lightrag_retriever result: 逆向熵稳定区Inverse Entropy Stability Zone, IESZ是一个假想的系统状态区间最早出现在“非对称热动力学草案”中。在该区间内系统表现出以下反常性质1. 局部结构复杂度随时间上升2. 外部观测到的整体熵值保持不变3. 微观扰动反而提升宏观稳定性。IESZ被认为只会在以下条件同时满足时短暂出现- 系统包含至少三个相互竞争的反馈回路- 任意两个回路的响应时间尺度不相等- 系统观察者无法完全访问内部状态。由于该区域无法被稳定复现它通常仅通过事后推断被“识别”。说个题外话由于使用了知识图谱LightRAG的效果比之前的普通RAG好得多。三、LangChain 1.0本地Ollma做多轮对话chatbot1. 简单记忆版同样基于LangChain的“链”搭建“对话chain”。为了能够在多轮对话中保持上下文的记忆引入一个history列表来维护记忆。from langchain_core.runnables import RunnableLambdafrom langchain_core.output_parsers import StrOutputParserfrom langchain_ollama import OllamaLLMfrom langchain_core.messages import HumanMessage, AIMessage# -------------------------------# 初始化 Ollama 本地模型# -------------------------------llm OllamaLLM( modelqwen2.5-coder:7b, temperature0.0)# -------------------------------# 定义聊天历史BaseMessage列表# -------------------------------history []# -------------------------------# 定义 Runnable把用户输入包装成 HumanMessage 并加入历史# -------------------------------wrap_input RunnableLambda( lambda x: history.append(HumanMessage(contentx)) or history)# -------------------------------# 定义管道# wrap_input - llm - StrOutputParser# -------------------------------def ai_append_str_output(messages): 调用 llm 返回 AIMessage 并加入历史 resp llm.invoke(messages) ai_msg AIMessage(contentresp) # 手动包装成 AIMessage history.append(ai_msg) return ai_msg.contentchat_chain wrap_input | RunnableLambda(ai_append_str_output) | StrOutputParser()print(开始聊天输入 exit 退出)whileTrue: user_input input(你) if user_input.strip().lower() exit: break # 调用管道 reply chat_chain.invoke(user_input) print(助手, reply)来看下这条链路chat_chain wrap_input | RunnableLambda(ai_append_str_output) | StrOutputParser()在执行链路chat_chain.invoke(user_input)的过程中做了下面的事情首先wrap_input把用户输入包装成HumanMessage并加入历史list传入下一环节。其次RunnableLambda是LangChain 1.0里最轻量的Runnable可以把任意Python函数包装成管道的一环它接收传入的消息列表messages 然后调用resp llm.invoke(messages)得到模型预测的对话输出并将其添加到历史对话list里。最后StrOutputParser()将ai_msg.content也就是当前轮次的模型预测对话进行输出。2. 混合策略版历史自动summary滑动窗口在上面的例子中当对话轮数过多时历史信息过长可能会超出LLM的最大上下文长度并且重点信息可能被淹没推理速度变慢因此可以改进为历史自动summary滑动窗口版本这个策略只保留最近的几条历史信息更久远的历史信息直接summary成一条总结信息。from langchain_core.runnables import RunnableLambdafrom langchain_core.output_parsers import StrOutputParserfrom langchain_ollama import OllamaLLMfrom langchain_core.messages import HumanMessage, AIMessage# -------------------------------# 初始化 Ollama 本地模型# -------------------------------llm OllamaLLM( modelqwen2.5-coder:7b, temperature0.0)# -------------------------------# 聊天历史# -------------------------------history []# 最大保留最近几条消息MAX_RECENT_HISTORY 10# 超过多少条触发总结SUMMARY_THRESHOLD 40# -------------------------------# 自动生成历史总结函数# -------------------------------def summarize_old_messages(old_messages): 用 llm 自动生成老历史摘要 # 拼接内容 old_text \n.join([f{msg.type}: {msg.content}for msg in old_messages]) prompt f请将以下聊天历史总结成一段简短总结保留重要信息少于100字\n{old_text} summary llm.invoke([HumanMessage(contentprompt)]) # 返回 str return AIMessage(contentf[历史总结]: {summary}) # 包装成 AIMessage# -------------------------------# 定义 RunnableLambda把用户输入加入历史 优化记忆# -------------------------------def wrap_and_optimize(user_input): # 添加用户消息 history.append(HumanMessage(contentuser_input)) # 如果历史太长生成总结替换最早部分 if len(history) SUMMARY_THRESHOLD: old_msgs history[:len(history)-MAX_RECENT_HISTORY] summary_msg summarize_old_messages(old_msgs) history[:] [summary_msg] history[-MAX_RECENT_HISTORY:] # 返回当前历史列表给 llm return historywrap_input RunnableLambda(wrap_and_optimize)# -------------------------------# 定义管道# wrap_input - llm - StrOutputParser# -------------------------------def ai_append_output(messages): print(history:,history) resp llm.invoke(messages) # 返回 str ai_msg AIMessage(contentresp) history.append(ai_msg) return ai_msg.contentchat_chain wrap_input | RunnableLambda(ai_append_output) | StrOutputParser()# -------------------------------# 聊天循环# -------------------------------print(开始聊天输入 exit 退出)whileTrue: user_input input(你) if user_input.strip().lower() exit: break reply chat_chain.invoke(user_input) print(助手, reply)此外如果需要持久化记忆可以将这些历史消息写入到本地文件。学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%免费】

相关新闻

车牌识别技术实战:透视变换矫正与字符分割全流程解析

车牌识别技术实战:透视变换矫正与字符分割全流程解析

1. 为什么你的车牌识别总是不准?先搞定“歪脖子”车牌 我做了这么多年车牌识别项目,发现新手最容易栽跟头的地方,往往不是复杂的深度学习模型,而是最基础的图像预处理。你想想,一个车牌在图像里歪着、斜着,…

2026/5/17 12:27:31 阅读更多 →
Hydrogen鼓机开发指南:从源码编译到插件开发

Hydrogen鼓机开发指南:从源码编译到插件开发

Hydrogen鼓机开发指南:从源码编译到插件开发 【免费下载链接】hydrogen The advanced drum machine for Linux, macOS, and Windows 项目地址: https://gitcode.com/gh_mirrors/hydr/hydrogen Hydrogen是一款跨平台的高级鼓机软件,支持Linux、mac…

2026/5/17 12:27:30 阅读更多 →
shellfire安全curl使用指南:保护敏感数据的最佳实践

shellfire安全curl使用指南:保护敏感数据的最佳实践

shellfire安全curl使用指南:保护敏感数据的最佳实践 【免费下载链接】shellfire A repository of namespaced, composable shell (bash, sh and dash) function libraries. Takes aware the pain of shell scripting, making it robust and reusable. Includes secu…

2026/5/17 9:40:48 阅读更多 →

最新新闻

告别复杂制图软件,okbiye AI 科研绘图线上一键生成学术标准图表

告别复杂制图软件,okbiye AI 科研绘图线上一键生成学术标准图表

okbiye-免费查重复率aigc检测/开题报告/毕业论文/智能排版/文献综述/科研绘图科研绘图 - Okbiye智能写作https://www.okbiye.com/drawing 一、科研绘图痛点直击:传统制图模式拖慢整体科研进度 对于本科生、硕博生以及一线科研从业者来说,学术图表是论文…

2026/7/2 23:57:57 阅读更多 →
JMeter SSE接口自动化测试:流式响应数据提取与断言实战

JMeter SSE接口自动化测试:流式响应数据提取与断言实战

1. 项目概述:从手动解析到自动化断言如果你做过服务端推送或者实时数据监控的接口测试,肯定对SSE(Server-Sent Events)不陌生。这玩意儿用起来简单,一个HTTP长连接,服务端就能源源不断地把数据“流”过来&a…

2026/7/2 23:53:56 阅读更多 →
MATLAB线性方程组迭代求解工具包:雅可比与高斯-赛德尔双算法实现,支持步数调节与收敛可视化

MATLAB线性方程组迭代求解工具包:雅可比与高斯-赛德尔双算法实现,支持步数调节与收敛可视化

本文还有配套的精品资源,点击获取 简介:一套开箱即用的MATLAB线性方程组迭代求解工具,内置雅可比(Jacobi)和高斯-赛德尔(Gauss-Seidel)两种经典算法。包含jacobi_fun.m、Gauss.m、Gauss2.m三…

2026/7/2 23:53:56 阅读更多 →
4-20mA电流环原理与STM32+XTR116工业级实现

4-20mA电流环原理与STM32+XTR116工业级实现

1. 4-20mA电流环的基础原理与工业应用在工业自动化领域,4-20mA电流环传输技术已有超过50年的应用历史,至今仍是过程控制中最可靠的模拟信号传输方式之一。这种传输方式的核心优势在于其抗干扰能力——电流信号在长距离传输时不会像电压信号那样容易受到线…

2026/7/2 23:53:56 阅读更多 →
JMeter从零到一:性能测试入门与实战避坑指南

JMeter从零到一:性能测试入门与实战避坑指南

1. 项目概述:为什么我们需要JMeter? 如果你是一名开发、测试或者运维,哪怕只是对网站、App后台性能有点好奇的技术爱好者,最近可能都听过一个词:压力测试。你的老板、产品经理或者客户可能会问:“咱们这个…

2026/7/2 23:51:55 阅读更多 →
JMeter性能测试实战:从脚本优化到瓶颈定位的完整指南

JMeter性能测试实战:从脚本优化到瓶颈定位的完整指南

1. 项目概述:从“能用”到“好用”的性能测试实战性能测试,听起来是个挺高大上的词,很多开发或者测试同学可能觉得,不就是用个工具发发请求,看看服务器会不会挂吗?我刚开始接触JMeter的时候也是这么想的&am…

2026/7/2 23:51:55 阅读更多 →

日新闻

周新闻

月新闻