欢迎回来
登录你的知识库账户
忘记密码?
还没有账户?立即注册
创建账户
注册你的专属知识库
已有账户?去登录
找回密码
输入注册邮箱获取验证码
返回登录
请输入图片中的验证码以继续注册
加载中...
取消
新建收藏
手动添加你喜欢的内容
取消
编辑头像与昵称
上传新头像或修改你的显示昵称
支持 JPG/PNG,最大 2MB
取消

问题反馈

notebasewww.notebase.cn
控制台
内容库
动态
管理
账户
U
用户
--
在线
v0.8.7 · 知识库
笔记
KnowledgeBase
网络无边,知识有迹。
0笔记
0工具
30推荐

分类导航

按主题直达

编辑精选

站内用户贡献 · 真实笔记

最新收录

每日更新
继续浏览全部内容 →
>
笔记
0
加载中...
工具
0
此页用于记录用户反馈问题后的每一次改进
笔记用法

“写笔记”支持四种格式——Word 文档、Excel 表格、Markdown、纯文本,起稿或二次编辑时都能随时切换,同一篇笔记想用哪种形态来记,都由你说了算。

md、txt、csv、json 这类纯文本则原样载入,不做多余加工。拿一张现成的表倒进来、改几笔、再导出去,等于白用一台免费的格式转换器。

要带走就在右上角点“下载”,可导出 PDF、Word、Markdown、Excel、TXT 等格式;列表卡片“⋯”菜单里,也有同样的下载入口。

工具用法

在“工具”页点“+ 上传工具”即可发布:填好名称与链接,再用 Markdown 把使用方法写清楚——能解决什么问题、怎么装、怎么用,比堆介绍实在。

要分发安装包就一并上传压缩包(ZIP、RAR、7Z、TAR.GZ,最大 35MB),别人在详情页一键下载;只放链接不带附件也可以。

工具按大家的收藏热度排序,好用的自然会被顶上来。发布后可在详情页或卡片菜单里编辑、下架。

隐藏笔记

写笔记时勾上“隐藏”,这篇就只存在于你自己的账号里:不进列表、不进搜索、不上首页精选,也不会出现在任何公开的页面,链接发给别人同样打不开。

适合放密码、草稿、日记这类只给自己看的内容;想公开,去“发布”打开它,把“隐藏”的勾去掉再保存,之后编辑会默认保持原状态,不会悄悄变回公开。

数据安全

你的内容会同时保存在多个副本上,系统定期做备份与完整性校验,再配合异地容灾机制:就算某台机器出问题,数据也不会丢,可以长期放心存放;特别重要的资料,仍建议你另外再留一份备份。

技术

全站跑在容器化、模块化的现代架构上,更新、部署、回滚都很快,扩展性和稳定性都按长期运营的标准来设计(Built for reliability, designed to scale)。

理念

这个网站最早只是一个人的笔记仓库,后来慢慢长成现在的知识中枢。设计上很克制——没有广告、没有追踪、没有推荐算法,只是干干净净地存放一些东西;既然做好了,就公开出来,万一有人用得上呢。

原则

不做大而全,不做平台梦,保持简单、保持克制、保持好奇。所有内容都由用户贡献、由用户维护:不会突然冒出付费墙,不会在角落塞广告位,也不会把你的数据卖给第三方。

更多

产品会持续迭代,站内日志页记录着每一次改动,改了什么都有迹可循;想了解这个站是怎么一步步走到今天的,翻翻日志就能看到来龙去脉。

举报

如果在这里看到涉嫌违规的内容,点对应卡片右侧的“举报”按钮就能提交,我们会尽快核实处理;也谢谢你花一点时间,一起把这里维护干净。

趋势
// 点击导航加载发现
归档
// 归档为空
最近浏览
// 暂无浏览记录
发布
// 加载中...
用户发布
// 加载中...
用户管理
// 加载中...
访问统计
// 加载中...
内容审核
// 加载中...
个人信息
// 加载中...
返回首页

ReActAgent 使用指南:构建会思考、能行动的 AI Agent

