学习LangChain day1

学习 LangChain Day 1:从模型调用到消息结构

今天不急着做一个复杂的 Agent,而是先把 LangChain 最基础、也最容易混淆的几个概念弄清楚:它是什么、环境如何搭建、模型如何初始化、一次调用到底发生了什么,以及消息对象为什么不只是一个字符串。

学习日期:2026-10-05


一、为什么要学习 LangChain?

刚开始接触大模型开发时,我们通常会直接调用某个模型厂商提供的 SDK。代码可能只有几行:准备 API Key,传入一段文本,等待模型返回答案。这种方式非常适合入门,但当需求变复杂后,问题就会逐渐出现:

  • 不同模型厂商的 SDK 写法不一样,切换模型时需要重写代码;
  • 模型调用、提示词、工具调用、数据库检索和结果解析混在一起,代码越来越难维护;
  • 想查看一次请求中到底调用了哪些工具、花了多少时间、消耗了多少 token,不容易;
  • 当模型需要多轮对话时,单纯拼接字符串会让角色、上下文和工具结果变得混乱;
  • 当一个任务需要多个步骤时,很难清晰地表达"先检索,再判断,最后回答"的流程。

LangChain 的价值,就在于它为这些常见能力提供了统一的抽象。它不是一个"大模型",也不是某一家模型服务,而是一个帮助我们构建 LLM 应用的开发框架。

可以把它理解成一层应用开发接口:底层可以接入不同的聊天模型,上层可以组合提示词、消息、工具、检索器、结构化输出和工作流。这样,我们关注的是"应用要完成什么任务",而不是把所有精力都放在某个供应商的请求格式上。

一个典型的 LangChain 应用可能长这样:

text 复制代码
用户问题
   ↓
消息与提示词整理
   ↓
调用聊天模型
   ↓
模型判断是否需要工具
   ↓
调用搜索、数据库或业务 API
   ↓
把工具结果重新交给模型
   ↓
生成最终答案

这里的每一步都可以独立替换。例如,可以把一个模型换成另一个模型,把向量数据库换成普通数据库,把搜索工具换成企业内部 API,而不用完全重写上层业务代码。

1. LangChain 中最核心的几个概念

1.1 Model:模型

模型负责根据输入生成输出。聊天模型通常接收一组带有角色的消息,并返回一条 AI 消息。

1.2 Message:消息

消息不仅包含文本,还包含角色、消息 ID、工具调用、token 使用情况和供应商返回的附加信息。消息是聊天模型应用中的基本数据结构。

1.3 Runnable:可运行对象

LangChain 中许多组件都遵循 Runnable 接口,因此可以使用统一的 invoke、batch、stream 和异步方法。模型、提示词模板、输出解析器,甚至由多个组件组合出的链,都可以被当作 Runnable 使用。

1.4 Tool:工具

工具是模型可以请求调用的函数。例如搜索天气、查询订单、读取数据库、执行计算等。模型本身通常不会直接执行函数,而是先返回一个工具调用请求,由应用程序真正执行工具,再把结果作为 ToolMessage 交回模型。

1.5 Retriever:检索器

检索器负责从文档库、向量数据库或其他数据源中找出与问题相关的内容。它经常和 RAG 应用一起使用:先找到资料,再让模型基于资料回答问题。


二、LangChain 家族的四大支柱

学习资料中经常把 LangChain 生态概括为四个部分:LangChain、LangGraph、LangSmith 和 LangServe。它们分别对应应用组件、流程编排、开发观测和服务化。

2.1 LangChain:应用组件层

LangChain 是最基础、最常用的部分。它提供了模型、消息、提示词模板、工具、检索器、输出解析器等组件,并规定了较统一的调用方式。

