继续上篇内容。了解在解析中出现的讲多个步骤串联起来的链Chains。
概念补充
- StrOutputParser StrOutputParser() 是 LangChain 里的一个输出解析器,其主要功能是把语言模型(LLM)返回的输出转换为字符串类型。需要纯文本内容时使用。
- LCEL LCEL 是 LangChain 引入的一种新的链式调用语法,它借助 |(管道运算符)来构建链式操作。这种语法让开发者能够以更直观、简洁的方式组合不同的组件,例如提示模板、语言模型、输出解析器等。 比如不使用LCEL时创建链实例将llm与prompt串联起来为
title_chain = LLMChain(llm=llm_creative, prompt=title_prompt)
使用LCEL为
title_chain = title_prompt | llm_creative | StrOutputParser() # LCEL
- RunnablePassthrough
RunnablePassthrough可以用来传递原始输入或修改字典。RunnablePassthrough.assign() 允许你将前一个步骤的输出(或者原始输入)分配给一个新的键,或者合并到现有的字典中,从而为下一个步骤准备好输入。
多步骤串联:步骤链条Chains
使用LangChain可以将多个步骤串联起来,形成一个处理流程,也就是Chains。 这个“步骤”可以是LLM调用或其他组件串联。 最简单的链就是“提示模板 + LLM”。复杂的链可以包含多个LLM调用,或者LLM调用与工具使用等。
SimpleSequentialChain:简单顺序链
SimpleSequentialChain可以将多个子链串联起来作为简单顺序链,前一个链的输出直接作为下一个链的输入。每个子链都只有一个输入和一个输出。
场景: 步骤1 (LLM调用): 用户提供一个主题,LLM写一个关于该主题的简短故事的标题。 步骤2 (LLM调用): 将上一步生成的标题作为输入,LLM基于这个标题写一个简短的故事情节摘要。
import os
# 基础对话所需
from langchain_deepseek import ChatDeepSeek
from langchain_core.messages import SystemMessage, HumanMessage
# 提示模板
from langchain_core.prompts import ChatPromptTemplate, PromptTemplate
# 输出解析器
from langchain_core.output_parsers import StrOutputParser
# 链条
from langchain.chains import LLMChain, SimpleSequentialChain, SequentialChain
# 用于传递原始输入或修改字典
from langchain_core.runnables import RunnablePassthrough
# 环境key
os.environ["DEEPSEEK_API_KEY"] = 'sk-xxx'
def get_deepseek_key():
key = os.getenv('DEEPSEEK_API_KEY')
if key is None:
raise ValueError("DEEPSEEK_API_KEY not found in environment variables.")
return key
# --- LLM 初始化 ---
def create_deepseek_llm():
api_key = get_deepseek_key()
if not api_key:
raise ValueError("没有ds key")
return ChatDeepSeek(
model = "deepseek-chat",
temperature=1, # 低温度,更具备确定性
max_tokens=1024,
timeout=None,
max_retries=2,
api_key=api_key
)
def test_simple_sequential_chain():
print("测试简单序列链条")
# step 1:创建生成故事标题的链实例1
deepseek = create_deepseek_llm()
title_prompt = ChatPromptTemplate.from_template(
"你是一位富有想象力的作家。为一个关于“{topic}”的短篇故事写一个引人入胜的标题。"
)
title_chain = title_prompt | deepseek | StrOutputParser() # 使用LCEL
# step 2:创建基于标题写故事情节的链实例2
synopsis_prompt = ChatPromptTemplate.from_template(
"你是一位编剧。根据以下标题写一个简短的故事情节(大约100字):\n标题:{story_title}"
)
"""
SimpleSequentialChain 期望每个链只有一个输入(在第一个链中)和一个输出
它会自动将第一个链的输出传递给第二个链的输入(变量名需要匹配或自动推断)
如果前一个链的输出是字符串,且后一个链的提示模板只有一个输入变量,它会自动映射
"""
synopsis_chain = synopsis_prompt | deepseek | StrOutputParser()
"""
setp 3:在链之间传递值 使用RunnablePassthrough.assign()
"""
full_chain = RunnablePassthrough.assign(
story_title_from_llm = title_chain
) | {"story_title":lambda x: x["story_title_from_llm"],} | synopsis_chain
# step 4:运行链
topic_input = "一个能与动物对话的女孩"
try:
print(f"\n为主题“{topic_input}”生成故事:")
synopsis = full_chain.invoke({"topic":"一个能与动物对话的女孩"})
print(f"生成的故事概要: {synopsis}")
except Exception as e:
import traceback
print(f"\n生成故事失败: {e}")
traceback.print_exc()
if __name__ == '__main__':
test_simple_sequential_chain()
- 输出测试 ![[【LangChain】LangChain2-基础概念P2-链式调用Chains.png]]
SequentialChain
SequentialChain 更加灵活,它允许链中的每个子链有多个输入和输出,并且你可以明确指定如何将前一个链的输出映射到下一个链的输入。你还可以访问所有中间步骤的输出。 (多个输入/输出,可以访问中间步骤结果)