1. 本章目标 #

上一章用 create_agent(model="deepseek:...") 直接传了模型字符串。能跑通,但调参、流式、批量、结构化输出这些能力还没拆开讲。

本章把 Chat Model 单独讲清楚:

用统一接口调用聊天模型:初始化、调参、流式、批量,并把它交给 Agent。

学完你应能:

参考文档:

2. Chat Model 在系统里的位置 #

模型是 Agent 的「大脑」,但不必每次都上 Agent。翻译、分类、摘要、抽取这类固定流程,直接调 Chat Model 往往更简单、更便宜。

单独调用:  用户输入 ──► Chat Model ──► AIMessage
Agent 调用:用户输入 ──► create_agent(内部循环调 Model + Tools)──► 最终回答

LangChain 的价值之一,是给不同供应商套上统一接口:业务代码尽量写一次,换模型时主要改标识与集成包。

除文本生成外,现代聊天模型通常还支持:

能力 作用 本章 / 后续
Tool calling 请求调用外部工具 §7 预览;第 4 / 8 章
Structured output 按 schema 输出 §7 预览;第 6 章
Streaming 边生成边返回 §4.2
Multimodality 图文等多模态 第 4 章

记住:Chat Model 的返回值通常是 AIMessage(不是裸字符串);文本在 .content。

3. 两种初始化方式 #

创建模型有两条常见路:

  1. 统一工厂 init_chat_model("provider:model") —— 本章默认
  2. 供应商专用类(如 ChatDeepSeek)或 OpenAI 兼容类 —— 细调 / 迁移时更直观

先掌握方式 A,再按需用方式 B。

3.1. 方式 A:init_chat_model(推荐) #

统一工厂:用 "provider:model" 字符串即可,切换供应商时主要改字符串。
额外参数(temperature、timeout 等)以关键字传入,各供应商写法大体类似。

3.1.1. init_chat_model.py #

# 从 langchain.chat_models 导入统一初始化聊天模型的工厂函数
from langchain.chat_models import init_chat_model
# 从 dotenv 导入用于加载环境变量的函数
from dotenv import load_dotenv

# 加载 .env 中的环境变量;override=True 表示覆盖已存在的同名变量
load_dotenv(override=True)

# 使用「provider:model」字符串创建聊天模型,其余参数以关键字参数传入
model = init_chat_model(
    # 指定供应商为 deepseek,模型名为 deepseek-v4-flash
    "deepseek:deepseek-v4-flash",
    # 设置生成温度;数值越低,输出越稳定、越确定
    temperature=0.2,
# 结束 init_chat_model 调用并得到模型实例
)

# 调用模型;传入的字符串会自动当作一条用户消息
result = model.invoke("用一句话介绍 LangChain")
# 打印模型返回的 AIMessage 中的文本内容
print(result.content)

前提:已安装对应集成包(本章 DeepSeek 需 langchain-deepseek),且 .env 里有可用密钥。

3.2. 方式 B:供应商专用类 #

需要细调厂商特有参数,或对照该厂商文档示例时,专用类更直观。以 DeepSeek 为例:

3.2.1. ChatDeepSeek.py #

# 从 langchain_deepseek 导入 DeepSeek 专用聊天模型类
from langchain_deepseek import ChatDeepSeek
# 从 dotenv 导入用于加载环境变量的函数
from dotenv import load_dotenv

# 加载 .env 中的环境变量;override=True 表示覆盖已存在的同名变量
load_dotenv(override=True)

# 使用供应商专用类创建 DeepSeek 聊天模型实例
model = ChatDeepSeek(
    # 指定模型名称为 deepseek-v4-flash
    model="deepseek-v4-flash",
    # 设置生成温度;数值越低,输出越稳定、越确定
    temperature=0.2,
    # 设置调用失败时的最大重试次数
    max_retries=2,
# 结束 ChatDeepSeek 初始化并得到模型实例
)

