Chapter 4 · Messages and the tool-calling loop
Introduce a model while keeping tools limited to fixed public course data. Understand the full cycle: model requests a tool, the tool returns a result, and the model responds again.
Mechanics and design choices
MessagesState includes message merging. bind_tools exposes schemas to the model, ToolNode executes calls and produces matching tool messages, and tools_condition inspects the latest model message for tool_calls. Tool results must match call IDs. The OpenAI-compatible endpoint used here must actually support tool calling; compatibility does not guarantee every feature.
Example
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)Run and verify
Also install langchain-openai. Configure MODEL_NAME, OPENAI_API_KEY, and optionally OPENAI_BASE_URL. Execution calls a paid external model. Verify a tool message and 12 hours; a natural-language answer alone is insufficient evidence of tool use.
Pitfalls
Do not promote tool output into higher-priority instructions. Validate arguments and authorization in code. Model output is not permission; paid or mutating operations need an approval boundary.
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. What does bind_tools do?
2. What must tool responses match?
3. Does text generation guarantee tool calling?
4. When does the tool loop exit?
Hands-on exercises
- Test course_hours.invoke for known and unknown courses.
- Record message types and verify the model runs after tool output.
- Add another read-only tool and verify selection instead of guessing.
Official references
Verified on: 2026-09-17.