001.LangChain v1.0 基础入门

一:LangChain 框架介绍

1.1. 用 LangChain 能做什么?

核心价值:让开发者用 10 行代码完成原本需要 1000 行代码的 AI 应用,并且自动获得状态持久化、人工干预、并发控制等企业级能力。

1.0 的架构风格可以用一句话概括:以“统一智能体抽象 + 标准化内容表示 + 可插拔治理中间件”为设计骨干,以 LangGraph 为底座运行时,实现“开发简单性”与“生产可控性”的兼顾。

你要做什么AI应用?
│
├─ 只想简单调用模型聊天(翻译/问答)
│   └─> 直接用 OpenAI SDK(更轻量,无需 LangChain)
│
├─ 需要联网查资料、执行代码、操作数据库
│   └─> 用 LangChain 1.0(快速搭建 Agent)
│       └─> 参考:客服机器人、数据分析助手
│
├─ 流程很复杂(多人审批/定时任务/状态分支)
│   └─> 用 LangGraph 1.0(精确控制每个步骤)
│       └─> 参考:自动化工作流、ERP 系统集成
│
└─ 不确定,先试试想法
    └─> 用 LangChain 1.0 快速验证,后期可无缝迁移到 LangGraph

1.2. LangChain 生态概览

模型层(Models)

LangChain 1.0 的统一模型抽象层,为所有模型提供标准化调用,覆盖文本、多模态、Embedding、Rerank 等多类型模型,实现跨供应商一致体验

工具层(Tools)

工具系统提供统一 Tool 抽象,支持所有主流模型的 Tool Calling,深度集成 LangGraph,构建可执行 agent 环境的关键能力层

记忆层(Memory)

记忆层提供统一 State 管理、对话记录、长期检索、多模态 Memory 等能力,支持持久化与复杂工作流状态流转

Agent 层(Agents)

LangChain 1.0 Agents 系统实现从碎片化到标准化升级,以 create_agent 为核心接口,基于 LangGraph 构建统一 Agent 抽象,10 行代码即可创建基础 Agent,封装 "模型调用 → 工具选择 → 执行 → 结束" 闭环流程

工作流层(Workflows)

Workflows 体系实现从 线性链式(Chain)到图结构(Graph) 的范式转移,以 StateGraph 为核心画布,将业务逻辑解耦为 "节点(Node)+ 边(Edge)+ 状态(State)",原生支持循环(Loop)与条件分支,完美适配复杂任务编排、容错重试及长会话保持。

调试监控层(Debugging)

LangChain 1.0 调试监控层实现了从日志黑盒到全链路可观测性(Observability) 的质变,深度集成 LangSmith 平台,自动捕获链(Chain)与图(Graph)的每一步骤状态、Token 消耗及延迟,支持 "Trace → Playground" 一键回放调试,彻底解决复杂 Agent 逻辑难以排查的痛点。

其他关键组件 (LangGraph & LangServe)

1.3. LangChain 1.0 底层运行架构

# 简化版架构示意图
┌─────────────────────────────────────────┐
│        LangChain 1.0 应用层              │
│  (create_agent, 工具和中间件)            │
└──────────────────┬──────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────────┐
│        LangGraph 编排层                  │
│  (StateGraph, Nodes, Edges, Checkpoints)│
└──────────────────┬──────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────────┐
│        LCEL 运行时层                     │
│  (Runnable 接口, | 运算符, 流式 / 批处理)  │
└──────────────────┬──────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────────┐
│        大语言模型 API(OpenAI / DeepSeek)    │
└─────────────────────────────────────────┘

1.4. Runnable 底层执行引擎

Runnable 是 LangChain 1.0 的“统一接口标准”,任何可以运行的组件——模型、Prompt、工具、解析器、Memory、Graph 节点——在 1.0 中都被抽象为 Runnable。

Runnable 使所有 LangChain 组件能够以统一接口组合、执行、链式调用,并支撑 LCEL(LangChain Expression Language)的整个运行语义,支撑可组合、可并行、可路由的链式执行,是 LangChain 1.0 的核心底座之一。

核心思想:Runnable 抽象与可组合链(Composable Chains)

所有对象都可以 .invoke()、.batch()、.stream()、.astream_events(),这实现了真正的统一调用接口。

Prompt Runnable

from langchain_core.prompts import ChatPromptTemplate

# 1. 定义一个 Prompt (Runnable)
prompt = ChatPromptTemplate.from_template("Tell me a joke about {topic}")

# Prompt 也可以调用 invoke / stream
print(prompt.invoke({"topic": "ice cream"}))

messages=[HumanMessage(content='Tell me a joke about ice cream', additional_kwargs={}, response_metadata={})]

Tool Runnable

from langchain_core.tools import tool

# 2. 定义一个简单的 Tool (Runnable)
@tool
def multiply(a: int, b: int) -> int:
    """Multiplies a and b."""
    return a * b

# Tool 也可以调用 invoke / batch
print(multiply.invoke({"a": 2, "b": 3})) 

# Tool 也可以调用 batch (自动并行)
print(multiply.batch([{"a": 2, "b": 3}, {"a": 4, "b": 5}]))
# 输出: [6, 20]

Runnable = LCEL 的语法基础

LCEL(| 运算符)是由 Runnable 定义的组合语义:

