一、核心技术知识点梳理

1. LangChain Expression Language (LCEL) —— 大模型应用的“万能串联工具”

先举个通俗的例子:你想做一杯奶茶,需要“煮茶→加奶→加糖→摇匀”四个步骤,每个步骤都是一个“工具”,LCEL就相当于“流水线”,把这四个工具串起来,你只要放入原料(茶叶、牛奶),流水线就会自动完成所有步骤,最后得到奶茶。

对应到我们的聊天机器人,“煮茶”就是“提示词模板”,“加奶”就是“大模型”,“加糖”就是“输出解析器”,LCEL就是把这些组件串起来的“流水线”,让你不用手动一步步操作,一键得到结果。

(1)定义

LCEL是LangChain专门设计的“表达式语言”,核心就是用最简单的语法,把我们需要的各种工具(提示词、大模型、解析器等)串联起来,快速搭建复杂的AI聊天机器人,不用写大量复杂代码。

官方定义(简化版):LangChain 专属表达式语言,用极简语法串联各类组件,构建复杂大模型应用。

(2)核心作用(重中之重,结合实际场景讲)

我们的聊天机器人不能只“问一句、答一句”,比如用户让你“翻译一句话并给出回复建议”,这就需要两个步骤:先翻译,再给建议——这就是LCEL要解决的问题,核心作用有两个:

  • 级联调用:一个链的结果作为另一个链的输入(比如“翻译链”的结果,作为“建议链”的输入),实现多步骤逻辑。

  • 并行调用:多个链同时执行(比如同时把一句话翻译成中文和法语),不用等一个翻译完再翻译另一个,提升效率。

简单说:LCEL让聊天机器人能“做多件事、做好多步事”,而不是只会“单步操作”。

(3)核心语法(最简单,记死这一个就够)

核心语法就是管道符 |(键盘上“Backspace”下面的键,shift+反斜杠),和我们电脑里“复制→粘贴”的逻辑一样,也和Linux系统的管道符逻辑完全一致:前一个组件的输出 = 后一个组件的输入

举个极简例子:A | B | C,意思就是“把A的结果传给B,B处理完再传给C,最后输出C的结果”,对应到我们的代码里,就是“提示词模板 | 大模型 | 解析器”。

不用记复杂语法,只要记住:想串联组件,就用“|”把它们连起来,顺序不能乱(先提示词、再大模型、最后解析器)。

(4)核心优势(为什么要用LCEL)

如果没有LCEL,你要实现“翻译+给建议”,需要写十几行代码,判断每个步骤的结果、手动传递数据;有了LCEL,一行代码就能搞定,核心优势有4个,结合场景解释:

  • 无需编写复杂逻辑:不用手动处理“步骤衔接”“数据传递”,管道符自动帮你完成。

  • 一行代码构建复杂处理链:比如“提示词→大模型→解析器→另一个大模型→另一个解析器”,只要用“|”连起来,一行搞定。

  • 支持动态链:可以根据用户输入,自动切换不同的链(比如用户问“翻译”就走翻译链,问“总结”就走总结链),不用提前写死所有逻辑。

  • 支持流式输出、异常处理:流式输出就是“AI一边生成、一边显示”(比如ChatGPT的打字效果),异常处理就是代码出错时,不会直接崩溃,能给出提示,不用怕报错。

2. LCEL 核心组件(所有可串联的“工具”,逐个拆解)

先记住一个核心规则:所有LCEL组件都继承自Runnable(顶级父类)。什么是父类?就像所有“交通工具”(汽车、火车、飞机)都有“能运输”这个共同属性,Runnable就是所有组件的“共同模板”,只要是这个模板的“子类”(也就是我们下面讲的组件),都能用法管道符“|”串联起来。

下面逐个讲解每个组件,重点讲“是什么、做什么、怎么用”,结合后面的代码,让你一看就懂:

(1)ChatPromptTemplate —— 给AI“定规矩”的提示词模板
  • 作用:标准化AI的输入格式,告诉AI“你要做什么、怎么做”,避免每次调用AI都手动写提示词,还能动态替换参数(比如“翻译到{language}”,{language}可以灵活替换成中文、法语)。

  • 通俗理解:就像老师给学生布置作业,“把这篇英文翻译成中文,要求准确、简洁”——这句话就是“提示词模板”,AI就是学生,会按照这个“规矩”做事。

  • 常用用法:用from_messages方法创建,支持“系统提示(system)”“用户输入(user)”“助手回复(assistant)”三种角色,后面代码会详细演示。

