[LangChain] 学习笔记(02):LCEL 链式调用与动态模型配置实战

📌 核心结论(TL;DR)

  1. LCEL 灵魂 :LangChain 表达式语言(LCEL)通过重载管道符 |,将实现了 Runnable 协议的组件(模型、解析器等)像积木一样串联,实现优雅的链式编程。

  2. 动态切换 :利用 init_chat_model 结合 configurable_fields,可以在不修改底层代码的情况下,在运行时动态切换大模型厂商(如 OpenAI 切 DeepSeek)并调整参数。

  3. 组件解耦 :通过 LCEL 组装,Prompt、Model、Parser 各司其职,极大地提高了代码的复用性和可维护性。

🔍 一、 原理图解与核心概念

1. 什么是 Runnable 协议?

在 LangChain 中,能使用 | 符号连接的前提是,该组件必须实现 Runnable 协议。它规定了组件必须具备的核心能力:

  • invoke:单次同步调用。

  • batch:批量并行调用。

  • stream:流式输出(打字机效果)。

    大语言模型(ChatOpenAI)、输出解析器(StrOutputParser)、甚至提示词模板(PromptTemplate)全部实现了此协议。

2. LCEL 的链式魔法

python 复制代码
# 将模型输出直接传给字符串解析器
chain = model | parser 

底层相当于调用了 RunnableSequence(first=model, last=parser)。数据像流水线一样,从上游流向下游。

💻 二、 精选核心代码片段

1. 基础链式调用(以 DeepSeek 为例)

python 复制代码
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage
from langchain_core.output_parsers import StrOutputParser

model = ChatOpenAI(
    model="deepseek-chat",
    api_key="your_api_key",
    base_url="https://api.deepseek.com", # 注意:目前官方推荐使用根路径,无需 /v1
)

messages = [
    SystemMessage(content="请补全一段故事,100个字以内:"),
    HumanMessage(content="一只猫正在__?")
]

# 使用 LCEL 构建链
chain = model | StrOutputParser()
print(chain.invoke(messages))

2. 进阶:运行时动态切换模型(DeepSeek 与 Ollama 无缝切换)

通过 configurable_alternatives,实现极高的灵活性,且无需安装额外的模型集成包。

python 复制代码
from langchain_openai import ChatOpenAI
from langchain_ollama import ChatOllama
from langchain_core.messages import HumanMessage
from langchain_core.runnables import ConfigurableField

# 1. 定义默认的基础模型(云端 DeepSeek)
base_model = ChatOpenAI(
    model="deepseek-chat",
    api_key="your_deepseek_api_key",
    base_url="https://api.deepseek.com",
    temperature=0.3
)

# 2. 挂载备选模型(本地 Ollama)
model = base_model.configurable_alternatives(
    ConfigurableField(id="llm_provider"),
    default_key="deepseek",
    ollama=ChatOllama(
        model="deepseek-r1:1.5b", # 确保你本地已拉取该模型
        base_url="http://127.0.0.1:11434",
        temperature=0.3
    )
)

messages = [HumanMessage(content="请用一句话介绍你自己。")]

# ==========================================
# 场景一:使用云端 DeepSeek(默认走 default_key)
# ==========================================
print("=== 使用云端 DeepSeek ===")
result_cloud = model.invoke(messages)
print(result_cloud.content)

# ==========================================
# 场景二:动态切换到本地 Ollama
# ==========================================
print("\n=== 动态切换到本地 Ollama ===")
result_local = model.invoke(
    messages,
    config={
        "configurable": {
            "llm_provider": "ollama" # 这里指定走备选模型
        }
    }
)
print(result_local.content)

(完整的包含多轮对话与异常处理的代码已上传至 Gitee 仓库)

⚠️ 三、 踩坑排查排雷

  1. 报错 UnicodeEncodeError: 'ascii' codec can't encode characters :httpx 默认用 ASCII 编码 HTTP 请求头。如果 API Key 里混入了中文空格、全角字符或不可见字符,就会崩溃。排查 :重新复制纯 ASCII 的 Key,或在代码中使用 key.encode("ascii", errors="ignore").decode("ascii") 清洗。

  2. 报错 Unsupported model_provider='deepseek' :init_chat_model 需要安装 langchain-deepseek 集成包才能识别。排查 :若因 Python 版本限制无法安装,直接用 ChatOpenAI 并指定 base_url 即可完美兼容。

  3. Connection Error 或 Timeout :如果你在国内直连 OpenAI 会报错;或者本地 Ollama 服务没有启动。排查 :检查代理设置,或确保终端执行过 ollama run <model_name> 启动本地服务。

  4. 链最后输出了 AIMessage 对象而非字符串 :忘了在链的最后加 StrOutputParser()。大模型原生返回的是包含元数据的 AIMessage,解析器负责提取纯文本。

相关推荐
xixingzhe21 小时前
图表中同比与环比的区别:看趋势还是看变化?
开发语言·python
weixin_448119941 小时前
Datawhale Jev Cookbook 202610 笔记5
笔记
程序员梅雨1 小时前
【从零开始学习数据仓库 | 第二篇】: 拉链表 & 数仓分层
大数据·数据仓库·学习
andyweike1 小时前
Swift
开发语言·ios·swift
纪念 2291 小时前
C++算法(六)
开发语言·c++·算法
智慧光迅AINOPOL2 小时前
POF光电复合缆多业务承载原理
网络·安全·智能路由器
一木 之林2 小时前
Dify学习笔记 04 · 检索底座:Embedding、Rerank与向量数据库(第46-54集)
笔记·学习·embedding·dify
ljt27249606612 小时前
Python笔记(十一)--Numpy(一)
笔记·python·numpy
feng_you_ying_li2 小时前
linux之网络层
linux·运维·网络