chain = prompt | model | StrOutputParser()
output = chain.invoke({"topic": "LangChain"})

这三者本质都是 Runnable:

PromptTemplate → Runnable
Model → Runnable
Parser → Runnable

任何 LCEL chain = 多个 Runnable 的组合。

技术 在 LangChain 1.0 的角色
LangChain 构建 LLM + prompt + tool + outputparser 的组件生态
LangGraph 构建 Agent / 多步工作流 / 状态机的框架
LCEL / Runnable LangChain 的底层执行引擎,依然核心

二:LangChain 模块化管理的定位与描述

LangChain 把“核心抽象”与“具体实现 / 第三方集成 / 历史实现”拆分成多个包,以实现更清晰的 API 边界、减小核心包体积、并把社区贡献与厂商集成模块化管理。主要目标是:核心更稳定、可维护;集成可按需安装。

2.1. LangChain 1.0 核心依赖包及作用

依赖包名称 核心作用 详细功能介绍
langchain-core 核心抽象层和 LCEL 定义所有组件(如模型、消息、提示词模板、工具、运行环境)的标准接口和基本抽象。它包含了 LangChain 表达式语言 (LCEL),这是构建链式应用的基础。这是一个轻量级不含第三方集成的基石包。
langchain 应用认知架构(主包) 包含构建 LLM 应用的通用高阶逻辑,如 Agents (如新的 create_agent() 函数)、Chains 和通用的检索策略 (Retrieval Strategies)。它建立在 langchain-core 之上,是用于组合核心组件的“胶水”层。
langchain-community 社区第三方集成 包含由 LangChain 社区维护的非核心或不太流行的第三方集成,例如:大部分的文档加载器 (Document Loaders)、向量存储 (Vector Stores)、不太流行的 LLM / Chat Model 集成等。为了保持包的轻量,所有依赖项都是可选的。
langchain-openai / langchain-[厂商名称] 特定厂商深度集成 针对关键合作伙伴的集成包(如 langchain-openai, langchain-anthropic)。它们被单独分离出来,以提供更好的支持、可靠性更轻量级的依赖。它们只依赖于 langchain-core。
langchain-classic 旧版本兼容 包含 LangChain v0.x 版本中的已弃用 (deprecated) 或旧版功能,如旧的 LLMChain、旧版 Retrievers、Indexing API 和 Hub 模块。它的主要作用是为用户提供一个平稳的迁移期,确保旧代码在升级到 v1.0 后仍能运行。

1. langchain-core

# 安装:pip install langchain
from langchain_core.prompts import PromptTemplate

prompt_template = PromptTemplate.from_template(
    "为生产{product}的公司起一个好名字?"
)

formatted_prompt = prompt_template.format(product="智能水杯")

response = model.invoke(formatted_prompt)

2. langchain 主包

模块 核心内容 来源说明
langchain.agents create_agentAgentState 智能体创建核心
langchain.messages AIMessageHumanMessagetrim_messages 从 langchain-core 重新导出
langchain.tools @toolBaseTool 从 langchain-core 重新导出
langchain.chat_models init_chat_modelBaseChatModel 统一模型初始化
langchain.embeddings init_embeddings 嵌入模型管理
from langchain.agents import create_agent

# 创建智能体
agent_executor = create_agent(llm, tools)

result = agent.invoke({
    "messages": [{
        "role": "user",
        "content": "会议决定:张三需要在下周一前完成项目报告"
    }]
})

3. langchain-community 第三方集成库

收集并维护社区 / 第三方贡献的集成(例如某些云厂商、开源向量库、特殊工具适配器等)。这些集成实现了 langchain-core 定义的接口,但不属于主包维护范畴。官方会把这些放到 langchain-community 仓库 / 包,便于社区共同维护。

包含内容

特点

# 安装:pip install langchain-community
from langchain_community.document_loaders import NotionDBLoader

# 从 Notion 数据库加载文档
loader = NotionDBLoader(
    integration_token="secret_...",
    database_id="your-db-id"
)

documents = loader.load()

print(f"加载了{len(documents)}条文档")

4. langchain-openai(厂商/提供者集成包)

#!pip install langchain-openai
from langchain_openai import ChatOpenAI

model = ChatOpenAI(model="gpt-4o-mini")

question = "你好,请你介绍一下你自己。"

result = model.invoke(question)
print(result.content)

主流厂商包列表

langchain-community 的区别

维度 langchain-openai langchain-community 中的 OpenAI
维护方 OpenAI 官方 + LangChain 团队 社区维护
更新频率 即时跟进 API 更新 延迟数周
功能完整性 支持所有新特性(如音频、视觉) 仅基础功能
生产可用性 ✅ 强烈推荐 ⚠️ 谨慎使用

最佳实践

5. langchain-classic

# pip intsall langchain-classic
from langchain_classic.chat_models import ChatOpenAI

model = ChatOpenAI(model="gpt-4o-mini")
res = model.invoke("请介绍一下你自己")

三:核心概念与组件

3.1. LLM / ChatModel 大模型接口

Pasted image 20260703151900.png

LangChain 区分两种模型类型:

import os
from dotenv import load_dotenv

load_dotenv(override=True)

DeepSeek_API_KEY = os.getenv("DEEPSEEK_API_KEY")
DeepSeek_BASE_URL = os.getenv("DEEPSEEK_BASE_URL")