(2)ChatOpenAI —— 对接大模型的“连接器”
  • 作用:作为LangChain和大模型(比如阿里云百炼、OpenAI)之间的“桥梁”,负责把我们的提示词发送给大模型,再把大模型的响应拿回来。

  • 通俗理解:就像你用手机给朋友发消息,手机就是“ChatOpenAI”,负责把你的消息发出去、把朋友的回复收回来;大模型就是“你的朋友”,负责处理消息、给出回复。

  • 关键参数:后面代码会详细讲,这里先记3个核心:model(用哪个大模型)、base_url(大模型的接口地址)、openai_api_key(身份验证密钥)。

(3)StrOutputParser —— 把AI的“_raw响应”变成“纯文本”的“转换器”
  • 作用:大模型返回的响应不是纯文本,而是一个“对象”(里面包含很多信息,比如响应内容、时间、状态),这个组件的作用就是“提取对象里的纯文本内容”,方便我们直接打印、使用。

  • 通俗理解:就像你收到一个快递,快递盒(对应大模型的响应对象)里有你买的东西(对应纯文本内容),StrOutputParser就是“拆开快递盒,把里面的东西拿出来”。

  • 核心功能:将大模型返回的AIMessage对象,转换为字符串(也就是提取AIMessage的content属性)。

(4)RunnableMap —— 让多个链“同时干活”的“并行工具”
  • 作用:实现“并行调用”,让多个链同时执行,不用按顺序等待,比如同时翻译中文和法语,提升效率。

  • 通俗理解:就像你同时用两个锅做饭,一个锅煮米饭、一个锅炒青菜,不用等米饭煮好再炒青菜,节省时间——RunnableMap就是“两个锅”,让两个链(煮米饭、炒青菜)同时工作。

  • 用法:用字典的形式,把要并行的链存起来,key是自定义的名称(比如“zh_translation”),value是对应的链。

(5)RunnableLambda —— 让普通Python函数“能被串联”的“适配器”
  • 作用:把我们自己写的普通Python函数,封装成LCEL的组件,这样就能用管道符“|”和其他组件串联起来(比如合并两个并行链的结果)。

  • 通俗理解:就像你有一个普通的勺子(普通Python函数),不能直接放到流水线上(LCEL链),RunnableLambda就是“给勺子装一个接口”,让它能适配流水线,和其他工具一起工作。

  • 常用场景:合并多个链的结果、对结果进行二次处理(比如拼接字符串、修改格式)。

(6)RunnableWithMessageHistory —— 让AI“记住上下文”的“记忆工具”
  • 作用:保存每一轮的聊天记录(用户的提问、AI的回复),让AI能记住之前的对话内容,实现“多轮自动聊天”(比如你问“今天天气怎么样”,再问“适合穿什么衣服”,AI能知道“你说的是今天的天气”)。

  • 通俗理解:就像你和朋友聊天,朋友会记住你之前说的话,不会你刚说过“我喜欢吃苹果”,下一秒朋友就问“你喜欢吃什么”——RunnableWithMessageHistory就是AI的“记忆”,帮它记住之前的对话。

  • 注意:这是实现多轮聊天的核心组件,后面会结合代码详细演示。

二. 核心链类型(LCEL的“实战用法”,结合代码+运行流程)

链(Chain)就是“用管道符串联起来的组件集合”,不同的串联方式,对应不同的链类型,我们结合“代码+详细解析+运行流程”,逐个讲解,每段代码都能直接复制运行,每一步都讲清楚“为什么这么写、运行时发生了什么”。

(1)基础链 —— 单步骤处理(入门必学,最基础、最常用)
① 核心定义

基础链是最简单的链,只有“单一步骤”,核心逻辑:提示词模板 → 大模型 → 输出解析器,也就是“给AI发指令 → AI处理 → 拿到纯文本结果”,适合简单场景(比如单纯翻译、单纯提问)。