2026/7/5人工智能

最近在折腾 AI Agent 相关的东西,发现很多人对 ReAct 模式感兴趣但又不太清楚怎么落地。正好我手头有个项目用到了 LangChain 的 ReActAgent,踩了不少坑也积累了点经验,干脆整理成一篇笔记分享出来。这篇文章不会只贴代码,我会把背后的原理、为什么这么设计、实际工程中要注意什么都说清楚。

先聊聊 ReAct 到底是什么

先说个背景。传统的 LLM 调用模式就是“你问一句,它答一句”,比如你问“今天北京天气怎么样”,它可能直接回答“抱歉,我无法获取实时数据”。这很尴尬——模型有知识但没法采取行动。

ReAct(Reason + Act)这个名字很直白:推理 + 行动。它的核心思路是:让 LLM 不只是输出文本,而是输出一个“思考链”(Reasoning),然后根据思考结果决定调用什么工具(Action),再根据工具返回的结果继续推理,直到得出最终答案。

打个比方:传统 LLM 像个只会背书的学生,你问他“食堂今天有什么菜”,他只能凭记忆瞎猜。ReAct 模式下的 LLM 则像个会办事的助理——他会先想“我需要查一下食堂菜单”,然后掏出手机打开食堂 App 查数据,看到结果后再告诉你“今天有红烧肉和清炒时蔬”。

ReActAgent 的核心组件

在 LangChain 里,ReActAgent 由三个关键部分组成:

  1. LLM:负责推理和决策的大脑
  2. 工具列表(Tools):Agent 可以调用的外部能力,比如搜索、计算、API 调用
  3. 提示词模板(Prompt Template):指导 LLM 如何输出思考过程和调用工具的指令

这三者缺一不可。LLM 再聪明,没有工具也只能纸上谈兵;工具再多,LLM 不会推理也只会乱用。

手把手搭建一个 ReActAgent

第一步:准备 LLM

我用的是 OpenAI 的模型,但理论上任何支持函数调用(function calling)或工具调用的模型都行。这里我选了 gpt-4o-mini,性价比不错,日常实验够用了。

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="gpt-4o-mini",
    temperature=0,  # 做 Agent 时建议 temperature 设低一点,减少随机性
    api_key="your-api-key"  # 实际用环境变量管理
)

为什么 temperature 要设 0? 因为 Agent 需要稳定、可预测的推理路径,而不是创意发散。想象一下,如果助理每次思考都“天马行空”,那工具调用就会乱套。

第二步:定义工具

工具是 Agent 的“手脚”。我定义了两个最常用的工具:一个用于计算,一个用于获取当前时间。

from langchain_core.tools import tool
from datetime import datetime
import math

@tool
def calculator(expression: str) -> str:
    """计算数学表达式,支持加减乘除、幂运算等。输入应为合法的数学表达式字符串。"""
    try:
        # 安全起见,只允许数学运算,避免执行任意代码
        allowed_names = {
            "abs": abs, "round": round, "min": min, "max": max,
            "pow": pow, "sqrt": math.sqrt, "pi": math.pi, "e": math.e
        }
        result = eval(expression, {"__builtins__": {}}, allowed_names)
        return f"计算结果: {result}"
    except Exception as e:
        return f"计算错误: {str(e)}"

@tool
def get_current_time() -> str:
    """返回当前的日期和时间。不需要输入参数。"""
    return f"当前时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"

这里有个重要的设计细节:工具的文档字符串(docstring) 非常重要。LLM 会读取这个 docstring 来决定什么时候调用这个工具、传什么参数。所以描述要清晰、准确,最好包含示例。

比如 calculator 工具的 docstring 里我特意写了“支持加减乘除、幂运算等”,这样 LLM 就知道 2**10 这种表达式也能处理。

第三步:创建提示词模板

这是最容易翻车的地方。LangChain 的 ReActAgent 默认需要一个特定格式的提示词模板,里面要包含 {input}、{agent_scratchpad} 等占位符。

from langchain.agents import create_react_agent
from langchain_core.prompts import PromptTemplate