1. DeepSeek

# 1 导入 ChatDeepSeek
from langchain_deepseek import ChatDeepSeek

# 2 初始化模型参数
model = ChatDeepSeek(
    model="deepseek-chat",
    temperature=0.0,    # 温度参数,用于控制模型的随机性,值越小则随机性越小
    max_tokens=512,     # 最大生成 token 数
    timeout=30,         # 超时时间,单位秒
    base_url=DeepSeek_BASE_URL # 默认为 https://api.deepseek.com
)

# 3 定义问题
question = "你好,请你介绍一下你自己。"

# 4 调用模型
result = model.invoke(question)

# 5 输出结果
print(result.content)

2. DashScope

from langchain_community.chat_models.tongyi import ChatTongyi

model = ChatTongyi() # 默认 qwen-turbo 模型

question = "你好,请你介绍一下你自己。"

result = model.invoke(question)
print(result.content)

3. OpenAI

# 1 导入 OpenAI
from langchain_openai import OpenAI

# 2 初始化模型
llm = OpenAI(model="gpt-4o-mini")

# 3 定义问题
question = "你好,请你介绍一下你自己。"

# 4 调用模型
result = llm.invoke(question)

# 5 打印结果
print(result)

4. Ollama

# 1 导入 OllamaLLM
from langchain_ollama import OllamaLLM

# 2 初始化本地模型
llm = OllamaLLM(model="deepseek-r1:8b")

# 3 定义问题
question = "你好,请你介绍一下你自己。"

# 4 调用模型
result = llm.invoke(question)

# 5 打印结果
print(result)

5. Vllm

# 连接本地 vLLM 服务
from langchain_openai import ChatOpenAI

# 连接到本地 vLLM 服务, 配置长连接池,减少握手开销
model = ChatOpenAI(
    model="qwen-32b-chat",                  # 指定使用的模型名称
    base_url="http://localhost:8000/v1",    # vLLM 的 OpenAI API 地址
    api_key="EMPTY",                        # vLLM 不验证 key,可以随便写
    max_retries=5,                          # 增加重试次数
    timeout=120.0,                          # 超时时间设长
    http_client={                           # 自定义 HTTP 客户端
        "limits": {
            "max_connections": 100,         # 最大连接数
            "max_keepalive_connections": 20    # 最大保持活动连接数
        }
    }
)

6. init_chat_model()

# 使用 init_chat_model 初始化 DeepSeek 模型
from langchain.chat_models import init_chat_model

# 1. 初始化模型(自动识别供应商)
model = init_chat_model(
    "deepseek-chat",                # 指定 DeepSeek 的聊天模型
    model_provider="deepseek",      # 指定模型提供商为 deepseek
)

# 一行代码切换模型,业务代码 0 改动
# model = init_chat_model("gpt-4o", model_provider="openai")
# model = init_chat_model("claude-3-5-sonnet", model_provider="anthropic")

question = "你好,请你介绍一下你自己。"

result = model.invoke(question)
print(result.content)

RateLimit 模型速率限制器

# 1. 定义带速率限制的 load_chat_model 函数
from langchain.chat_models import init_chat_model
from langchain_core.rate_limiters import InMemoryRateLimiter

# 2. 配置速率限制器
rate_limiter = InMemoryRateLimiter(
    requests_per_second=5,       # 每秒最多 5 个请求
    check_every_n_seconds=1.0    # 每 1 秒检查一次是否超过速率限制
)  

# 3. 对模型调用进行封装,后续直接调用传参数就行
def load_chat_model(
    model: str,         
    provider: str,    
    temperature: float = 0.7,    
    max_tokens: int | None = None,    
    base_url: str | None = None,    
):
    return init_chat_model(
        model=model,               # 模型名称
        model_provider=provider,   # 模型供应商
        temperature=temperature,   # 温度参数,用于控制模型的随机性,值越小则随机性越小
        max_tokens=max_tokens,     # 最大生成 token 数
        base_url=base_url,         # 专用于自定义 API Server 或代理
        rate_limiter=rate_limiter  # 自动限速
    )
# 调用 load_chat_model 函数初始化 gpt-4o-mini 模型
model = load_chat_model(
    model="gpt-4o-mini",    # 指定 OpenAI 的 gpt-4o-mini 模型
    provider="openai",      # 指定模型提供商为 openai
)

res = model.invoke("请介绍一下你自己")
res

.with_retry() 模型重试机制

# 为模型添加指数退避重试策略
model = model.with_retry(
	stop_after_attempt=3,         # 最多重试 3 次
	wait_exponential_jitter=True  # 指数退避 + 随机抖动
)

7. init_embeddings()

# 1. 使用 init_embeddings 初始化嵌入模型
from langchain.embeddings import init_embeddings

# 2. 初始化 OpenAI 的 text-embedding-3-small 嵌入模型
embedding = init_embeddings(model="text-embedding-3-small", provider="openai")   

# 3. 将文本转换为向量表示
res = embedding.embed_query("Hello world")    

# 4. 打印向量的前 10 个元素
print(res[:10])
# 定义 load_embedding 函数封装嵌入模型初始化逻辑
# 该函数用于根据指定的模型名称、提供商和可选的自定义 API 地址,快速初始化并返回一个嵌入模型实例
from langchain.embeddings import init_embeddings

