章节 01
导读 / 主楼:从零构建AI Agent:工具调用、ReAct与多步工作流的实践指南
深入解析一个从零构建的AI Agent项目,涵盖工具调用机制、ReAct推理循环、多步研究工作流以及与Notion的集成实践。
正文
深入解析一个从零构建的AI Agent项目,涵盖工具调用机制、ReAct推理循环、多步研究工作流以及与Notion的集成实践。
章节 01
深入解析一个从零构建的AI Agent项目,涵盖工具调用机制、ReAct推理循环、多步研究工作流以及与Notion的集成实践。
章节 02
python\ntools = [\n {\n \"name\": \"search_web\",\n \"description\": \"Search the web for current information...\",\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"query\": {\n \"type\": \"string\",\n \"description\": \"The search query to look up\"\n }\n },\n \"required\": [\"query\"]\n }\n }\n]\n\n\n这个设计体现了工具调用的核心原则:每个工具必须有明确的名称、描述和输入Schema。描述部分尤其重要——它直接告诉LLM在什么情况下应该使用这个工具。良好的工具描述应该包含使用场景和预期输入格式。\n\n### 工具执行与结果反馈\n\n当LLM决定调用工具时,API会返回一个tool_use类型的响应块,包含工具名称、输入参数和一个唯一的工具调用ID。Agent需要:\n\n1. 解析响应,识别所有tool_use块\n2. 根据工具名称执行相应的本地函数\n3. 将执行结果格式化为tool_result块,关联原始的工具调用ID\n4. 将结果反馈给LLM,让其决定下一步行动\n\n项目代码展示了如何处理多个并行工具调用——通过遍历所有tool_use块,依次执行每个工具,最后一次性将所有结果返回给LLM。这种批处理方式比串行调用更高效。\n\n## ReAct推理循环:思考与行动的交替\n\n### ReAct模式的核心逻辑\n\nReAct(Reasoning + Acting)是构建AI Agent的经典范式。它模拟人类解决问题的过程:先思考需要什么信息,然后采取行动获取信息,再基于新信息继续思考。\n\n项目中的run_agent函数实现了这一循环:\n\n1. 初始化:将用户问题加入消息历史\n2. 首次调用:向LLM发送问题和可用工具定义\n3. 循环判断:检查LLM的停止原因——如果是tool_use,继续循环;如果是stop,给出最终答案\n4. 工具执行:调用工具,收集结果\n5. 反馈迭代:将工具结果加入消息历史,再次调用LLM\n6. 终止条件:达到最大轮次或LLM给出最终答案\n\n### 系统提示词的设计艺术\n\n项目的系统提示词设计值得仔细研究:\n\n\nYou are a research assistant that thoroughly investigates questions before answering.\n\nWhen given a question:\n1. Think about what information you need to answer it well\n2. Search for that information\n3. Evaluate what you found - is it enough...\n4. If not, identify what's missing and search again...\n5. Once you have sufficient information, provide a comprehensive answer...\n\nAlways cite specific facts from your search results. Never make up information.\n\n\n这个提示词的成功之处在于它将ReAct模式显式编码为步骤指令。LLM被明确告知要遵循"思考→搜索→评估→再搜索→回答"的流程,而不是直接生成答案。这种显式指导显著提高了Agent的可靠性。\n\n## 多步工作流:从简单循环到复杂管道\n\n### 工作流设计的演进\n\nworkflow_agent.py展示了如何将简单的ReAct循环扩展为结构化的多节点工作流。与agent.py的交互式循环不同,工作流版本采用了明确的阶段划分:\n\n1. 规划节点(Planner):分析问题,生成搜索查询列表\n2. 研究节点(Researcher):并行执行所有搜索,收集原始结果\n3. 综合节点(Synthesizer):将原始结果整理为结构化发现\n4. 撰写节点(Writer):基于发现生成最终答案\n\n### 状态管理:TypedDict模式\n\n工作流使用TypedDict定义状态对象,明确每个阶段的数据流转:\n\npython\nclass ResearchState(TypedDict):\n question: str # 原始问题(只读)\n queries: list[str] # 规划阶段生成的查询\n raw_results: list[str] # 研究阶段收集的结果\n findings: str # 综合阶段的结构化发现\n final_answer: str # 撰写阶段的最终答案\n turn_count: int # 搜索轮次计数\n\n\n这种显式状态管理比隐式的消息历史更清晰,也更容易调试。每个节点接收完整状态,修改自己负责的字段,返回更新后的状态。\n\n### 工具选择的强制模式\n\n规划节点的一个技巧是使用tool_choice={\"type\": \"tool\", \"name\": \"generate_queries\"}强制LLM以特定工具格式输出。这确保LLM不会用自然语言回复,而是生成结构化的查询列表,便于下游节点处理。\n\n## 工程实践中的关键考量\n\n### 错误处理与边界情况\n\n项目代码展示了几个重要的工程实践:\n\n- 最大轮次限制:防止Agent陷入无限循环\n- 空结果处理:搜索工具返回空结果时的优雅降级\n- 未知工具处理:防御性编程,处理LLM可能请求的未定义工具\n\n### 调试与可观测性\n\n代码中穿插的print语句虽然简单,但体现了Agent开发中的关键需求——可观测性。每个阶段都输出进度信息("Generated X queries"、"Executing search..."、"Findings generated"),让开发者可以追踪Agent的决策过程。在生产环境中,这些应该替换为结构化的日志系统。\n\n## 扩展方向与应用场景\n\n### 从研究助手到通用Agent\n\n这个项目的架构可以轻松扩展为其他类型的Agent:\n\n- 代码助手:将搜索工具替换为代码执行、文件操作、Git命令\n- 数据分析Agent:集成Pandas、SQL查询、可视化工具\n- 客服Agent:连接知识库、工单系统、CRM工具\n\n### 与Notion集成的启示\n\n项目描述中提到Notion集成,虽然代码片段中未展示具体实现,但这一方向很有代表性。将Agent与生产力工具连接,可以实现:\n\n- 自动整理研究笔记到Notion数据库\n- 从Notion页面提取上下文作为Agent的记忆\n- 将Agent生成的报告直接发布为Notion文档\n\n这种集成模式体现了Agent的价值——不仅是回答问题,而是真正完成工作流程。\n\n## 结语:Agent开发的未来\n\n这个从零构建的Agent项目虽然代码量不大,但涵盖了AI Agent开发的核心理念:工具调用让LLM能够影响外部世界,ReAct循环让推理与行动交替进行,多步工作流让复杂任务可分解、可管理。\n\n随着MCP(Model Context Protocol)等标准化协议的兴起,Agent的工具生态将更加丰富。理解这些基础机制,将帮助开发者在快速演进的技术浪潮中保持清醒的判断力——知道什么应该外包给框架,什么需要自己掌控。章节 03
引言:AI Agent的崛起\n\n2024-2025年,AI领域最显著的趋势之一是从简单的问答模型向能够自主执行任务的AI Agent转变。与仅提供文本回复的传统LLM不同,Agent可以调用工具、浏览网页、操作数据库、甚至与其他服务交互。本文将深入分析一个从零构建的AI Agent开源项目,展示工具调用、ReAct推理架构和多步工作流的实现细节,为希望理解Agent内部机制的开发者提供实践参考。\n\n项目架构概览\n\n该项目由三个核心文件组成,分别对应Agent开发的三个层次:\n\n- agent.py:基础的ReAct Agent实现,展示工具调用和推理循环的核心机制\n- workflow_agent.py:多节点研究工作流,演示如何将复杂任务分解为规划、研究、综合、撰写四个阶段\n- test_setup.py:环境测试和配置验证\n\n这种分层设计让学习者可以循序渐进——先理解基础的工具调用,再掌握多步推理,最后学习完整的工作流编排。\n\n工具调用的实现机制\n\n工具定义与Schema设计\n\n项目中的工具调用基于Anthropic的Claude API,但其实现模式具有通用性。以网络搜索工具为例:\n\npython\ntools = [\n {\n \"name\": \"search_web\",\n \"description\": \"Search the web for current information...\",\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"query\": {\n \"type\": \"string\",\n \"description\": \"The search query to look up\"\n }\n },\n \"required\": [\"query\"]\n }\n }\n]\n\n\n这个设计体现了工具调用的核心原则:每个工具必须有明确的名称、描述和输入Schema。描述部分尤其重要——它直接告诉LLM在什么情况下应该使用这个工具。良好的工具描述应该包含使用场景和预期输入格式。\n\n工具执行与结果反馈\n\n当LLM决定调用工具时,API会返回一个tool_use类型的响应块,包含工具名称、输入参数和一个唯一的工具调用ID。Agent需要:\n\n1. 解析响应,识别所有tool_use块\n2. 根据工具名称执行相应的本地函数\n3. 将执行结果格式化为tool_result块,关联原始的工具调用ID\n4. 将结果反馈给LLM,让其决定下一步行动\n\n项目代码展示了如何处理多个并行工具调用——通过遍历所有tool_use块,依次执行每个工具,最后一次性将所有结果返回给LLM。这种批处理方式比串行调用更高效。\n\nReAct推理循环:思考与行动的交替\n\nReAct模式的核心逻辑\n\nReAct(Reasoning + Acting)是构建AI Agent的经典范式。它模拟人类解决问题的过程:先思考需要什么信息,然后采取行动获取信息,再基于新信息继续思考。\n\n项目中的run_agent函数实现了这一循环:\n\n1. 初始化:将用户问题加入消息历史\n2. 首次调用:向LLM发送问题和可用工具定义\n3. 循环判断:检查LLM的停止原因——如果是tool_use,继续循环;如果是stop,给出最终答案\n4. 工具执行:调用工具,收集结果\n5. 反馈迭代:将工具结果加入消息历史,再次调用LLM\n6. 终止条件:达到最大轮次或LLM给出最终答案\n\n系统提示词的设计艺术\n\n项目的系统提示词设计值得仔细研究:\n\n\nYou are a research assistant that thoroughly investigates questions before answering.\n\nWhen given a question:\n1. Think about what information you need to answer it well\n2. Search for that information\n3. Evaluate what you found - is it enough...\n4. If not, identify what's missing and search again...\n5. Once you have sufficient information, provide a comprehensive answer...\n\nAlways cite specific facts from your search results. Never make up information.\n\n\n这个提示词的成功之处在于它将ReAct模式显式编码为步骤指令。LLM被明确告知要遵循"思考→搜索→评估→再搜索→回答"的流程,而不是直接生成答案。这种显式指导显著提高了Agent的可靠性。\n\n多步工作流:从简单循环到复杂管道\n\n工作流设计的演进\n\nworkflow_agent.py展示了如何将简单的ReAct循环扩展为结构化的多节点工作流。与agent.py的交互式循环不同,工作流版本采用了明确的阶段划分:\n\n1. 规划节点(Planner):分析问题,生成搜索查询列表\n2. 研究节点(Researcher):并行执行所有搜索,收集原始结果\n3. 综合节点(Synthesizer):将原始结果整理为结构化发现\n4. 撰写节点(Writer):基于发现生成最终答案\n\n状态管理:TypedDict模式\n\n工作流使用TypedDict定义状态对象,明确每个阶段的数据流转:\n\npython\nclass ResearchState(TypedDict):\n question: str 原始问题(只读)\n queries: list[str] 规划阶段生成的查询\n raw_results: list[str] 研究阶段收集的结果\n findings: str 综合阶段的结构化发现\n final_answer: str 撰写阶段的最终答案\n turn_count: int 搜索轮次计数\n\n\n这种显式状态管理比隐式的消息历史更清晰,也更容易调试。每个节点接收完整状态,修改自己负责的字段,返回更新后的状态。\n\n工具选择的强制模式\n\n规划节点的一个技巧是使用tool_choice={\"type\": \"tool\", \"name\": \"generate_queries\"}强制LLM以特定工具格式输出。这确保LLM不会用自然语言回复,而是生成结构化的查询列表,便于下游节点处理。\n\n工程实践中的关键考量\n\n错误处理与边界情况\n\n项目代码展示了几个重要的工程实践:\n\n- 最大轮次限制:防止Agent陷入无限循环\n- 空结果处理:搜索工具返回空结果时的优雅降级\n- 未知工具处理:防御性编程,处理LLM可能请求的未定义工具\n\n调试与可观测性\n\n代码中穿插的print语句虽然简单,但体现了Agent开发中的关键需求——可观测性。每个阶段都输出进度信息("Generated X queries"、"Executing search..."、"Findings generated"),让开发者可以追踪Agent的决策过程。在生产环境中,这些应该替换为结构化的日志系统。\n\n扩展方向与应用场景\n\n从研究助手到通用Agent\n\n这个项目的架构可以轻松扩展为其他类型的Agent:\n\n- 代码助手:将搜索工具替换为代码执行、文件操作、Git命令\n- 数据分析Agent:集成Pandas、SQL查询、可视化工具\n- 客服Agent:连接知识库、工单系统、CRM工具\n\n与Notion集成的启示\n\n项目描述中提到Notion集成,虽然代码片段中未展示具体实现,但这一方向很有代表性。将Agent与生产力工具连接,可以实现:\n\n- 自动整理研究笔记到Notion数据库\n- 从Notion页面提取上下文作为Agent的记忆\n- 将Agent生成的报告直接发布为Notion文档\n\n这种集成模式体现了Agent的价值——不仅是回答问题,而是真正完成工作流程。\n\n结语:Agent开发的未来\n\n这个从零构建的Agent项目虽然代码量不大,但涵盖了AI Agent开发的核心理念:工具调用让LLM能够影响外部世界,ReAct循环让推理与行动交替进行,多步工作流让复杂任务可分解、可管理。\n\n随着MCP(Model Context Protocol)等标准化协议的兴起,Agent的工具生态将更加丰富。理解这些基础机制,将帮助开发者在快速演进的技术浪潮中保持清醒的判断力——知道什么应该外包给框架,什么需要自己掌控。