# 这个模板告诉 LLM 如何思考和行动
react_prompt = PromptTemplate.from_template(
    """你是一个智能助手,可以通过思考和调用工具来回答问题。

请按照以下格式输出:

问题:用户提出的问题
思考:你当前的想法和推理过程
行动:你要调用的工具名称
行动输入:传给工具的具体参数
观察:工具返回的结果
...(可以重复思考-行动-观察循环)
思考:我现在有了足够的信息
最终答案:对用户的最终回复

可用的工具:
{tools}

工具名称列表(用逗号分隔):
{tool_names}

开始!

问题:{input}
思考:{agent_scratchpad}"""
)

agent_scratchpad 是什么? 这是关键。它记录了 Agent 之前所有的思考-行动-观察历史。每次循环,新的思考结果都会被追加到这个变量里,让 LLM 知道“我已经做了什么、得到了什么结果”,从而做出下一步决策。

第四步:组装 Agent

工具和提示词都有了,接下来把它们组装起来。

from langchain.agents import AgentExecutor

# 先把工具列表准备好
tools = [calculator, get_current_time]

# 创建 ReAct Agent
agent = create_react_agent(
    llm=llm,
    tools=tools,
    prompt=react_prompt
)

# 用 AgentExecutor 包装,让它能实际执行工具调用
agent_executor = AgentExecutor(
    agent=agent,
    tools=tools,
    verbose=True,  # 打开详细日志,方便调试
    handle_parsing_errors=True,  # 如果 LLM 输出格式不对,自动重试
    max_iterations=10  # 防止无限循环
)

verbose=True 在开发阶段特别有用,你能看到 Agent 每一步的思考过程和工具调用结果。handle_parsing_errors 是个保险——LLM 偶尔会输出格式不规范的 JSON 或文本,开启后 Agent 会自动重试。

第五步:跑起来看看效果

先试一个需要计算的问题:

response = agent_executor.invoke({"input": "2的10次方是多少?"})
print(response["output"])

输出日志(verbose=True 时你会看到):

> 进入 AgentExecutor 循环...
思考:用户问的是2的10次方,这是一个数学计算,我可以调用 calculator 工具。
行动:calculator
行动输入:2**10
观察:计算结果: 1024
思考:计算完成,现在可以给出最终答案。
最终答案:2的10次方是1024。

完美。再试试需要时间信息的问题:

response = agent_executor.invoke({"input": "现在是几点?"})
print(response["output"])

输出:

> 进入 AgentExecutor 循环...
思考:用户想知道当前时间,我应该调用 get_current_time 工具。
行动:get_current_time
行动输入:{}
观察:当前时间: 2025-03-15 14:32:18
思考:获取到了当前时间,可以回答用户了。
最终答案:现在是 2025年3月15日 14点32分。

注意 行动输入 是空字典 {},因为 get_current_time 不需要参数。

进阶:让 Agent 调用自定义 API

光有计算器和时间功能还不够,实际项目中我们经常需要 Agent 调用内部 API。比如,我想让 Agent 能查用户订单信息。

定义更复杂的工具

import requests

@tool
def get_order_status(order_id: str) -> str:
    """根据订单ID查询订单状态。order_id 是字符串类型的订单编号,例如 'ORD-2025-001'。"""
    # 这里假装调了一个内部 API
    # 实际项目中替换为真实的 API 调用
    api_url = f"https://api.example.com/orders/{order_id}"
    try:
        # 模拟请求,实际使用时取消注释下面两行
        # response = requests.get(api_url, timeout=5)
        # return response.json().get("status", "未知状态")
        
        # 模拟数据
        mock_data = {
            "ORD-2025-001": "已发货,预计3月18日到达",
            "ORD-2025-002": "正在打包中",
            "ORD-2025-003": "已取消"
        }
        return mock_data.get(order_id, "未找到该订单")
    except Exception as e:
        return f"查询失败: {str(e)}"

这里我故意用了 mock 数据,但结构跟真实 API 一致。实际项目中要注意:工具函数里尽量做异常处理,因为 LLM 可能会传入不存在的订单号或者格式错误的参数,工具应该优雅地返回错误信息,而不是直接崩溃。