def load_embedding(
    model: str,    # 模型名称
    provider: str,    # 模型提供商
    base_url: str | None = None,    # 自定义 API 服务器地址
):
    # 调用 init_embeddings 完成嵌入模型的初始化
    return init_embeddings(
        model=model,    # 模型名称
        provider=provider,    # 模型提供商
        base_url=base_url    # 自定义 API 服务器地址
    )
# 加载指定的文本嵌入模型(text-embedding-3-small)并指定提供商为 openai
load_embedding("text-embedding-3-small", "openai")

# 使用已加载的嵌入模型对文本 "Hello world" 进行向量化,返回一个向量列表
res = embedding.embed_query("Hello world")

# 打印该向量列表的前 10 个元素,方便快速查看结果
print(res[:10])

3.2. 消息列表 messages

messages 与:

完全一致。

# 导入 OpenAI 官方 SDK,用于调用兼容 OpenAI 接口的模型服务
from openai import OpenAI

# 初始化 DeepSeek 的 API 客户端
client = OpenAI(api_key=DeepSeek_API_KEY, base_url="https://api.deepseek.com")

# 指定模型为 deepseek-chat,构造系统提示和用户提问
response = client.chat.completions.create(
    model="deepseek-chat",  # 使用的模型名称
    messages=[
        {"role": "system", "content": "你是乐于助人的助手,请根据用户的问题给出回答"},  # 系统角色,定义助手行为
        {"role": "user", "content": "你好,请你介绍一下你自己。"},  # 用户提问内容
    ],
)

messages 模板被称为 “消息管道”:

这是 LangChain 最核心的思想:让 prompt 模块化、结构化、可维护。模型需要清楚:谁在说话?哪句是历史内容?哪句是现在的请求?哪些是规则?哪些不能被忽略?仅靠纯文本 Prompt 是无法做到的。

role 作用
system 设定模型的身份、风格、规则,是“最高优先级”
user 表示用户提问内容,是本轮对话的主体输入
assistant / ai 表示模型历史回答,有助于形成上下文记忆
tool 工具调用结果(用于 Agent)
developer 开发者提示(OpenAI 新增 role),模型的功能逻辑 / 工程约束
# 构建对话历史,依次包含系统设定、助手开场白和用户问题
messages = [
    {"role": "system", "content": "你是技术专家,回答要专业。"},    # 系统角色:设定助手为技术专家
    {"role": "assistant", "content": "我准备好了,请问您遇到什么问题?"},  # 助手角色:主动询问用户问题
    {"role": "user", "content": "我的电脑会自动重启。"}             # 用户角色:描述电脑故障
]

# 调用模型生成回复
resp = model.invoke(messages)

# 打印模型返回的回复内容
print(resp.content)

messages 的执行顺序与优先级(非常关键)

LLM 按如下顺序解析:

模型永远会参考全部 messages 才得出最终输出。

# 导入所需的消息类型
from langchain.messages import HumanMessage, SystemMessage

# 创建系统消息,设定模型角色为编程专家
system_msg = SystemMessage("你是一个编程专家。")

# 创建用户消息,请求生成一段 3 行的 Python 示例代码
human_msg = HumanMessage("给我写一段 3 行的 Python 示例。")

# 将系统消息和用户消息组合成消息列表
messages = [system_msg, human_msg]

# 调用模型,传入消息列表并获取响应
resp = model.invoke(messages)

# 提取并返回模型生成的内容
resp.content

3.3. Prompt 提示词模版

1. PromptTemplate

# 导入 PromptTemplate 类,用于构建可复用的提示词模板
from langchain_core.prompts import PromptTemplate  

# 创建模板:{} 中的变量会被动态替换
# 类比:邮件模板中的 {{姓名}} 占位符
template = PromptTemplate(
    input_variables=["product", "feature"],  # 明确声明变量名,确保模板知道需要哪些输入
    template="请为 {product} 的 {feature} 功能写一段宣传文案。"  # 定义模板字符串,占位符将在运行时被替换
)

# 格式化:填充变量,将具体值传入模板生成最终提示词
prompt_text = template.format(
    product="智能手机",  # 替换模板中的 {product}
    feature="AI摄影"   # 替换模板中的 {feature}
)

print("生成的提示词:")
print(prompt_text)
# 输出:请为智能手机的 AI 摄影功能写一段宣传文案。

partial_variables 固定变量

partial_variables = 提前填充固定变量,使 PromptTemplate 成为“半成品模版”

# 1. 创建 PromptTemplate 对象,指定需要填充的变量为 user_question
template = PromptTemplate(
    input_variables=["user_question"],
    template="""
    你是一个专业的技术支持,回答风格:{style}。
    请先复述用户问题,然后提供解决方案。

    用户问题:{user_question}

    解决方案:""",
    
    partial_variables={"style": "简洁明了"} # 可选:部分变量固定,这里预设 style 为“简洁明了”,后续可覆盖
)

# 2. 使用 partial 方法覆盖 style 为“通俗易懂”,再填充用户问题
prompt = template.partial(style="通俗易懂").format(user_question="电脑无法开机")

# 3. 调用模型生成回复
response = model.invoke(prompt)

# 4. 打印最终生成的提示词
print(f"打印生成的提示词:{prompt}")
print("=" * 60)