如果把开发一个大模型应用比作搭积木,那么 LangChain 就提供了许多已经做好的积木:

  • 模型积木:连接不同厂商的聊天模型;
  • 消息积木:管理系统消息、用户消息、AI 消息和工具消息;
  • 提示词积木:把变量填充到固定模板中;
  • 工具积木:将普通 Python 函数包装成模型可调用的工具;
  • 检索积木:从文档和数据库中查找相关信息;
  • 解析积木:把模型输出转换为字符串、JSON 或自定义对象;
  • 组合积木:把多个 Runnable 串接成一个完整流程。

2.2 LangGraph:复杂流程与 Agent 编排层

如果任务只有"输入问题 → 调用模型 → 返回回答"三步,普通 LangChain 就足够了。但如果任务开始出现循环、分支、状态保存和人工确认,就需要更强的流程编排能力。

例如一个客服 Agent 可能需要:

  1. 先识别用户意图;
  2. 如果是订单问题,查询订单系统;
  3. 如果是退款问题,检查退款规则;
  4. 如果金额较大,暂停并等待人工确认;
  5. 工具失败时自动重试;
  6. 最后总结处理结果。

这种流程不是一条简单的直线,而是一张有节点、有边、有状态的图。LangGraph 用图结构表达这些步骤,并支持循环、持久化、暂停、恢复和人工介入。

2.3 LangSmith:开发、调试与评估层

LangSmith 可以理解为大模型应用的"运行记录和质量分析平台"。当应用出现问题时,我们不仅想知道最终回答错了,还想知道:

  • 当时传给模型的完整消息是什么?
  • 模型实际返回了什么?
  • 是否调用了工具?工具参数是否正确?
  • 哪一步耗时最长?
  • 总共消耗了多少 token?
  • 新版本提示词是否比旧版本更好?

LangSmith 可以通过追踪记录这些运行过程,也可以帮助我们构造数据集和评估流程。

2.4 LangServe:服务化层

LangServe 的目标是把 LangChain 的 Runnable 暴露成 HTTP 接口,让其他前端或业务系统可以通过 API 调用。它适合把一个已经写好的链快速包装为服务。

不过需要注意,生态项目会随着版本变化。学习资料里仍然常见"四大支柱"的说法,但实际开发时应该以当前官方文档和项目状态为准。LangServe 的仓库目前已归档,新项目进行部署时要优先查看官方推荐的 LangChain 或 LangGraph 部署方式。

2.5 四者之间如何配合?

可以用下面的方式理解:

text 复制代码
LangChain:提供组件
LangGraph:组织复杂流程
LangSmith:观察和评估运行过程
LangServe:把流程提供给外部系统调用

例如,一个企业知识库问答应用可以这样组合:

text 复制代码
LangChain:模型 + 文档加载 + 检索器 + 提示词
LangGraph:多轮检索、重写问题、判断是否继续检索
LangSmith:查看每次检索和模型调用,评估回答质量
服务层:将最终问答流程提供给前端或其他业务系统

三、Conda 安装与虚拟环境配置

3.1 为什么需要虚拟环境?

Python 项目经常会依赖第三方库,而不同项目可能依赖同一个库的不同版本。例如:

  • 项目 A 需要 langchain==某个版本;
  • 项目 B 需要另一个版本;
  • 某个模型集成包又依赖特定版本的 pydantic 或 httpx。

如果所有项目都安装在系统 Python 中,升级一个项目的依赖可能导致另一个项目无法运行。虚拟环境的作用,就是为每个项目创建一个相对独立的 Python 和依赖空间。

Conda 不仅能创建 Python 虚拟环境,还能管理一些 Python 之外的二进制依赖。对于刚开始学习大模型应用的同学,使用 Miniconda 就足够了;如果希望安装很多科学计算工具,也可以选择 Anaconda Distribution。

3.2 安装 Conda

Windows 上常见的两种选择是:

  • Miniconda:体积小,只包含 Conda 和基础 Python 环境,安装什么由自己决定;
  • Anaconda:预装较多数据科学软件,占用空间更大,但开箱即用。

安装后打开 Anaconda Prompt 或 PowerShell,执行:

powershell 复制代码
conda --version