② 完整代码(逐行注释+详细解析)
# -------------------------- 1. 导入所有依赖库 --------------------------
# 为什么要导入这些库?每一个都讲清楚:
# StrOutputParser:把AI返回的对象转换成纯文本(前面讲过的“拆快递盒”工具)
from langchain_core.output_parsers import StrOutputParser
# ChatPromptTemplate:创建提示词模板(给AI“定规矩”的工具)
from langchain_core.prompts import ChatPromptTemplate
# load_key:导入我们自己写的密钥加载函数(从config文件夹里拿密钥)
from config.load_key import load_key
# ChatOpenAI:对接大模型的“连接器”(给大模型发消息、收消息)
from langchain_openai import ChatOpenAI

# -------------------------- 2. 定义提示词模板 --------------------------
# from_messages:创建多角色的提示词模板(system+user,最常用的格式)
# 列表套元组,每个元组是(角色,内容),角色有3种:
# system:给AI定“身份”和“规则”,AI会一直遵守这个规则
# user:用户的输入(比如要翻译的文本、要问的问题)
# assistant:AI的回复(这里不用写,是AI生成的)
prompt_template = ChatPromptTemplate.from_messages([
    # 系统提示:告诉AI“你的任务是把英文翻译成指定语言”
    ("system", "Translate the following from English into {language}"),
    # 用户输入:{text}是动态参数,后面调用时会替换成具体的英文文本
    ("user", "{text}")
])

# -------------------------- 3. 初始化大模型客户端 --------------------------
# 这里是对接阿里云百炼大模型,每一个参数都讲透:
llm = ChatOpenAI(
    model="qwen-plus",  # 大模型名称:阿里云百炼的“通义千问增强版”,也可以用qwen-turbo(基础版)
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",  # 阿里云百炼的接口地址(固定不变)
    openai_api_key=load_key("BAILIAN_API_KEY"),  # 加载API密钥(从config/load_key.py里拿)
    temperature=0.0  # 温度参数:0=结果最稳定、不随机,1=结果最随机
)

# -------------------------- 4. 初始化输出解析器 --------------------------
# 实例化StrOutputParser,后面用来解析AI的响应
parser = StrOutputParser()

# -------------------------- 5. 用LCEL构建基础链 --------------------------
# 核心语法:管道符|,串联3个组件,顺序不能乱!
# 逻辑顺序:prompt_template(处理用户参数→生成完整提示词)→ llm(把提示词发给大模型→得到响应对象)→ parser(解析响应对象→纯文本)
chain = prompt_template | llm | parser

# -------------------------- 6. 调用链并输出结果 --------------------------
# invoke():同步调用链(最常用的调用方式)
# 传入的参数是字典,key必须和提示词模板里的{变量名}完全一致(这里是{text}和{language})
# 比如这里:text=要翻译的英文,language=中文
print("=== 基础翻译链结果 ===")
# 调用链,得到结果并打印
print(chain.invoke({"text": "nice to meet you", "language": "Chinese"}))
③ 代码调用流程+运行过程(搞懂每一步)

我们一步步拆解“调用chain.invoke(...)”后,电脑到底做了什么,就像老师一步步带你走流程:

  1. 第一步:你传入参数{"text": "nice to meet you", "language": "Chinese"},这个字典会被传给prompt_template(提示词模板);

  2. 第二步:prompt_template会替换动态参数,生成完整的提示词(相当于你手动写:“系统:把以下英文翻译成中文;用户:nice to meet you”);

  3. 第三步:管道符“|”把这个“完整提示词”传给llm(大模型客户端);

  4. 第四步:llm拿着你的API密钥,通过base_url访问阿里云百炼大模型,把完整提示词发过去;

  5. 第五步:大模型处理提示词,生成响应(这里是“很高兴认识你”),但这个响应是一个“对象”(里面包含响应内容、时间等信息);

  6. 第六步:管道符“|”把这个“响应对象”传给parser(输出解析器);

  7. 第七步:parser提取响应对象里的纯文本内容(“很高兴认识你”);

  8. 第八步:print()把这个纯文本结果打印出来,你就能看到最终的翻译结果。

运行结果预期:打印“很高兴认识你”(如果密钥配置正确,直接复制代码就能运行成功)。