# 调用模型;传入的字符串会自动当作一条用户消息
result = model.invoke("用一句话介绍 LangChain")
# 打印模型返回的 AIMessage 中的文本内容
print(result.content)

也可以用 OpenAI 兼容接口指向 DeepSeek(适合迁移已有 ChatOpenAI 代码,或走兼容网关):

3.2.2. ChatOpenAI_compatible.py #

# 导入 os 模块,用于读取环境变量
import os
# 从 langchain_openai 导入 OpenAI 兼容的聊天模型类
from langchain_openai import ChatOpenAI
# 从 dotenv 导入用于加载环境变量的函数
from dotenv import load_dotenv

# 加载 .env 中的环境变量;override=True 表示覆盖已存在的同名变量
load_dotenv(override=True)

# 使用 OpenAI 兼容接口创建指向 DeepSeek 的聊天模型实例
model = ChatOpenAI(
    # 指定模型名称为 deepseek-v4-flash
    model="deepseek-v4-flash",
    # 从环境变量读取 DeepSeek API 密钥
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    # 设置 API 基地址;优先读 OPENAI_API_BASE,否则默认 DeepSeek 官方地址
    base_url=os.getenv("OPENAI_API_BASE", "https://api.deepseek.com"),
    # 设置生成温度;数值越低,输出越稳定、越确定
    temperature=0.2,
# 结束 ChatOpenAI 初始化并得到模型实例
)

# 调用模型并打印返回的 AIMessage 文本内容
print(model.invoke("用一句话介绍 LangChain").content)

注意:兼容模式下,密钥与 base_url 必须指向真实可用的 DeepSeek(或网关)地址,不能沿用 OpenAI 默认值。

3.3. 怎么选 #

场景 建议
多数业务代码 init_chat_model("deepseek:...")
深度绑定某一厂商 SDK 能力 ChatDeepSeek / ChatOpenAI 等
已有 OpenAI 风格代码,换兼容网关 ChatOpenAI + base_url

本章默认:init_chat_model("deepseek:deepseek-v4-flash")。

3.4. 换供应商示意(只改标识与集成包) #

统一工厂的好处在换模型时最明显:业务调用代码不动,主要改字符串与依赖包。

# DeepSeek
model = init_chat_model("deepseek:deepseek-v4-flash")

# OpenAI(需 langchain-openai / langchain[openai])
model = init_chat_model("openai:gpt-4o-mini")

# Anthropic(需 langchain-anthropic)
model = init_chat_model("anthropic:claude-sonnet-4-6")

# Ollama 本地(需 langchain-ollama,且服务已启动)
model = init_chat_model("ollama:llama3.2")

完整列表见 Providers。
本地 Ollama 还要保证本机服务已启动、模型已拉取,否则连不上。

4. 调用方式:invoke / stream / batch #

Chat Model(以及后面拼好的链)都是 Runnable,常见三种同步用法:

方法 含义 典型场景
invoke 一次输入 → 一次完整输出 默认、脚本、接口同步处理
stream 增量产出 打字机式展示长回答
batch 一批输入并行处理 批量摘要、批量分类

建议:先 invoke 跑通,再上 stream / batch。

4.1. invoke:一次拿完整结果 #

最常用。输入可以是:

4.1.1. invoke.py #

# 从 langchain.chat_models 导入统一初始化聊天模型的函数
from langchain.chat_models import init_chat_model
# 从 dotenv 导入用于加载 .env 环境变量的函数
from dotenv import load_dotenv

# 加载 .env 文件中的环境变量;override=True 表示覆盖已存在的同名变量
load_dotenv(override=True)

# 初始化 DeepSeek 聊天模型,temperature=0 使输出更确定、更稳定
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)

# 以单条字符串作为输入调用模型,并打印返回的 AIMessage 文本内容
print(model.invoke("1+1等于几?只答数字。").content)