如果能看到版本号,说明 Conda 已经可以使用。如果 PowerShell 提示找不到 conda,可以先打开 Anaconda Prompt;也可以执行一次 Shell 初始化:

powershell 复制代码
conda init powershell

执行后关闭并重新打开 PowerShell。

3.3 创建项目环境

powershell 复制代码
conda create -n langchain-day1 python=3.11 -y

命令中:

  • create 表示创建环境;
  • -n langchain-day1 表示环境名称为 langchain-day1;
  • python=3.11 表示在环境中安装 Python 3.11;
  • -y 表示自动确认安装。

启用环境:

powershell 复制代码
conda activate langchain-day1

成功后,命令行前面通常会出现环境名:

text 复制代码
(langchain-day1) PS C:\Users\...

确认当前 Python 来自虚拟环境:

powershell 复制代码
python --version
where.exe python

3.4 安装 LangChain 相关依赖

先升级 pip:

powershell 复制代码
python -m pip install --upgrade pip

再安装基础包和 OpenAI 聊天模型集成:

powershell 复制代码
python -m pip install -U langchain langchain-openai

这里建议使用 python -m pip,而不是直接输入 pip。这样可以明确表示:使用当前虚拟环境中的 Python 来执行 pip,避免系统中有多个 Python 时装错位置。

后续根据模型供应商安装对应的集成包。LangChain 的核心包和模型供应商集成通常是分开的,例如:

powershell 复制代码
# 以下仅为示意,请根据实际供应商选择
python -m pip install -U langchain-anthropic
python -m pip install -U langchain-google-genai

3.5 API Key 的安全配置

不要这样写:

python 复制代码
model = ChatOpenAI(api_key="sk-真实密钥")

因为代码一旦上传到 GitHub、发送给他人或出现在截图中,密钥就可能泄露。更安全的做法是使用环境变量:

powershell 复制代码
$env:OPENAI_API_KEY = "你的_API_Key"

Python 代码只负责读取:

python 复制代码
import os

print(bool(os.getenv("OPENAI_API_KEY")))

如果使用 .env 文件:

text 复制代码
OPENAI_API_KEY=你的_API_Key

安装并读取:

powershell 复制代码
python -m pip install python-dotenv
python 复制代码
from dotenv import load_dotenv

load_dotenv()

.env 必须加入 .gitignore:

gitignore 复制代码
.env
.venv/
__pycache__/

3.6 退出、删除和导出环境

退出当前环境:

powershell 复制代码
conda deactivate

查看已有环境:

powershell 复制代码
conda env list

删除环境:

powershell 复制代码
conda remove -n langchain-day1 --all

导出环境依赖,便于在另一台机器上复现:

powershell 复制代码
conda env export -n langchain-day1 > environment.yml

根据文件创建环境:

powershell 复制代码
conda env create -f environment.yml

四、两种模型初始化方式

LangChain 中的聊天模型不是简单的字符串处理函数。初始化模型时,我们是在创建一个可以接受消息、生成 AI 消息,并且支持统一 Runnable 调用接口的对象。

下面以 ChatOpenAI 为例。模型名只是示例,实际使用时应替换成当前账号和服务商支持的模型。

4.1 直接实例化具体模型类

python 复制代码
from langchain_openai import ChatOpenAI

model = ChatOpenAI(
    model="gpt-4o-mini",
    temperature=0.2,
    max_tokens=512,
    timeout=30,
    max_retries=2,
)

response = model.invoke("用一句话解释 LangChain。")
print(response.content)

这种方式的特点是:直接导入某个供应商对应的模型类。代码读起来很直观,别人一看就知道项目使用的是哪个模型集成。

它特别适合下面的情况:

  • 项目确定只使用一个模型供应商;
  • 需要使用该供应商的专属功能;
  • 需要查看该集成特有的参数和返回字段;
  • 希望类型提示和 IDE 补全更加明确。

4.2 使用 init_chat_model

