Skip to content

第 4 章 · 消息状态与工具调用闭环 ​

本章接入模型,但工具只读取固定的公开课程资料,不访问网络或写入文件。目标是理解模型提出工具请求、工具返回结果、模型再次回答的完整闭环。

工作机制与设计选择 ​

MessagesState 内置消息合并规则。模型必须通过 bind_tools 获知工具模式;ToolNode 执行调用并生成对应工具消息;tools_condition 检查最近模型消息是否带 tool_calls。每个工具结果应匹配调用 ID,不能只拼接一段字符串假装工具消息。这里使用 OpenAI 兼容 Provider;服务需要支持工具调用,不是所有兼容端点都实现所有特性。

示例 ​

python
import os
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langgraph.graph import StateGraph, MessagesState, START
from langgraph.prebuilt import ToolNode, tools_condition

@tool
def course_hours(course: str) -> str:
    """Return estimated hours for a known course."""
    return {"langgraph": "12 hours", "deepagents": "10 hours"}.get(course.lower(), "Unknown course")

model = ChatOpenAI(
    model=os.environ["MODEL_NAME"],
    api_key=os.environ["OPENAI_API_KEY"],
    base_url=os.environ.get("OPENAI_BASE_URL", "https://api.openai.com/v1"),
).bind_tools([course_hours])

def assistant(state: MessagesState):
    return {"messages": [model.invoke(state["messages"])]}

builder = StateGraph(MessagesState)
builder.add_node("assistant", assistant)
builder.add_node("tools", ToolNode([course_hours]))
builder.add_edge(START, "assistant")
builder.add_conditional_edges("assistant", tools_condition)
builder.add_edge("tools", "assistant")
graph = builder.compile()
result = graph.invoke(
    {"messages": [{"role": "user", "content": "Use course_hours to find the hours for langgraph."}]},
    {"recursion_limit": 12},
)
for message in result["messages"]:
    print(message.type, message.content)

运行与验收 ​

额外安装 langchain-openai;在终端配置 MODEL_NAME、OPENAI_API_KEY,可选 OPENAI_BASE_URL。运行会调用外部模型并计费。验收检查是否出现 tool 消息及 12 hours;如果没有,视为工具调用能力或提示未达标,不能只根据最终自然语言判定通过。

容易踩的坑 ​

不要将工具输出当成更高优先级指令。工具应在代码边界验证参数和权限;模型输出不能替代授权。真实付费或修改操作应增加下一章介绍的审批边界。

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. bind_tools 做什么?

2. 工具响应要匹配什么?

3. 支持文本生成就一定支持工具调用吗?

4. 何时退出工具循环?

动手实践 ​

  1. 直接测试 course_hours.invoke 的已知课程和未知课程输入。
  2. 记录消息类型序列,确认 tool 消息后模型重新执行。
  3. 增加一个只读工具,验证模型选择正确工具而不是猜测。

官方参考 ​

核验日期:2026-09-17。