# 5. 打印模型返回的内容
print(response.content)
项目 input_variables partial_variables
是不是用户必须提供?
何时填入? .format() Template 定义时 / .partial() 覆盖
是否可覆盖?
是否支持函数? 支持(动态变量)
适合场景 用户输入内容 prompt 预设、系统指令

2. ChatPromptTemplate

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.messages import SystemMessage, HumanMessage

# 使用 messages 模板字符串(最常用)
chat_template = ChatPromptTemplate.from_messages([
    # SystemMessage: 定义 AI 角色和行为准则
    ("system", "你是一个专业的 Python 代码审查助手。请严格检查代码风格、潜在 Bug 和性能问题。"),
    # HumanMessage: 用户输入
    ("human", "请审查以下代码:\n\n{code_snippet}"),
    # AIMessage: 可选,提供示例输出(Few-shot)
    ("ai", "我发现了以下问题:1. 缺少类型注解 2. 使用全局变量"),
    # HumanMessage: 用户的后续指令
    ("human", "{follow_up_instruction}")
])

# 格式化:生成消息列表
messages = chat_template.format_messages(
    code_snippet="def add(a,b):\n    return a+b", 
    follow_up_instruction="请给出优化后的代码"
)

print("生成的消息结构:")
for i, msg in enumerate(messages):
    print(f"\n--- 消息 {i+1} ---")
    print(f"角色: {msg.schema}")
    print(f"内容: {msg.content}")

# 直接传递给模型
response = model.invoke(messages)
print("\n 模型审查结果:")
print(response.content_blocks[0]["text"])

3. LangChain Hub 模版库

使用提示词模版库之前需要先到 LangSmith 官网上申请一个 api_key,官网地址:https://smith.langchain.com/

hub 提示词模版库地址:https://smith.langchain.com/hub/

import os
from dotenv import load_dotenv
load_dotenv()

# 从 langsmith 库引入 Client 类
from langsmith import Client 

# 通过 LangSmith 的 LANGSMITH_API_KEY 创建 Client 实例化
client = Client(api_key=os.getenv("LANGSMITH_API_KEY"))

# 从 hub 上拉取对应的 prompt 模版
# 指定 prompt 标识符"rlm/rag-prompt",获取可用于 RAG 场景的提示模板
prompt = client.pull_prompt("rlm/rag-prompt", include_model=True)

print(prompt) # input_variables=['context', 'question'] input_types={} partial_variables={} metadata={'lc_hub_owner': 'rlm', 'lc_hub_repo': 'rag-prompt', 'lc_hub_commit_hash': '50442af133e61576e74536c6556cefe1fac147cad032f4377b60c436e6cdcb6e'} messages=[HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['context', 'question'], input_types={}, partial_variables={}, template="You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise.\nQuestion: {question} \nContext: {context} \nAnswer:"), additional_kwargs={})]
# 使用模板
formatted = prompt.format(
        context="""
                LangChain 是一个构建 LLM 应用的框架,
                目标是把 LLM 与外部工具、数据源和复杂工作流连接起来 —— 支持从简单的 prompt 封装到复杂的 Agent
                (能够调用工具、做决策、执行多步任务)""",   # 模板中定义的上下文变量,用于填充到模板中
        question="什么是LangChain?")                   # 模板中定义的问题变量,用于填充到模板中

print("\n格式化后:")
print(formatted)

response = model.invoke(formatted)
print(response.content) # LangChain 是一个用于构建大型语言模型(LLM)应用的框架。它旨在将 LLM 与外部工具、数据源和复杂工作流连接起来,支持从简单的提示封装到复杂的代理。这个框架可以实现工具调用、决策制定和多步任务执行。

3.4. 标准化内容块 Content Blocks

支持类型:text 、 tool_call 、 image 、 audio 、 video

场景 内容块作用
📄 文档解析(PDF / 图片 / 表格) 用 image block 把 Document OCR 图像传给模型
🔊 语音问答(ASR) 用 audio block 发送语音样本
🎞 多模态 RAG 将检索到的图片、图表、视频帧作为 input blocks 传给模型
🤖 多工具 Agent 工具返回的媒体统一包装成 block 再传回模型
🧪 模型评估(LangSmith / LangChain Playground) 进行 multimodal prompt 测试与 A/B,对 content blocks 标注与评估。

输出提取 content_blocks

# 加载 DeepSeek 提供的推理模型 deepseek-reasoner
deepseek_model = load_chat_model(
    model="deepseek-reasoner",  # 指定模型名称
    provider="deepseek",         # 指定模型提供商
)

# 调用模型
res = deepseek_model.invoke("请介绍一下你自己")

# 从模型返回的结果中提取内容块
res.content_blocks

content_blocks 是 LangChain v1 的标准化多模态消息单元,可以用 dict 结构把图片与音频纳入消息里,框架会把它们转换为各 provider 可识别的格式;在实际使用时务必确认目标模型 / provider 对 multimodal 的支持和所需的 mime_type / metadata 字段。

from langchain_core.messages import HumanMessage, SystemMessage

# 创建系统提示
system_msg = SystemMessage("你是一个专业的问答专家。")