python 复制代码
from langchain.chat_models import init_chat_model

model = init_chat_model(
    "openai:gpt-4o-mini",
    temperature=0.2,
    max_tokens=512,
    timeout=30,
    max_retries=2,
)

response = model.invoke("用一句话解释 LangChain。")
print(response.content)

init_chat_model 提供了一个相对统一的初始化入口。它将供应商和模型写在模型标识中,例如:

text 复制代码
provider:model_name

这样的写法有利于把模型名称放进配置文件,或者根据环境变量选择不同模型:

python 复制代码
import os
from langchain.chat_models import init_chat_model

model_name = os.getenv("CHAT_MODEL", "openai:gpt-4o-mini")
model = init_chat_model(model_name, temperature=0.2)

4.3 两者的本质区别

两种方式最终都希望得到一个聊天模型对象,后续通常都可以调用 invoke、stream、batch 等方法。主要区别在于初始化阶段的抽象层次不同:

对比项 直接实例化模型类 init_chat_model
代码形式 ChatOpenAI(...) init_chat_model("openai:...")
抽象程度 更具体 更统一
供应商特性 更容易访问 需要确认统一入口是否暴露
切换模型 通常需要修改导入和初始化代码 可通过配置修改模型标识
适用项目 供应商固定、需要专属能力 教程、平台化封装、多供应商切换

需要注意:统一初始化不代表不同供应商的参数完全一致。一个供应商支持的参数,另一个供应商可能不支持;即使参数名称相同,含义也可能略有差异。因此切换模型时,除了改模型名称,还要检查 API Key、模型能力、参数兼容性和返回格式。

4.4 模型初始化常用参数

model

指定模型名称。模型名通常由供应商定义,不同服务商不能混用。模型名称写错时,常见结果是请求失败或返回模型不存在。

temperature

控制输出的随机性。一般来说:

  • 较低的值:回答更稳定、格式更容易控制;
  • 较高的值:表达更丰富,但可能更发散;
  • 事实抽取、分类、代码生成等任务通常会使用较低值;
  • 创意写作、头脑风暴可以适当提高。

它不是"智力参数",调高并不意味着模型一定更聪明。

max_tokens

限制模型最多生成多少 token。它通常只限制输出长度,不等于上下文窗口大小。输入消息本身也会占用上下文空间。

timeout

请求超时时间。网络不稳定、模型响应慢或服务端排队时,超时可以防止程序无限等待。

max_retries

请求失败时的最大重试次数。重试适合处理临时网络问题或服务端限流,但不是所有错误都应该重试,例如 API Key 错误、模型名称错误通常需要直接修正配置。

api_key

身份验证密钥。建议通过环境变量传入,而不是硬编码到源代码。

base_url

自定义 API 地址。某些兼容 OpenAI API 的服务可以使用它,但要确认该服务的路径、认证方式和响应格式与当前集成兼容。

4.5 初始化参数与调用配置的区别

下面两段代码解决的是不同问题:

python 复制代码
model = ChatOpenAI(
    model="gpt-4o-mini",
    temperature=0.2,
)

这是初始化模型,设置模型的默认行为。

python 复制代码
response = model.invoke(
    "介绍 LangChain。",
    config={
        "tags": ["day1"],
        "metadata": {"source": "blog"},
    },
)

这是配置某一次 Runnable 运行 ,设置运行名称、标签、元数据或并发行为。后文会详细说明 config。


五、模型调用方式:普通、流式、批量和异步

LangChain 的模型对象通常遵循 Runnable 接口,因此调用方法具有比较统一的命名。可以把它们理解为三种维度:

  • 调用一条还是多条输入;
  • 一次性返回还是边生成边返回;
  • 使用同步代码还是异步代码。

5.1 invoke:一次调用一次返回

python 复制代码
response = model.invoke("什么是 LangChain?")

print(type(response))
print(response.content)

