LLM Cookbook学习——使用 LangChain 开发应用程序>模型链 Chains

发布时间:2026/9/1 7:16:54
LLM Cookbook学习——使用 LangChain 开发应用程序>模型链 Chains 一、为什么需要 Chain前面学习 LangChain 时我们已经接触到了LLM Prompt Output Parser Memory如果只是完成一个非常简单的任务我们可以直接用户输入 ↓ Prompt ↓ LLM ↓ Answer例如输入 大号床单套装 Prompt 描述制造“大号床单套装”的一个公司的最佳名称是什么 LLM 豪华床纺这种任务非常简单。但是实际的大模型应用通常不是“一次 Prompt 调用”就结束。例如我们希望处理一条国外用户评论法语评论 ↓ 翻译成英文 ↓ 总结评论 ↓ 识别原始语言 ↓ 根据总结生成回复 ↓ 使用原始语言回复用户这已经包含多个步骤。如果全部手写result1 llm(...) result2 llm(...) result3 llm(...) result4 llm(...)代码会越来越复杂。因此 LangChain 提出了Chain也就是把多个模型调用、Prompt、数据处理步骤按照一定逻辑连接起来。可以把 Chain 理解成AI 应用中的流水线二、什么是 ChainChain 最简单的理解Input ↓ Step 1 ↓ Step 2 ↓ Step 3 ↓ Output每一个 Step 都可以是Prompt LLM Retriever Parser 另一个 Chain Tool 自定义函数因此Chain 的核心不是“大语言模型”而是流程编排。三、本章四种 Chain本章主要介绍Chain │ ├── LLMChain │ ├── SimpleSequentialChain │ ├── SequentialChain │ └── Router Chain └── MultiPromptChain它们的关系可以简单理解为LLMChain ↓ 单个任务 SimpleSequentialChain ↓ 多个单输入单输出任务串联 SequentialChain ↓ 复杂多输入多输出任务串联 Router Chain ↓ 根据输入动态选择执行哪条链这是整章最需要掌握的结构。四、LLMChain4.1 什么是 LLMChainLLMChain是最基础的一种 Chain。它主要把Prompt LLM组合起来。即Input ↓ PromptTemplate ↓ LLM ↓ Output五、初始化语言模型教程首先导入from langchain.chat_models import ChatOpenAI from langchain.prompts import ChatPromptTemplate from langchain.chains import LLMChain然后llm ChatOpenAI( temperature0.0 )七、创建 Prompt Template定义提示prompt ChatPromptTemplate.from_template( 描述制造{product}的一个公司的最佳名称是什么? )这里{product}是一个变量。例如product 大号床单套装那么真正发送给模型的 Prompt 类似描述制造大号床单套装的一个公司的最佳名称是什么?所以PromptTemplate可以理解为固定 Prompt 动态变量八、创建 LLMChain接下来chain LLMChain( llmllm, promptprompt )这一步把Prompt LLM组合成LLMChain内部结构LLMChain │ ┌────────────┴────────────┐ │ │ Prompt LLM │ │ └────────────┬────────────┘ ↓ Output九、运行 LLMChain例如product 大号床单套装 chain.run(product)内部过程大号床单套装 ↓ 替换 {product} ↓ 完整 Prompt ↓ LLM ↓ 公司名称例如输出豪华床纺十、LLMChain 的本质因此LLMChain( llmllm, promptprompt )本质就是Input ↓ Format Prompt ↓ Call LLM ↓ Output可以近似理解成def chain(product): prompt_text prompt.format( productproduct ) result llm(prompt_text) return resultLangChain 只是把这个过程进行了标准化封装。十一、为什么一个 LLMChain 不够假设我们想实现产品 ↓ 生成公司名称 ↓ 根据公司名称生成公司介绍这里已经需要调用 LLM 两次。第一步产品 ↓ 公司名称第二步公司名称 ↓ 公司介绍这时就需要Sequential Chain十二、SimpleSequentialChainSimpleSequentialChain中文可以理解为简单顺序链。其特点是Chain 1 Output ↓ Chain 2 Input ↓ Chain 2 Output ↓ Chain 3 Input即上一条链的输出直接作为下一条链的输入。十三、创建第一个子链首先first_prompt ChatPromptTemplate.from_template( 描述制造{product}的一个公司的最好的名称是什么 )构建chain_one LLMChain( llmllm, promptfirst_prompt )它的作用product ↓ Chain 1 ↓ company_name例如大号床单套装 ↓ 优床制造公司十四、创建第二个子链第二个 Promptsecond_prompt ChatPromptTemplate.from_template( 写一个20字的描述对于下面这个公司{company_name}的 )然后chain_two LLMChain( llmllm, promptsecond_prompt )它的作用company_name ↓ Chain 2 ↓ company_description例如优床制造公司 ↓ 优床制造公司是一家专注于生产高品质床具的公司。十五、组合两个 Chain然后from langchain.chains import SimpleSequentialChain创建overall_simple_chain SimpleSequentialChain( chains[ chain_one, chain_two ], verboseTrue )结构SimpleSequentialChain │ ↓ chain_one │ 公司名称 ↓ chain_two │ ↓ 公司介绍十六、运行 SimpleSequentialChain例如product 大号床单套装 overall_simple_chain.run(product)完整过程大号床单套装 ↓ Chain 1 ↓ 优床制造公司 ↓ Chain 2 ↓ 优床制造公司是一家专注于生产高品质床具的公司。十七、verboseTrue 是什么这里verboseTrue非常适合调试。它会输出链的执行过程。例如 Entering new SimpleSequentialChain chain... 优床制造公司 优床制造公司是一家专注于生产高品质床具的公司。 Finished chain.如果verboseFalse通常只返回最终结果。因此开发阶段非常推荐verboseTrue因为可以观察每个 Chain 的输出是什么 数据有没有正确传给下一步 哪里出现了异常十八、SimpleSequentialChain 的限制它非常简单但是限制也非常明显每一步只能处理一个输入和一个输出。结构必须类似A ↓ B ↓ C ↓ D不能很方便地处理A ────────┐ │ ↓ B → C → D ↑ │ E如果后面的 Chain 同时需要原始输入 前面某一步结果 另外一个 Chain 的结果SimpleSequentialChain 就不够用了。因此需要SequentialChain十九、SequentialChainSequentialChain 是更加通用的顺序链。核心特点可以同时保存和传递多个变量。例如原始评论 Review │ ├───────────────┐ ↓ ↓ 翻译成英文 判断语言 ↓ ↓ English_Review language ↓ │ 生成 summary │ ↓ │ └───────┬───────┘ ↓ 生成最终回复 ↓ followup_message这已经不是简单的“一条直线”。而是多变量数据流二十、SequentialChain 示例任务教程实现的是用户评论 ↓ 翻译成英文 ↓ 英文评论 ↓ 进行总结同时原始评论 ↓ 判断是什么语言最后总结 原始语言 ↓ 生成对应语言的回复因此完整流程Review │ ┌────────────┴────────────┐ │ │ ↓ ↓ Chain 1 Chain 3 │ │ English_Review language │ │ ↓ │ Chain 2 │ │ │ summary │ └────────────┬────────────┘ ↓ Chain 4 ↓ followup_message这个图非常重要。二十一、第一个 Chain翻译评论first_prompt ChatPromptTemplate.from_template( 把下面的评论review翻译成英文: \n\n{Review} )构建chain_one LLMChain( llmllm, promptfirst_prompt, output_keyEnglish_Review )输入Review输出English_Review特别注意output_keyEnglish_Review二十二、output_key 的作用为什么需要output_key因为 SequentialChain 中同时存在很多数据Review English_Review summary language followup_message必须告诉 LangChain当前 Chain 输出的数据叫什么名字。因此output_keyEnglish_Review可以理解为state[English_Review] chain_one(...)这样后面的 Chain 就可以引用{English_Review}二十三、第二个 Chain总结评论Promptsecond_prompt ChatPromptTemplate.from_template( 请你用一句话来总结下面的评论review: \n\n{English_Review} )Chainchain_two LLMChain( llmllm, promptsecond_prompt, output_keysummary )数据流English_Review ↓ Chain 2 ↓ summary二十四、第三个 Chain识别语言Promptthird_prompt ChatPromptTemplate.from_template( 下面的评论review使用的什么语言:\n\n{Review} )Chainchain_three LLMChain( llmllm, promptthird_prompt, output_keylanguage )注意这里输入不是English_Review而是最初的Review所以 SequentialChain 能够保存原始输入供后面的 Chain 再次使用。二十五、第四个 Chain生成最终回复Promptfourth_prompt ChatPromptTemplate.from_template( 使用特定的语言对下面的总结写一个后续回复: \n\n总结: {summary} \n\n语言: {language} )Chainchain_four LLMChain( llmllm, promptfourth_prompt, output_keyfollowup_message )这里非常关键。Chain 4 同时依赖summary language即Chain 2 Output Chain 3 Output这就是为什么SimpleSequentialChain已经不够了。二十六、构建 SequentialChainfrom langchain.chains import SequentialChain创建overall_chain SequentialChain( chains[ chain_one, chain_two, chain_three, chain_four ], input_variables[ Review ], output_variables[ English_Review, summary, followup_message ], verboseTrue )二十七、input_variables这里input_variables[Review]表示整个 SequentialChain 最开始需要用户提供Review相当于函数def overall_chain(Review): ...二十八、output_variables这里output_variables[ English_Review, summary, followup_message ]表示整个 Chain 最后需要返回English_Review summary followup_message例如{ Review: ..., English_Review: ..., summary: ..., followup_message: ... }二十九、SequentialChain 的核心状态字典理解 SequentialChain 最好的方法是把它想象成维护了一个state {}假设最初state { Review: 法语评论 }运行 Chain 1state[English_Review] ...得到state { Review: ..., English_Review: ... }运行 Chain 2state[summary] ...现在state { Review: ..., English_Review: ..., summary: ... }运行 Chain 3state[language] French于是state { Review: ..., English_Review: ..., summary: ..., language: French }最后 Chain 4 使用summary language得到state[followup_message] ...所以SequentialChain 的本质是让多个 Chain 共享一个不断扩展的变量状态。三十、SimpleSequentialChain 和 SequentialChain 区别这是本章非常容易考察的一个知识点。对比SimpleSequentialChainSequentialChain数据流单线多变量每步输入通常一个可以多个每步输出通常一个可以多个保留中间变量较弱可以支持复杂依赖不适合适合配置复杂度低高最简单的记忆SimpleSequentialChain A → B → C → D而SequentialChain A → B ──┐ │ ↓ └→ C → D三十一、前面三种 Chain 都有一个共同特点截至目前LLMChain SimpleSequentialChain SequentialChain都有一个共同点执行路径是提前确定好的。例如Chain1 ↓ Chain2 ↓ Chain3 ↓ Chain4无论用户输入什么流程都固定。但真实系统可能不是这样。比如用户问题可能属于物理 数学 历史 计算机如果全部使用同一个 Prompt你是一个专家请回答 {question}效果通常不如物理问题 → 物理 Prompt 数学问题 → 数学 Prompt 历史问题 → 历史 Prompt 计算机问题 → 计算机 Prompt所以需要Router Chain三十二、什么是 Router ChainRouter Chain 可以理解为大模型世界中的路由器。输入Question首先判断这个问题属于哪一类然后Question │ ↓ Router │ ┌───────────┼───────────┐ │ │ │ ↓ ↓ ↓ Physics Math History Chain Chain Chain因此 Router Chain 的最大特点是运行路径不是固定的而是根据输入动态选择。三十三、Router Chain 的两个核心组成Router 系统主要包含Router Chain和Destination ChainsRouter Chain负责判断输入应该去哪里Destination Chains负责真正执行任务例如Router │ ├── Physics Chain ├── Math Chain ├── History Chain └── Computer Science Chain三十四、本章 Router 示例教程创建了四类专家物理学 数学 历史 计算机科学每个专家拥有不同 Prompt。因此整体结构Question │ ↓ LLM Router │ 判断问题属于哪个领域 │ ┌─────────────┼─────────────┐ ↓ ↓ ↓ Physics Math History Chain Chain Chain ↓ Computer Science Chain三十五、物理 Prompt例如physics_template 你是一个非常聪明的物理专家。 你擅长用一种简洁并且易于理解的方式回答问题。 当你不知道问题答案时你承认你不知道。 这是一个问题 {input} 核心就是角色设定 回答风格 约束 用户问题三十六、数学 Prompt数学 Prompt 强调把复杂问题拆成多个子问题例如复杂数学问题 ↓ 拆分 ↓ 解决子问题 ↓ 组合结果 ↓ 最终答案三十七、历史 Prompt历史 Prompt 强调历史背景 历史证据 分析 反思 评估因此同样的问题如果使用不同 Prompt模型行为也会产生明显差异。三十八、计算机 Prompt计算机 Prompt 强调算法 步骤 复杂度 问题求解 时间复杂度 空间复杂度这实际上就是给不同任务配置不同的 Expert Prompt。三十九、prompt_infos定义好多个 Prompt 后需要告诉 Router有哪些可选 Prompt 每个 Prompt 擅长什么例如prompt_infos [ { 名字: 物理学, 描述: 擅长回答关于物理学的问题, 提示模板: physics_template }, { 名字: 数学, 描述: 擅长回答数学问题, 提示模板: math_template }, { 名字: 历史, 描述: 擅长回答历史问题, 提示模板: history_template }, { 名字: 计算机科学, 描述: 擅长回答计算机科学问题, 提示模板: computerscience_template } ]四十、Router 为什么需要 description这是非常关键的一点。Router 并不是根据chain 的代码判断应该选择谁。而主要依赖name description例如物理学 擅长回答关于物理学的问题 数学 擅长回答数学问题当输入什么是黑体辐射Router 根据描述判断黑体辐射 → 物理学因此Router 的路由质量很大程度取决于 Destination Description 是否清晰。四十一、构建 Destination Chains首先创建一个字典destination_chains {}然后for p_info in prompt_infos: name p_info[名字] prompt_template p_info[提示模板] prompt ChatPromptTemplate.from_template( templateprompt_template ) chain LLMChain( llmllm, promptprompt ) destination_chains[name] chain最终destination_chains大致类似{ 物理学: physics_chain, 数学: math_chain, 历史: history_chain, 计算机科学: computer_chain }四十二、Default Chain还有一个非常重要的设计Default Chain因为用户可能问推荐几部科幻电影这既不是物理 数学 历史 计算机怎么办需要Default Chain作为兜底。四十三、创建 Default Chaindefault_prompt ChatPromptTemplate.from_template( {input} ) default_chain LLMChain( llmllm, promptdefault_prompt )也就是说如果 Router 无法匹配任何专家 ↓ Default Chain ↓ 普通 LLM 回答这是一种非常重要的软件设计思想Fallback / Graceful Degradation即无法走专业路径 ↓ 至少还有通用路径四十四、Router 本身也是一个 LLM这是这一节非常值得理解的一点。教程使用LLMRouterChain它并不是传统的if question.contains(physics):也不是关键词分类。而是Question ↓ LLM ↓ 判断属于哪个 Destination所以实际上Router本身也是一次 LLM 调用。四十五、Router 的输出Router 需要返回{ destination: ..., next_inputs: ... }其中destination表示接下来调用哪个 Chain例如物理学 数学 历史 计算机科学 DEFAULT而next_inputs表示传给目标 Chain 的输入四十六、RouterOutputParser因为 Router LLM 返回的是文本。但是程序真正需要的是{ destination: ..., next_inputs: ... }所以需要RouterOutputParser()它负责LLM Text Output ↓ Parser ↓ Structured Data例如json { destination: 物理学, next_inputs: 什么是黑体辐射 }Parser 将其转换成程序可以读取的数据。 --- # 四十七、构建 Router Chain 核心代码 python router_prompt PromptTemplate( templaterouter_template, input_variables[input], output_parserRouterOutputParser() )然后router_chain LLMRouterChain.from_llm( llm, router_prompt )整体Question ↓ Router Prompt ↓ LLM ↓ RouterOutputParser ↓ destination next_inputs四十八、MultiPromptChain最终chain MultiPromptChain( router_chainrouter_chain, destination_chainsdestination_chains, default_chaindefault_chain, verboseTrue )整体结构终于完整User Input │ ↓ Router Chain │ 判断 Destination │ ┌──────────────┼──────────────┐ │ │ │ ↓ ↓ ↓ Physics Mathematics History Chain Chain Chain │ └── Computer Science 如果无法匹配 ↓ Default Chain四十九、物理问题的执行过程输入chain.run( 什么是黑体辐射 )Router黑体辐射 ↓ 属于物理问题所以Router ↓ Physics Chain ↓ 物理专家 Prompt ↓ LLM ↓ Answer五十、数学问题输入chain.run( 22等于多少 )Router22 ↓ 数学于是Math Chain负责回答。五十一、Router Chain 的优势如果没有 Router所有问题 ↓ 同一个 Prompt ↓ LLM而有了 RouterUser Question │ ↓ Router │ ┌────────┼────────┐ ↓ ↓ ↓ Prompt A Prompt B Prompt C ↓ ↓ ↓ LLM LLM LLM优势不同任务使用不同 Prompt 不同领域使用不同策略 系统模块化 更容易维护 更容易扩展五十二、Router Chain 在真实系统中的应用例如 AI 客服用户问题 ↓ Router │ ├── 售前咨询 Chain ├── 订单查询 Chain ├── 退款 Chain ├── 技术支持 Chain └── 投诉 Chain再例如企业 AI 助手User Query ↓ Router │ ├── HR Chain ├── Finance Chain ├── IT Chain ├── Legal Chain └── General Chain五十三、四种 Chain 的完整对比Chain核心功能数据流特点使用场景LLMChainPrompt LLM单步单任务SimpleSequentialChain多个 Chain 串联一进一出简单流水线SequentialChain多 Chain 多变量多输入多输出复杂工作流Router Chain动态选择 Chain分支结构多任务系统五十四、从程序结构角度理解四种 ChainLLMChain类似def task(x): return llm(prompt(x))SimpleSequentialChain类似def workflow(x): x chain1(x) x chain2(x) x chain3(x) return xSequentialChain类似def workflow(review): english_review chain1(review) summary chain2(english_review) language chain3(review) reply chain4( summary, language ) return { english_review: english_review, summary: summary, reply: reply }Router Chain类似def router(question): category classify(question) if category physics: return physics_chain(question) elif category math: return math_chain(question) elif category history: return history_chain(question) elif category computer: return computer_chain(question) else: return default_chain(question)这四段伪代码把本章几乎所有核心内容都概括了。五十五、Chain 本质上是在构建有向图如果进一步抽象会发现Chain其实就是节点之间的数据流。比如 SequentialChainReview │ ├─────────────┐ ↓ ↓ Translate Detect Language ↓ ↓ Summary │ └──────┬──────┘ ↓ Reply可以看成Directed Graph也就是有向图。节点Prompt LLM Parser Retriever Tool Function边数据流这其实已经非常接近现代 LLM Workflow / Agent Framework 的底层思想。五十六、Chain 和普通 Python Pipeline 有什么区别有人可能会问这些东西我直接用 Python 函数串起来不就可以了吗当然可以。例如english translate(review) summary summarize(english) language detect_language(review) reply generate_reply(summary, language)完全可以实现。LangChain Chain 的价值主要是统一接口 Prompt 管理 模型调用 日志 Tracing 输入输出约定 组件组合 后续扩展所以Chain 不是 Python 做不到而是把 LLM Application Workflow 标准化。五十七、一个容易产生的误区很多初学者看到Chain会认为Chain 多次调用 ChatGPT。并不准确。更准确地说Chain 多个组件按照既定的数据依赖关系组成一个工作流。里面可以有LLM Prompt Memory Retriever Parser Tool Database Function因此LLM Chain只是 Chain 中的一种。五十八、Chain 与 Prompt Chain 的区别Prompt Chain 更强调Prompt1 ↓ LLM ↓ Prompt2 ↓ LLM而 LangChain 中的 Chain 是更加通用的抽象Component A ↓ Component B ↓ Component C例如后面的 RAGQuestion ↓ Retriever ↓ Documents ↓ Prompt ↓ LLM也可以看成一个 Chain。五十九、为什么 Chain 对复杂 LLM 应用很重要一个真正的 AI Application 往往不是Question ↓ LLM ↓ Answer而是Question ↓ Intent Classification ↓ Router ↓ Knowledge Retrieval ↓ Prompt Construction ↓ LLM ↓ Output Parser ↓ Validation ↓ Answer甚至Answer ↓ 不通过 ↓ 重新调用模型因此随着系统复杂度提高最困难的问题会逐渐从 Prompt Engineering 转向 Workflow Engineering。六十、LLM Application 的三个层次学习到这里可以把 LLM 应用分成三个层次。第一层单次 PromptPrompt ↓ LLM第二层ChainPrompt ↓ LLM ↓ Prompt ↓ LLM ↓ Parser第三层复杂 Workflow / AgentInput ↓ Router ↓ Planning ↓ Tool ↓ Retriever ↓ LLM ↓ Evaluation ↓ Replan所以 Chain 实际上是从简单 LLM 调用走向复杂 AI Agent 的重要过渡。六十一、本章最重要的变量关系SequentialChain 中一定要搞清input_variables output_key output_variablesinput_variables整个 Chain 的入口input_variables[Review]output_key某一个子 Chain 的输出名称output_keysummaryoutput_variables整个 Chain 最终返回哪些变量output_variables[ English_Review, summary, followup_message ]关系input_variables ↓ Chain ↓ output_key ↓ 成为其他 Chain 的 Input ↓ 最终部分结果进入 output_variables六十二、Router 最重要的三个概念Router 部分重点记住Router Chain Destination Chains Default Chain对应Router Chain 负责 去哪 Destination Chain 负责 干活 Default Chain 负责 没人匹配怎么办可以记成Router 调度员 Destination Chain 专家 Default Chain 全科医生六十三、本章完整知识结构LangChain Chains │ ├── LLMChain │ │ │ ├── Prompt │ └── LLM │ ├── SimpleSequentialChain │ │ │ ├── Chain 1 │ ├── Chain 2 │ └── Chain 3 │ ├── SequentialChain │ │ │ ├── input_variables │ ├── output_key │ ├── output_variables │ └── 多变量依赖 │ └── Router Chain │ ├── Router Chain │ ├── Destination Chains │ ├── Default Chain │ └── RouterOutputParser六十四、一张图理解本章第一阶段 Input ↓ Prompt ↓ LLM ↓ Output LLMChain然后升级Input ↓ Chain1 ↓ Chain2 ↓ Chain3 ↓ Output SimpleSequentialChain继续升级Input │ ┌─────┴─────┐ ↓ ↓ Chain1 Chain3 ↓ ↓ Chain2 │ └─────┬─────┘ ↓ Chain4 SequentialChain最后Input │ ↓ Router │ ┌────────┼────────┐ ↓ ↓ ↓ Chain A Chain B Chain C │ 无匹配 → Default Router Chain这就是本章的完整演进过程。六十九、最终总结本章介绍的核心并不是四个 LangChain 类而是 AI Workflow 从简单到复杂的四个阶段LLMChain ↓ 封装单个 LLM 任务 SimpleSequentialChain ↓ 线性流水线 SequentialChain ↓ 多变量数据流 Router Chain ↓ 动态分支工作流最终可以用一句话总结Chain 的本质就是把大模型应用中的多个处理步骤通过明确的数据输入输出关系连接起来。如果再进一步抽象节点 数据流 路由 LLM Workflow七十、本章思维导图模型链 Chains │ ├── 1. LLMChain │ ├── PromptTemplate │ ├── LLM │ └── Input → Prompt → LLM → Output │ ├── 2. SimpleSequentialChain │ ├── 多 Chain │ ├── 单输入单输出 │ └── A → B → C → D │ ├── 3. SequentialChain │ ├── input_variables │ ├── output_key │ ├── output_variables │ └── 多输入、多输出、多依赖 │ └── 4. Router Chain ├── Router Chain ├── Destination Chains ├── Default Chain ├── RouterOutputParser └── 根据输入动态选择执行路径