# 构造用户消息:文本 + 图像
human_msg = HumanMessage(content=[
    {"type": "text", "text": "请描述图像:"},
    {
    	"type": "image_url", 
	     "image_url": {
	     	"url": "https://zrj18330672592.oss-cn-beijing.aliyuncs.com/20251015134735612.png", 
		     "mime_type": "image/jpeg",
		     "metadata": "RAG 基础流程图"
		}
    },
])

# 形成消息列表
messages = [system_msg, human_msg]

# 框架会懒解析 content -> content_blocks
for cb in human_msg.content_blocks:
    print(cb)   # content block 对象视图
{'type': 'text', 'text': '请描述图像:'}
{'type': 'image', 'id': 'lc_46bc4293-da92-41eb-bbac-1ffbdeee83b2', 'url': 'https://zrj18330672592.oss-cn-beijing.aliyuncs.com/20251015134735612.png', 'extras': {'image_url_mime_type': 'image/jpeg', 'image_url_metadata': 'RAG基础流程图'}}

Pasted image 20260703161548.png

内容块创建标准格式

comparison = """
┌─────────────┬──────────────────────────────────────────────────────┐
│ 内容块类型    │ 标准格式(LangChain 1.0)                              │
├─────────────┼──────────────────────────────────────────────────────┤
│ 文本        │ {"type": "text", "text": "..."}                      │
│ 图像        │ {"type": "image", "url": "...", "mime_type": "..."}  │
│ 音频        │ {"type": "audio", "url": "...", "mime_type": "..."}  │
│ 视频        │ {"type": "video", "url": "...", "mime_type": "..."}  │
│ 文件        │ {"type": "file", "url": "...", "mime_type": "..."}   │
│ Base64 图像 │ {"type": "image", "base64": "...", "mime_type": "..."} │
│ Base64 音频 │ {"type": "audio", "base64": "...", "mime_type": "..."} │
│ OpenAI 图像 │ {"type": "image_url", "image_url": {"url": "..."}}   │
└─────────────┴──────────────────────────────────────────────────────┘
"""

# OpenAI 内容块支持对比表:
support_table = """
┌─────────────┬──────────┬─────────────────────────────────────┐
│ 内容块类型   │ 支持情况 │ 说明                                │
├─────────────┼──────────┼─────────────────────────────────────┤
│ text        │ ✅ 支持  │ 纯文本内容                          │
│ image_url   │ ✅ 支持  │ 图像 URL(支持 jpg, png, gif, webp)│
│ audio       │ ❌ 不支持│ 需要先用 Whisper 转录为文本         │
│ video       │ ❌ 不支持│ 需要提取关键帧或转录音频            │
│ file        │ ❌ 不支持│ 需要提取文本内容                    │
└─────────────┴──────────┴─────────────────────────────────────┘
"""

3.5. 批处理流程

在使用大模型时,如果需要同时处理多条独立请求(例如多个问题或多段文本),则可以使用批量调用(Batch)方法一次性提交这些请求。LangChain 中的 batch() 方法允许你同时发送一组请求,模型会在后台并行处理,然后返回所有结果:

import time
from datetime import datetime

# 记录开始时间
start_time = time.time()
print(f"⏱️  开始时间: {datetime.now().strftime('%H:%M:%S.%f')[:-3]}")

# 批量提问
responses = model.batch([
    "请介绍下你自己。",
    "请问什么是机器学习?",
    "你知道机器学习和深度学习区别么?"
])

# 记录结束时间
end_time = time.time()
total_duration = end_time - start_time

print(f"⏱️  结束时间: {datetime.now().strftime('%H:%M:%S.%f')[:-3]}")
print(f"📊 总耗时: {total_duration:.2f}s")

for response in responses:
    print(response)
特性 说明
执行位置 batch() 在客户端(Client-side)并行调用模型,而非调用模型提供商的批量 API(如 OpenAI 或 Anthropic 自带的 batch API)。
返回结果 默认会在所有任务完成后,统一返回完整结果列表。
并行优势 多条独立请求可同时执行,无需等待彼此完成。
适用场景 文档摘要、批量问答、数据预处理、多样本分类等。

当然,我们也可以进行流式批处理,也就是每个任务完成后就立即获取结果(而不是等待全部完成),可以使用 batch_as_completed() 方法。

# 使用 model.batch_as_completed 批量提交多个问题,并逐个获取回答
for response in model.batch_as_completed([
    "请介绍下你自己。",
    "请问什么是机器学习?",
    "你知道机器学习和深度学习区别么?"
]):
print(response)

异步并发处理 RunnableConfig

可以在 config 参数中设置批处理的并发数,例如

from langchain_core.runnables import RunnableConfig

# 配置:最多 2 个并发任务
config = RunnableConfig(
    max_concurrency=2,    # 最大并发数:限制同时运行的任务数量,防止资源耗尽
    abstimeout=8.0,       # 单个任务超时时间(秒):超过此时间未完成的任务将被强制终止
    metadata={"request_id": "abc123", "task": "query"},  # 元数据:记录请求 ID 和任务类型,便于追踪和日志分析
)

# 创建一个带有 {product} 占位符变量的模板
prompt_template = PromptTemplate.from_template(
    "为生产 {product} 的公司起一个好名字?"
)

# 准备一个输入列表
inputs = ["彩色袜子", "环保咖啡杯", "智能水杯"]
formatted_prompts = [prompt_template.format(product=product) for product in inputs]