返回值通常不是普通字符串,而是 AIMessage 或类似的消息对象。直接打印 response 可以看到更多元数据;只想获取回答文本时,可以读取 response.content。

也可以传入消息列表:

python 复制代码
from langchain_core.messages import SystemMessage, HumanMessage

messages = [
    SystemMessage(content="你是一位简洁的 Python 老师。"),
    HumanMessage(content="解释列表和元组的区别。"),
]

response = model.invoke(messages)
print(response.content)

5.2 stream:边生成边显示

普通调用需要等模型生成结束后才能看到结果,流式调用则会把结果拆成多个块陆续返回:

python 复制代码
for chunk in model.stream("用三句话介绍 LangChain。"):
    print(chunk.text, end="", flush=True)
print()

流式调用适合聊天窗口,因为用户不需要等待整段回答生成完毕。用户先看到开头内容,会感觉系统响应更快。

但流式返回的每个 chunk 不一定是完整的词、句子或消息。有的块可能只有文本增量,有的块可能包含工具调用片段、元数据或空内容。因此实际项目中要根据返回类型处理,而不能默认每个块都有完整的 content。

将文本收集成完整答案:

python 复制代码
chunks = []

for chunk in model.stream("解释什么是流式输出。"):
    print(chunk.text, end="", flush=True)
    chunks.append(chunk.text)

full_text = "".join(chunks)
print("\n\n完整答案:", full_text)

5.3 batch:批量处理多条输入

当有多条互相独立的问题时,可以使用 batch:

python 复制代码
questions = [
    "LangChain 是什么?",
    "LangGraph 解决什么问题?",
    "LangSmith 有什么用?",
]

responses = model.batch(questions)

for question, response in zip(questions, responses):
    print("问题:", question)
    print("回答:", response.content)
    print("---")

batch 能让代码表达得更清楚:我们不是手动写三次 invoke,而是明确告诉 LangChain"这里有一批独立输入"。实际底层是否合并成一个供应商请求,取决于具体 Runnable 和模型集成,不能简单认为一定只发出一次 HTTP 请求。

5.4 并发控制:max_concurrency

批量任务数量较大时,不应该无节制地同时请求模型,否则可能触发限流:

python 复制代码
responses = model.batch(
    questions,
    config={"max_concurrency": 3},
)

这里表示尽量将同时执行的任务数限制在 3 个。它不是模型参数,而是 Runnable 的运行配置。

5.5 异步调用

异步方法适合异步 Web 框架、批量网络请求或需要同时等待多个模型任务的程序。方法名称通常在同步方法前加 a:

python 复制代码
import asyncio

async def main():
    response = await model.ainvoke("什么是异步调用?")
    print(response.content)

asyncio.run(main())

异步批量调用:

python 复制代码
async def main():
    questions = [
        "什么是 LangChain?",
        "什么是 LangGraph?",
        "什么是 LangSmith?",
    ]

    responses = await model.abatch(
        questions,
        config={"max_concurrency": 3},
    )

    for response in responses:
        print(response.content)

异步流式调用:

python 复制代码
async def main():
    async for chunk in model.astream("用一句话介绍 LangSmith。"):
        print(chunk.text, end="", flush=True)
    print()

5.6 方法对应关系

需求 同步方法 异步方法
单次完整调用 invoke ainvoke
单次流式调用 stream astream
多条输入 batch abatch
多条输入流式处理 stream/组合 Runnable astream/异步事件接口

同步和异步不是"哪个更高级",而是适用于不同的程序结构。简单脚本使用同步方法更容易理解;异步 Web 服务和高并发任务则更适合异步方法。


六、图片补充内容:profile、model_kwargs、extra_body 和 config

这一部分按图片标注内容做一个简要说明,不展开供应商的全部专属参数。

6.1 profile

profile 用来查看模型能力或限制信息,例如上下文长度、token 限制、工具调用或多模态能力等。可以这样查看:

python 复制代码
print(getattr(model, "profile", None))

不同模型集成和版本提供的字段可能不同,因此不能把 profile 当作所有模型都完全一致的配置表。