测试复杂场景

tools = [calculator, get_current_time, get_order_status]
agent = create_react_agent(llm=llm, tools=tools, prompt=react_prompt)
agent_executor = AgentExecutor(
    agent=agent, 
    tools=tools, 
    verbose=True,
    handle_parsing_errors=True,
    max_iterations=10
)

response = agent_executor.invoke({"input": "我的订单ORD-2025-002现在什么状态?"})
print(response["output"])

输出日志:

> 进入 AgentExecutor 循环...
思考:用户想查询订单 ORD-2025-002 的状态,我需要调用 get_order_status 工具。
行动:get_order_status
行动输入:{"order_id": "ORD-2025-002"}
观察:正在打包中
思考:查询成功,订单状态是“正在打包中”。
最终答案:您的订单 ORD-2025-002 目前正在打包中,请耐心等待。

踩坑记录与最佳实践

1. 提示词模板的格式陷阱

ReAct 的提示词模板对格式要求很严格。{agent_scratchpad} 必须放在最后,而且前面要有明确的格式说明。我一开始没注意,把模板写成了:

问题:{input}
{agent_scratchpad}
思考:

结果 Agent 完全不按套路出牌,一直输出无关内容。后来查文档才发现,agent_scratchpad 前面必须有“思考:”这样的前缀引导,LLM 才知道怎么续写。

正确做法:严格按照 LangChain 官方示例的格式,在 {agent_scratchpad} 前面加上“思考:”前缀,让 LLM 从思考开始续写。

2. 工具命名要直观

工具的名字和 docstring 会直接影响 LLM 的调用决策。我试过给计算器工具起名叫 math_op,结果 LLM 有时候认不出来,宁愿自己瞎算也不调用。改成 calculator 之后准确率明显提升。

经验:工具名用通俗易懂的英文单词,docstring 里说清楚“什么时候用、怎么用、参数是什么”。

3. 控制循环次数

max_iterations 这个参数一定要设。我遇到过 Agent 陷入死循环的情况——它反复调用同一个工具,每次得到相同的结果,然后继续调用。设个 10 次的上限,既防止无限循环,也避免 token 浪费。

4. 错误处理不能少

LLM 生成的工具调用参数有时候是错的。比如它会传 order_id=123(数字)而不是字符串。工具函数里要做类型检查和异常捕获,返回友好的错误信息,这样 Agent 就能根据错误信息调整参数重试。

@tool
def get_order_status(order_id: str) -> str:
    if not isinstance(order_id, str):
        return "错误:订单ID必须是字符串格式"
    # ... 后续逻辑

5. 日志是调试神器

verbose=True 能让你看到 Agent 的每一步思考。生产环境可以关掉,但开发阶段一定要开着。有一次 Agent 老是调用错误工具,我一看日志才发现是 docstring 写得太模糊,LLM 理解错了。

总结

ReActAgent 的本质是给 LLM 装上了“手脚”和“思考能力”。通过定义清晰的工具和提示词模板,我们可以让 AI 完成需要多步推理和外部数据获取的复杂任务。

这篇文章里我们只用了三个简单工具,但同样的模式可以扩展到调用数据库、发邮件、操作文件系统等任何你能想到的外部能力。关键是要掌握好提示词模板的格式、工具的定义规范,以及异常处理机制。

如果你正在构建自己的 AI Agent,建议先从最简单的场景开始,比如“计算+时间查询”,跑通流程后再逐步增加工具。别一上来就想搞个万能 Agent,那只会让你在调试中崩溃。

最后留个思考题:如果想让 Agent 能记住对话历史(比如用户说“刚才那个订单怎么样了”),你觉得应该在哪个环节做改造?欢迎在评论区讨论。

编写使用方法
Markdown 格式 · Ctrl+Enter 确定
新建笔记
预览
数据表格
点击单元格编辑 · Tab 移动
A1fx
Sheet1
BIH1H2≡🔗</>
隐私提醒

取消
编辑工具
取消