目录
[一、为什么需要 LangChain?](#一、为什么需要 LangChain?)
[1.1 原生大模型 API 的痛点](#1.1 原生大模型 API 的痛点)
[1.2 LangChain 如何解决这些问题](#1.2 LangChain 如何解决这些问题)
[二、LangChain 的定位与生态架构](#二、LangChain 的定位与生态架构)
[2.1 LangChain 的定位](#2.1 LangChain 的定位)
[2.2 生态体系](#2.2 生态体系)
[2.3 安装方式](#2.3 安装方式)
[4.1 配置环境变量](#4.1 配置环境变量)
[4.2 项目结构建议](#4.2 项目结构建议)
[4.3 验证安装](#4.3 验证安装)
[5.1 概述](#5.1 概述)
[5.2 消息类型](#5.2 消息类型)
[5.3 基础用法:初始化与调用](#5.3 基础用法:初始化与调用)
[5.4 关键参数说明](#5.4 关键参数说明)
[5.5 兼容 OpenAI 格式的第三方模型](#5.5 兼容 OpenAI 格式的第三方模型)
[5.6 批量调用(batch)](#5.6 批量调用(batch))
[六、模块二:Prompt Templates(提示模板)](#六、模块二:Prompt Templates(提示模板))
[6.1 概述](#6.1 概述)
[6.2 三种 Prompt 模式对比](#6.2 三种 Prompt 模式对比)
[6.3 方式一:原生字符串 Prompt](#6.3 方式一:原生字符串 Prompt)
[6.4 方式二:PromptTemplate(文本模板)](#6.4 方式二:PromptTemplate(文本模板))
[6.5 方式三:ChatPromptTemplate(聊天模板)------推荐](#6.5 方式三:ChatPromptTemplate(聊天模板)——推荐)
[6.6 进阶:Partial Variables(部分变量填充)](#6.6 进阶:Partial Variables(部分变量填充))
[6.7 进阶:Few-Shot Prompt Template](#6.7 进阶:Few-Shot Prompt Template)
[七、模块三:Chains 与 LCEL(链与表达式语言)](#七、模块三:Chains 与 LCEL(链与表达式语言))
[7.1 概述](#7.1 概述)
[7.2 LCEL 核心思想](#7.2 LCEL 核心思想)
[7.3 三种 Chain 示例](#7.3 三种 Chain 示例)
[链 1:PromptTemplate | LLM | StrOutputParser](#链 1:PromptTemplate | LLM | StrOutputParser)
[链 2:ChatPromptTemplate | LLM | StrOutputParser](#链 2:ChatPromptTemplate | LLM | StrOutputParser)
[链 3:ChatPromptTemplate | LLM(JSON mode) | JsonOutputParser](#链 3:ChatPromptTemplate | LLM(JSON mode) | JsonOutputParser)
[7.4 LCEL 进阶组件](#7.4 LCEL 进阶组件)
[7.5 Chain 的流式与异步](#7.5 Chain 的流式与异步)
[8.1 概述](#8.1 概述)
[8.2 核心机制](#8.2 核心机制)
[8.3 基础用法:非流式输出](#8.3 基础用法:非流式输出)
[8.4 流式输出版本](#8.4 流式输出版本)
[8.5 记忆轮数控制](#8.5 记忆轮数控制)
[8.6 持久化存储(简述)](#8.6 持久化存储(简述))
[九、模块五:Output Parsers(输出解析器)](#九、模块五:Output Parsers(输出解析器))
[9.1 概述](#9.1 概述)
[9.2 三种常用 Parser 对比](#9.2 三种常用 Parser 对比)
[9.3 StrOutputParser](#9.3 StrOutputParser)
[9.4 JsonOutputParser](#9.4 JsonOutputParser)
[9.5 PydanticOutputParser](#9.5 PydanticOutputParser)
[9.6 JsonOutputParser vs PydanticOutputParser 选型指南](#9.6 JsonOutputParser vs PydanticOutputParser 选型指南)
[10.1 案例:带记忆的智能客服工单助手](#10.1 案例:带记忆的智能客服工单助手)
[11.1 环境与安装问题](#11.1 环境与安装问题)
[11.2 API 调用问题](#11.2 API 调用问题)
[11.3 Memory 相关问题](#11.3 Memory 相关问题)
[11.4 调试技巧](#11.4 调试技巧)
[12.1 本课核心知识点回顾](#12.1 本课核心知识点回顾)
[12.2 进阶学习路线](#12.2 进阶学习路线)
[12.3 学习资源推荐](#12.3 学习资源推荐)
一、为什么需要 LangChain?
1.1 原生大模型 API 的痛点
直接调用 OpenAI、Claude 等大模型的原生 API,虽然能完成基本的文本生成任务,但在构建实际应用时会遇到以下问题:
| 痛点 | 具体表现 |
|---|---|
| Prompt 管理混乱 | 手动拼接字符串模板,变量替换容易出错,难以复用和版本管理 |
| 上下文维护困难 | 多轮对话的历史消息需要自行维护列表、裁剪、序列化 |
| 输出不可控 | 模型返回的是自由文本,需要额外编写正则或解析逻辑提取结构化数据 |
| 多步推理编排复杂 | 将多个 LLM 调用串联(如先分类再生成再审核),需要手写大量胶水代码 |
| 模型切换成本高 | 从 OpenAI 换到其他模型提供商,需要重写大量调用逻辑 |
| 缺乏可观测性 | 调试链路困难,不知道每一步的输入输出和耗时 |
1.2 LangChain 如何解决这些问题
┌─────────────────────────────────────────────────┐
│ 你的 AI 应用 │
├─────────────────────────────────────────────────┤
│ LangChain 抽象层(统一接口) │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │Models│ │Prompt│ │Chains│ │Memory│ │Parser│ │
│ └──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘ │
├─────┼────────┼────────┼────────┼────────┼───────┤
│ └────────┴────────┴────────┴────────┘ │
│ 统一的 LCEL 管道语法 │
├─────────────────────────────────────────────────┤
│ OpenAI | Anthropic | 百度文心 | 智谱 | 本地模型 ... │
└─────────────────────────────────────────────────┘
LangChain 的核心价值在于:
- 标准化抽象:为不同的模型提供商提供统一的调用接口
- 组件化设计:Prompt、Model、Parser、Memory 等模块可自由组合
- 声明式编排 :通过 LCEL(管道语法
|)将组件像积木一样拼接 - 生态完善:配套调试工具(LangSmith)、部署工具(LangServe)、Agent 框架(LangGraph)
二、LangChain 的定位与生态架构
2.1 LangChain 的定位
LangChain = 大模型的"操作系统" + "连接器"
它不是一个模型本身,而是一个框架层,提供了一套标准化的组件和工具,让开发者能够像搭积木一样构建复杂的 AI 应用。
2.2 生态体系
LangChain 的生态系统由以下部分组成:
| 组件 | 作用 | 说明 |
|---|---|---|
langchain-core |
核心抽象层 | 定义了 LCEL、基础接口、消息类型等 |
langchain |
认知架构层 | Chains、Agents、Retrieval 等高层抽象 |
langchain-community |
社区集成 | 第三方模型和工具的集成(已逐步独立为 langchain-xxx 包) |
langchain-openai |
OpenAI 集成 | OpenAI / Azure OpenAI 的专用适配 |
langchain-anthropic |
Anthropic 集成 | Claude 系列模型适配 |
langchain-text-splitters |
文本分割 | 用于 RAG 场景的文档切分 |
LangGraph |
Agent 编排 | 基于图结构的复杂 Agent 工作流 |
LangSmith |
调试监控 | 链路追踪、评估、测试平台 |
LangServe |
部署服务 | 将 LangChain 应用一键部署为 REST API |
2.3 安装方式
python
# 核心库 + OpenAI 集成(推荐起步安装)
pip install langchain langchain-openai
# 如需使用其他提供商,单独安装对应集成包
pip install langchain-anthropic # Claude
pip install langchain-community # 社区集成(本地模型、向量数据库等)
# 如需文档加载和分割(RAG 场景)
pip install langchain-text-splitters
# 如需使用 UnstructuredLoader 等文档加载器
pip install unstructured
版本说明 :本文基于
langchain >= 0.2,该版本将核心接口拆分到langchain-core包中。如果你使用的是 0.1.x 版本,部分导入路径可能不同,建议升级。
三、核心概念总览
LangChain 的核心组件可以用以下关系图来理解:
python
┌──────────────┐
│ 用户输入 │
└──────┬───────┘
▼
┌────────────────┐
│ Prompt Template │ ← 模块二:指令系统
└────────┬───────┘
▼
┌────────────────┐
│ Model (LLM) │ ← 模块一:大脑
└────────┬───────┘
▼
┌────────────────┐
│ Output Parser │ ← 模块五:格式化输出
└────────┬───────┘
▼
┌────────────────┐
│ 结构化结果 │
└────────────────┘
辅助模块:
┌────────────┐ ┌────────────────────┐
│ Memory │ │ Chains (LCEL 编排) │
│ 模块四: │ │ 模块三: │
│ 上下文记忆 │ │ 管道式组件串联 │
└────────────┘ └────────────────────┘
| 模块 | 核心类 | 一句话说明 |
|---|---|---|
| Models | ChatOpenAI, ChatAnthropic 等 |
统一接口对接各家大模型 |
| Prompts | PromptTemplate, ChatPromptTemplate |
结构化管理和填充提示词 |
| Chains | LCEL 管道(` | ` 语法) |
| Memory | RunnableWithMessageHistory |
自动管理多轮对话历史 |
| Parsers | StrOutputParser, JsonOutputParser, PydanticOutputParser |
将模型输出转为结构化数据 |
四、环境准备
4.1 配置环境变量
在项目根目录下创建 .env 文件,存放敏感的 API 配置:
python
# .env 文件内容
MODEL_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx
MODEL_BASE_URL=https://api.openai.com/v1
MODEL_NAME=gpt-4o-mini
安全提示 :
.env文件应加入.gitignore,切勿提交到版本控制系统中。
4.2 项目结构建议
python
your_project/
├── .env # 环境变量(不提交到 git)
├── .gitignore
├── requirements.txt
├── 01_models.py # 模块一示例
├── 02_prompt_template.py # 模块二示例
├── 03_chains.py # 模块三示例
├── 04_memory.py # 模块四示例
└── 05_output_parser.py # 模块五示例
4.3 验证安装
python
import langchain
print(f"LangChain 版本: {langchain.__version__}")
from langchain_openai import ChatOpenAI
print("langchain-openai 导入成功")
五、模块一:Models(模型层)
5.1 概述
Models 模块是 LangChain 的"大脑",负责与大语言模型进行交互。LangChain 将不同厂商的模型封装为统一的接口,使得切换模型提供商时只需更改少量配置。
LangChain 中的模型分为两大类:
| 类型 | 基类 | 适用场景 | 特点 |
|---|---|---|---|
| LLM | BaseLLM |
补全式模型(如 GPT-3 text-davinci) | 输入输出均为字符串,已逐渐被淘汰 |
| Chat Model | BaseChatModel |
对话式模型(如 GPT-4、Claude) | 输入输出为消息对象列表,支持多角色 |
当前主流推荐使用 Chat Model ,即
ChatOpenAI等以Chat开头的类。
5.2 消息类型
Chat Model 使用消息(Message) 作为输入输出的基本单位。LangChain 定义了以下核心消息类型:
python
from langchain_core.messages import (
SystemMessage, # 系统消息:设定模型的角色和行为规则
HumanMessage, # 用户消息:模拟用户输入
AIMessage, # AI 消息:模型的回复
AIMessageChunk, # AI 消息片段:流式输出时的增量部分
ToolMessage, # 工具消息:工具调用的返回结果(Agent 场景)
)
各消息类型的角色对应关系:
python
SystemMessage → "你是一个资深翻译官" (角色设定)
HumanMessage → "请把以下句子翻译成英文:..." (用户输入)
AIMessage → "The translation is: ..." (模型回复)
5.3 基础用法:初始化与调用
python
import os
from dotenv import load_dotenv
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_openai import ChatOpenAI
# 加载环境变量
env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)
MODEL_API_KEY = os.getenv("MODEL_API_KEY")
MODEL_BASE_URL = os.getenv("MODEL_BASE_URL")
MODEL_NAME = os.getenv("MODEL_NAME")
# 初始化 Chat Model
my_llm = ChatOpenAI(
api_key=MODEL_API_KEY,
base_url=MODEL_BASE_URL,
model=MODEL_NAME,
temperature=0.7, # 控制输出随机性,0=确定性,1=高随机
)
if __name__ == "__main__":
# ========== 方式一:非流式输出 ==========
print("【非流式输出】")
result = my_llm.invoke("请介绍下北京的历史。")
print(type(result)) # <class 'langchain_core.messages.AIMessage'>
print(result.content) # 获取纯文本内容
print(result.usage_metadata) # token 使用统计(部分模型支持)
print()
# ========== 方式二:流式输出 ==========
print("【流式输出】")
for chunk in my_llm.stream("请介绍下北京的历史。"):
print(chunk.content, end="", flush=True)
print("\n")
# ========== 方式三:使用角色消息 ==========
print("【角色消息】")
result = my_llm.invoke([
SystemMessage(content="你是一个历史学家,每次回答都会用一句话进行回答。回答不超过20个字。"),
HumanMessage(content="请介绍下北京的历史。")
])
print(result.content)
5.4 关键参数说明
python
ChatOpenAI(
api_key="...", # API 密钥
base_url="...", # API 基础地址(兼容 OpenAI 格式的第三方服务也用这个)
model="gpt-4o-mini", # 模型名称
temperature=0.7, # 温度参数:0~2,越低越确定性
max_tokens=1024, # 最大输出 token 数
timeout=30, # 请求超时时间(秒)
max_retries=2, # 失败重试次数
streaming=False, # 是否开启流式输出(全局设置)
)
temperature 参数详解:
| 值 | 行为 | 适用场景 |
|---|---|---|
| 0 | 输出几乎确定,每次结果一致 | 分类、提取、代码生成 |
| 0.3 ~ 0.7 | 适度随机,兼顾创意和准确性 | 通用问答、摘要 |
| 0.8 ~ 1.2 | 较高随机性 | 创意写作、头脑风暴 |
| > 1.2 | 高度随机,可能出现不连贯内容 | 实验性用途 |
5.5 兼容 OpenAI 格式的第三方模型
LangChain 的 ChatOpenAI 类不仅支持 OpenAI 官方 API,还兼容所有遵循 OpenAI API 格式的服务。这意味着你可以用同一套代码对接多种模型:
python
# 对接 DeepSeek
deepseek_llm = ChatOpenAI(
api_key="your-deepseek-key",
base_url="https://api.deepseek.com/v1",
model="deepseek-chat",
)
# 对接智谱 GLM
zhipu_llm = ChatOpenAI(
api_key="your-zhipu-key",
base_url="https://open.bigmodel.cn/api/paas/v4",
model="glm-4",
)
# 对接本地 Ollama(需先启动 Ollama 服务)
ollama_llm = ChatOpenAI(
api_key="ollama", # Ollama 不需要真实 key,随便填
base_url="http://localhost:11434/v1",
model="qwen2:7b",
)
这就是 LangChain "统一接口" 的价值------业务代码完全不变,只改初始化参数即可切换底层模型。
5.6 批量调用(batch)
当需要对多条输入执行相同的 LLM 调用时,batch 方法可以显著提升效率(框架会自动并发):
python
questions = [
"北京的简称是什么?",
"上海的简称是什么?",
"广州的简称是什么?",
]
results = my_llm.batch(questions)
for q, r in zip(questions, results):
print(f"Q: {q}")
print(f"A: {r.content}\n")
六、模块二:Prompt Templates(提示模板)
6.1 概述
Prompt 是与大模型交互的"指令系统"。LangChain 提供了多种模板机制,让 Prompt 的管理更加结构化、可复用、可维护。
Prompt Template 的核心价值:
- 参数化 :将变量用
{变量名}占位,运行时动态填充 - 可复用:同一模板可用于不同的输入
- 可组合:与 Chain 无缝衔接,作为流水线的第一个环节
- 可校验:自动检查必填变量是否都已提供
6.2 三种 Prompt 模式对比
| 模式 | 类 | 输入格式 | 适用场景 |
|---|---|---|---|
| 原生字符串 | 无(直接 f-string) | 简单文本 | 快速原型、一次性调用 |
| PromptTemplate | PromptTemplate |
纯文本模板 | 单轮文本补全 |
| ChatPromptTemplate | ChatPromptTemplate |
消息列表模板 | 多角色对话(主流推荐) |
6.3 方式一:原生字符串 Prompt
最直接的方式,用 Python f-string 手动拼接:
python
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)
my_llm = ChatOpenAI(
api_key=os.getenv("MODEL_API_KEY"),
base_url=os.getenv("MODEL_BASE_URL"),
model=os.getenv("MODEL_NAME"),
)
def generate_advertisement(product: str) -> str:
"""原生字符串方式生成广告语"""
prompt = f"""
请为以下产品写一句广告语:
产品:{product}
要求:
- 不超过20字
- 朗朗上口
"""
response = my_llm.invoke(prompt)
return response.content
if __name__ == "__main__":
print(generate_advertisement("口红"))
优缺点分析:
- 优点:简单直观,无需学习额外 API
- 缺点:变量管理混乱,无法校验必填项,不利于复用和测试
6.4 方式二:PromptTemplate(文本模板)
PromptTemplate 是 LangChain 提供的基础字符串模板类,适用于纯文本输入的场景:
python
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate
env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)
my_llm = ChatOpenAI(
api_key=os.getenv("MODEL_API_KEY"),
base_url=os.getenv("MODEL_BASE_URL"),
model=os.getenv("MODEL_NAME"),
)
# ========== 创建模板 ==========
# 方式 A:from_template(自动推断变量)
prompt_template = PromptTemplate.from_template(
"请为产品【{product}】写一句不超过20字的广告语。"
)
# 方式 B:显式指定变量列表(更严格)
prompt_template = PromptTemplate(
template="请为产品【{product}】写一句不超过20字的广告语。",
input_variables=["product"], # 显式声明变量
)
def generate_advertisement(product: str) -> str:
prompt = prompt_template.format(product=product)
print(f"填充后的 Prompt:\n{prompt}\n")
response = my_llm.invoke(prompt)
return response.content
if __name__ == "__main__":
print(generate_advertisement("智能手表"))
PromptTemplate 的常用方法:
python
# format() → 返回字符串
prompt_str = prompt_template.format(product="耳机")
# format_messages() → 返回消息列表(PromptTemplate 较少用)
# invoke() → 返回填充后的 PromptValue 对象(推荐在 Chain 中使用)
prompt_value = prompt_template.invoke({"product": "耳机"})
print(prompt_value.to_string()) # 转为字符串
6.5 方式三:ChatPromptTemplate(聊天模板)------推荐
ChatPromptTemplate 是最常用的模板类型,支持定义多个角色的消息:
python
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)
my_llm = ChatOpenAI(
api_key=os.getenv("MODEL_API_KEY"),
base_url=os.getenv("MODEL_BASE_URL"),
model=os.getenv("MODEL_NAME"),
)
def generate_advertisement(product: str) -> str:
chat_prompt_template = ChatPromptTemplate.from_messages([
("system", "你是一位资深营销专家,擅长撰写精炼的广告语。"),
("user", "请为产品【{product}】写一句不超过20字的广告语。"),
])
# format_messages() 返回 Message 对象列表
messages = chat_prompt_template.format_messages(product=product)
print(f"消息列表: {messages}")
print(f"消息类型: {[type(m).__name__ for m in messages]}\n")
response = my_llm.invoke(messages)
return response.content
if __name__ == "__main__":
print(generate_advertisement("口红"))
from_messages 支持的元组格式:
python
ChatPromptTemplate.from_messages([
("system", "你是一个..."), # 系统角色
("user", "用户的问题:{question}"), # 用户角色
("assistant", "好的,让我..."), # AI 角色(用于 few-shot 示例)
("user", "继续:{follow_up}"), # 多轮对话
])
6.6 进阶:Partial Variables(部分变量填充)
当模板中某些变量的值在创建时就已确定,可以使用 partial 方法预先填充:
python
from langchain_core.prompts import ChatPromptTemplate
# 场景:系统角色固定,只有用户输入变化
template = ChatPromptTemplate.from_messages([
("system", "你是一个{role}。"),
("user", "{question}"),
])
# 先填充 role,留下 question 动态填入
partial_template = template.partial(role="资深Python开发者")
# 后续只需提供 question
messages = partial_template.format_messages(question="如何反转链表?")
print(messages)
6.7 进阶:Few-Shot Prompt Template
通过提供少量示例,引导模型按特定格式或风格输出:
python
from langchain_core.prompts import ChatPromptTemplate, FewShotChatMessagePromptTemplate
# 定义示例
examples = [
{"input": "开心", "output": "😊"},
{"input": "伤心", "output": "😢"},
{"input": "愤怒", "output": "😡"},
]
# 定义示例的格式模板
example_prompt = ChatPromptTemplate.from_messages([
("human", "{input}"),
("ai", "{output}"),
])
# 构建 Few-Shot 模板
few_shot_prompt = FewShotChatMessagePromptTemplate(
example_prompt=example_prompt,
examples=examples,
)
# 最终完整模板
final_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个情感分析助手,将中文情感词转换为对应的 emoji。"),
few_shot_prompt,
("human", "{input}"),
])
# 使用
messages = final_prompt.format_messages(input="惊讶")
print(messages)
七、模块三:Chains 与 LCEL(链与表达式语言)
7.1 概述
单个组件(Prompt、Model、Parser)的能力是有限的。Chains(链) 的作用是将多个组件串联起来,形成一个完整的处理流水线。
LangChain v0.2+ 使用 LCEL(LangChain Expression Language) 作为链的编排方式,核心语法是管道操作符 |。
7.2 LCEL 核心思想
python
# LCEL 管道语法:左边组件的输出 → 右边组件的输入
chain = prompt | model | parser
# 等价于:
# 1. prompt.invoke(input) → 生成 PromptValue
# 2. model.invoke(prompt_value) → 生成 AIMessage
# 3. parser.invoke(ai_message) → 生成最终输出(str / dict / Pydantic 对象)
LCEL 的设计哲学:
- 声明式:描述"做什么",而非"怎么做"
- 统一接口 :所有组件都实现
Runnable协议,支持invoke、stream、batch、ainvoke(异步) - 自动并行 :
RunnableParallel可以并行执行多个分支 - 流式友好:管道天然支持逐 chunk 流式传递
7.3 三种 Chain 示例
链 1:PromptTemplate | LLM | StrOutputParser
最基础的文本生成链:
python
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)
llm = ChatOpenAI(
api_key=os.getenv("MODEL_API_KEY"),
base_url=os.getenv("MODEL_BASE_URL"),
model=os.getenv("MODEL_NAME"),
temperature=0.7,
)
def chain_01_text_prompt(product: str) -> str:
"""PromptTemplate(字符串)→ LLM → 解析成 str"""
prompt = PromptTemplate.from_template(
"请为产品【{product}】写一句不超过20字的广告语。"
)
chain = prompt | llm | StrOutputParser()
return chain.invoke({"product": product})
if __name__ == "__main__":
print(chain_01_text_prompt("智能手表"))
链 2:ChatPromptTemplate | LLM | StrOutputParser
带角色设定的聊天链(最常用):
python
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)
llm = ChatOpenAI(
api_key=os.getenv("MODEL_API_KEY"),
base_url=os.getenv("MODEL_BASE_URL"),
model=os.getenv("MODEL_NAME"),
temperature=0.7,
)
def chain_02_chat_prompt(product: str) -> str:
"""ChatPromptTemplate(system/user)→ LLM → 解析成 str"""
prompt = ChatPromptTemplate.from_messages([
("system", "你是一位资深营销专家。输出要朗朗上口,不超过20字。"),
("user", "请为产品【{product}】写一句广告语。"),
])
chain = prompt | llm | StrOutputParser()
return chain.invoke({"product": product})
if __name__ == "__main__":
print(chain_02_chat_prompt("口红"))
链 3:ChatPromptTemplate | LLM(JSON mode) | JsonOutputParser
结构化输出链,将 LLM 输出解析为 Python 字典:
python
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)
llm = ChatOpenAI(
api_key=os.getenv("MODEL_API_KEY"),
base_url=os.getenv("MODEL_BASE_URL"),
model=os.getenv("MODEL_NAME"),
temperature=0.3,
)
def chain_03_json_output(user_issue: str) -> dict:
"""
ChatPromptTemplate → LLM(JSON mode) → JsonOutputParser
说明:
- response_format={"type":"json_object"} 是 OpenAI 风格的 JSON mode 参数;
不是所有模型都支持,不支持时可仅依赖提示词约束 + 手动 json.loads。
"""
json_llm = llm.bind(
response_format={"type": "json_object"},
temperature=0.3,
)
prompt = ChatPromptTemplate.from_messages([
("system", "你是客服工单分析助手,只输出 JSON 对象,不要输出多余文字。"),
("user",
"对下面工单分类并给出摘要,输出 JSON,键严格为:"
'category(退款问题/物流问题/商品问题/其他), confidence(0-1), summary(<=50字)。\n'
"工单:{issue}"
),
])
chain = prompt | json_llm | JsonOutputParser()
return chain.invoke({"issue": user_issue})
if __name__ == "__main__":
issue = "上周买的鞋子码数偏小,能换大一码吗?运费谁出?"
result = chain_03_json_output(issue)
print(result)
print(f"类型: {type(result)}")
print(f"分类: {result['category']}")
7.4 LCEL 进阶组件
RunnablePassthrough(透传器)
将输入原样传递到下一个环节,常用于并行分支中保留原始输入:
python
from langchain_core.runnables import RunnablePassthrough, RunnableParallel
# 场景:同时需要原始问题和 LLM 生成的答案
parallel = RunnableParallel(
original=RunnablePassthrough(), # 原样透传输入
answer=chain, # 通过 chain 生成答案
)
result = parallel.invoke({"product": "耳机"})
# result = {"original": {"product": "耳机"}, "answer": "xxx广告语xxx"}
RunnableLambda(自定义函数)
将任意 Python 函数包装为 LCEL 可用的组件:
python
from langchain_core.runnables import RunnableLambda
def word_count(text: str) -> dict:
"""统计字数并包装结果"""
return {
"text": text,
"word_count": len(text),
"is_short": len(text) <= 20,
}
word_counter = RunnableLambda(word_count)
# 将自定义函数接入链
chain_with_count = prompt | llm | StrOutputParser() | word_counter
result = chain_with_count.invoke({"product": "耳机"})
print(result)
# {'text': '轻盈入耳,声临其境。', 'word_count': 10, 'is_short': True}
RunnableParallel(并行执行)
同时执行多个分支,常用于 RAG 场景中同时获取上下文和原始问题:
python
from langchain_core.runnables import RunnableParallel
# 并行执行两个链
parallel_chain = RunnableParallel(
advertisement=prompt | llm | StrOutputParser(),
slogan_count=prompt | llm | StrOutputParser() | RunnableLambda(lambda x: f"字数:{len(x)}"),
)
results = parallel_chain.invoke({"product": "耳机"})
print(results)
# {"advertisement": "...", "slogan_count": "字数:10"}
7.5 Chain 的流式与异步
LCEL 链天然支持流式输出和异步调用:
python
# ===== 流式输出 =====
chain = prompt | llm | StrOutputParser()
for chunk in chain.stream({"product": "耳机"}):
print(chunk, end="", flush=True)
print()
# ===== 异步调用 =====
import asyncio
async def main():
result = await chain.ainvoke({"product": "耳机"})
print(result)
asyncio.run(main())
# ===== 异步流式 =====
async def stream_main():
async for chunk in chain.astream({"product": "耳机"}):
print(chunk, end="", flush=True)
print()
asyncio.run(stream_main())
八、模块四:Memory(记忆管理)
8.1 概述
大模型本身是无状态的------每次 API 调用都是独立的,模型不会"记住"之前的对话。但实际的聊天应用需要维护上下文,让用户可以进行多轮连贯的对话。
LangChain 通过 RunnableWithMessageHistory 提供了自动化的记忆管理方案。
8.2 核心机制
python
用户第1轮: "你好"
→ 自动注入历史 [] + HumanMessage("你好")
→ 模型回复 → 存入历史
用户第2轮: "你是谁?"
→ 自动注入历史 [HumanMessage("你好"), AIMessage("...")] + HumanMessage("你是谁?")
→ 模型回复 → 存入历史
用户第3轮: "刚才说了什么?"
→ 自动注入完整历史 + HumanMessage("刚才说了什么?")
→ 模型能"回忆"之前的对话
8.3 基础用法:非流式输出
python
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.chat_history import InMemoryChatMessageHistory
env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)
my_llm = ChatOpenAI(
api_key=os.getenv("MODEL_API_KEY"),
base_url=os.getenv("MODEL_BASE_URL"),
model=os.getenv("MODEL_NAME"),
temperature=0.7,
)
# ========== 会话历史存储 ==========
# 实际生产中,可替换为 Redis、数据库等持久化方案
store = {}
def get_session_history(session_id: str) -> InMemoryChatMessageHistory:
"""获取或创建指定会话的历史记录"""
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory()
return store[session_id]
# ========== 用 RunnableWithMessageHistory 包装 LLM ==========
with_memory = RunnableWithMessageHistory(
my_llm,
get_session_history,
)
def demo_with_memory(session_id: str, user_input: str) -> str:
"""
with_memory 运行时,会自动:
1. 从 get_session_history 获取该 session 的历史消息
2. 将历史消息与本次输入一起发送给模型
3. 将模型回复追加到历史记录中
"""
result = with_memory.invoke(
[HumanMessage(content=user_input)],
config={"configurable": {"session_id": session_id}},
)
return result.content
if __name__ == "__main__":
# ===== 用户 1 的会话 =====
session_id = "user_1"
print("【用户1 第1轮】")
print(demo_with_memory(session_id, "你好"))
print("*" * 80)
print("【用户1 第2轮】")
print(demo_with_memory(session_id, "你是谁?"))
print("*" * 80)
# ===== 用户 2 的独立会话 =====
session_id = "user_2"
print("【用户2 第1轮】")
print(demo_with_memory(session_id, "世界上人口最多的国家是哪个国家?"))
print("*" * 80)
print("【用户2 第2轮】")
print(demo_with_memory(session_id, "那第二呢?"))
print("*" * 80)
关键点 :不同
session_id对应独立的对话历史,互不影响。"user_1"和"user_2"各自维护独立的上下文。
8.4 流式输出版本
python
import os
from dotenv import load_dotenv
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.messages import HumanMessage
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_openai import ChatOpenAI
env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)
my_llm = ChatOpenAI(
api_key=os.getenv("MODEL_API_KEY"),
base_url=os.getenv("MODEL_BASE_URL"),
model=os.getenv("MODEL_NAME"),
temperature=0.7,
streaming=True, # 开启流式
)
store = {}
def get_session_history(session_id: str) -> InMemoryChatMessageHistory:
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory()
return store[session_id]
with_memory = RunnableWithMessageHistory(
my_llm,
get_session_history,
)
def demo_with_memory_stream(session_id: str, user_input: str) -> None:
"""流式输出版本:逐 chunk 实时打印"""
for chunk in with_memory.stream(
[HumanMessage(content=user_input)],
config={"configurable": {"session_id": session_id}},
):
print(chunk.content, end="", flush=True)
print()
if __name__ == "__main__":
session_id = "user_1"
demo_with_memory_stream(session_id, "你好")
print("*" * 80)
demo_with_memory_stream(session_id, "你是谁?")
print("*" * 80)
8.5 记忆轮数控制
在实际应用中,不限制历史消息会导致两个问题:
- 1.Token 超限:对话越长,Prompt 越大,最终超出模型的上下文窗口
- 2.成本增加:Token 数量直接影响 API 调用费用
解决方法:限制保留最近 N 轮对话
python
def get_session_history(session_id: str, max_history: int = 10) -> InMemoryChatMessageHistory:
"""
获取会话历史,只保留最近 max_history 条消息。
注意:这里 max_history=10 指的是消息条数(不是轮数),
1轮对话 = 1条 HumanMessage + 1条 AIMessage = 2条消息,
所以 max_history=10 实际保留最近 5 轮对话。
"""
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory()
history = store[session_id]
# 裁剪:只保留最近 max_history 条消息
history.messages = history.messages[-max_history:]
return history
进阶方案 :在生产环境中,还可以使用
ConversationBufferWindowMemory(固定窗口)或ConversationSummaryMemory(摘要压缩)等策略。但在 LangChain v0.2+ 中,官方更推荐在get_session_history函数中自行控制裁剪逻辑,以获得更大的灵活性。
8.6 持久化存储(简述)
InMemoryChatMessageHistory 将历史存储在内存中,进程退出后数据即丢失。生产环境中,通常需要持久化方案:
python
# 方案一:Redis(需 pip install langchain-community)
from langchain_community.chat_message_histories import RedisChatMessageHistory
def get_session_history(session_id: str):
return RedisChatMessageHistory(
session_id=session_id,
url="redis://localhost:6379",
)
# 方案二:SQLite(需 pip install langchain-community)
from langchain_community.chat_message_histories import SQLChatMessageHistory
def get_session_history(session_id: str):
return SQLChatMessageHistory(
session_id=session_id,
connection="sqlite:///chat_history.db",
)
九、模块五:Output Parsers(输出解析器)
9.1 概述
LLM 的原始输出是自然语言文本,但在应用开发中,我们经常需要将输出转换为结构化数据格式(字符串、JSON 字典、Pydantic 对象等)。Output Parser 正是负责这一转换的组件。
9.2 三种常用 Parser 对比
| Parser | 输出类型 | 典型场景 |
|---|---|---|
StrOutputParser |
str |
文本生成、摘要、翻译 |
JsonOutputParser |
dict |
分类结果、结构化提取 |
PydanticOutputParser |
Pydantic 对象 | 强类型数据、需要字段校验 |
9.3 StrOutputParser
最简单的解析器,从 AIMessage 中提取 .content 字符串:
python
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)
llm = ChatOpenAI(
api_key=os.getenv("MODEL_API_KEY"),
base_url=os.getenv("MODEL_BASE_URL"),
model=os.getenv("MODEL_NAME"),
temperature=0.7,
)
def summarize_one_sentence(text: str) -> str:
"""将输入文本用一句话概括"""
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个中文文本摘要助手,只输出一句话摘要,不要解释。"),
("user", "请用一句话总结:{text}"),
])
chain = prompt | llm | StrOutputParser()
return chain.invoke({"text": text})
if __name__ == "__main__":
article = "我昨天买的耳机音质不错,但左耳偶尔断连,想问能否换货以及流程需要多久。"
print(summarize_one_sentence(article))
9.4 JsonOutputParser
强制模型输出 JSON 字符串,并将其解析为 Python 字典。通常与 Pydantic 模型配合使用,自动生成格式说明:
python
import os
from typing import List, Literal
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import JsonOutputParser
from pydantic import BaseModel, Field
env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)
llm = ChatOpenAI(
api_key=os.getenv("MODEL_API_KEY"),
base_url=os.getenv("MODEL_BASE_URL"),
model=os.getenv("MODEL_NAME"),
temperature=0.3,
)
# ========== 用 Pydantic 定义期望的输出结构 ==========
class WordPair(BaseModel):
word: str = Field(description="英文单词")
translate: str = Field(description="中文翻译")
pos: Literal[
"noun", "verb", "adj", "adv", "prep", "pron", "conj", "interj", "other"
] = Field(description="词性")
class WordListOutput(BaseModel):
word_list: List[WordPair] = Field(description="单词翻译列表")
# 创建 Parser
parser = JsonOutputParser(pydantic_object=WordListOutput)
def translate_words(text: str) -> dict:
"""将英文单词翻译成中文,并返回结构化 JSON"""
prompt = f"""
请将以下英文单词翻译成中文,并以 JSON 格式返回。
请只输出 JSON,不要包含任何解释性文字。
每个单词需要给出词性 pos,pos 只能从以下集合中选择:
["noun","verb","adj","adv","prep","pron","conj","interj","other"]
返回格式要求如下:
{parser.get_format_instructions()}
单词:{text}
"""
# 使用 bind 约束 JSON 输出模式(OpenAI 兼容接口)
json_llm = llm.bind(response_format={"type": "json_object"}, temperature=0.3)
# 流式获取完整内容
full_content = ""
for chunk in json_llm.stream(prompt):
if chunk.content:
print(chunk.content, end="", flush=True)
full_content += chunk.content
print()
return parser.parse(full_content)
if __name__ == "__main__":
result = translate_words("hello, work")
print("*" * 80)
print(f"解析结果: {result}")
print(f"结果类型: {type(result)}")
print(f"第一个单词: {result['word_list'][0]}")
输出示例:
python
{"word_list": [{"word": "hello", "translate": "你好", "pos": "interj"}, {"word": "work", "translate": "工作", "pos": "verb"}]}
9.5 PydanticOutputParser
与 JsonOutputParser 类似,但最终输出的是一个经过 Pydantic 校验的 Python 对象,而非裸字典。这意味着你可以直接使用对象属性访问和类型校验:
python
import os
from typing import Literal
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.prompts import ChatPromptTemplate
from pydantic import BaseModel, Field
env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)
llm = ChatOpenAI(
api_key=os.getenv("MODEL_API_KEY"),
base_url=os.getenv("MODEL_BASE_URL"),
model=os.getenv("MODEL_NAME"),
temperature=0.3,
)
# ========== 定义结构化输出模型 ==========
class TicketResult(BaseModel):
"""客服工单分析结果"""
category: Literal["退款问题", "物流问题", "商品问题", "其他"] = Field(
description="工单分类"
)
confidence: float = Field(
ge=0, le=1, description="置信度 0~1"
)
summary: str = Field(
max_length=50, description="一句话概括(不超过50字)"
)
def classify_ticket_with_schema(issue: str) -> str:
"""使用 PydanticOutputParser 将工单分类为结构化结果"""
parser = PydanticOutputParser(pydantic_object=TicketResult)
prompt = ChatPromptTemplate.from_messages([
("system", "你是客服工单分析助手。请严格按要求输出。"),
("user",
"根据工单内容提取结构化结果。\n"
"{format_instructions}\n" # 自动注入 JSON Schema 说明
"工单:{issue}"
),
]).partial(format_instructions=parser.get_format_instructions())
# Chain: Prompt → LLM → Pydantic 校验解析
chain = prompt | llm | parser
result = chain.invoke({"issue": issue})
# result 是 TicketResult 类型的 Pydantic 对象
print(f"类型: {type(result)}")
print(f"分类: {result.category}")
print(f"置信度: {result.confidence}")
print(f"摘要: {result.summary}")
# 转为 JSON 字符串
return result.model_dump_json(indent=2)
if __name__ == "__main__":
issue = "快递一直没更新,快递到哪里了?已经三天了,能帮我查一下吗?"
result_json = classify_ticket_with_schema(issue)
print(result_json)
输出示例:
python
类型: <class '__main__.TicketResult'>
分类: 物流问题
置信度: 0.95
摘要: 快递三天未更新,客户查询物流状态
{
"category": "物流问题",
"confidence": 0.95,
"summary": "快递三天未更新,客户查询物流状态"
}
9.6 JsonOutputParser vs PydanticOutputParser 选型指南
| 特性 | JsonOutputParser | PydanticOutputParser |
|---|---|---|
| 返回类型 | dict |
Pydantic 对象 |
| 类型校验 | 无(手动校验) | 自动校验(类型、范围、长度) |
| 属性访问 | result["key"] |
result.key |
| 错误处理 | 解析失败返回原始文本 | 解析失败抛出 ValidationError |
| 适用场景 | 简单结构、灵活键名 | 严格结构、需要字段约束 |
与 bind(response_format) 配合 |
更常用 | 也可配合使用 |
建议 :如果你需要严格的类型校验和字段约束(如
confidence必须在 0~1 之间),优先使用PydanticOutputParser。如果只是简单获取 JSON 数据,JsonOutputParser更轻量。
十、实战综合案例
10.1 案例:带记忆的智能客服工单助手
将前面所学的 Models、Prompt、Chains、Memory、Parser 五个模块整合,构建一个完整的应用:
python
import os
from typing import Literal
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.messages import HumanMessage
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.chat_history import InMemoryChatMessageHistory
from pydantic import BaseModel, Field
env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")
load_dotenv(env_path)
# ========== 初始化模型 ==========
llm = ChatOpenAI(
api_key=os.getenv("MODEL_API_KEY"),
base_url=os.getenv("MODEL_BASE_URL"),
model=os.getenv("MODEL_NAME"),
temperature=0.3,
)
# ========== 定义结构化输出 ==========
class TicketResult(BaseModel):
category: Literal["退款问题", "物流问题", "商品问题", "其他"] = Field(description="工单分类")
confidence: float = Field(ge=0, le=1, description="置信度")
summary: str = Field(max_length=50, description="摘要")
reply_to_customer: str = Field(max_length=200, description="建议回复客户的话术")
# ========== 构建分析链 ==========
parser = PydanticOutputParser(pydantic_object=TicketResult)
analysis_prompt = ChatPromptTemplate.from_messages([
("system",
"你是客服工单分析助手。请分析工单并生成结构化结果和建议回复。\n"
"{format_instructions}"
),
("user", "工单内容:{issue}"),
]).partial(format_instructions=parser.get_format_instructions())
analysis_chain = analysis_prompt | llm | parser
# ========== 构建带记忆的对话链 ==========
chat_prompt = ChatPromptTemplate.from_messages([
("system", "你是一位耐心的客服主管,帮助客服人员处理工单问题。结合历史对话上下文回答。"),
("placeholder", "{history}"), # 历史消息占位符
("user", "{input}"),
])
chat_chain = chat_prompt | llm
# ========== 记忆管理 ==========
store = {}
def get_session_history(session_id: str) -> InMemoryChatMessageHistory:
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory()
return store[session_id]
chat_with_memory = RunnableWithMessageHistory(
chat_chain,
get_session_history,
input_messages_key="input",
history_messages_key="history",
)
# ========== 主程序 ==========
if __name__ == "__main__":
# 第一步:分析工单
issue = "我上周买的运动鞋,穿了一天就开胶了,质量太差了!要求退款!"
print("【工单分析结果】")
result = analysis_chain.invoke({"issue": issue})
print(f"分类: {result.category}")
print(f"置信度: {result.confidence}")
print(f"摘要: {result.summary}")
print(f"建议回复: {result.reply_to_customer}")
print("=" * 80)
# 第二步:带记忆的多轮对话
session_id = "客服小王"
print(f"\n【{session_id} 的工作对话】")
resp1 = chat_with_memory.invoke(
{"input": f"我收到一个工单:'{issue}',分析结果是'{result.category}',我该怎么处理?"},
config={"configurable": {"session_id": session_id}},
)
print(f"Q1: 这个工单该怎么处理?")
print(f"A1: {resp1.content}\n")
resp2 = chat_with_memory.invoke(
{"input": "如果客户坚持要退款,我需要走什么流程?"},
config={"configurable": {"session_id": session_id}},
)
print(f"Q2: 如果客户坚持要退款,走什么流程?")
print(f"A2: {resp2.content}")
十一、常见问题与排坑指南
11.1 环境与安装问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
ModuleNotFoundError: No module named 'langchain_openai' |
未安装集成包 | pip install langchain-openai |
ImportError: cannot import name 'xxx' from 'langchain' |
v0.2+ 导入路径变更 | 从 langchain_core 导入,如 from langchain_core.prompts import ChatPromptTemplate |
.env 文件加载不到 |
路径问题 | 使用 os.path.abspath 构建绝对路径 |
11.2 API 调用问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
AuthenticationError |
API Key 无效 | 检查 .env 中的 key 是否正确 |
RateLimitError |
请求频率过高 | 添加 max_retries 参数,或使用 time.sleep 限流 |
| JSON 输出解析失败 | 模型输出了非 JSON 内容 | 在 Prompt 中更明确地约束"只输出 JSON",或使用 response_format |
11.3 Memory 相关问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 模型"失忆" | session_id 不一致 |
确保同一用户使用固定的 session_id |
| 对话越长越慢 | 历史消息无限增长 | 裁剪 history.messages,保留最近 N 条 |
| Token 超出限制 | 上下文过长 | 限制历史轮数 + 设置 max_tokens |
11.4 调试技巧
python
# 方法一:使用 verbose 模式(LangChain 0.1.x 常用)
# 方法二:使用 LangSmith(推荐,需注册 https://smith.langchain.com)
import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "your-langsmith-key"
# 方法三:手动打印中间结果
chain = prompt | llm | StrOutputParser()
# 打印 prompt 的实际内容
prompt_value = prompt.invoke({"product": "耳机"})
print(prompt_value.to_string())
# 打印模型原始输出
raw_output = (prompt | llm).invoke({"product": "耳机"})
print(raw_output) # AIMessage 对象
print(raw_output.content) # 纯文本
十二、课程总结与进阶方向
12.1 本课核心知识点回顾
python
┌──────────────────────────────────────────────────────────────┐
│ LangChain 核心架构 │
├──────────┬───────────────┬────────────┬──────────┬───────────┤
│ Models │ Prompts │ Chains │ Memory │ Parsers │
│ 模型层 │ 提示模板层 │ 编排层 │ 记忆层 │ 解析层 │
│ │ │ │ │ │
│ChatOpenAI│PromptTemplate │ LCEL │Runnable │StrOutput │
│ 统一接口 │ChatPrompt │ 管道 │With │JsonOutput │
│ 流式/批量 │FewShot │ | 语法 │Message │Pydantic │
│ │Partial │ │History │Output │
└──────────┴───────────────┴────────────┴──────────┴───────────┘
| 序号 | 知识点 | 关键收获 |
|---|---|---|
| 1 | LangChain 定位 | 大模型应用开发框架,提供标准化组件和统一接口 |
| 2 | Models | ChatOpenAI 为核心,支持流式、批量、多模型兼容 |
| 3 | Prompt Templates | ChatPromptTemplate 为主流,支持角色分离、变量填充、Few-Shot |
| 4 | Chains (LCEL) | 用 ` |
| 5 | Memory | RunnableWithMessageHistory 自动管理会话历史,按 session_id 隔离 |
| 6 | Output Parsers | StrOutputParser(文本)、JsonOutputParser(字典)、PydanticOutputParser(强类型对象) |
12.2 进阶学习路线
python
本课内容(基础五模块)
│
├──→ RAG(检索增强生成)
│ ├── Document Loaders(文档加载)
│ ├── Text Splitters(文本分割)
│ ├── Embeddings & Vector Stores(向量化与存储)
│ └── Retrievers(检索器)
│
├──→ Agents(智能体)
│ ├── Tool Calling(工具调用)
│ ├── LangGraph(图状态机编排)
│ └── Multi-Agent(多智能体协作)
│
├──→ 部署与运维
│ ├── LangServe(API 部署)
│ └── LangSmith(调试、监控、评估)
│
└──→ 高级技巧
├── Streaming(深度流式处理)
├── Callbacks(回调机制)
├── Custom Components(自定义组件)
└── Structured Output(原生结构化输出)
12.3 学习资源推荐
| 资源 | 地址 | 说明 |
|---|---|---|
| LangChain 官方文档 | https://python.langchain.com/docs/ | 最权威的参考资料 |
| LangChain GitHub | https://github.com/langchain-ai/langchain | 源码与示例 |
| LangSmith | https://smith.langchain.com | 链路调试与监控平台 |
| LangGraph 文档 | https://langchain-ai.github.io/langgraph/ | Agent 编排框架 |
| DeepLearning.AI 课程 | https://www.deeplearning.ai/short-courses/ | LangChain 作者亲授的免费课程 |