# Jupyter 已经支持顶级 await,无需 asyncio.run()
results = await model.abatch(formatted_prompts, config=config)

for i, r in enumerate(results):
    print(f"=== Query {i+1} ===")
    print(r.content)
    print(r.model_config)

# 可能输出: ['Fun Socks Co.', 'Green Cup Co.', 'HydraSmart']

特别注意

更多 config 参数解释如下:

属性名 类型 说明
max_concurrency int 最大并行执行数
timeout float 每个请求的最大超时时间(秒)
callbacks list 触发事件回调,用于日志或监控
metadata dict 额外的上下文信息,可用于追踪

3.6. 流式传输 (Streaming)

需要注意的是:

  1. 流式输出依赖于整个程序链路都支持“逐块处理”。如果程序中的某个环节必须等待完整输出(如需一次性写入数据库),则无法直接使用 Streaming;
  2. LangChain 1.0 进一步优化了流式机制,引入自动流式模式(Auto-streaming)。例如在 Agent 中,如果整体程序处于 streaming 模式,即便节点中调用 model.invoke(),LangChain 也会自动流式化模型调用。

每个 AIMessageChunk 都可以通过加法 + 操作符拼接。LangChain 内部为此设计了“消息块相加(chunk summation)”机制。

# 使用 .stream() 方法进行流式传输
for chunk in model.stream("用一段话描述大海。"):
    print(chunk.content, end="", flush=True)  # 逐块打印
        
# 输出会像真正的打字效果一样,一个一个词地出现。

# 初始化变量,用于累积模型返回的完整内容
full = None  # 初始值为空

# 使用流式方式调用模型,逐块接收返回内容
for chunk in model.stream("你好,好久不见"):
    # 如果是第一块内容,则直接赋值;否则拼接到已有内容
    full = chunk if full is None else full + chunk
    # 打印当前累积的文本内容
    print(full.text)

astream_events()

LangChain 还支持通过 astream_events() 对语义事件进行异步流式监听,适合需要过滤不同事件类型的复杂场景。

你能看到 完整语义生命周期事件,包括:

非常适合:

import asyncio
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate

# 1. 构建最简单的 Prompt + LLM
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个专业的 AI 助手。"),
    ("human", "{question}")
])

# 2. 初始化 ChatOpenAI 实例,指定使用 gpt-3.5-turbo 模型
llm = ChatOpenAI(model="gpt-3.5-turbo")

# 3. 使用管道符将 prompt 模板与 llm 连接,构建可运行的链
chain = prompt | llm

# 4. 使用 astream_events() 监听所有语义事件
events = chain.astream_events(
    {"question": "请用一句话介绍一下 LangChain 1.0 的核心思想。"},
    version="v1",  # 必须指明版本,v1 才有语义事件
)

async for event in events:
    # 打印事件类型
    print(f"""[Event] type={event["event"]}""")
    # 展示关键字段
    if "data" in event:
        print("   data:", event["data"])
    print("-----------------------------")

3.7. 结构化输出解析

with_structured_output()

使用 Pydantic 的 BaseModel 定义一个严格的数据结构。每个字段都明确了类型(如 str、int、float),并用 Field(..., description="...") 提供语义描述。据此,模型回复时,LangChain 会要求 LLM 的输出必须能填充这些字段。然后使用 with_structured_output 即可引导模型进行结构化输出。

from typing import List
from pydantic import BaseModel, Field
from langchain_openai import ChatOpenAI

# 1. 定义期望的输出结构 (Pydantic 模型)
class Person(BaseModel):
    """Information about a person."""
    name: str = Field(description="人的姓名")
    age: int = Field(description="人的年龄")
    high: int = Field(description="人的身高")
    hobbies: List[str] = Field(description="人的爱好列表")

# 2. 初始化模型并绑定结构化输出格式
llm = ChatOpenAI(model="gpt-4o", temperature=0)

structured_llm = llm.with_structured_output(Person)

# 3. 调用模型并获取 Pydantic 对象,构造提示:要求提取约翰·多伊的姓名、年龄和兴趣爱好
prompt = "提取名为约翰·多伊的人的信息,提取不到的数据就为空值。他30岁,喜欢阅读、远足和弹吉他."

result = structured_llm.invoke(prompt)

# 4. 验证结果
print(f"Type of result: {type(result)}")
print(f"Result object: {result}")