(2)级联链 —— 多步骤处理(一个链的结果作为另一个链的输入)
① 核心定义

级联链就是“多个基础链串联起来”,核心逻辑:基础链1 → 基础链2 → ... → 输出结果,也就是“第一步处理的结果,作为第二步的输入”,适合复杂场景(比如“翻译+给回复建议”“总结+生成文案”)。

比如我们要做“翻译一句话,再给出5字内的回复示例”,就需要两个步骤:第一步翻译(基础链1),第二步根据翻译结果给建议(基础链2)——这就是级联链。

② 完整可代码(基于基础链,逐行注释+解析)
# -------------------------- 基于上面的基础链,构建级联链 --------------------------
# 1. 定义新的提示词模板:用于“根据翻译结果,生成5字内的回复示例”
# from_template:简化版的提示词模板(只有单角色,这里默认是user角色)
# {talk}是动态参数,后面会把“基础链chain的结果”传给这个参数
analysis_prompt = ChatPromptTemplate.from_template(
    "我应该怎么回答这句话? {talk} 。给我一个五个字以内的示例"
)

# 2. 构建级联链:核心是“把第一个链的结果,作为第二个链的输入”
# 语法解析:{"talk": chain} → 把基础链chain的输出,赋值给新提示词里的{talk}参数
# 完整逻辑:chain(翻译)→ 把翻译结果传给{talk} → analysis_prompt(生成建议提示词)→ llm(大模型处理)→ parser(解析结果)
chain2 = {"talk": chain} | analysis_prompt | llm | parser

# 3. 调用级联链并输出中间过程(新增:展示每一步的中间结果)
# 第一步:获取基础链chain的翻译结果(中间过程1)
translation_result = chain.invoke({"text": "nice to meet you", "language": "Chinese"})
print("=== 级联链中间过程1:基础链翻译结果 ===")
print(translation_result)  # 打印翻译后的文本,即传给{talk}的内容

# 第二步:查看analysis_prompt生成的完整提示词(中间过程2)
# 用format方法传入{talk}参数,模拟级联链中提示词的生成过程
complete_prompt = analysis_prompt.format(talk=translation_result)
print("\n=== 级联链中间过程2:生成的完整提示词 ===")
print(complete_prompt)  # 打印最终传给大模型的完整指令

# 第三步:调用级联链,获取最终结果(原有逻辑保留)
print("\n=== 级联链结果 ===")
final_result = chain2.invoke({"text": "nice to meet you", "language": "Chinese"})
print(final_result)

③ 代码调用流程+运行过程(重点看“结果怎么传递”)

级联链的运行过程,是在基础链的基础上,多了“结果传递”的步骤,一步步拆解:

  1. 第一步:传入参数{"text": "nice to meet you", "language": "Chinese"},首先传给chain(基础翻译链);

  2. 第二步:chain运行,得到翻译结果“很高兴认识你”(和基础链的运行过程一样);

  3. 第三步:{"talk": chain} 这一步,把chain的输出(“很高兴认识你”),赋值给analysis_prompt里的{talk}参数;

  4. 第四步:analysis_prompt生成完整提示词(“我应该怎么回答这句话? 很高兴认识你 。给我一个五个字以内的示例”);

  5. 第五步:管道符把这个完整提示词传给llm,大模型处理后,生成响应对象(比如“我也是”);

  6. 第六步:parser解析响应对象,得到纯文本“我也是”;

  7. 第七步:打印结果,完成级联链的调用。

运行结果预期:打印“我也是”“你好呀”等5字内的回复示例(大模型可能会有细微差异,都是正常的)。

关键提醒:级联链的顺序不能乱,必须是“第一个链的输出,能匹配第二个链的输入参数”(比如这里chain的输出,刚好是analysis_prompt需要的{talk})。

(3)并行链 —— 多任务同时处理(多个链同时执行,合并结果)
① 核心定义

并行链就是“多个链同时执行”,核心逻辑:多个链并行运行 → 合并结果,不用等一个链运行完再运行另一个,适合“同时处理多个同类任务”(比如同时翻译多种语言、同时生成多个版本的文案)。

比如我们要“把一句话同时翻译成中文和法语”,如果用基础链,需要先翻译中文、再翻译法语,浪费时间;用并行链,两个翻译链同时执行,最后把两个结果合并,效率翻倍。