6.2 model_kwargs

model_kwargs 通常用于传递底层模型集成支持的额外模型参数:

python 复制代码
model = ChatOpenAI(
    model="你的模型名",
    model_kwargs={"top_p": 0.9},
)

具体参数必须查看当前模型集成的文档。

6.3 extra_body

extra_body 常用于向兼容 OpenAI API 的服务传递供应商自定义的请求体字段:

python 复制代码
model = ChatOpenAI(
    model="你的模型名",
    extra_body={"top_k": 40},
)

它并不是所有模型都支持的通用参数,能否生效取决于服务端。

6.4 调用时的 config

config 是一次 Runnable 运行的配置:

python 复制代码
response = model.invoke(
    "介绍一下 LangChain。",
    config={
        "run_name": "day1-introduction",
        "tags": ["tutorial", "day1"],
        "metadata": {"chapter": 1},
    },
)

它常用于追踪、筛选、元数据记录和并发控制。可以记成:

text 复制代码
模型初始化参数:决定模型默认怎么工作
调用 config:描述这一次运行如何被记录和执行

七、LangSmith 是什么?

LangSmith 是 LangChain 生态中的开发和观测平台。它的作用可以简单概括为:把一次大模型应用运行过程记录下来,让开发者能够调试、评估和改进应用。

7.1 为什么需要 LangSmith?

假设用户说:"你的回答不准确。"只看最终答案,我们很难判断问题出在哪里。可能是:

  • 提示词写得不清楚;
  • 历史消息没有正确传入;
  • 检索器找到的资料不相关;
  • 工具返回了错误数据;
  • 模型没有正确理解工具调用结果;
  • 同一个问题在不同模型上的表现不同。

如果记录了完整运行链路,就可以逐步检查每个环节,而不是凭感觉修改代码。

7.2 主要功能

运行追踪

查看一次调用经过了哪些步骤,包括输入、输出、耗时、模型名称和工具调用。

调试

定位提示词、消息结构、工具参数和模型输出中的问题。

评估

准备一批测试问题,使用规则或评估模型比较输出质量,观察新版本是否真的变好了。

项目管理

把不同实验归类到不同项目,便于比较不同模型、提示词和代码版本。

7.3 开启追踪

powershell 复制代码
$env:LANGSMITH_TRACING = "true"
$env:LANGSMITH_API_KEY = "你的_LangSmith_API_Key"
$env:LANGSMITH_PROJECT = "langchain-day1"

只在本地或安全的部署环境中保存 API Key,不能把密钥提交到公开仓库。


八、消息格式与消息对象字段

8.1 为什么模型输入不是一个字符串?

聊天模型需要区分"谁说了什么"。同一句话,如果是系统指令、用户问题或上一轮 AI 回复,含义可能完全不同。因此聊天模型通常接收消息列表:

python 复制代码
[
    SystemMessage(...),
    HumanMessage(...),
    AIMessage(...),
    ToolMessage(...),
]

消息列表不仅保存对话文本,还能表达工具调用和工具结果。

8.2 四种常见消息类型

SystemMessage

用于设置模型的行为和规则,例如角色、回答风格、输出格式和限制条件:

python 复制代码
from langchain_core.messages import SystemMessage

SystemMessage(content="你是一名严谨的 Python 教师。")

系统消息不是用户问题,而是对模型的整体行为说明。

HumanMessage

表示用户输入:

python 复制代码
from langchain_core.messages import HumanMessage

HumanMessage(content="解释一下列表和元组的区别。")
AIMessage

表示模型生成的消息。它的 content 可以是回答文本,也可以同时包含工具调用信息。

ToolMessage

表示工具执行结果。它通常需要通过 tool_call_id 与之前 AI 消息中的工具调用对应起来。

8.3 常见消息字段