# 5. 判断 result 是否属于 Person 类
assert isinstance(result, Person)
Type of result: <class '__main__.Person'>
Result object: name='约翰·多伊' age=30 high=0 hobbies=['阅读', '远足', '弹吉他']
structured_llm = llm.with_structured_output(Person, include_raw=True)
Type of result: <class 'dict'>
Result object: {'raw': AIMessage(content='{"name":"约翰·多伊","age":30,"hobbies":["阅读","远足","弹吉他"]}', additional_kwargs={'parsed': Person(name='约翰·多伊', age=30, hobbies=['阅读', '远足', '弹吉他']), 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 27, 'prompt_tokens': 165, 'total_tokens': 192, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_cbf1785567', 'id': 'chatcmpl-CdCdia77rTAVnBuqiWo80HxvDZX97', 'service_tier': 'default', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--a36ddb6c-d53b-45c9-bcb5-dcf880f3d2f5-0', usage_metadata={'input_tokens': 165, 'output_tokens': 27, 'total_tokens': 192, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), 'parsed': Person(name='约翰·多伊', age=30, hobbies=['阅读', '远足', '弹吉他']), 'parsing_error': None}

agent 中结构化输出

from pydantic import BaseModel, Field,field_validator
from typing import Literal
from langchain.agents import create_agent

# 1. 定义天气结构化输出模型
class WeatherForecast(BaseModel):
    """天气预报结构化输出"""
    city: str = Field(description="城市名称")
    temperature: int = Field(description="温度(摄氏度)")
    condition: Literal["晴", "雨", "多云", "雪"] = Field(description="天气状况")

# 2. 加载模型
model = load_chat_model(
    model="gpt-4o-mini",
    provider="openai",
)

# 3. 创建智能体
agent = create_agent(
    model=model,                      # 加载的模型
    tools=[],                         # 工具列表,这里为空
    response_format=WeatherForecast   # 指定结构化输出格式
)

# 4. 调用智能体解析天气描述
result = agent.invoke({
    "messages": [{
        "role": "user",
        "content": "北京今天阳光明媚,温度10度"
    }]
})

# 5. 提取并打印结果
forecast = result["structured_response"]
print(f"{forecast.city}天气: {forecast.condition}, {forecast.temperature}°C") # 北京天气: 晴, 10°C

带判断的结构

from pydantic import BaseModel

# 1. 定义年龄模型,限制范围 0-150
class AgeProfile(BaseModel):
    name: str
    age: int = Field(ge=0, le=150)  # 年龄必须在 0-150 之间

# 2. 定义模型
model = load_chat_model(
    model="gpt-4o-mini",
    provider="openai",
)

# 3. 创建智能体 agent
agent = create_agent(
    model=model,
    tools=[],
    response_format=AgeProfile
)

# 4. 模型返回 age=999(非法值)
result = agent.invoke({
    "messages": [{
        "role":"user",
        "content": "张三的年龄是 999 岁"  # 明显不合理的数据
    }]
})

# LangChain 会自动:
# 1. 捕获 ValidationError
# 2. 在 ToolMessage 中反馈错误详情
# 3. 让模型重新生成
# 最终返回合法值
print(result["structured_response"]) # name='张三' age=150

JsonOutputParser

from langchain_core.output_parsers import JsonOutputParser
import json
from pydantic import BaseModel, Field

# 1. 定义输出结构
class WeatherInfo(BaseModel):
    """天气信息"""
    city: str = Field(description="城市名称")
    temperature: int = Field(description="温度(摄氏度)")
    condition: str = Field(description="天气状况")

# 2. 创建 JSON 输出解析器
json_parser = JsonOutputParser(pydantic_object=WeatherInfo)

# 3. 创建提示模板(关键:必须包含 "json" 这个词)
prompt = ChatPromptTemplate.from_template(
"""请根据以下信息提取天气数据,并以 JSON 格式返回。

信息:{weather_info}

请返回包含以下字段的 JSON:
- city: 城市名称
- temperature: 温度(摄氏度)
- condition: 天气状况

必须返回以下 JSON 格式(不要包含任何其他文本):
{{"city": "城市名称", "temperature": 温度数字, "condition": "天气状况"}}

例如:{{"city": "北京", "temperature": 25, "condition": "晴"}}

JSON 格式:
""")

# 4. 定义模型
model = load_chat_model(
    model="gpt-4o-mini",
    provider="openai",
)

# 5. 构建链
runnable = prompt | model | json_parser

# 6. 调用
result = runnable.invoke({"weather_info": "北京今天晴,温度25度"})
print(result) # {'city': '北京', 'temperature': 25, 'condition': '晴'}
print(result["city"]) # 北京
分类 常用解析器 作用
基础解析 StrOutputParser 将模型输出解析成纯字符串(默认)
JSON 结构化解析 JsonOutputParser 将 LLM 输出强制解析为 JSON
PydanticOutputParser 使用 Pydantic v1 模型进行结构化输出
PydanticOutputFunctionsParser 用于 Function Calling 的 Pydantic 结构化解析
列表解析 CommaSeparatedListOutputParser 输出如 "a,b,c" → ["a", "b", "c"]
ListOutputParser 更通用的列表解析
布尔/数值解析 BooleanOutputParser 输出 "yes" / "no" → True / False
FloatOutputParser 输出模型内容转 float
IntOutputParser 输出模型内容转 int
复杂结构化 EnumOutputParser 让模型输出固定几个选项之一
DataclassOutputParser 使用 Python dataclass 进行结构化输出

结构化输出关键要点:

  1. 输出 json 格式提示词必须包含 "json" 关键词
    • DeepSeek API 要求提示词中包含 "json" 这个词
    • 否则会报错:Prompt must contain the word 'json'
  2. 推荐方案对比
    • 方案 1 (JsonOutputParser):最简洁,推荐使用
    • 方案 2 (with_structured_output):需要提示词包含 "json"
    • 方案 3 (可选手动 JSON 解析):最稳定,适合关键应用
  3. 配置建议
    • 设置 temperature=0.0 获得更稳定的输出
    • 最好提供清晰的 JSON 格式示例
  4. 常见错误
    • 提示词中没有 "json" 关键词
    • 没有设置低温度参数
    • 没有提供 JSON 格式示例
    • 没有处理解析异常