② 完整代码(逐行注释+解析,重点看并行逻辑)
# -------------------------- 并行链+级联回复:并行翻译+各自生成回复建议 --------------------------
# 核心逻辑:并行执行两个“翻译+级联回复”的完整链,即:
# 中文翻译链 → 中文回复建议(级联)、法语翻译链 → 法语回复建议(级联),两个级联链同时执行
# 1. 导入并行执行、自定义函数相关组件(前面讲过的RunnableMap和RunnableLambda)
from langchain_core.runnables import RunnableMap, RunnableLambda

# 2. 定义翻译提示词模板(中文+法语,固定翻译目标语言)
# 中文翻译提示词模板(和基础链一致)
prompt_template_zh = ChatPromptTemplate.from_messages([
    ("system", "Translate the following from English into Chinese"),
    ("user", "{text}")
])
# 法语翻译提示词模板(和基础链一致)
prompt_template_fr = ChatPromptTemplate.from_messages([
    ("system", "Translate the following from English into French"),
    ("user", "{text}")
])

# 3. 定义级联回复的提示词模板(中文回复+法语回复,对应两个翻译结果)
# 中文回复提示词:根据中文翻译结果,生成5字内中文回复示例
prompt_zh_cascade = ChatPromptTemplate.from_template(
    "根据这句话的中文翻译,给出5字内的中文回复示例:{zh_talk}"
)
# 法语回复提示词:根据法语翻译结果,生成5字内法语回复示例(贴合法语表达习惯)
prompt_fr_cascade = ChatPromptTemplate.from_template(
    "According to the French translation, give a French reply example within 5 words: {fr_talk}"
)

# 4. 构建基础翻译链(中文+法语)
chain_zh_trans = prompt_template_zh | llm | parser  # 中文翻译链:提示词→大模型→解析器
chain_fr_trans = prompt_template_fr | llm | parser  # 法语翻译链:提示词→大模型→解析器

# 5. 构建级联链:给每个翻译链添加“回复建议”的级联逻辑(核心新增)
# 中文级联链:中文翻译 → 中文回复建议(翻译结果作为回复提示词的参数)
chain_zh_cascade = {"zh_talk": chain_zh_trans} | prompt_zh_cascade | llm | parser
# 法语级联链:法语翻译 → 法语回复建议(翻译结果作为回复提示词的参数)
chain_fr_cascade = {"fr_talk": chain_fr_trans} | prompt_fr_cascade | llm | parser

# 6. 用RunnableMap实现并行执行(并行两个级联链,核心步骤)
# 作用:让中文级联链(翻译+回复)和法语级联链(翻译+回复)同时执行,不用等待对方
parallel_cascade_chains = RunnableMap({
    "zh_translation": chain_zh_trans,       # 中文翻译结果(单独保留,方便查看)
    "zh_reply": chain_zh_cascade,          # 中文翻译对应的回复建议(级联结果)
    "fr_translation": chain_fr_trans,       # 法语翻译结果(单独保留,方便查看)
    "fr_reply": chain_fr_cascade           # 法语翻译对应的回复建议(级联结果)
})

# 7. 用RunnableLambda合并并行+级联的最终结果(整理格式,方便查看)
# x代表parallel_cascade_chains的输出(字典),包含4个key:上面定义的4个结果
final_chain = parallel_cascade_chains | RunnableLambda(
    lambda x: f"=== 并行级联最终结果 ===\n"
              f"中文翻译:{x['zh_translation']}\n"
              f"中文回复建议(5字内):{x['zh_reply']}\n"
              f"法语翻译:{x['fr_translation']}\n"
              f"法语回复建议(5字内):{x['fr_reply']}"
)

# 8. 调用并行级联链并输出详细中间过程(新增,清晰展示每一步)
# 中间过程1:单独查看两个翻译链的执行结果(模拟并行翻译的各自输出)
print("=== 中间过程1:两个翻译链单独执行结果 ===")
zh_trans_result = chain_zh_trans.invoke({"text": "nice to meet you"})
fr_trans_result = chain_fr_trans.invoke({"text": "nice to meet you"})
print(f"中文翻译结果:{zh_trans_result}")
print(f"法语翻译结果:{fr_trans_result}")