# 构造多轮对话:用 dict 消息列表(role/content)表示系统提示与用户问题
conversation = [
    # 系统消息:设定助手角色与回答风格
    {"role": "system", "content": "你是简洁的中文助手,回答尽量短。"},
    # 用户消息:提出关于 Chat Model 的问题
    {"role": "user", "content": "什么是 Chat Model?"},
# 结束多轮对话消息列表的定义
]
# 将多轮消息列表传入模型并打印返回的 AIMessage 文本内容
print(model.invoke(conversation).content)

返回值是 AIMessage(不是裸字符串)。常用字段:

调试时若打印出整个对象而不是句子,多半是忘了取 .content。

4.2. stream:边生成边打印 #

长回答时,流式可以降低等待感。
model.stream 产出的是 AIMessageChunk;增量文本一般用 .text,也可以累加成完整消息。

4.2.1. stream.py #

# 从 langchain.chat_models 导入统一初始化聊天模型的函数
from langchain.chat_models import init_chat_model
# 从 dotenv 导入用于加载 .env 环境变量的函数
from dotenv import load_dotenv

# 加载 .env 文件中的环境变量;override=True 表示覆盖已存在的同名变量
load_dotenv(override=True)

# 初始化 DeepSeek 聊天模型
model = init_chat_model("deepseek:deepseek-v4-flash")

# 以流式方式调用模型;每个 chunk 是 AIMessageChunk,.text 取增量文本
for chunk in model.stream("用三句话介绍 Agent 是什么"):
    # 打印当前增量文本;end="" 不换行,flush=True 立即刷新输出缓冲区
    print(chunk.text, end="", flush=True)
# 流式输出结束后打印换行,使终端光标落到下一行
print()

需要「流式过程中拼出完整消息」时,可对 chunk 做累加:

4.2.2. stream_accumulate.py #

# 从 langchain.chat_models 导入统一初始化聊天模型的函数
from langchain.chat_models import init_chat_model
# 从 dotenv 导入用于加载 .env 环境变量的函数
from dotenv import load_dotenv

# 加载 .env 文件中的环境变量;override=True 表示覆盖已存在的同名变量
load_dotenv(override=True)

# 初始化 DeepSeek 聊天模型
model = init_chat_model("deepseek:deepseek-v4-flash")

# 用于累加流式 chunk 的变量,初始为 None
full = None
# 以流式方式调用模型,逐块接收 AIMessageChunk
for chunk in model.stream("用一句话解释 temperature 参数"):
    # 首个 chunk 直接赋值,后续 chunk 与已有结果相加拼成完整消息
    full = chunk if full is None else full + chunk
    # 可选:观察「到目前为止」的完整文本
    # print(full.text)

# 流式结束后打印累加得到的完整文本
print("最终:", full.text)

累加得到的 full 可以当作历史里的一条助手消息,再发起下一轮 invoke(见练习 2)。

与第 2 章 agent.stream 的区别(别混):

API 流的是什么
model.stream 模型 token / 文本块
agent.stream Agent 图节点更新(模型步、工具步等)

4.3. batch:并行多请求 #

适合一批彼此独立的问题。
这是客户端并发多个请求,不是厂商侧的「离线 Batch API」。用 max_concurrency 控制并发数。

4.3.1. batch.py #

# 从 langchain.chat_models 导入初始化聊天模型的函数
from langchain.chat_models import init_chat_model

# 从 dotenv 导入加载环境变量的函数
from dotenv import load_dotenv

# 加载 .env 中的环境变量,并覆盖已存在的同名变量
load_dotenv(override=True)

# 初始化 DeepSeek 聊天模型,温度设为 0 以保证输出更稳定
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)

# 批量并发调用模型,同时处理多条提示词并收集响应
responses = model.batch(
    # 构造包含四季概括任务的提示词列表
    [
        # 要求用四个字概括春天
        "用四个字概括春天",
        # 要求用四个字概括夏天
        "用四个字概括夏天",
        # 要求用四个字概括秋天
        "用四个字概括秋天",
        # 要求用四个字概括冬天
        "用四个字概括冬天",
    ],
    # 设置最大并发数为 4,加快批量请求速度
    config={"max_concurrency": 4},
)

