LangChain 核心技术全解析:从入门到实战

目录

[一、为什么需要 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 验证安装)

五、模块一:Models(模型层)

[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 进阶组件)

RunnablePassthrough(透传器)

RunnableLambda(自定义函数)

RunnableParallel(并行执行)

[7.5 Chain 的流式与异步](#7.5 Chain 的流式与异步)

八、模块四:Memory(记忆管理)

[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 协议,支持 invokestreambatchainvoke(异步)
  • 自动并行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. 1.Token 超限:对话越长,Prompt 越大,最终超出模型的上下文窗口
  2. 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 作者亲授的免费课程
相关推荐
H_unique4 小时前
LangChain:消息
开发语言·langchain
JaydenAI4 小时前
[Deep Agents:LangChain的Agent Harness-12]利用create_deep_agent整合所有的Harness中间件
langchain·agent·deep agents·harness
Derrick__15 小时前
LangChain基础实战手记:如何给大模型装上“大脑(记忆)”和“双手(工具)”?
人工智能·python·langchain·个人开发
狐狐生风7 小时前
LangGraph 生产级部署全解:FastAPI + Docker
python·docker·langchain·prompt·fastapi·langgraph·agentai
code bean7 小时前
【LangChain 】 自定义解析器实战指南:从原理到 10 个业务场景落地
算法·langchain
monkeyhlj7 小时前
LangChain - V1.0
python·langchain·ai编程
不穿铠甲的穿山甲7 小时前
LangChain-4.高级提示词技术
microsoft·百度·langchain
狐狐生风8 小时前
LangGraph Human-in-the-loop 全解
python·langchain·prompt·langgraph·agentai
lbb 小魔仙8 小时前
告别腾讯会议40分钟限制:用ToDesk协作版开在线会议,免费不限时远程会议新方案
python·langchain·jenkins