用 init_chat_model 初始化任意聊天模型,用 create_agent 构建 Agent,再用流式输出让响应实时显示。
LangChain 的 Module 1 从最基础的能力入手:如何调用大语言模型(LLM)?如何构建一个能记住对话、会调用工具的 Agent?
这一节(1.1_foundational_models)关注的是最基础的三件事:
init_chat_model 统一不同厂商的模型接口create_agent 把模型包装成一个能持续对话的智能体agent.stream() 让 LLM 的响应像打字机一样逐字显示,而不是等全部生成完再显示本课程使用 DeepSeek 作为主要 LLM(也支持 Gemini 等)。DeepSeek 提供兼容 OpenAI API 格式的接口,因此在 LangChain 里用 model_provider="openai" 加上自定义 base_url 即可接入。这种"兼容层"设计让你可以用同一套 LangChain 代码切换不同厂商的模型。
LangChain 提供 init_chat_model 函数,统一了不同 LLM 提供商的初始化方式。你只需要传入模型名称、提供商标识符和 API 密钥,就能得到一个标准的聊天模型对象。
最简单的用法是直接用 LangChain 官方集成的模型类:
from langchain_google_genai import ChatGoogleGenerativeAI
# 直接初始化 Gemini 模型
model = ChatGoogleGenerativeAI(model="gemini-2.5-flash-lite")
# 直接调用:注意这是 model.invoke,不是 agent.invoke
response = model.invoke("What's the capital of the Moon?")
print(response.content)
model.invoke() 直接调用原始模型,返回的是 AIMessage 对象,通过 .content 取文本内容。而 agent.invoke() 返回的是包含完整消息历史的字典 {"messages": [...]}。两者的接口不同。
notebook 里定义了一个 deepseek_model() 工厂函数,封装了所有 DeepSeek 相关的初始化细节:
from dotenv import load_dotenv
load_dotenv() # 从 .env 文件加载 DEEPSEEK_API_KEY 等环境变量
import os
from langchain.chat_models import init_chat_model
DEEPSEEK_MODEL = "deepseek-v4-flash"
DEEPSEEK_BASE_URL = "https://api.deepseek.com"
def deepseek_model(model: str = DEEPSEEK_MODEL, max_tokens=200, **kwargs):
return init_chat_model(
model=model,
model_provider="deepseek", # 或 "openai"(DeepSeek 兼容 OpenAI 格式)
max_tokens=max_tokens,
base_url=DEEPSEEK_BASE_URL,
api_key=os.environ["DEEPSEEK_API_KEY"],
**kwargs
)
使用工厂函数初始化模型:
model = deepseek_model(temperature=1)
print(model) # 打印模型对象,确认配置
# 直接调用模型(不经过 Agent)
response = model.invoke("what is 1+1?")
print(response.content) # → "The answer is 2."
| 参数 | 说明 | 示例值 |
|---|---|---|
model |
模型 ID 字符串 | "deepseek-v4-flash" |
model_provider |
LangChain 路由到哪个 provider 的适配器 | "deepseek" / "openai" / "google-genai" |
max_tokens |
最大输出 token 数量 | 200 / 1000 |
temperature |
输出随机性(0=确定性,1=最随机) | 0 / 1 |
base_url |
自定义 API 端点(DeepSeek/本地模型用) | "https://api.deepseek.com" |
create_agent 是 LangChain 提供的高层 API,它把一个聊天模型包装成一个完整的 LangGraph Agent(底层是一个带 checkpointer 的 StateGraph)。
Agent 相比原始模型多了什么?
messages 列表,支持多轮对话from langchain.agents import create_agent
# 最基础的用法:只传入模型
agent = create_agent(model=deepseek_model())
create_agent 在底层构建了一个 LangGraph StateGraph,包含一个 model 节点(调用 LLM)和一个 tools 节点(执行工具调用)。它们通过条件边(conditional edge)连接:模型输出工具调用时走向 tools 节点,否则结束。这就是 ReAct(Reasoning + Acting)模式的实现。
调用 Agent 用 agent.invoke({"messages": [...]}),输入是一个包含 messages 键的字典,消息可以用 HumanMessage 对象或字典格式传入。
from langchain.messages import HumanMessage
agent = create_agent(deepseek_model())
messages = [
{"role": "user", "content": "what is 1+1?"},
{"role": "assistant", "content": "2"},
{"role": "user", "content": "how about times 5?"}
]
response = agent.invoke({"messages": messages})
print(response['messages'][-1].content)
Agent 的响应是一个字典,核心键是 messages,它是一个消息列表,包含完整的对话历史:
print(len(response['messages'])) # → 4(3 条输入 + 1 条 AI 响应)
for msg in response['messages']:
print(msg.content)
通常只需要最后一条 AI 消息:response['messages'][-1].content。这是最常见的取值模式——取消息列表的最后一项,再取 .content 属性获取文本内容。
用 agent.invoke() 需要等模型全部生成完才能看到结果。agent.stream() 则让模型每生成一个 token 就立即推送,实现"打字机效果"——这在 UI 交互和长响应场景下体验要好得多。
messages = [{"role": "user", "content": "Tell me all about Luna City, the capital of the Moon"}]
for token, metadata in agent.stream(
{"messages": messages},
stream_mode="messages" # 关键:按消息/token 流式推送
):
if token.content: # 过滤空 token(工具调用消息没有 content)
print(token.content, end="", flush=True) # 不换行,实时打印
| stream_mode | 推送时机 | 适合场景 |
|---|---|---|
"messages" |
每生成一个 token/消息片段就推送 | UI 打字机效果、实时响应显示 |
"values" |
每完成一个 LangGraph 节点就推送完整 State | 监控 Agent 内部步骤状态 |
"updates" |
每个节点完成后推送该节点的 State 变更 | 调试节点输出 |
在流式循环里,agent.stream() 同时返回 token(消息内容)和 metadata(执行元数据)。metadata 包含 LangGraph 内部运行时信息,对调试和追踪非常有用。
for token, metadata in agent.stream(
{"messages": messages},
stream_mode="messages"
):
# 第一个 token 时打印 metadata
print(metadata)
break
| 字段 | 含义 |
|---|---|
langgraph_step |
当前是 LangGraph 执行的第几步(从 1 开始) |
langgraph_node |
当前正在执行的节点名称(如 'model' 或 'tools') |
langgraph_triggers |
触发当前节点执行的来源(边/事件名称) |
ls_provider |
实际使用的 LLM 提供商 |
ls_model_name |
实际使用的模型 ID |
在生产环境中,metadata 常用于:① 日志记录和监控(追踪每次调用使用了哪个模型);② 调试(查看 Agent 执行到了哪个节点出了问题);③ 计费分析(通过 ls_model_name 统计各模型的使用量)。
from dotenv import load_dotenv
load_dotenv()
import os
from langchain.chat_models import init_chat_model
from langchain.agents import create_agent
from langchain.messages import HumanMessage
# 1. 初始化模型
def deepseek_model(**kwargs):
return init_chat_model(
model="deepseek-v4-flash",
model_provider="deepseek",
api_key=os.environ["DEEPSEEK_API_KEY"],
base_url="https://api.deepseek.com",
max_tokens=500,
**kwargs
)
# 2. 构建 Agent
agent = create_agent(deepseek_model())
# 3. 同步调用
response = agent.invoke({"messages": [HumanMessage(content="Hello!")]})
print(response['messages'][-1].content)
# 4. 流式调用
for token, _ in agent.stream(
{"messages": [{"role": "user", "content": "Tell me a joke"}]},
stream_mode="messages"
):
if token.content:
print(token.content, end="", flush=True)
model_provider 指定适配器invoke:等待完整响应,返回消息列表stream:逐 token 推送,打字机效果token.content 过滤空消息response['messages']:完整消息历史response['messages'][-1].content:AI 最新回复