# 遍历批量调用返回的全部响应结果
for r in responses:
    # 打印当前响应的文本内容
    print(r.content)

batch 的结果顺序与输入顺序一致。
若希望「谁先完成谁先返回」,可用 batch_as_completed(顺序可能乱,需对照输入索引)。

4.3.2 batch_as_completed.py #

# 从 langchain.chat_models 导入初始化聊天模型的函数
from langchain.chat_models import init_chat_model

# 从 dotenv 导入加载环境变量的函数
from dotenv import load_dotenv

# 加载 .env 中的环境变量,并覆盖已存在的同名变量
load_dotenv(override=True)

# 初始化 DeepSeek 聊天模型,温度设为 0 以保证输出更稳定
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)

# 批量并发调用模型,同时处理多条提示词并收集响应
responses = model.batch_as_completed(
    # 构造包含四季概括任务的提示词列表
    [
        # 要求用四个字概括春天
        "用四个字概括春天",
        # 要求用四个字概括夏天
        "用四个字概括夏天",
        # 要求用四个字概括秋天
        "用四个字概括秋天",
        # 要求用四个字概括冬天
        "用四个字概括冬天",
    ],
    # 设置最大并发数为 4,加快批量请求速度
    config={"max_concurrency": 4},
)

# batch_as_completed 按完成顺序产出 (索引, 消息) 元组
for index, r in responses:
    # 打印原始输入序号与当前响应文本
    print(index, r.content)

与第 7 章 RunnableParallel 的差别:batch 是「多份输入、同一条模型」;并行链常是「一份输入、多条支路」。

4.4. 异步:ainvoke / astream #

在 Web 服务(FastAPI 等)里应优先用异步接口,避免同步 invoke 阻塞事件循环:

import asyncio
from langchain.chat_models import init_chat_model
from dotenv import load_dotenv

load_dotenv(override=True)

model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)


async def main():
    msg = await model.ainvoke("用一句话介绍 Chat Model")
    print(msg.content)
    async for chunk in model.astream("用一句话介绍 stream"):
        print(chunk.text, end="", flush=True)


asyncio.run(main())

与第 7 章链上异步一致:同步用 invoke/stream,异步用 ainvoke/astream。create_agent 也支持 await agent.ainvoke(...)。

5. 常用参数调优 #

参数决定「稳不稳、贵不贵、会不会超时」。
通过 init_chat_model(..., **kwargs) 传入即可(供应商类同理)。

参数 含义 实战建议
temperature 随机性;越高越发散 抽取 / 工具调用偏 0~0.3;创意写作可更高
max_tokens 最大生成长度 控制成本与超长胡言
timeout 等待超时(秒) 弱网或长生成可加大
max_retries 失败重试次数 默认约 6;弱网可 10~15。401/404 等客户端错误通常不重试

没有放之四海而皆准的默认值:分类、工具决策偏稳,文案头脑风暴偏活。

5.1. parameters.py #

# 从 langchain.chat_models 导入初始化聊天模型的函数
from langchain.chat_models import init_chat_model
# 从 dotenv 导入加载环境变量的函数
from dotenv import load_dotenv

# 加载 .env 文件中的环境变量,并允许覆盖已存在的同名变量
load_dotenv(override=True)

# 偏确定:适合分类、抽取、要稳的工具决策
# 初始化一个偏确定性的聊天模型实例,赋值给变量 strict
strict = init_chat_model(
    # 指定使用的模型名称:DeepSeek V4 Flash
    "deepseek:deepseek-v4-flash",
    # 将温度设为 0,使输出更稳定、可复现
    temperature=0,
    # 限制单次回复最多生成 256 个 token
    max_tokens=256,
    # 设置请求超时时间为 60 秒
    timeout=60,
    # 请求失败时最多重试 6 次
    max_retries=6,
# 结束 init_chat_model 的参数列表
)