# 中间过程2:单独查看两个级联回复的执行过程(翻译→回复建议)
print("\n=== 中间过程2:两个级联回复单独执行结果 ===")
# 中文级联回复过程:先翻译,再生成回复
zh_cascade_result = chain_zh_cascade.invoke({"text": "nice to meet you"})
# 法语级联回复过程:先翻译,再生成回复
fr_cascade_result = chain_fr_cascade.invoke({"text": "nice to meet you"})
print(f"中文翻译→中文回复建议:{zh_trans_result} → {zh_cascade_result}")
print(f"法语翻译→法语回复建议:{fr_trans_result} → {fr_cascade_result}")

# 中间过程3:查看parallel_cascade_chains的输出(字典格式,包含所有并行+级联结果)
print("\n=== 中间过程3:并行级联链输出的字典结果 ===")
parallel_cascade_result = parallel_cascade_chains.invoke({"text": "nice to meet you"})
print(parallel_cascade_result)  # 格式:{"zh_translation": "...", "zh_reply": "...", "fr_translation": "...", "fr_reply": "..."}

# 中间过程4:查看合并后的最终结果(整理后,清晰直观)
print("\n=== 中间过程4:合并后的并行级联最终结果 ===")
final_result = final_chain.invoke({"text": "nice to meet you"})
print(final_result)

③ 代码调用流程+运行过程(重点看“并行”和“合并”,结合并行级联逻辑)

并行链的核心是“同时执行”,本次结合级联回复后,核心逻辑变为「并行执行两个级联链」(中文翻译→中文回复、法语翻译→法语回复),和基础链、普通级联链的“顺序执行”完全不同,一步步拆解(对应修改后代码):

  1. 第一步:传入参数{"text": "nice to meet you"},传给parallel_cascade_chains(并行级联工具);该参数会自动传递给两个级联链,无需单独给每个链传参。

  2. 第二步:parallel_cascade_chains同时启动两个级联链,互不影响、同步执行——分别是「中文级联链(chain_zh_cascade)」和「法语级联链(chain_fr_cascade)」。

  3. 第三步:两个级联链各自执行内部逻辑(每一条级联链都是“翻译→回复”的顺序): - 中文级联链:先通过chain_zh_trans(中文翻译链)得到翻译结果“很高兴认识你”,再将该结果传给回复提示词,生成5字内中文回复(如“我也是”); - 法语级联链:先通过chain_fr_trans(法语翻译链)得到翻译结果(如“enchanté de vous rencontrer”),再将该结果传给回复提示词,生成5字内法语回复(如“moi aussi”)。

  4. 第四步:parallel_cascade_chains将两个级联链的所有结果(中文翻译、中文回复、法语翻译、法语回复)整理成一个字典,格式是{"zh_translation": "很高兴认识你", "zh_reply": "我也是", "fr_translation": "enchanté de vous rencontrer", "fr_reply": "moi aussi"}

  5. 第五步:管道符把这个字典传给RunnableLambda(自定义合并函数),函数将字典中的4个结果拼接成清晰的格式,方便查看。

  6. 第六步:打印拼接后的最终结果,完成整个并行级联链的调用。

运行结果预期:打印整理后的并行级联结果,示例如下(法语翻译和回复可能有细微差异,均为正常): === 并行级联最终结果 === ``中文翻译:很高兴认识你 ``中文回复建议(5字内):我也是 ``法语翻译:enchanté de vous rencontrer ``法语回复建议(5字内):moi aussi

关键提醒:1. RunnableMap里的多个链(本次是两个级联链),必须需要相同的输入参数(这里都是{text}),否则会报错;如果参数不同,需要单独传递。2. 每个级联链的输入参数要和自身提示词模板的变量匹配(如中文级联链的{zh_talk},必须对应中文翻译链的输出)。

(4)LangGraph图形化查看链:可视化链的运行逻辑

LCEL构建的链(基础链、级联链、并行级联链),可以通过LangGraph库实现图形化可视化,直观看到组件的串联关系、运行顺序,不用再死记硬背代码逻辑,适合排查问题、梳理流程。

① 核心作用

