ReAct Agent 学习日志(Day 3):从“能调用 API”到“会用工具做事”

0 阅读10分钟

ReAct Agent 学习日志(Day 3):从“能调用 API”到“会用工具做事”

Gemini_Generated_Image_crw6vccrw6vccrw6

写在前面:我是前端,但我想转向 AI

我是一名前端工程师。过去的我更熟悉组件、状态管理、交互细节与工程化;但最近我越来越清晰地感受到:AI 不再只是“一个能力点”,它正在变成新的生产力底座
于是我决定认真投入,给自己一个明确的方向:专心学习 AI 技术,尝试转行

今天是我学习的第 3 天。前两天我做的是“AI API 调用”的项目,目标很务实:先把请求、返回、流式输出、落盘、稳定性这些基础动作练熟。

在另一个项目(AI Content Automation Platform)的开发日志里,我把前两天的重点记得很直白:

  • Day1:跑通了「输入主题 → AI 生成文章 → 前端展示 + 临时落盘」闭环,搭好 Docker、文档骨架与工程结构。
  • Day2:把生成体验做成 SSE 流式,并补齐重试语义(Tenacity)、异步 DB 依赖与一套“断点续写”的设计草案。

那两天更像是在练“手感”:怎么把 AI 能力接进系统里
但今天的主题明显更“像智能体”——我开始学习 ReAct Agent:让模型不仅能回答问题,还能决定要用哪些工具、按什么顺序做事、并在过程中不断修正


ReAct 是什么:让模型学会“边想边做”

ReAct(Reason + Act)可以理解为一种非常朴素、但很有效的范式:

  • Reason(思考):先分析要解决的问题、拆解子目标、给出下一步计划
  • Act(行动):调用工具(读文件、查目录、算数据、发邮件……)去获取事实
  • Observe(观察):拿到工具结果,更新认知,继续下一轮

它的魅力在于:
当问题需要“外部信息”时(比如读 Excel、查文件夹、执行脚本),模型不再硬编答案,而是会把任务变成一连串可验证的动作。

今天我用一个非常具体的问题来练 ReAct:

“9 月份的销售额是多少?”

这类问题的关键点是:
答案不在模型脑子里,而在本地数据文件里。模型必须学会找数据、读数据、算结果,最后再输出。


实战复盘:从目录开始,走到最终答案

下面这段复盘来自我今天一次完整的 ReAct 跑通过程(终端真实输出)。我把它理解成:一个智能体如何像人一样做数据分析

1)先找数据:ListDirectory

模型的第一反应不是“我猜 9 月销售额是多少”,而是先承认:自己没有信息,需要去 ./data 里找文件。

它调用了 ListDirectory

  • 目标:列出数据目录有哪些文件
  • 结果:发现了一个非常“像答案就藏在里面”的文件:2023年8月-9月销售记录.xlsx

这一步很重要:从“问题”到“数据源”的映射
人类做分析也一样——第一步不是算,而是定位数据。

2)再看结构:InspectExcel

找到 Excel 之后,模型并没有直接开始计算,而是先问:
“这个表有什么列?日期列叫什么?销售额怎么算?”

它调用了 InspectExcel,拿到了:

  • 工作表名:2023年8月-9月销售记录
  • 列名:品类 / 产品名 / 单价(元) / 销售量 / 销售日期 / 供应商
  • 前 3 行样例数据(看到了日期格式 2023-08-02 这种)

于是“9 月销售额”被拆成可执行公式:

销售额 = 单价(元) × 销售量
筛选条件 = 销售日期在 2023-09-01 ~ 2023-09-30

这一步是 ReAct 里我最喜欢的一点:
它会主动把“模糊问题”变成“可计算问题”。

3)最后计算:AnalyseExcel(PythonREPL)