字段 说明 常见消息
type 消息类型,如 system、human、ai、tool 所有消息
content 消息主体,可以是字符串或内容块列表 所有消息
name 可选名称,用于标识消息来源 部分消息
id 消息唯一标识 部分消息
tool_calls AI 请求调用工具的信息 AIMessage
tool_call_id 工具结果对应的调用 ID ToolMessage
response_metadata 模型或供应商返回的附加信息 AIMessage
usage_metadata 输入、输出和总 token 使用量等信息 AIMessage
additional_kwargs 集成保留的供应商特有字段 视集成而定

8.4 一个完整的消息调用示例

python 复制代码
from langchain_core.messages import SystemMessage, HumanMessage

messages = [
    SystemMessage(
        content="你是一名学习助手。回答要分点,并给出一个简单例子。"
    ),
    HumanMessage(
        content="什么是 Runnable?"
    ),
]

response = model.invoke(messages)

print("消息类型:", response.type)
print("回答内容:", response.content)
print("响应元数据:", response.response_metadata)
print("Token 使用:", response.usage_metadata)

这些字段并不一定全部有值。是否返回 token 使用量、模型名称、结束原因和供应商原始字段,取决于具体模型集成和服务端响应。

8.5 工具调用的消息流

当模型使用工具时,对话可能是:

text 复制代码
HumanMessage:帮我查询订单 1001 的状态
        ↓
AIMessage:请调用 get_order(order_id="1001")
        ↓
ToolMessage:订单 1001 当前状态为"已发货"
        ↓
AIMessage:订单 1001 已发货,预计明天送达

这里的关键是:工具结果不是普通字符串随便拼接进去,而是使用工具消息,并通过调用 ID 建立对应关系。这样模型和框架才能知道这个结果属于哪一次工具调用。


九、content 与 content_blocks 的区别

9.1 content 是什么?

content 是消息对象的主体内容。最简单的文本回答通常是一个字符串:

python 复制代码
response = model.invoke("你好")
print(response.content)

对于多模态或包含特殊内容的消息,content 也可能是一个列表,里面包含文本、图片、音频或供应商特有的数据结构。

9.2 content_blocks 是什么?

content_blocks 可以理解为一种更结构化的内容访问方式。它把消息主体拆分为若干内容块,并尽量使用统一的类型表达,例如文本块、图片块、工具调用块等。

这样做的好处是,应用程序可以根据块的类型处理内容,而不需要把所有返回值都当作字符串:

python 复制代码
for block in response.content_blocks:
    print(block)

具体块的字段会受到模型、供应商和 LangChain 版本的影响,因此写代码时应先打印实际结构,再决定如何解析。

9.3 对比表

对比项 content content_blocks
定位 消息的原始主体 结构化访问内容的接口
最适合 纯文本回答、快速读取 多模态内容、工具调用、统一解析
数据形态 字符串或列表 内容块列表
兼容性 可能保留供应商原始格式 更适合跨模型处理,但受集成支持影响
使用建议 简单场景优先读取 需要区分内容类型时使用

9.4 调试时怎么判断?

python 复制代码
response = model.invoke("介绍一下 LangChain")

print("content 的类型:", type(response.content))
print("content:", response.content)
print("content_blocks:", response.content_blocks)

可以这样做一个简单的文本提取:

python 复制代码
texts = []

for block in response.content_blocks:
    if block.get("type") == "text":
        texts.append(block.get("text", ""))

print("".join(texts))

不过,不同版本和集成返回的块可能不是普通字典,也可能存在不同字段名,因此生产代码需要根据实际返回对象编写更稳健的解析逻辑。

9.5 什么时候用哪个?

  • 只需要显示普通文本:优先使用 response.content;
  • 需要处理图片、音频或视频:检查 content_blocks;
  • 需要识别工具调用:查看 AIMessage.tool_calls,同时结合内容块;
  • 需要兼容多个模型供应商:不要假设所有模型的原始 content 格式相同;
  • 正在调试模型响应:同时打印 content、content_blocks 和完整消息对象。