将LCEL链的运行逻辑(组件串联、并行/顺序执行关系),以图形化的方式展示(ASCII字符图或可视化图表),清晰看到“提示词→大模型→解析器”的衔接的关系,以及并行链的同步执行逻辑,降低理解难度。

② 图形化查看步骤(完整可操作,直接复制执行)
# 第一步:安装所需依赖库(已安装可跳过,和前面必装依赖一致)
pip install langgraph grandalf

# 第二步:调用LangGraph的图形化方法,打印链的ASCII图形
# 以并行级联链final_chain为例(其他链同理,替换final_chain即可)
# print_ascii():生成ASCII字符图形,直接打印在终端,无需额外配置
print("=== 并行级联链的图形化展示(ASCII格式) ===")
final_chain.get_graph().print_ascii()

# 补充说明:如果想生成更直观的可视化图表(如PNG),可添加以下代码(可选)
# from langchain.graphs import LangGraph
# graph = LangGraph.from_chain(final_chain)
# graph.draw("chain_graph.png")  # 在项目根目录生成图表文件
③ 图形化结果说明

运行上述代码后,终端会输出一串ASCII字符组成的图形,核心对应关系如下:

  • 图形中的“节点”:对应LCEL链的各个组件(提示词模板、大模型、解析器、RunnableMap等);

  • 图形中的“箭头”:对应管道符「|」的逻辑,箭头方向=组件的执行顺序;

  • 并行链标识:RunnableMap对应的节点会显示“并行”相关标识,清晰区分顺序执行和并行执行的组件。

示例(简化版ASCII图形): ``Input -> RunnableMap (并行执行) ``RunnableMap -> ChatPromptTemplate (中文提示词) ``RunnableMap -> ChatPromptTemplate (法语提示词) ``ChatPromptTemplate (中文提示词) -> llm (大模型) ``ChatPromptTemplate (法语提示词) -> llm (大模型) ``llm (大模型) -> parser (解析器) ``parser (解析器) -> RunnableLambda (结果合并)

补充说明:LangChain的链式语法功能非常强大,除了示例中用到的组件,还可以链接向量数据库、文档加载器、工具调用等更多组件,完成更复杂的应用逻辑,后续会逐步接触到;同时也支持根据用户输入的问题,动态构建不同的链(比如用户问“翻译”走翻译链,问“总结”走总结链),无需提前写死所有逻辑。

四、代码逐行深度解析(结合新内容更新)

1. 导入模块解析(新增LangGraph相关)

  • StrOutputParser:解决「AI返回的是对象,我们需要纯文本」的问题,提取大模型响应中的核心内容,方便打印和后续使用。

  • ChatPromptTemplate:标准化对话格式,通过固定模板+动态参数,避免每次调用大模型都手动拼接提示词,提升效率且不易出错。

  • ChatOpenAI:LangChain官方封装的大模型客户端,兼容OpenAI格式接口,可无缝对接阿里云百炼等第三方大模型,负责传递提示词和接收大模型响应。

  • RunnableMap:LCEL并行执行核心组件,用于实现多个链的同步执行,将多个链的输出整理为字典格式,方便后续合并。

  • RunnableLambda:将普通Python函数转为LCEL可串联组件,核心用于对链的结果进行二次处理(如拼接并行链结果、格式化输出)。

  • langgraph:用于实现LCEL链的图形化可视化,核心提供get_graph().print_ascii()方法,将链的运行逻辑以ASCII图形展示,方便排查问题。

  • grandalf:LangGraph的依赖库,用于支撑图形化渲染,确保ASCII图形或可视化图表能正常生成。

2. 提示词模板解析

  • from_messages:支持多角色对话(system/用户/助手),是聊天机器人、多步骤链的标准格式,system角色定规则,user角色传输入,助手角色存响应(无需手动编写)。

  • {变量名}:动态参数,调用链时通过字典传入赋值,灵活适配不同需求(如基础链的{text}和{language}、级联链的{talk}),实现“一套模板复用多个场景”。