# 偏发散:适合头脑风暴
# 初始化一个偏创造性的聊天模型实例,赋值给变量 creative
creative = init_chat_model(
    # 指定使用的模型名称:DeepSeek V4 Flash
    "deepseek:deepseek-v4-flash",
    # 将温度设为 0.9,使输出更发散、更有创意
    temperature=0.9,
    # 限制单次回复最多生成 256 个 token
    max_tokens=256,
# 结束 init_chat_model 的参数列表
)

# 定义提示词:要求模型为咖啡店起名,且只输出店名本身
prompt = "给咖啡店起一个店名,只输出店名本身。"
# 调用确定性模型生成回复,并打印 temperature=0 时的结果内容
print("temperature=0 :", strict.invoke(prompt).content)
# 调用创造性模型生成回复,并打印 temperature=0.9 时的结果内容
print("temperature=0.9:", creative.invoke(prompt).content)

多跑几次你会看到:低 temperature 更稳,高 temperature 更多变。
同一业务里也可以准备两个模型实例:strict 做抽取,creative 做文案。

6. 把模型实例交给 Agent #

第 2 章写的是 create_agent(model="deepseek:...")。
其实 model 既可以是字符串,也可以是已配置好的模型实例。

什么时候该传实例?

6.1. agent_with_model.py #

# 从 langchain.agents 导入 create_agent,用于创建智能体
from langchain.agents import create_agent

# 从 langchain.chat_models 导入 init_chat_model,用于初始化聊天模型
from langchain.chat_models import init_chat_model

# 从 dotenv 导入 load_dotenv,用于加载环境变量
from dotenv import load_dotenv

# 加载 .env 中的环境变量;override=True 表示覆盖已存在的同名变量
load_dotenv(override=True)

# 初始化聊天模型实例并赋值给 model
model = init_chat_model(
    # 指定提供商与模型名称:deepseek 的 deepseek-v4-flash
    "deepseek:deepseek-v4-flash",
    # 设置温度为 0,使输出更确定、随机性更低
    temperature=0,
    # 设置请求超时时间为 60 秒
    timeout=60,
)


# 定义获取天气信息的工具函数,参数为城市名,返回字符串
def get_weather(city: str) -> str:
    # 函数文档字符串:说明该函数用于获取指定城市的天气信息
    """获取指定城市的天气信息。"""
    # 返回模拟的天气结果字符串
    return f"{city} 今天晴,气温 25°C。"


# 创建智能体,绑定模型、工具列表与系统提示词
agent = create_agent(
    # 传入已初始化的模型实例,而不是模型名称字符串
    model=model,
    # 将 get_weather 注册为智能体可调用的工具
    tools=[get_weather],
    # 设置系统提示:需要天气时请调用工具,不要编造
    system_prompt="需要天气时请调用工具,不要编造。",
)

# 调用智能体,传入用户关于成都天气的提问消息
result = agent.invoke({"messages": [{"role": "user", "content": "成都天气怎么样?"}]})
# 打印智能体最终回复消息的文本内容
print(result["messages"][-1].content)

字符串写法和实例写法在「能跑通」层面通常一致;差别在于配置是否集中、是否可复用。

7. 能力预览:工具绑定与结构化输出 #

Chat Model 不只会「聊天」。本节只做入口预览,细节见后续章节:

能力 一句话 后续章节
bind_tools 让模型提出要调哪个工具 第 4 章手工环;第 8 章 Tools
with_structured_output 让模型按 schema 返回对象 第 6 章

7.1. bind_tools(模型层工具调用) #

不经过完整 Agent 时,也可以让模型「提出」要调哪个工具。
注意:这只产生 调用意图(tool_calls),不会自动执行你的 Python 函数。

