
LangChain Chain 与 Runnable把大模型调用串成流水线模型会调了提示词模板也会写了但真正的魔法在于——把一堆组件串起来让数据像流水线一样自动流转。这就是 LangChain 最核心的概念Chain链和 Runnable可运行接口。本文带你从一个组件一个组件手动调进化到一条管道全自动处理感受 LCEL 管道符的真正威力。一、Chain 是什么为什么需要它1.1 先看没有 Chain 的写法假设你要做一个翻译 摘要的功能——先把中文翻译成英文再对英文做摘要。没有 Chain 的话你得这么写fromlangchain.promptsimportChatPromptTemplatefromlangchain_openaiimportChatOpenAI llmChatOpenAI(modelgpt-4o-mini)# 第一步翻译translate_promptChatPromptTemplate.from_template(将以下中文翻译成英文{text})translate_messagestranslate_prompt.format_messages(textLangChain 是一个强大的大模型应用开发框架)translate_resultllm.invoke(translate_messages)# 第二步摘要需要手动拿上一步的输出当输入summary_promptChatPromptTemplate.from_template(用一句话概括以下英文内容{english_text})summary_messagessummary_prompt.format_messages(english_texttranslate_result.content)summary_resultllm.invoke(summary_messages)print(summary_result.content)每一步的输出都要手动取出来再塞进下一步的输入——两步就这样十步呢代码会变成一堆中间变量像意大利面条一样缠在一起。1.2 有了 Chain 之后同样的逻辑用 LCEL 管道符|串起来fromlangchain.promptsimportChatPromptTemplatefromlangchain_openaiimportChatOpenAIfromlangchain.schema.output_parserimportStrOutputParser llmChatOpenAI(modelgpt-4o-mini)# 定义两条独立的链translate_chain(ChatPromptTemplate.from_template(将以下中文翻译成英文{text})|llm|StrOutputParser())summary_chain(ChatPromptTemplate.from_template(用一句话概括以下英文内容{english_text})|llm|StrOutputParser())# 调用数据自动流转englishtranslate_chain.invoke({text:LangChain 是一个强大的大模型应用开发框架})summarysummary_chain.invoke({english_text:english})print(f翻译{english})print(f摘要{summary})Chain 的本质把多个组件串成一条流水线每个组件的输出自动变成下一个组件的输入。你不用再手动管数据传递只管把什么拼到什么后面。二、管道符|的魔法LCEL 深入LCELLangChain Expression Language的核心就是管道符|。它的设计灵感来自 Unix 管道——cat file | grep key | sort数据从左流到右。2.1 管道符的底层Runnable 接口所有能用|拼接的组件都实现了同一个接口Runnable。这个接口定义了统一的调用方法方法行为适用场景invoke(input)同步调用一次性返回普通脚本、调试ainvoke(input)异步调用FastAPI、异步 Web 框架stream(input)同步流式输出实时展示生成内容astream(input)异步流式输出异步 流式batch(inputs)批量处理多条数据批量翻译、批量分析2.2 一条链四种调用方式fromlangchain.promptsimportChatPromptTemplatefromlangchain_openaiimportChatOpenAIfromlangchain.schema.output_parserimportStrOutputParser promptChatPromptTemplate.from_template(给一个关于{topic}的冷笑话)llmChatOpenAI(modelgpt-4o-mini)chainprompt|llm|StrOutputParser()# 方式一invoke同步resultchain.invoke({topic:程序员})# 方式二stream流式一个字一个字往外蹦forchunkinchain.stream({topic:程序员}):print(chunk,end,flushTrue)# 方式三batch批量处理resultschain.batch([{topic:程序员},{topic:产品经理},{topic:设计师},])# 方式四ainvoke异步importasyncioasyncdefmain():resultawaitchain.ainvoke({topic:程序员})print(result)asyncio.run(main())一条链写好四种调用方式全都有。这就是 Runnable 接口的威力——你不需要为每种调用方式写不同的代码接口层帮你全搞定了。三、输出解析器让模型输出结构化默认情况下模型返回的是纯文本。但很多时候你需要的是结构化的数据——JSON、列表、字典。输出解析器就是干这个的。3.1 StrOutputParser最简单的解析器把模型输出的消息对象转换成人话字符串fromlangchain.schema.output_parserimportStrOutputParser chainprompt|llm|StrOutputParser()# 没有 StrOutputParser → 返回 AIMessage 对象# 有 StrOutputParser → 返回纯字符串resultchain.invoke({topic:Python})print(type(result))# class str3.2 JsonOutputParser让模型输出 JSONfromlangchain.promptsimportChatPromptTemplatefromlangchain_openaiimportChatOpenAIfromlangchain.schema.output_parserimportJsonOutputParserfrompydanticimportBaseModel,Field# 定义期望的数据结构classMovie(BaseModel):title:strField(description电影名称)director:strField(description导演)year:intField(description上映年份)rating:floatField(description豆瓣评分1-10分)# 创建解析器parserJsonOutputParser(pydantic_objectMovie)# 模板中注入格式说明promptChatPromptTemplate.from_messages([(system,你是一个电影数据库。请按以下JSON格式输出\n{format_instructions}),(human,介绍一下电影《肖申克的救赎》),])# 组装链chainprompt|llm|parser resultchain.invoke({format_instructions:parser.get_format_instructions(),})print(result)# {title: 肖申克的救赎, director: 弗兰克·德拉邦特, year: 1994, rating: 9.7}3.3 常用解析器一览解析器输入输出典型场景StrOutputParserAIMessagestr日常对话、文本生成JsonOutputParserAIMessagedict结构化数据提取CommaSeparatedListOutputParserAIMessagelist提取关键词列表DatetimeOutputParserAIMessagedatetime提取日期时间PydanticOutputParserAIMessagePydantic 对象复杂结构化输出四、RunnableLambda把自定义函数塞进链里有时候你想在链的中间插入一步自定义逻辑——比如对文本做预处理、过滤敏感词、记录日志。RunnableLambda可以把任何 Python 函数变成一个可拼接的组件4.1 基础用法fromlangchain.schema.runnableimportRunnableLambdafromlangchain.promptsimportChatPromptTemplatefromlangchain_openaiimportChatOpenAIfromlangchain.schema.output_parserimportStrOutputParser# 定义一个普通函数defto_uppercase(text:str)-str:returntext.upper()# 包装成 Runnableuppercase_runnableRunnableLambda(to_uppercase)# 塞进链里promptChatPromptTemplate.from_template(解释一下{topic})llmChatOpenAI(modelgpt-4o-mini)chainprompt|llm|StrOutputParser()|uppercase_runnable resultchain.invoke({topic:Python})print(result)# 全部大写输出4.2 实战给输出加个水印fromlangchain.schema.runnableimportRunnableLambdadefadd_watermark(text:str)-str:returntext\n\n---\n由 AI 生成仅供参考chainprompt|llm|StrOutputParser()|RunnableLambda(add_watermark)resultchain.invoke({topic:机器学习})# 输出末尾自动加上水印4.3 多步自定义处理fromlangchain.schema.runnableimportRunnableLambdadefremove_think_tags(text:str)-str:去掉模型的 思考过程 标签importrereturnre.sub(r思考过程.*?/思考过程,,text,flagsre.DOTALL)deftrim_whitespace(text:str)-str:returntext.strip()# 串成处理链cleanup_chain(RunnableLambda(remove_think_tags)|RunnableLambda(trim_whitespace))# 挂在主链后面full_chainprompt|llm|StrOutputParser()|cleanup_chainRunnableLambda 的本质把链外的逻辑变成链内的组件。任何 Python 函数只要输入输出类型对得上就能无缝嵌入流水线。五、RunnablePassthrough数据直通与分流RunnablePassthrough是一个看似简单但极其有用的组件——它原样传递数据不做任何修改。听起来没用它的真正威力在于数据分流和并行。5.1 基础数据直通fromlangchain.schema.runnableimportRunnablePassthrough passthroughRunnablePassthrough()resultpassthrough.invoke(hello)print(result)# hello —— 原样通过5.2 核心用法数据分流RAG 场景中最常见的模式——一个问题进来同时传给检索器和提示词模板fromlangchain.schema.runnableimportRunnablePassthrough,RunnableLambdafromlangchain.promptsimportChatPromptTemplatefromlangchain_openaiimportChatOpenAIfromlangchain.schema.output_parserimportStrOutputParser# 模拟检索器defretrieve_docs(query:str)-str:return相关文档内容LangChain 是一个 LLM 应用开发框架...# 用 RunnablePassthrough 做数据分流chain({context:RunnableLambda(retrieve_docs),# 走检索question:RunnablePassthrough(),# 原样直传}|ChatPromptTemplate.from_template(根据以下资料回答问题\n{context}\n\n问题{question})|ChatOpenAI(modelgpt-4o-mini)|StrOutputParser())resultchain.invoke(LangChain 是什么)print(result)5.3 数据流图解输入LangChain 是什么 │ ├──→ retrieve_docs() ──→ 相关文档内容... │ │ │ ├──→ {context: 相关文档..., question: LangChain 是什么} │ │ │ └──→ RunnablePassthrough() ────┘ │ ▼ 提示词模板 → 模型 → 输出RunnablePassthrough 的精髓它让你可以复制一份原始数据同时保留原始数据继续往下传。这在需要把同一份数据同时喂给多个组件时非常有用。六、RunnableParallel让多个任务同时跑有些场景下你需要同时调用多个模型或执行多个操作然后汇总结果。RunnableParallel就是做这个的——并行执行统一汇总。6.1 基础用法fromlangchain.schema.runnableimportRunnableParallel,RunnableLambdadefanalyze_sentiment(text:str)-str:return正面defextract_keywords(text:str)-str:returnPython, 框架, 大模型# 并行执行两个分析任务parallel_chainRunnableParallel(sentimentRunnableLambda(analyze_sentiment),keywordsRunnableLambda(extract_keywords),)resultparallel_chain.invoke(LangChain 是一个优秀的 Python 大模型框架)print(result)# {sentiment: 正面, keywords: Python, 框架, 大模型}6.2 实战同时调用两个模型对比结果fromlangchain.schema.runnableimportRunnableParallelfromlangchain.promptsimportChatPromptTemplatefromlangchain_openaiimportChatOpenAIfromlangchain.schema.output_parserimportStrOutputParser promptChatPromptTemplate.from_template(用一句话解释{concept})# 用两个不同的模型gpt4_chainprompt|ChatOpenAI(modelgpt-4o-mini)|StrOutputParser()qwen_chainprompt|ChatOpenAI(modelqwen-plus,base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1,api_keyyour-key)|StrOutputParser()# 并行调用compare_chainRunnableParallel(gpt4gpt4_chain,qwenqwen_chain,)resultcompare_chain.invoke({concept:递归})print(fGPT-4:{result[gpt4]})print(f通义千问:{result[qwen]})七、Chain 的调试看清每一步发生了什么链越长调试越难。LangChain 提供了几个调试利器7.1 全局调试开关importlangchain langchain.debugTrue# 开启全局调试# 之后每条链的每次调用都会打印详细的中间过程chain.invoke({topic:AI})输出会显示每一步的输入、输出、耗时等详细信息。7.2 单条链调试用 RunnableLambda 打印中间结果fromlangchain.schema.runnableimportRunnableLambdadefdebug_print(data):print(f[DEBUG] 当前数据:{data})returndata# 原样返回不影响链chain(prompt|llm|RunnableLambda(debug_print)# 插入调试节点|StrOutputParser())7.3 分步执行手动检查每一步# 链 分步执行prompt_valueprompt.invoke({topic:AI})print(f提示词:{prompt_value})llm_resultllm.invoke(prompt_value)print(f模型输出:{llm_result})finalStrOutputParser().invoke(llm_result)print(f最终结果:{final})调试技巧复杂链先分段跑通再拼成一条完整链。一段一段验证比直接调一整条链然后猜哪里出错效率高十倍。八、总结组件作用一句话管道符|拼接组件LangChain 的胶水数据自动流转Runnable 接口统一调用规范invoke/stream/batch/ainvoke四种方式全支持StrOutputParser提取文本把消息对象变成人话字符串JsonOutputParser提取 JSON让模型输出结构化数据RunnableLambda自定义函数入链任何 Python 函数秒变链内组件RunnablePassthrough数据直通复制数据、分流RAG 的标配RunnableParallel并行执行多个任务同时跑结果统一汇总Chain 的精髓就四个字组合优于继承。你不用写一个翻译摘要格式化的大类而是把三个小功能串起来——每个小功能独立可测组合起来又能完成复杂任务。这就是 LangChain 最核心的设计哲学。参考资料LangChain LCEL 官方文档LangChain Runnable 接口文档