上篇你四步跑通了 create_agent——Models + Tools 就能干活。但塞进去的那个「大脑」到底怎么创建、怎么调用?这篇把 Models 单独拆开:ChatOpenAI、init_chat_model,以及 invoke 与 stream。
小明发现 Agent「换模型」很烦
小明把 Agent 跑通了,同事突然说:
把 qwen-plus 换成另一家兼容接口试试,
聊天页还要支持「一个字一个字往外蹦」的效果。
他打开 agent_loop.py,发现模型创建埋在 get_chat_model() 里;再翻自己以前的脚本,有的地方直接 ChatOpenAI(...),有的抄了 init_chat_model(...),流式输出又是另一套 for chunk in ...。
更糟的是,他分不清:
model.invoke("你好") # 整段返回?
model.stream("你好") # 和 Agent 的 invoke 是一回事吗?
create_agent(model, tools=...) # 换模型是不是改这一处就行?
小明去找老张:”Agent 我会建了,但大脑接口还是一团浆糊。”
老张说:”那就把镜头从指挥官拉回大脑——先把 ChatModel 的创建方式和两种访问方式吃透。Agent 只是把这个模型插进去。”
什么是 Models(ChatModel)
老张在白板上写:
模型 = 大语言模型(LLM)
能理解人类语言,生成内容、翻译、摘要、回答问题……
在 LangChain 里日常接触的是 ChatModel:
输入:字符串 或 Messages
输出:AIMessage(或流式 chunk)
“比喻:模型是发动机。create_agent 是整车控制系统——油门、换挡它帮你管,但你得会选发动机、会看转速表。
两种常见「装发动机」的方式:
A. ChatOpenAI(...) → 显式指定 OpenAI 兼容端(通义等最直观)
B. init_chat_model(...)→ 官方统一入口(换 provider 时少改胶水)
两种常见「踩油门」的方式:
invoke → 阻塞:等整段生成完再返回
stream → 流式:边生成边吐 chunk,适合打字机 UI
| 维度 |
invoke |
stream |
| 等待方式 |
阻塞到完整结果 |
迭代 chunk |
| 返回形态 |
一条 AIMessage |
多个部分 chunk |
| 适合 |
脚本、批处理、Agent 内部一步决策 |
聊天窗口、长文生成体验 |
| 心智负担 |
低 |
要自己拼接 chunk.content |
小明:”Agent 里用的是哪一种?”
“create_agent 吃的是 已经建好的 ChatModel 实例。框架内部会多次 invoke 做决策;你给用户做「流式聊天页」时,往往是对裸模型或链做 stream,别和 Agent 状态机搅在一起——先分开学。”
代码拆解:模型工厂 + 三种演示
1. 模型工厂:llm.py
import os
from dotenv import load_dotenv
from langchain.chat_models import init_chat_model
from langchain_openai import ChatOpenAI
load_dotenv()
def get_chat_model(*, temperature: float = 0.7) -> ChatOpenAI:
"""显式 ChatOpenAI(通义等兼容端最直观)。"""
return ChatOpenAI(
model=os.environ.get("OPENAI_MODEL", "qwen-plus"),
api_key=os.environ["OPENAI_API_KEY"],
base_url=os.environ.get("OPENAI_BASE_URL"),
temperature=temperature,
)
def get_init_chat_model(*, temperature: float = 0.7):
"""官方统一入口 init_chat_model。"""
return init_chat_model(
os.environ.get("OPENAI_MODEL", "qwen-plus"),
model_provider="openai",
api_key=os.environ["OPENAI_API_KEY"],
base_url=os.environ.get("OPENAI_BASE_URL"),
temperature=temperature,
)
参数上你暂时记住:
-
-
-
temperature:随机度;Agent 演示常用 0,闲聊可略高
get_chat_model 与 get_init_chat_model 在兼容 OpenAI 协议时,日常效果接近;前者类型明确是 ChatOpenAI,后者走统一入口。”
2. 演示 A:ChatOpenAI + invoke
main.py:
from langchain_core.messages import HumanMessage, SystemMessage
from llm import get_chat_model, get_init_chat_model
def demo_chat_openai_invoke() -> None:
"""A. ChatOpenAI:字符串 invoke + 消息列表 invoke。"""
model = get_chat_model(temperature=0.3)
msg = model.invoke("用一句话介绍 LangChain 是做什么的。")
print(type(msg).__name__, ":", msg.content)
msg2 = model.invoke(
[
SystemMessage(content="你是简洁的技术助教,回答不超过 40 字。"),
HumanMessage(content="什么是 ChatModel?"),
]
)
print("messages:", msg2.content)
“两个用法要刻进肌肉:
-
-
Messages 列表 —— 正式用法;System / Human 角色分开,后面 Messages、多模态、记忆都建在这上面
返回的是消息对象,读正文用 .content,不是裸字符串。”
3. 演示 B:init_chat_model
def demo_init_chat_model() -> None:
"""B. 官方统一入口 init_chat_model。"""
model = get_init_chat_model(temperature=0.3)
msg = model.invoke("用一句话说明 init_chat_model 的用途。")
print(type(model).__name__, ":", msg.content)
“同事要你换供应商时,优先想的是改工厂函数,而不是满项目搜 ChatOpenAI。这就是统一入口的价值。”
4. 演示 C:stream
def demo_stream() -> None:
"""C. 流式输出。"""
model = get_chat_model(temperature=0.3)
print("流式:", end="", flush=True)
n = 0
for chunk in model.stream("用两三句话介绍什么是流式输出,适合初学者。"):
print(chunk.content or "", end="", flush=True)
n += 1
print()
print("chunk 数量:", n)
“stream 返回可迭代对象。每个 chunk.content 可能是一小段字,要自己拼;flush=True 是为了终端立刻刷出来,模拟打字机。
注意:chunk.content 可能是空,所以用 or \"\",避免打印 None。”
5. 接到 Agent:创建智能体时注入模型
大脑就是这样插进去的:
agent = create_agent(
get_chat_model(temperature=0),
tools=TOOLS,
system_prompt="你是助手。需要查天气或做加法时必须调用工具,不要编造。",
)
result = agent.invoke({"messages": [{"role": "user", "content": question}]})
“导图里的「在 Agent 中使用模型」就两步:创建智能体时传入 model → 调用智能体。
换发动机 = 换 get_chat_model / get_init_chat_model 的实现或环境变量,不必改工具循环。”
小明复述:”工厂造 ChatModel;invoke 整段、stream 逐片;Agent 吃的是模型实例。”
“对。main.py 里三个 demo 默认只开了一个,你本地把注释打开就能全跑。”
def main() -> None:
demo_init_chat_model()
print("Day1 OK")
总结
老张说:”第三篇只办一件事——把大脑接口钉死。”
“三个核心理解:
-
ChatModel 是 Agent 的发动机 —— 用工厂创建,用环境变量换端
-
两条创建路 ——
ChatOpenAI 直观;init_chat_model 统一入口
-
两种访问 ——
invoke 阻塞整段;stream 逐 chunk,服务不同场景”
LangChain 支线进度:
认识 LangChain
↓
Agent 快速入门(create_agent)
↓
Models(本篇:工厂 + invoke/stream)
↓
Messages → Prompts/LCEL → Tools → Memory → …
小明说:”下一篇该把 Messages 和多模态搞清楚了——invoke 吃列表时那些 SystemMessage / HumanMessage 到底怎么排。”
“对。下一篇:Messages 与多模态——消息类型、在线图片、本地 base64。”
会建 Agent 不够,还要会换大脑、会选 invoke 还是 stream。模型工厂让配置只有一处真相。