十、一个可运行的 Day 1 示例

下面把本章最重要的知识串起来:初始化模型、构造消息、普通调用、流式调用和批量调用。

python 复制代码
from langchain.chat_models import init_chat_model
from langchain_core.messages import SystemMessage, HumanMessage


model = init_chat_model(
    "openai:gpt-4o-mini",
    temperature=0.2,
    max_tokens=512,
)


messages = [
    SystemMessage(content="你是一名 LangChain 入门老师,请用清晰的中文回答。"),
    HumanMessage(content="什么是 Runnable?"),
]


# 1. 普通调用
response = model.invoke(
    messages,
    config={
        "run_name": "day1-invoke",
        "tags": ["day1", "invoke"],
    },
)
print("普通调用:")
print(response.content)


# 2. 流式调用
print("\n流式调用:")
for chunk in model.stream("请用三句话解释消息对象。"):
    print(chunk.text, end="", flush=True)
print()


# 3. 批量调用
print("\n批量调用:")
questions = [
    "LangChain 是什么?",
    "LangSmith 是什么?",
]

responses = model.batch(questions, config={"max_concurrency": 2})
for item in responses:
    print(item.content)

运行前需要确认:

  1. 已启用正确的 Conda 环境;
  2. 已安装 langchain 和对应模型集成包;
  3. API Key 已通过环境变量配置;
  4. 模型名称与当前服务商支持的模型一致;
  5. 网络可以访问对应模型服务。

十一、今日总结

今天的重点不是记住很多 API,而是建立一个正确的整体认识:

  1. LangChain 是大模型应用开发框架,不是模型本身。
  2. LangChain 生态可以从组件、流程、观测和服务化四个角度理解。
  3. Conda 虚拟环境可以隔离项目依赖,减少版本冲突。
  4. 直接实例化模型类更具体,init_chat_model 更适合统一封装和切换。
  5. invoke、stream、batch 和异步方法表达了不同的调用模式。
  6. 模型初始化参数与 Runnable 的 config 不是同一类配置。
  7. 消息对象不仅有文本,还可以承载工具调用、元数据和 token 使用信息。
  8. 简单文本可以读取 content,复杂或多模态内容需要关注 content_blocks。
  9. LangSmith 可以帮助我们观察、调试和评估模型应用。

下一步学习建议

下一篇可以继续学习:

  • Prompt Template 如何管理提示词;
  • prompt | model | parser 这种 Runnable 链式组合;
  • 结构化输出与 Pydantic 模型;
  • Tool Calling 的完整流程;
  • 文档加载、向量化和 RAG;
  • LangGraph 中的节点、边和状态。

官方参考资料

相关推荐
传奇开心果编程1 小时前
【现代声明式UI学与练】第7课 组件通信——父传子、子传父、跨层级通信、状态提升与 Context
学习·flutter·react native·ui·swiftui·android jetpack
老A的AI实验室1 小时前
Cyber Weekly #84
人工智能·ai·llm·agi·genai
流浪0012 小时前
大模型技术全景(十一):智能体通信协议 MCP、A2A 与 ANP
llm·agent·通信协议·mcp·a2a·anp
小此方2 小时前
LangChain/LangGraph(二)大模型接入篇一:API接入,从API Key到API请求报文,使用Apifox完成大模型接口调用
ai·langchain
stereohomology2 小时前
免费额度大的:qoder,workbuddy.ai,zcode还是有区别的
llm·薅羊毛
我命由我123452 小时前
Photoshop - Photoshop 矢量蒙版
学习·职场和发展·产品运营·求职招聘·职场发展·产品经理·photoshop
半糖程序员3 小时前
从零构建 Agent(10):保存并恢复会话
agent
熊猫钓鱼>_>3 小时前
越顺,越空:当 AI 把学习 “优化“ 到消失
人工智能·学习·ai·llm·agent·ai编程·metaai
一条破秋裤3 小时前
02_注册设备号_从主次设备号到成对注销
学习