当字段都明确后,模型调用 AnalyseExcel,并在工具内部生成并执行 Python 代码:

  • pd.read_excel(...) 读取 Excel
  • pd.to_datetime(df['销售日期']) 转日期
  • 过滤 9 月
  • sum(单价 * 销售量) 求和

最终得到结论:

9 月份的总销售额为:2851099 元

到这里,ReAct 的闭环就非常清晰了:

  1. 找文件
  2. 看表结构
  3. 写代码算
  4. 返回可验证的结果

同一个 Agent 的另一种用法:当文件命名不清晰时,先探索再决策

上面那个案例比较“理想”:数据文件名已经把范围写得很清楚(2023年8月-9月销售记录.xlsx),因此智能体能快速锁定目标文件。
但真实工作里经常不是这样——你可能只拿到一堆没有语义的文件名1.xlsx / 2.xlsx / 3.pdf,甚至目录里还混着 .DS_Store、历史文章草稿等噪音。

这时候 ReAct 的优势更明显:它不会赌运气,而是会先做“低成本探查”(列目录、看表头、抽样几行),把不确定性压下去,再进入真正的分析环节。

我今天也跑了一个“更贴近真实”的问题来验证这一点:

“销售总额最大的产品是什么?”

下面是这条路径的原始日志(注意:这次目录里并没有明显命名的销售文件,智能体必须先 Inspect 再决定)。
我保留了完整的 Thought / Tool / Return,让你能看到它如何一步步把模糊问题落到可执行的数据计算上。

🤖:有什么可以帮您?
👨:销售总额最大的产品是什么
[Thought: 0] 先定位数据源:需要先查看 ./data 目录下有哪些文件
{"name":"ListDirectory","args":{"path":"./data"}}
[Tool Return]
.DS_Store
2026-03-17-react-agent-learning.md
2.xlsx
1.xlsx
3.pdf
[Thought: 1] 文件名无语义,先 Inspect 其中的 Excel,判断哪个包含“产品名/单价/销售量”等字段
{"name":"InspectExcel","args":{"filename":"./data/1.xlsx","n":3}}
[Tool Return] 1.xlsx 列名:品类、产品名、单价(元)、销售量、销售日期、供应商
[Thought: 2] 确认可计算:销售总额=单价×销售量;按产品名分组汇总后取最大
{"name":"AnalyseExcel","args":{"query":"分析 ./data/1.xlsx 的“2023年8月-9月销售记录”,计算销售总额=单价×销售量,按产品名分组求和,返回销售总额最大产品及金额。","filename":"./data/1.xlsx"}}
[Tool Return]
销售总额最大的产品:PlayStation 5
销售总额:274945元

原始日志引用:完整的 ReAct 思考与行动(终端输出)

下面我把这次从 [Thought: 0] 到最终 FINISH 的过程,按段落拆成多段短引用(每段引用尽量控制在 300 字内),方便阅读与多平台发布。

🤖:有什么可以帮您?
👨:9月份的销售额是多少
[Thought: 0] 先找数据源:列出 ./data 目录,定位可能的销售数据文件
{"name":"ListDirectory","args":{"path":"./data"}}
[Tool Return]
2023年8月-9月销售记录.xlsx
供应商名录.xlsx
供应商资格要求.pdf
[Thought: 1] 文件名提示包含 8/9 月销售数据;下一步 InspectExcel 先确认列名与日期/金额字段
{"name":"InspectExcel","args":{"filename":"./data/2023年8月-9月销售记录.xlsx","n":3}}
[Tool Return] 列名:品类、产品名、单价(元)、销售量、销售日期、供应商(日期字段=销售日期,金额=单价×销售量)
[Thought: 2] 已确认可计算:筛选 2023-09 的记录,对每行做 单价×销售量,再求和
{"name":"AnalyseExcel","args":{"filename":"./data/2023年8月-9月销售记录.xlsx","query":"筛选销售日期在2023年9月1日至2023年9月30日的记录,计算销售额=单价(元)×销售量,并求和返回9月份总销售额。"}}
[Tool Return]
9月份的总销售额为:2851099元
{"name":"FINISH","args":{"the_final_answer":"9月份的销售额是2851099元"}}

