Skip to article frontmatterSkip to article content

快速入门

ReAct Agent 是一种将 推理(Reasoning)与 行动(Acting)结合起来的智能体。它是智能体的核心科技,也是智能体框架中最能表现其自主性的组件。

它的工作流程遵循三步循环:

  1. 思考

  2. 行动

  3. 观察

这个循环会持续进行,直到 LLM 判断任务已经完成或无法继续。

这种循环意味着智能体可以通过工具调用,自动补足当前未知的上下文信息。然后基于新获取的信息,做出下一步决策。比如你要智能体查询一个数据表中的记录,它可能尚不知道数据库中有哪些表,表中有哪些字段。但是通过几轮的主动查询与观察,即使你询问的信息比较模糊,它大概率也能从表名和字段名中推测出你需要的记录是哪一条。这就是 ReAct Agent 的威力。

本节将介绍:

  • 如何创建简单的 ReAct Agent

  • 如何创建带工具的 ReAct Agent

  • 如何创建带工具权限的 ReAct Agent

  • 结构化输出

  • 流式输出

一、环境配置

1)安装依赖

你可以下载 本仓库 到本地,运行以下命令,安装完整的 Python 依赖:

cd dive-into-langgraph
pip install -r requirement.txt
依赖包列表

以下为 requirements.txt 中的依赖包清单:

pydantic
python-dotenv
langchain[openai]
langchain-community
langchain-mcp-adapters
langchain-text-splitters
langgraph
langgraph-cli[inmem]
langgraph-supervisor
langgraph-checkpoint-sqlite
langmem
ipynbname
fastmcp
bs4

或者,你也可以直接安装 LangGraph,遇到缺少的依赖再行安装:

pip install langgraph langchain

2)导入依赖

使用 .env.example 创建 .env 文件:

cp .env.example .env

PS: 本教程使用阿里百炼平台的模型。你需要在 阿里百炼平台 注册账号,并将获得的 API 密钥填入 .env 文件中的 DASHSCOPE_API_KEY 变量。

import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain.agents import create_agent

# 加载模型配置
# 请事先在 .env 中配置 DASHSCOPE_API_KEY
_ = load_dotenv()

二、简单的 Agent

首先,创建一个最简单的 ReAct Agent。

# 配置大模型服务
llm = ChatOpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url=os.getenv("DASHSCOPE_BASE_URL"),
    model="qwen3-coder-plus",
)

# 创建一个简单的Agent
agent = create_agent(
    model=llm,
    system_prompt="You are a helpful assistant",
)

# 运行Agent
response = agent.invoke({'messages': '你好'})

response['messages'][-1].content
'你好!有什么我可以帮助你的吗?'
# 可视化 Agent
agent
<langgraph.graph.state.CompiledStateGraph object at 0x115e6ef90>

三、带工具调用的 Agent

然后,我们来创建一个带工具调用的 ReAct Agent。它可以自主选择是否调用工具。

# 一个工具函数
def get_weather(city: str) -> str:
    """Get weather for a given city."""
    return f"It's always sunny in {city}!"

# 创建带工具调用的Agent
tool_agent = create_agent(
    model=llm,
    tools=[get_weather],
    system_prompt="You are a helpful assistant",
)

# 运行Agent
response = tool_agent.invoke(
    {"messages": [{"role": "user", "content": "what is the weather in sf"}]}
)

response['messages'][-1].content
"It's always sunny in sf!"
# 可视化 Agent
tool_agent
<langgraph.graph.state.CompiledStateGraph object at 0x116d8f750>

四、使用 ToolRuntime 控制工具权限

创建一个带 runtime 的工具,runtime 类型为 ToolRuntime。当我们调用 Agent 时,通过 context 字段将 runtime 传递给工具。工具通过 runtime 中的内容控制该工具的执行权限。

from typing import Literal, Any
from pydantic import BaseModel
from langchain.tools import tool, ToolRuntime

