入主城堡:LangChain 核心架构与快速上手
经过前面六篇文章的铺垫,你已经在 AI 新世界的门口徘徊了足够久。你知道了模型能做什么,弄清了它快与慢的脾气,还亲手把文字变成了向量。而承载这一切操作的那只“幕后黑手”——LangChain,至今只在我们耳边若隐若现地出现。
今天,我们不绕弯子,直接推开 LangChain 城堡的大门,走进去一探究竟。你会弄明白它的核心架构长什么样,然后亲手在城堡里组装第一件“法器”:一条真正的链。
一、LangChain 的设计哲学:一切皆组件,一切皆可组合
1.1 一个熟悉的失落感
回想一下你写原生 Python 项目时的习惯。你会把代码拆成函数、类、模块,每个部分职责清晰,然后用简单的调用把它们组合起来。逻辑清晰,代码复用性极高。
但到了 LLM 应用的早期阶段,很多人却被“打回原形”——为了让模型完成某个任务,他们不得不在一个巨大的脚本里拼字符串、手动管理消息数组、写一堆if...else来分支处理。这种体验,就像回到了没有标准库的原始时代。
1.2 LangChain 的回答:用乐高式组件,拼出复杂应用
LangChain 的核心理念,就是把与 LLM 交互的每一个环节都抽象成一个可替换、可组合的组件。提示词、模型、输出解析器、对话记忆、工具……每一样都是一块乐高积木。
这些积木有一个统一的设计:它们都实现了Runnable 接口。只要是一个 Runnable,你就可以:
- 用
invoke同步调用它 - 用
ainvoke异步调用它 - 用
batch批量调用它 - 用
stream流式调用它 - 用管道符号
|把它和另一个 Runnable 串起来
这种统一性,就是 LangChain 的“内功心法”。当你掌握了 Runnable 的规则,你就掌握了整个框架的使用之道。
1.3 城堡地图:六大核心模块
在深入代码之前,先给你一张 LangChain 的模块地图。可以把它们想象成城堡里的六个核心功能厅:
| 模块 | 职责 | 生活化比喻 |
|---|---|---|
| Model I/O | 统一管理模型调用、提示词模板、输出解析器 | 城堡的“通信厅” |
| Retrieval | 文档加载、文本拆分、嵌入、向量数据库 | 城堡的“图书馆” |
| Chains | 将多个组件编排为流水线 | 城堡的“自动化流水线车间” |
| Memory | 管理对话历史,让模型记住上下文 | 城堡的“记忆礼堂” |
| Agents | 让模型自主决策,选用工具,规划步骤 | 城堡的“战略指挥中心” |
| Callbacks | 监听和记录应用运行时的各种事件 | 城堡的“监控室” |
这六个模块各司其职,又通过 Runnable 接口无缝连接。接下来的系列文章,我们会逐一深入这些大厅。而今天,我们将首先走进通信厅和流水线车间——用模型、提示词模板和解析器,拼出第一条链。
二、快速上手:安装与环境就绪
2.1 安装核心包
在开始之前,请确保你的 Python 版本在 3.9 以上。然后打开终端,执行以下命令:
pipinstalllangchain langchain-deepseek langchain-core这三个包分别代表:
langchain:框架核心,包含链、代理、记忆等所有高级抽象。langchain-deepseek:DeepSeek 模型的 LangChain 集成,让我们可以用国产模型。langchain-core:最底层的核心抽象,包含我们接下来要用的消息类型、Runnable 接口等。
2.2 准备好你的 DeepSeek API Key
和之前一样,请确保DEEPSEEK_API_KEY环境变量已经设置好:
exportDEEPSEEK_API_KEY="sk-你的密钥"如果你还没有密钥,去 DeepSeek 开放平台 免费注册一个即可。新用户通常有赠送额度,足够你跑完本系列所有示例。
三、从“单品”到“链条”:直觉感受 LCEL
在 LangChain 中,有两种主要的应用组装方式:
- 旧式 Chain 类:通过继承和特定的类构造(如
LLMChain),在 LangChain 早期版本中广泛使用。 - LCEL(LangChain Expression Language):新一代的声明式组装语言,使用管道符
|将组件串联,代码更简洁、类型推断更强、流式和异步支持更原生。
我们整个系列都将使用 LCEL 作为主力组装方式。它是一种表达链的“DSL”——不借助任何魔法,只是 Python 的|运算符重载。你很快会爱上它的简洁。
我们先来感受一下 LCEL 的语法。假设有三个处理步骤:
输入 → 步骤A → 步骤B → 步骤C → 输出用 LCEL 写出来就是:
chain=step_a|step_b|step_c result=chain.invoke(input_data)是不是像写 Unix 管道一样自然?下面,我们就用这种风格,来组装第一条链。
四、你的第一条“链”:从提示词到回答的流水线
4.1 认识三个核心组件
一条最简单的链,只需要三块积木:
- Chat Model(聊天模型):负责与 LLM 对话,我们已经很熟悉了。
- Prompt Template(提示词模板):负责动态组装发送给模型的提示词,告别字符串拼接。
- Output Parser(输出解析器):负责将模型的原始回答转成我们需要的数据格式。
它们三者的协作关系,就像一条生产线:
模板把用户输入装进预设的“提问框架” →模型根据完整提示生成回答 →解析器把回答裁剪、格式化成最终结果。
我们用代码把这条流水线建起来。
4.2 搭第一条链:英文翻译助手
假设我们要做一个专门负责把中文翻译成英文的小助手。我们先一步一步写组件,再用管道把它们串起来。
第一步:创建模型
fromlangchain_deepseekimportChatDeepSeek# 实例化 DeepSeek 聊天模型,temperature=0 让输出更稳定model=ChatDeepSeek(model="deepseek-chat",temperature=0)temperature=0意味着模型在生成时会选择概率最高的词,输出几乎保持一致。对于翻译任务,我们需要的是确定性,而不是创造性。
第二步:创建提示词模板
fromlangchain_core.promptsimportChatPromptTemplate# 一个专门翻译的提示词模板,{input} 是预留的占位符prompt=ChatPromptTemplate.from_template("请将以下中文文本翻译成英文,只返回翻译结果,不要添加任何解释:\n\n{input}")这个模板的灵魂在于{input}占位符。将来每次调用时,不同的中文内容会填入这里,生成各不相同但格式统一的完整提示词。模板可以包含多个占位符,也可以引入系统消息、对话历史,这些我们会在后面的模板专题中详细展开。
第三步:创建输出解析器
fromlangchain_core.output_parsersimportStrOutputParser# 一个最简单的解析器:直接返回模型的文本内容,去除多余空白parser=StrOutputParser()StrOutputParser做的事情很简单——把模型回复消息的content取出来,并去掉首尾空格。它是最常用的解析器之一。将来我们会接触到更复杂的解析器,它们能把模型的输出转成 JSON、列表甚至 Python 对象。
第四步:用管道把它们串起来
# 一条优雅的流水线:输入 → 拼入模板 → 调用模型 → 解析输出chain=prompt|model|parser这一行代码,就是 LCEL 的魔力所在。数据从左向右流动,每个管道符|都把左边组件的输出交给右边组件处理。现在,你可以像调用一个普通函数一样调用这条链:
# 传入输入,链自动完成所有中间步骤result=chain.invoke({"input":"人生苦短,我用Python"})print(result)运行这段代码,你大概率会得到:
Life is short, I use Python.一切都在瞬间完成:输入被填入模板,模板生成了完整的提示词,提示词发给了 DeepSeek,DeepSeek 的回复被解析器提取为纯字符串,最后回到你的手中。
我们刚刚做了什么?我们不再是手动拼字符串→调用 API→手动取字段,而是把这些步骤声明为一条链。以后任何中文翻译需求,只需一行chain.invoke(...),就像调用一个普通函数。这就是 LangChain 带给我们的抽象提升。
4.3 稍微扩展:带风格控制的翻译链
链的魅力不仅在于“简化调用”,更在于“方便扩展”。如果我们想让用户指定翻译风格呢?改一下模板就行:
# 增加 {style} 占位符,让翻译风格可变fancy_prompt=ChatPromptTemplate.from_template("请将以下中文文本翻译成英文,风格要求:{style}。只返回翻译结果:\n\n{input}")# 新的链,同样的模型和解析器复用fancy_chain=fancy_prompt|model|parser# 同一个句子,让模型用莎士比亚风格翻译result=fancy_chain.invoke({"input":"人生苦短,我用Python","style":"莎士比亚式古典英语"})print(result)你可能会得到类似:
Brief is life's span, so Python I embrace.你什么都没有改,只是在invoke时多传了一个style参数。这种数据驱动的灵活性,正是提示词模板+链式编排的核心价值。
五、不止翻译:同一个模式,千变万化的应用
你现在手里握着的“模板 + 模型 + 解析器”的模式,是一把万能钥匙。它不仅仅是翻译用的,换个模板就能瞬间变身:
- 代码审查助手:模板 = “请审查以下代码,指出潜在问题并给出修改建议:\n\n{code}”
- 面试模拟官:模板 = “你是一位严格的{职位}面试官。请针对以下简历内容提出三个有深度的技术问题:\n\n{resume}”
- 文案润色器:模板 = “将以下草稿润色为正式的商务邮件,语气专业但不生硬:\n\n{draft}”
链的组件也可以任意替换。你可以把ChatDeepSeek换成别的模型(只要它也实现了 Chat Model 接口),可以把StrOutputParser换成别的解析器(比如 JSON 解析器),可以把提示词模板换成从文件加载的复杂多消息模板。一切可变,唯独“链”这个组织思想不变。
六、核心架构小结:一张你不必现在就背下来的图
在 LangChain 的城堡里,所有组件最终都指向一个共同的抽象——Runnable。无论是最底层的模型调用,还是你用 LCEL 拼出来的链,甚至是后续要学的智能体,它们都“长着同一张脸”:
Runnable ├── 输入类型(input_schema) ├── 输出类型(output_schema) ├── invoke / ainvoke(同步/异步调用) ├── batch / abatch(批量调用) ├── stream / astream(流式调用) └── pipe(|)操作(可链式组合)当你把任何东西都看成 Runnable 时,整个世界观就统一了。你不再在乎内部是模型还是解析器,只管把它们拼成想要的形状。这就是 LangChain 最优雅的地方。
七、今日收获与下篇预告
今天,我们正式迈进了 LangChain 的城堡,并装好了一条流水线:
- 你理解了LangChain 是乐高式组件框架,一切皆 Runnable,一切皆可组合。
- 你认识了LCEL(LangChain Expression Language),用管道符
|优雅地串联组件。 - 你亲手写出了第一条完整的链——从提示词模板到模型再到解析器,并体验了它的灵活与便利。
- 你看到了这个模式可以迅速复制到翻译、审查、润色等无数场景。
现在你已经会搭链了,但链本身不会说话。真正让链活起来的,是那个坐在链末端、回答你各种问题的聊天模型。下一篇文章《不只是问答:灵活定义你的聊天模型》,我们将深入聊天模型的更多配置选项,学习如何控制它的输出长度、随机性、角色行为,以及支持多轮对话的完整消息管理。
下一篇见!