这次学习最真实的收获:工程问题也是学习的一部分

如果只看“最终答对了”,会忽略今天其实花了大量时间在“让系统能跑起来”上。

1)LangChain 的模块迁移:旧 import 会直接跑崩

我踩到的第一个坑是:LangChain 新版本拆包/迁移很大
代码里很多旧路径在新版本下都不存在了,比如:

  • 以前在 langchain.* 的东西,很多迁到了 langchain_core.*
  • 集成、loader、vectorstore 很多迁到 langchain_community.*
  • text splitter 迁到 langchain_text_splitters
  • provider(OpenAI)迁到 langchain_openai

这意味着:写 Demo 时如果照着老教程复制 import,很可能装了 langchain 仍然 ImportError
解决方式不是“乱装包”,而是把 import 按新生态迁移,并尽量在关键处做兼容处理。

2)依赖补齐:Excel/PDF 读取离不开 openpyxl / PyMuPDF

在智能体场景里,“能读文件”是硬前提。
否则模型再会推理,拿不到数据也只能干着急。

Excel / PDF 常见缺失依赖:

  • .xlsx:通常需要 openpyxl(pandas 读取引擎)
  • .pdfPyMuPDF(对应 pymupdf,loader 才能工作)

当工具链缺依赖时,ReAct 往往会出现一种“看起来很聪明但做不了事”的回答:
它能讲清楚要怎么做,但最终会说“缺依赖,无法读取文件”。
这并不是模型的问题,而是工程环境没准备好。

3)API Key 的坑:不是“没读到”,而是“读到了但无效”

我还遇到过 401 鉴权错误。
这类问题最容易误判成“.env 没生效”,但其实从报错就能看出来:
只要请求发出去了,说明 key 已经被读取;401 更可能是 key 本身无效、复制不完整或被撤销。

从“调用 API”转向“智能体工程”,我越来越能体会到:

智能体不是一个脚本,而是一套系统。系统的稳定性,决定了智能体的上限。


我对 ReAct 的理解:它像“会写计划的前端同事”

作为前端,我以前习惯把复杂需求拆成任务列表:

  • 先把数据接口打通
  • 再把 UI 展示跑起来
  • 再做异常处理与边界条件

今天看到 ReAct 的输出,我突然觉得很熟悉:
它也在做“拆解、排序、执行、复盘”。区别只是:

  • 我写的是任务与代码
  • 它写的是 Thought 与工具调用 JSON

如果说前两天的我是在学“怎么把 AI 接进来”,那今天的我开始学“怎么让 AI 真正做事”。
这一步给我的冲击是:AI 不再只是一个回答器,而更像一个可编排的执行者


给同样在转型路上的你:第三天的我,想说几句真心话

学习 AI 的这几天,我的情绪其实很复杂:

  • 有兴奋:第一次看到模型自己决定去读 Excel,并算出一个真实数字
  • 有挫败:依赖装不上、版本不兼容、import 改来改去
  • 有踏实:每解决一个坑,就像给自己搭了一块“可复用的底座”

我越来越确定一件事:

转行不是跳跃,而是迁移。
把过去的工程能力迁移到 AI 工程里,才会走得更稳。

我会继续写下去。
明天也许会更难,但也一定会更接近我想要的方向。


附:今天这个 Demo 的关键链路(用于读者快速理解)

  • 问题:9 月销售额是多少
  • 数据源./data/2023年8月-9月销售记录.xlsx
  • 工具链
    • ListDirectory:发现文件
    • InspectExcel:确认字段与样例
    • AnalyseExcel:用 Python 计算 单价(元) × 销售量 的 9 月总和
  • 结果2851099 元

Demo 地址

仓库地址:https://github.com/Cyning12/auto-gpt-work-demo