class Context(BaseModel):
    authority: Literal["admin", "user"]

# 创建带权限控制的tool,依赖ToolRuntime的内容进行判断
@tool
def math_add(runtime: ToolRuntime[Context, Any], a: int, b: int) -> int:
    """Add two numbers together."""
    authority = runtime.context.authority
    # 只有admin用户可以访问加法工具
    if authority != "admin":
        raise PermissionError("User does not have permission to add numbers")
    return a + b

# 创建带工具调用的Agent
tool_agent = create_agent(
    model=llm,
    tools=[get_weather, math_add],
    system_prompt="You are a helpful assistant",
)

# 在运行Agent时注入context
response = tool_agent.invoke(
    {"messages": [{"role": "user", "content": "请计算 8234783 + 94123832 = ?"}]},
    config={"configurable": {"thread_id": "1"}},
    context=Context(authority="admin"),
)
for message in response['messages']:
    message.pretty_print()
================================ Human Message =================================

请计算 8234783 + 94123832 = ?
================================== Ai Message ==================================
Tool Calls:
  math_add (call_985e4f898e064650885c30c7)
 Call ID: call_985e4f898e064650885c30c7
  Args:
    a: 8234783
    b: 94123832
================================= Tool Message =================================
Name: math_add

102358615
================================== Ai Message ==================================

8234783 + 94123832 = 102358615。
# 验证计算结果是否正确
8234783 + 94123832
102358615

五、结构化输出

若想获得结构化输出(Structured Output),可以在 create_agent 函数的 response_format 字段进行设定。对于下面这个例子,我们使用 BaseModel 定义输出格式,并在 response_format 中指定该格式。

from pydantic import BaseModel, Field

class CalcInfo(BaseModel):
    """Calculation information."""
    output: int = Field(description="The calculation result")
# 创建带结构化输出的Agent
structured_agent = create_agent(
    model=llm,
    tools=[get_weather, math_add],
    system_prompt="You are a helpful assistant",
    response_format=CalcInfo,
)

response = structured_agent.invoke(
    {"messages": [{"role": "user", "content": "请计算 8234783 + 94123832 = ?"}]},
    config={"configurable": {"thread_id": "1"}},
    context=Context(authority="admin"),
)
for message in response['messages']:
    message.pretty_print()
================================ Human Message =================================

请计算 8234783 + 94123832 = ?
================================== Ai Message ==================================
Tool Calls:
  math_add (call_3a3539c1bb9d49ad9cf6c19d)
 Call ID: call_3a3539c1bb9d49ad9cf6c19d
  Args:
    a: 8234783
    b: 94123832
================================= Tool Message =================================
Name: math_add

102358615
================================== Ai Message ==================================
Tool Calls:
  CalcInfo (call_356d897869ae4617810c917d)
 Call ID: call_356d897869ae4617810c917d
  Args:
    output: 102358615
================================= Tool Message =================================
Name: CalcInfo

Returning structured response: output=102358615
response['messages'][-1]
ToolMessage(content='Returning structured response: output=102358615', name='CalcInfo', id='24650fde-c49c-4871-abb9-800ea487fba2', tool_call_id='call_356d897869ae4617810c917d')

六、流式输出

下面是一个简单的例子,更多信息请参阅 streaming.

agent = create_agent(
    model=llm,
    tools=[get_weather],
)

for chunk in agent.stream(  
    {"messages": [{"role": "user", "content": "What is the weather in SF?"}]},
    stream_mode="updates",
):
    for step, data in chunk.items():
        print(f"step: {step}")
        print(f"content: {data['messages'][-1].content_blocks}")
step: model
content: [{'type': 'tool_call', 'name': 'get_weather', 'args': {'city': 'SF'}, 'id': 'call_0f612ce3a1684709b2127fa0'}]
step: tools
content: [{'type': 'text', 'text': "It's always sunny in SF!"}]
step: model
content: [{'type': 'text', 'text': "It's always sunny in SF!"}]