7.1.1. bind_tools_preview.py #

# 从 langchain.chat_models 导入初始化聊天模型的函数
from langchain.chat_models import init_chat_model

# 从 langchain.tools 导入 tool 装饰器,用于将函数转换为工具
from langchain.tools import tool

# 从 dotenv 导入加载环境变量的函数
from dotenv import load_dotenv

# 加载 .env 文件中的环境变量,并覆盖已存在的同名变量
load_dotenv(override=True)


# 使用 @tool 装饰器,将下方函数注册为可供模型调用的工具
@tool
# 定义获取天气信息的工具函数,接收城市名称并返回字符串
def get_weather(city: str) -> str:
    # 工具的功能说明文档字符串,供模型理解该工具的用途
    """获取指定城市的天气信息。"""
    # 返回模拟的天气信息字符串
    return f"{city} 今天晴,气温 25°C。"


# 初始化 DeepSeek 聊天模型,温度设为 0 以保证输出更稳定
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
# 将天气工具绑定到模型上,使模型能够发起工具调用
model_with_tools = model.bind_tools([get_weather])

# 调用绑定了工具的模型,传入用户关于北京天气的提问
ai = model_with_tools.invoke("北京天气如何?")
# 打印模型返回的文本内容
print("content:", ai.content)
# 打印模型生成的工具调用信息
print("tool_calls:", ai.tool_calls)

注意:bind_tools 只让模型发出调用意图。真正执行工具、把结果塞回对话,通常交给 create_agent(第 2 章),或自己手写循环(第 4 章)。工具定义细节见第 8 章。

7.2. with_structured_output(结构化结果) #

需要模型直接返回可校验的结构化对象(而不是自由文本)时,用 with_structured_output。

传入 Pydantic 模型(或 JSON Schema),模型会按字段约束产出结果,适合工单分类、信息抽取、表单填充等。拿到的不再是一段话,而是带类型的对象,可直接入库或交给业务逻辑。

注意:部分模型在「思考 / thinking」模式下可能不支持强制工具选择。若 with_structured_output 报错,可按下方示例关闭 thinking 后再试。
本节只是预览;第 6 章会系统讲 schema 设计、解析失败,以及订单 / 工单抽取器。

7.2.1. structured_preview.py #

# 从 typing 模块导入 Literal,用于将字段取值限制为指定字面量
from typing import Literal

# 从 pydantic 导入 BaseModel 与 Field,用于定义带校验的数据模型
from pydantic import BaseModel, Field

# 从 langchain.chat_models 导入 init_chat_model,用于按提供商初始化聊天模型
from langchain.chat_models import init_chat_model

# 从 dotenv 导入 load_dotenv,用于从 .env 文件加载环境变量
from dotenv import load_dotenv

# 加载 .env 环境变量;override=True 表示覆盖进程中已存在的同名变量
load_dotenv(override=True)


# 定义客服工单摘要的 Pydantic 模型类
class Ticket(BaseModel):
    # 类文档字符串:说明该类用于表示客服工单摘要
    """客服工单摘要。"""

    # 问题类别字段,取值只能是「退款」「物流」「咨询」「其他」之一
    category: Literal["退款", "物流", "咨询", "其他"] = Field(description="问题类别")
    # 紧急程度字段,取值只能是「低」「中」「高」之一
    urgency: Literal["低", "中", "高"] = Field(description="紧急程度")
    # 一句话摘要字段,类型为字符串
    summary: str = Field(description="一句话摘要")


