从零开始学LangChain(四):Chains 链式调用
本系列教程将带你从零开始学习LangChain框架,构建强大的AI应用程序。
什么是链? 链(Chain)是LangChain的核心概念,它将多个操作串联起来,形成完整的工作流。
想象一下你要制作一份报告。没有链的时候,你需要手动管理每个步骤,先研究主题,然后创建大纲,写草稿,最后润色。每一步都需要单独处理,容易出错。使用链之后,你可以把这些步骤串联起来,形成清晰的工作流,每一步的输出自动成为下一步的输入,既模块化又易于维护。
链的优势主要体现在几个方面:每个环节独立,易于维护;链可以在不同场景重复使用;小链可以组合成大链;可以单独测试每个环节,方便调试。
LCEL基础:LangChain表达式语言 LCEL(LangChain Expression Language)是LangChain推荐的声明式方式,使用|操作符连接组件。
LCEL由几个核心组件构成。PromptTemplate是提示词模板,LLM/Chat Model是模型,Output Parser是输出解析器,使用|可以组合成链。
数据在链中的流转过程很清晰。输入数据先通过prompt.format()格式化提示词,生成消息对象,然后llm.invoke()调用模型,模型返回AIMessage,最后parser.parse()解析输出,得到最终结果。
创建基础链 简单的三步链 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 from langchain_openai import ChatOpenAIfrom langchain.prompts import ChatPromptTemplatefrom langchain.output_parsers import StrOutputParserllm = ChatOpenAI(model="gpt-3.5-turbo" , temperature=0.7 ) prompt = ChatPromptTemplate.from_template( "请用{style}风格解释{topic},不超过100字" ) parser = StrOutputParser() chain = prompt | llm | parser result = chain.invoke({ "style" : "幽默" , "topic" : "递归" }) print (result)
添加中间处理 使用RunnableLambda添加自定义处理步骤。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 from langchain_openai import ChatOpenAIfrom langchain.prompts import ChatPromptTemplatefrom langchain.output_parsers import StrOutputParserfrom langchain.schema.runnable import RunnableLambdadef add_prefix (text: str ) -> str : """给输出添加前缀""" return f"🤖 AI回答:\n{text} " llm = ChatOpenAI(model="gpt-3.5-turbo" ) prompt = ChatPromptTemplate.from_template("解释{topic}" ) parser = StrOutputParser() chain = ( prompt | llm | parser | RunnableLambda(add_prefix) ) result = chain.invoke({"topic" : "生成器" }) print (result)
顺序链 按顺序执行多个步骤,前一步的输出作为后一步的输入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 from langchain_openai import ChatOpenAIfrom langchain.prompts import ChatPromptTemplatefrom langchain.schema.output_parser import StrOutputParserllm = ChatOpenAI(model="gpt-3.5-turbo" , temperature=0.8 ) outline_prompt = ChatPromptTemplate.from_template( "为一部{genre}小说生成故事大纲,包含主角、冲突、结局" ) chapter_prompt = ChatPromptTemplate.from_template( "根据以下大纲写小说第一章(500字):\n\n{outline}" ) title_prompt = ChatPromptTemplate.from_template( "为以下内容生成一个吸引人的标题:\n\n{chapter}" ) outline_chain = outline_prompt | llm | StrOutputParser() chapter_chain = chapter_prompt | llm | StrOutputParser() title_chain = title_prompt | llm | StrOutputParser() story_chain = ( { "outline" : outline_prompt | llm | StrOutputParser() } | { "chapter" : chapter_prompt | llm | StrOutputParser(), "outline" : lambda x: x["outline" ] } | { "title" : title_prompt | llm | StrOutputParser(), "chapter" : lambda x: x["chapter" ] } )
并行链 同时执行多个独立的任务,提高效率。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 from langchain_openai import ChatOpenAIfrom langchain.prompts import ChatPromptTemplatefrom langchain.schema.output_parser import StrOutputParserfrom langchain.schema.runnable import RunnableParallelllm = ChatOpenAI(model="gpt-3.5-turbo" ) technical_prompt = ChatPromptTemplate.from_template( "从技术角度分析{product}的优缺点" ) business_prompt = ChatPromptTemplate.from_template( "从商业角度分析{product}的优缺点" ) user_prompt = ChatPromptTemplate.from_template( "从用户角度分析{product}的优缺点" ) analysis_chain = RunnableParallel( technical=technical_prompt | llm | StrOutputParser(), business=business_prompt | llm | StrOutputParser(), user=user_prompt | llm | StrOutputParser() ) result = analysis_chain.invoke({"product" : "ChatGPT" }) print ("=== 技术角度 ===" )print (result['technical' ])print ("\n=== 商业角度 ===" )print (result['business' ])print ("\n=== 用户角度 ===" )print (result['user' ])
还可以结合并行和顺序,先并行收集信息,再顺序生成报告。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 research_chain = RunnableParallel( market_analysis=research_prompt | llm | StrOutputParser(), tech_review=tech_prompt | llm | StrOutputParser(), user_feedback=survey_prompt | llm | StrOutputParser() ) | ( lambda x: f""" # 市场分析 {x['market_analysis' ]} # 技术评审 {x['tech_review' ]} # 用户反馈 {x['user_feedback' ]} """ ) | ( polish_prompt | llm | StrOutputParser() ) final_report = research_chain.invoke({"product" : "AI编程助手" })
条件链 根据条件选择不同的执行路径。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 from langchain_openai import ChatOpenAIfrom langchain.prompts import ChatPromptTemplatefrom langchain.schema.output_parser import StrOutputParserfrom langchain.schema.runnable import RunnableBranch, RunnableLambdallm = ChatOpenAI(model="gpt-3.5-turbo" ) code_chain = ChatPromptTemplate.from_template( "解释以下代码:\n\n{input}" ) | llm | StrOutputParser() question_chain = ChatPromptTemplate.from_template( "回答以下问题:\n\n{input}" ) | llm | StrOutputParser() creative_chain = ChatPromptTemplate.from_template( "基于以下主题创作一个小故事:\n\n{input}" ) | llm | StrOutputParser() def classify_input (inputs ): """分类输入类型""" text = inputs["input" ].lower() if "def " in text or "class " in text or "import " in text: return "code" elif "?" in text or "什么是" in text or "如何" in text: return "question" else : return "creative" branch = RunnableBranch( (lambda x: x["type" ] == "code" , code_chain), (lambda x: x["type" ] == "question" , question_chain), creative_chain ) full_chain = ( RunnableLambda(lambda x: {"input" : x, "type" : classify_input({"input" : x})}) | branch ) print ("=== 测试代码 ===" )print (full_chain.invoke("def add(a, b): return a + b" ))print ("\n=== 测试问题 ===" )print (full_chain.invoke("什么是Python?" ))print ("\n=== 测试创作 ===" )print (full_chain.invoke("未来的世界" ))
实战项目:智能文档处理流水线 创建一个完整的文档处理系统。
完整代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 from langchain_openai import ChatOpenAIfrom langchain.prompts import ChatPromptTemplatefrom langchain.schema.output_parser import StrOutputParserfrom langchain.schema.runnable import RunnableParallel, RunnablePassthroughclass DocumentPipeline : """文档处理流水线""" def __init__ (self ): self .llm = ChatOpenAI(model="gpt-3.5-turbo" , temperature=0.3 ) self .parser = StrOutputParser() def create_pipeline (self ): """创建完整的处理流水线""" summary_prompt = ChatPromptTemplate.from_template( "为以下文本生成简洁的摘要(50字以内):\n\n{text}" ) keywords_prompt = ChatPromptTemplate.from_template( "从以下文本中提取5个关键词,用逗号分隔:\n\n{text}" ) translate_prompt = ChatPromptTemplate.from_template( "将以下文本翻译成英文:\n\n{summary}" ) sentiment_prompt = ChatPromptTemplate.from_template( "分析以下文本的情感倾向(积极/中性/消极):\n\n{summary}" ) processing_step = RunnableParallel( summary=summary_prompt | self .llm | self .parser, keywords=keywords_prompt | self .llm | self .parser ) final_step = RunnablePassthrough.assign( translation=lambda x: translate_prompt.format (summary=x['summary' ]) | self .llm | self .parser, sentiment=lambda x: sentiment_prompt.format (summary=x['summary' ]) | self .llm | self .parser ) pipeline = processing_step | final_step return pipeline pipeline = DocumentPipeline() doc_chain = pipeline.create_pipeline() text = """ LangChain是一个强大的框架,用于开发由大语言模型驱动的应用程序。 它提供了标准化的接口,让开发者可以轻松切换不同的模型提供商, 并支持链式调用、工具集成、记忆管理等高级功能。 使用LangChain,可以快速构建聊天机器人、文档问答系统等AI应用。 """ result = doc_chain.invoke({"text" : text}) print ("=== 文档摘要 ===" )print (result['summary' ])print ("\n=== 关键词 ===" )print (result['keywords' ])print ("\n=== 英文翻译 ===" )print (result['translation' ])print ("\n=== 情感分析 ===" )print (result['sentiment' ])
常见错误 类型不匹配 症状是出现TypeError: expected string or bytes-like object错误。解决方案是确保每个环节的输入输出类型匹配,prompt输出ChatMessage,llm输出AIMessage,parser输出字符串。
1 2 3 4 5 6 chain = ( prompt | llm | parser )
变量名冲突 症状是出现ValueError: Duplicate key in dictionary错误。解决方案是使用不同的变量名避免冲突。
1 2 3 4 5 6 7 chain = ( { "summary" : summary_chain, "text" : lambda x: x["input" ] } )
系列导航