LangChain LangGraph
Module 1 Module 2 Module 3
Module 1 · Basic abilities
1 1.1a Foundation Model
2 1.1b Prompting
3 1.2a Tools
4 1.2b Web Search
5 1.3 Memory
6 1.4 Multimodal
7 1.5 Personal Chef
SUM Module Summary
HomeLangChainModule 1 · Basic abilities1.2a Tools
📓 Notebook 📖 Explained
LANGCHAIN MODULE 1 · LESSON 1.2a

Tools
@tool decorator · Agent tool call · ReAct loop

Use @tool to define a Python function as a tool and bind it to the Agent - the model will automatically decide when to call it, and the call result will be fed back to the model, forming a ReAct inference-action cycle.

1What is a tool? Why does Agent need tools?

LLM itself can only process text - it has no real-time networking capabilities, cannot execute code, and cannot call external APIs.ToolIt is the mechanism that gives Agent these capabilities: after packaging the Python function into a tool, the model can "call" it during the inference process, obtain real data, and then incorporate the results into subsequent inference.

Tool call vs direct LLM answer

Ask LLM "What is the square root of 467" - it might give 21.6 or a similar approximation, butNot guaranteed to be accurate. After binding thesquare_root tool, the model calls Python's x ** 0.5 which returns the exact value 21.61018278497431. This is the fundamental value of the tool’s existence: to allow Agents to leverage external precise calculations or real-time data.

2@tool decorator: turns Python functions into LangChain tools

Provided by LangChain@toolDecorators turn ordinary Python functions into tools that can be called by Agent. This isRecommended standard writing

Recommended format: specify name and description

from langchain.tools import tool

# 推荐写法:明确指定工具名称和描述
@tool("square_root", description="Calculate the square root of a number")
def square_root(x: float) -> float:
    return x ** 0.5

@toolWhat does the decorator do? It wraps the function into a LangChainStructuredToolObject, which contains:

propertysourceillustrate
name The first parameter of the decorator"square_root" The name identifier used when the model calls the tool
description Decoratordescription=parameter Tell the model what this tool is used for,The model relies on this to decide when to call
args_schema Type annotations for function parameters are automatically inferred JSON Schema of parameters (x: float{"x": {"type": "number"}}
func the decorated original function actual execution logic
importance of description

descriptionIt is the core basis for model decision-making. The model cannot see the source code of the tool, only thenameanddescription. If the description is inaccurate, the model may call (or not call) the tool at the wrong time.A good tool description should: state clearly what the tool does, when it should be used, and what its input and output are.

3Directly call the tool: tool.invoke() test

After the tool is defined, it can be used directly without going through the Agent.tool.invoke()Test whether it functions correctly:

# 直接调用工具测试,不需要 Agent
result = square_root.invoke({"x": 467})
print(result)  # → 21.61018278497431
Execution output
21.61018278497431
Development habits suggestions

Before binding the tool to the Agent, usetool.invoke()Independent testing tool logic. This can quickly check whether there is a bug in the tool itself or whether there is a problem when the Agent calls the tool - the two types of problems have completely different ways of repairing them.

4Bind tools to Agent: tools parameter

passcreate_agentoftoolsParameters, pass the tool list to the Agent:

from langchain.agents import create_agent
from langchain.messages import HumanMessage

agent = create_agent(
    model=deepseek_model(),
    tools=[square_root],    # 工具列表(可以绑定多个工具)
    system_prompt="You are an arithmetic wizard. Use your tools to calculate the square root and square of any number."
)

question = HumanMessage(content="What is the square root of 467?")
response = agent.invoke({"messages": [question]})
print(response['messages'][-1].content)
Execution output
The square root of **467** is approximately **21.6102**.

If you'd also like to know the square of any number, just let me know!

The model doesn't "calculate" the value itself - it callssquare_rootTools for precise results21.61018278497431, and then use this value in the reply.

5ReAct execution flow: how the model decides which tool to call

Agent's tool invocation followsReAct(Reasoning + Acting)model:

ReAct Tool Call Loop

user input
HumanMessage
LLM reasoning
Decide whether to call the tool
Execution tool
ToolMessage records results
LLM re-reasoning
Answer based on tool results
final reply
AIMessage

If necessary, you can cycle "Inference → Call Tool → Inference" multiple times until LLM thinks it can give the final answer.

Detailed explanation of specific steps

  1. Users send questionsHumanMessage("What is the square root of 467?")
  2. LLM see tool list: The model receives the name + description + args_schema of the tool. It reasoned: "This problem requires calculation, I should call the square_root tool"
  3. Model output tool_call: The content of AIMessage is empty, but there istool_calls=[{"name": "square_root", "args": {"x": 467}}]
  4. LangGraph Execution Tool: callsquare_root(x=467),get21.61018278497431, encapsulated asToolMessage
  5. LLM answers based on results: The model sees the tool results and generates the final AIMessage text response

6Response structure analysis: tool_calls and message history

After the tool is called,response['messages']The list contains 4 messages, one more than a normal callToolMessage

from pprint import pprint

pprint(response['messages'])
print("\n--- tool_calls 详情 ---")
print(response["messages"][1].tool_calls)
Message history (4 items)
1. HumanMessage: "What is the square root of 467?"

2. AIMessage: content=''  # Empty content, tool calls are in tool_calls
   tool_calls=[{
     'name': 'square_root',
     'args': {'x': 467},
     'id': 'call_00_...', 'type': 'tool_call'
   }]

3. ToolMessage: '21.61018278497431'  # Tool execution results

4. AIMessage: "The square root of **467** is approximately **21.6102**..."

Detailed explanation of AIMessage.tool_calls field

tool_call = response["messages"][1].tool_calls[0]
# 结构如下:
# {
#   "name": "square_root",    # 调用的工具名
#   "args": {"x": 467},       # 传入的参数
#   "id": "call_00_...",      # 工具调用 ID(用于匹配 ToolMessage)
#   "type": "tool_call"       # 固定值
# }
A common misunderstanding

When the tool is called,response['messages'][-1]It is the final text answer (AIMessage), not the tool result. The tool results inmessages[2]in ToolMessage. Usually we only needresponse['messages'][-1].contentGet the final text answer.

7Tool Design Best Practices

practiceRecommended practicesavoid
Tool name Verb + noun, clearly express function:"search_web""get_stock_price" Ambiguous name:"tool1""helper"
describe Explain the purpose, when to use it, input and output. Example:"Search the web for real-time information. Use when the question requires current data." Too brief:"search"
type annotation All parameters are type annotated (x: float), LangChain automatically generates schema Omit type annotations (resulting in inaccurate schema)
return value Returns a string or serializable dict to facilitate model understanding Return complex objects or binary data
Error handling Returns a descriptive error string to let the model know the reason for the failure Throws an exception (will interrupt the entire Agent execution)
Lesson 1.2a Core Points
@tool decorator
  • • Recommended format:@tool("name", description="...")
  • • Automatically generate JSON Schema from type annotations
  • tool.invoke({"x": 467})Can be independently tested
Tool calling process
  • • Model → tool_call → Tool Execution → ToolMessage
  • • messages list: Human + AI(empty) + Tool + AI(answer)
  • • Final answer:messages[-1].content