# deepseek-v4 默认开启 thinking;thinking 下不支持强制 tool_choice,
# 而 with_structured_output 默认走 function_calling,会触发 400
# 调用 init_chat_model 初始化 DeepSeek 聊天模型
model = init_chat_model(
    # 指定提供商与模型名称:deepseek 平台的 deepseek-v4-flash
    "deepseek:deepseek-v4-flash",
    # 将采样温度设为 0,使模型输出更稳定、更确定
    temperature=0,
    # 通过 extra_body 关闭 thinking,避免结构化输出时触发 400 错误
    extra_body={"thinking": {"type": "disabled"}},
    # 结束 init_chat_model 调用并完成模型实例创建
)
# 基于 Ticket 模型创建结构化输出提取器,强制模型按该 schema 返回
extractor = model.with_structured_output(Ticket)

# 调用提取器,将用户投诉文本解析为 Ticket 结构化对象
ticket = extractor.invoke("我的快递三天没更新了,很着急。")
# 打印解析得到的工单对象
print(ticket)

本章用 DeepSeek 做结构化输出时,请养成习惯:关 thinking + 偏低 temperature。

8. 查看 token 用量 #

上线后常要估成本、做限流。不少供应商会在 AIMessage.usage_metadata 里带回用量。

若为 None,可能是该模型或路径未返回用量,也可能需按供应商文档开启相关选项——先别假设一定有。

8.1. token_usage.py #

# 从 langchain.chat_models 导入初始化聊天模型的函数
from langchain.chat_models import init_chat_model

# 从 dotenv 导入加载环境变量的函数
from dotenv import load_dotenv

# 从 rich 导入增强版 print,用于更美观地打印输出
from rich import print

# 加载 .env 中的环境变量,并覆盖进程中已存在的同名变量
load_dotenv(override=True)

# 初始化 DeepSeek 聊天模型(模型标识为 deepseek-v4-flash)
model = init_chat_model("deepseek:deepseek-v4-flash")
# 调用模型,请求用一句话解释什么是 embedding
ai = model.invoke("用一句话解释什么是 embedding")

# 打印模型返回的文本内容
print(ai.content)
# 打印本次调用的 token 用量等元数据
print(ai.usage_metadata)
# 说明 usage_metadata 中常见字段的含义
# 常见字段示意:input_tokens / output_tokens / total_tokens

示例输出:

{
    'input_tokens': 88,
    'output_tokens': 91,
    'total_tokens': 179,
    'input_token_details': {'cache_read': 0},
    'output_token_details': {'reasoning': 60}
}
字段 含义 示例值
input_tokens 本次请求的输入 token 数(提示词等) 88
output_tokens 本次响应的输出 token 数(含正文与推理等) 91
total_tokens 总用量,一般为 input_tokens + output_tokens 179
input_token_details.cache_read 输入侧从缓存命中读取的 token 数(未命中则为 0) 0
output_token_details.reasoning 输出侧用于推理 / thinking 的 token 数 60

说明:*_token_details 是否出现、包含哪些子字段,取决于供应商与模型。开启 thinking 时常见 reasoning;启用 prompt cache 时常见 cache_read。
算账时别忘了:thinking / reasoning token 也会计入费用。

9. 练习 #

  1. 对比 temperature:同一提示跑 0 与 0.9 各 3 次,记录输出差异。
  2. 流式拼消息:用 full = full + chunk 得到完整 AIMessage,再把 full 作为历史的一部分发起第二轮 invoke。
  3. batch 压测:用 batch 一次问 5 个短问题,观察总耗时相对串行 invoke 的变化。
  4. 交给 Agent:把带 temperature=0 的模型实例传给 create_agent,对比字符串写法行为是否一致。

10. 本章小结 #

  1. Chat Model 可单独用,也可作为 Agent 的大脑。
  2. 优先用 init_chat_model("provider:model"),切换供应商成本低。
  3. 调用方式:invoke / stream / batch;Web 服务用 ainvoke / astream(§4.4)。
  4. 用 temperature / max_tokens / timeout / max_retries 控制稳定性与成本。
  5. bind_tools(→ 第 4 / 8 章)、with_structured_output(→ 第 6 章)是后续入口能力。

下一章:Messages 消息体系——System / Human / AI / Tool,以及多模态内容怎么表示。