3. 大模型初始化解析

  • model:指定大模型版本,阿里云百炼支持qwen-turbo(基础版,速度快)、qwen-plus(增强版,效果好)等,可根据需求选择。

  • base_url:对接非OpenAI的第三方大模型必须配置,本文中固定为阿里云百炼的兼容接口地址,确保大模型能正常接收请求。

  • api_key:身份验证核心,必须从阿里云百炼平台获取并正确配置,否则无法调用大模型,建议通过配置文件加载(避免硬编码泄露)。

  • temperature:控制大模型响应的随机性,0=结果最稳定、不随机(适合翻译、解析等精准需求),1=结果最随机(适合创意生成),建议设0。

4. LCEL链式语法解析(新增LangGraph相关)

  • 基础链prompt | llm | parser → 线性顺序执行,一步到底,适合单步骤需求(如单纯翻译、单纯提问)。

  • 级联链{"输入名": 上一个链} | 新组件 → 多步骤逻辑,复用已有链的结果,适合“第一步处理→第二步基于结果再处理”(如翻译→生成回复示例)。

  • 并行级联链RunnableMap({键: 链1, 键: 链2}) | 合并组件 → 多个级联链同步执行,互不等待,提升效率,适合多任务同时处理(如同时翻译两种语言+生成对应回复)。

  • 链的图形化chain.get_graph().print_ascii() → 无需额外复杂配置,直接打印链的ASCII图形,直观展示组件串联关系和执行顺序,适合梳理逻辑、排查错误。

5. 调用方法解析

  • invoke():同步调用,适合短文本、简单任务,调用时传入字典参数,键名必须和提示词中的{变量名}完全一致,否则会报错。

  • get_graph().print_ascii():LangGraph的核心调用方法,用于图形化展示链的逻辑,可作用于任何LCEL链(基础链、级联链、并行链等),直接调用即可生成图形。


五、核心概念拓展(结合新内容更新)

  1. Runnable顶级父类:LangChain所有可串联的组件(提示词模板、大模型、解析器、自定义函数、LangGraph相关组件)都继承自Runnable,这是LCEL能实现链式调用、组件自由串联的底层核心,只要是Runnable子类,都能用法管道符「|」串联。

  2. 动态链构建:LCEL支持根据用户输入动态生成不同的链,无需提前写死所有逻辑,比如用户问“翻译”就走翻译链,问“总结”就走总结链,灵活适配不同场景,降低代码冗余。

  3. LangGraph图形化核心:LangGraph是LCEL链的可视化工具,核心作用是将“抽象的链式逻辑”转化为“直观的图形”,无需掌握复杂的可视化语法,通过简单调用print_ascii()就能查看链的组件关系、执行顺序,大幅降低对复杂链的理解难度,同时便于排查组件串联错误。

  4. 复杂应用扩展:LCEL的扩展性极强,除了示例中用到的“提示词+大模型+解析器”基础组件,还可以链接向量数据库、文档加载器、工具调用等更多组件,构建能查资料、算数据、处理文档的全能大模型应用,后续会逐步深入讲解。

  5. 并行链核心注意点:RunnableMap中并行执行的多个链,必须拥有相同的输入参数(如本文中的{text}),否则会因输入不匹配报错;若不同链需要不同参数,需单独为每个链传递对应参数。


六、章节总结

  1. LCEL核心:以「|」管道符为核心,串联所有Runnable组件,无需编写复杂的衔接逻辑,就能快速构建大模型处理链,核心优势是简洁、高效、可扩展。

  2. 三种核心链类型:基础链(单步骤,适合简单需求如翻译)、级联链(多步骤,复用前一个链的结果如翻译→生成回复)、并行级联链(多任务同步执行,提升效率如同时翻译两种语言+生成回复)。

  3. 必备组件与工具:核心组件包括提示词模板(ChatPromptTemplate)、大模型客户端(ChatOpenAI)、输出解析器(StrOutputParser);辅助工具包括RunnableMap(并行)、RunnableLambda(结果处理)、LangGraph(图形化可视化)。

  4. LangGraph核心价值:通过简单调用,将抽象的链式逻辑转化为直观的ASCII图形,帮助快速梳理组件关系、排查错误,降低复杂链的理解和调试难度。

  5. 进阶方向:熟练掌握三种链的使用和LangGraph图形化调试,后续可学习链接向量数据库、工具调用等组件,构建更复杂的大模型应用,同时掌握动态链构建,实现更灵活的场景适配。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