📌 核心结论(TL;DR)
LCEL 灵魂:LangChain 表达式语言(LCEL)通过重载管道符 |,将实现了 Runnable 协议的组件(模型、解析器等)像积木一样串联,实现优雅的链式编程。
动态切换:利用 init_chat_model 结合 configurable_fields,可以在不修改底层代码的情况下,在运行时动态切换大模型厂商(如 OpenAI 切 DeepSeek)并调整参数。
组件解耦:通过 LCEL 组装,Prompt、Model、Parser 各司其职,极大地提高了代码的复用性和可维护性。
🔍 一、 原理图解与核心概念
1. 什么是 Runnable 协议?
在 LangChain 中,能使用 | 符号连接的前提是,该组件必须实现 Runnable 协议。它规定了组件必须具备的核心能力:
-
invoke:单次同步调用。
-
batch:批量并行调用。
-
stream:流式输出(打字机效果)。
大语言模型(ChatOpenAI)、输出解析器(StrOutputParser)、甚至提示词模板(PromptTemplate)全部实现了此协议。
2. LCEL 的链式魔法
# 将模型输出直接传给字符串解析器
chain = model | parser
底层相当于调用了 RunnableSequence(first=model, last=parser)。数据像流水线一样,从上游流向下游。
💻 二、 精选核心代码片段
1. 基础链式调用(以 DeepSeek 为例)
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,实现极高的灵活性,且无需安装额外的模型集成包。
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 仓库)

⚠️ 三、 踩坑排查排雷
报错 UnicodeEncodeError: 'ascii' codec can't encode characters:httpx 默认用 ASCII 编码 HTTP 请求头。如果 API Key 里混入了中文空格、全角字符或不可见字符,就会崩溃。排查:重新复制纯 ASCII 的 Key,或在代码中使用 key.encode("ascii", errors="ignore").decode("ascii") 清洗。
报错 Unsupported model_provider='deepseek':init_chat_model 需要安装 langchain-deepseek 集成包才能识别。排查:若因 Python 版本限制无法安装,直接用 ChatOpenAI 并指定 base_url 即可完美兼容。
Connection Error 或 Timeout:如果你在国内直连 OpenAI 会报错;或者本地 Ollama 服务没有启动。排查:检查代理设置,或确保终端执行过 ollama run <model_name> 启动本地服务。
链最后输出了 AIMessage 对象而非字符串:忘了在链的最后加 StrOutputParser()。大模型原生返回的是包含元数据的 AIMessage,解析器负责提取纯文本。



