ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AI Agent开发实战:从零搭建ReAct循环与Workflow编排

AI Agent开发实战:从零搭建ReAct循环与Workflow编排 1. 先搞清楚 AI Agent 到底在解决什么问题1.1 从“会聊天的模型”到“能办事的系统”很多人第一次接触 AI Agent脑子里浮现的是“更聪明的聊天机器人”。这个理解不算错但远远不够。聊天机器人解决的是“信息问答”你问它答对话结束任务也就结束了。而 AI Agent 解决的是“任务闭环”——你给它一个目标它自己去拆解步骤、调用工具、检查结果、遇到问题重试直到把事办完。举个具体的例子。你让一个纯 LLM 应用“帮我查一下上周的销售数据并生成周报”它大概率会回复你一段“我无法访问你的数据库”之类的话。但如果你把这件事交给一个配置好的 AI Agent它会先调用数据库查询工具拉取数据再用代码解释器做汇总统计接着调用文档生成工具产出周报最后通过邮件或消息接口把结果发出去。整个过程你只需要说一句话。这中间的差别就是Workflow 编排和工具调用带来的。Agent 不是一个模型而是一套“模型 工具 记忆 编排逻辑”的系统工程。Anthropic 在 2024 年底发布的那篇关于构建高效 Agent 的文章里把这个思路讲得很透最成功的 Agent 实现往往不是最复杂的框架而是最简单、最可控的组合模式。1.2 为什么现在大家都在聊 Agent三个条件同时成熟了。第一LLM 的推理能力和指令遵循能力到了可用的水平尤其是支持Function Calling和结构化输出的模型越来越多。第二工具生态起来了无论是搜索、代码执行、数据库连接还是各类 SaaS 接口都有现成的 SDK 可以接。第三成本降下来了以前跑一次复杂推理要几毛钱现在几分钱甚至几厘钱就能搞定。这三个条件缺一个Agent 都跑不起来。早两年做类似尝试的人应该记得那时候模型经常“幻觉”出根本不存在的工具名或者把参数格式写错整个流程动不动就断。现在虽然还会出问题但至少在一个设计良好的 Workflow 里成功率能做到 90% 以上。1.3 这篇文章适合谁看如果你是完全没接触过 Agent 的新手这篇文章会从最基础的概念讲起告诉你一个 Agent 由哪些部分组成每一部分为什么必须存在。如果你已经用过一些 Agent 框架但总觉得“不太听话”这篇文章会帮你理清 Workflow 编排的核心逻辑让你知道问题出在哪个环节。如果你正在做AI Agent 开发的技术选型文章里关于框架对比和工具选型的部分可以直接参考。我自己的经验是学 Agent 最快的方式不是先看框架文档而是先用最原始的方式手搓一个最小可用的版本。你只有亲手处理过“模型返回的 JSON 解析失败”这种问题才会真正理解为什么需要结构化输出约束。下面我就按这个思路从零开始拆。2. 一个 AI Agent 的最小构成与核心原理2.1 四个必备组件模型、工具、记忆、编排把 Agent 拆开看核心就四样东西。模型是大脑负责理解意图、做决策、生成内容。选模型的时候不要只看跑分要看它在你的具体任务上的表现。有些模型通用能力强但工具调用格式老出错有些模型专门针对 Function Calling 做了优化实际用起来反而更稳。工具是手脚让 Agent 能跟外部世界交互。最常见的工具包括搜索引擎、代码执行器、文件读写、HTTP 请求、数据库查询。工具的定义要尽可能清晰每个工具只做一件事参数说明要写明白。我见过太多人把工具设计得过于复杂一个工具干五件事结果模型根本不知道怎么传参。记忆分短期和长期。短期记忆就是当前对话的上下文决定了 Agent 能“记住”多少轮之前的交互。长期记忆通常用向量数据库或知识库来实现让 Agent 能跨会话记住用户偏好或领域知识。LLM Wiki 知识库这类方案就是典型的长期记忆实现。编排是骨架决定这些组件按什么顺序、什么条件组合起来。最简单的编排就是“模型输出 → 解析 → 调工具 → 把结果塞回模型 → 再输出”复杂一点的会有分支判断、循环重试、并行执行。2.2 ReAct 模式Agent 最基础的思考循环ReAct 是 Reasoning Acting 的缩写是目前大多数 Agent 的底层逻辑。它的工作流程是这样的模型接收用户输入和当前上下文模型输出一段“思考”Thought说明它打算做什么模型输出一个“动作”Action指定要调用的工具和参数系统执行工具拿到“观察结果”Observation把 Observation 追加到上下文回到第 1 步直到模型认为任务完成输出最终答案这个循环看起来简单但实际跑起来坑很多。最常见的问题是模型在 Thought 阶段想得很好但 Action 阶段参数格式写错了。比如它想调用search(queryAI Agent)结果输出成search(AI Agent)少了参数名。这时候就需要在系统提示词里把工具调用的格式约束死或者用支持结构化输出的模型来强制 JSON Schema。提示ReAct 循环一定要设最大迭代次数。我一般设 10 到 15 次超过就强制终止并返回当前结果。不然遇到模型“钻牛角尖”的情况它会一直循环调用同一个工具烧钱又费时。2.3 Workflow 编排把单步能力串成完整流程单个 ReAct 循环能解决“查个天气”这种简单任务但真实业务往往需要多步骤协作。比如“分析竞品动态并生成报告”这件事拆开看至少包括搜索竞品新闻、抓取关键页面内容、提取核心信息、对比分析、生成结构化报告、发送给相关人员。Workflow 编排就是把这些步骤按依赖关系组织起来。有两种主流做法一种是代码编排用 Python 或 TypeScript 把每一步写成函数用 if/else 和循环来控制流程。优点是可控性极强调试方便适合逻辑固定的场景。缺点是灵活性差流程一变就要改代码。另一种是模型编排让一个“规划模型”先输出任务分解和步骤依赖再由执行器按计划调用各个子 Agent 或工具。优点是灵活能处理没见过的任务组合。缺点是稳定性差规划模型本身可能出错而且多一层调用就多一层延迟和成本。我的建议是核心业务流程用代码编排边缘的、探索性的任务用模型编排。比如客服 Agent 的“查订单 → 判断状态 → 回复用户”这条主线用代码写死最稳。但用户问了一个没预设过的问题可以交给模型编排去尝试解决。2.4 为什么 Anthropic 强调“简单优先”Anthropic 在那篇 Agent 构建指南里反复强调一个观点能用简单 Workflow 解决的不要上复杂 Agent。很多人一上来就想搞“全自主 Agent”结果发现模型在开放环境里根本不可控今天能跑通的任务明天就失败。他们的建议是先用 Prompt Chaining提示链把任务拆成固定步骤每个步骤用 LLM 处理步骤之间用代码传递数据。如果 Prompt Chaining 不够用再考虑 Routing路由——根据输入类型分发给不同的处理链。再复杂一点用 Orchestrator-Workers编排器-工作者模式由一个主模型分解任务多个子模型并行执行。最后才考虑完全自主的 Agent。这个渐进思路非常实用。我自己的项目里80% 的需求用 Prompt Chaining 加简单条件分支就能搞定根本不需要 Agent 框架。剩下 20% 才需要真正的 Agent 能力。3. 从零搭建一个 AI Agent 的完整实操3.1 环境准备与技术选型先明确一点不要一上来就选框架。我见过太多人花一周时间研究 LangChain、AutoGPT、CrewAI 的区别结果连一个能跑通的 Demo 都没写出来。正确的做法是先用手写的方式实现一个最小 Agent理解每个环节在干什么然后再根据需求选框架。基础环境很简单python -m venv agent-env source agent-env/bin/activate pip install openai httpx pydantic模型接口方面OpenAI 的 API 格式目前是事实标准大多数模型服务商都兼容。如果你用 Anthropic 的 Claude接口略有不同但逻辑一致。国内的话通义千问、DeepSeek、智谱都有兼容 OpenAI 格式的接口切换成本很低。注意如果你在调用 Anthropic 服务时遇到unable to connect to anthropic services或failed to connect to api.anthropic.com这类报错先检查网络出口和 API Key 配置。另外claude doesnt look like an anthropic model: expected a gateway model route这个错误通常出现在用第三方网关转发请求时模型名称映射没配对。建议先用官方 SDK 直连测试确认基础链路通了再上网关。3.2 定义工具让模型知道它能做什么工具定义是整个 Agent 的地基。一个工具包含三部分名称、描述、参数 Schema。tools [ { type: function, function: { name: search_web, description: 搜索互联网获取最新信息。当需要查询实时数据、新闻或未知信息时使用。, parameters: { type: object, properties: { query: { type: string, description: 搜索关键词尽量具体 }, max_results: { type: integer, description: 返回结果数量默认5, default: 5 } }, required: [query] } } } ]描述字段非常关键。模型就是靠这段文字来判断“什么时候该用这个工具”。我踩过的坑是描述写得太笼统比如只写“搜索功能”结果模型在需要计算的时候也去调搜索。后来改成“搜索互联网获取最新信息不适用于数学计算”误调用率立刻降下来了。参数 Schema 用 JSON Schema 格式required字段一定要标清楚。如果某个参数有默认值在 description 里说明模型会自己决定要不要传。3.3 实现 ReAct 循环核心执行引擎下面是一个最简版的 ReAct 循环实现import json from openai import OpenAI client OpenAI() def run_agent(user_input, max_iterations10): messages [ {role: system, content: 你是一个助手可以使用工具来完成任务。每次只调用一个工具。}, {role: user, content: user_input} ] for i in range(max_iterations): response client.chat.completions.create( modelgpt-4o, messagesmessages, toolstools, tool_choiceauto ) msg response.choices[0].message # 没有工具调用说明模型认为任务完成 if not msg.tool_calls: return msg.content # 把模型的回复加入上下文 messages.append(msg) # 执行每个工具调用 for tool_call in msg.tool_calls: func_name tool_call.function.name func_args json.loads(tool_call.function.arguments) # 实际执行工具 result execute_tool(func_name, func_args) # 把结果塞回上下文 messages.append({ role: tool, tool_call_id: tool_call.id, content: str(result) }) return 达到最大迭代次数任务未完成这段代码的核心逻辑就是模型输出工具调用 → 执行 → 结果回传 → 模型继续决策。max_iterations是安全阀防止死循环。execute_tool函数根据工具名分发到具体实现def execute_tool(name, args): if name search_web: return search_web(args[query], args.get(max_results, 5)) elif name run_code: return run_code(args[code]) else: return f未知工具: {name}3.4 加入记忆让 Agent 记住上下文短期记忆直接靠 messages 列表维护就行。但要注意上下文长度限制超过模型窗口后需要做截断或摘要。我的做法是保留最近 10 轮完整对话更早的用 LLM 压缩成一段摘要放在系统提示里。长期记忆需要向量数据库。流程是把领域知识切块 → 用 Embedding 模型转向量 → 存入向量库 → 查询时先做相似度检索 → 把相关片段拼进提示词。这就是RAG的基本流程。LLM Wiki 知识库是 RAG 的一种变体它把知识组织成结构化的 Wiki 页面每个页面有明确的主题和关联关系。查询时先定位到相关页面再提取内容。相比纯向量检索Wiki 结构能保留更多上下文和层级关系适合知识体系比较复杂的场景。3.5 编排多步骤 Workflow单轮 ReAct 只能处理简单任务。复杂任务需要把多个 ReAct 实例或固定步骤串起来。下面是一个“竞品分析报告”的 Workflow 示例def competitor_analysis_workflow(company_name): # 步骤1搜索竞品新闻 news search_agent(f{company_name} 最新动态 2025) # 步骤2提取关键信息 key_points extract_agent(news) # 步骤3对比分析 analysis analyze_agent(key_points, company_name) # 步骤4生成报告 report generate_report_agent(analysis) return report每个xxx_agent内部都是一个完整的 ReAct 循环。步骤之间用代码传递数据这样比让一个模型从头到尾自己规划要稳定得多。如果步骤之间有条件分支比如“如果新闻数量少于3条就扩大搜索范围”直接在代码里写 if/else 就行。Workflow 编排的精髓就是把不确定的交给模型把确定的交给代码。4. 实际开发中绕不开的坑与排查方法4.1 工具调用格式错误最常见也最烦人模型返回的 JSON 解析失败是最高频的问题。表现包括参数名拼错、缺少必填字段、JSON 格式不合法、把字符串当数字传。排查思路分三步。第一检查工具定义是否清晰参数名是否容易混淆。第二在系统提示词里加一句“调用工具时严格按照 JSON Schema 输出不要添加额外字段”。第三如果模型本身对 Function Calling 支持不好考虑用支持结构化输出的模型或者用 Instructor 这类库做输出约束。我实测下来GPT-4o 和 Claude 3.5 Sonnet 在工具调用上的稳定性明显好于小模型。如果成本敏感至少用 7B 以上且专门做过 Function Calling 微调的模型。4.2 循环调用同一个工具模型“卡住了”有时候模型会反复调用同一个工具比如一直搜索同一个关键词。原因通常是工具返回的结果没有提供足够的新信息模型不知道下一步该干什么。解决办法有两个。一是在工具返回结果里加一个提示比如“如果以上结果不包含所需信息请尝试更换关键词或使用其他工具”。二是在系统提示里加约束“同一个工具连续调用不要超过2次如果2次都没有得到有用信息请换一种方式或直接告知用户无法完成”。4.3 上下文爆炸Token 消耗失控多轮 ReAct 循环会让上下文迅速膨胀。一次搜索返回 2000 字调三次就 6000 字再加上系统提示和历史对话很容易超过模型窗口。我的做法是工具返回结果先做一次摘要再塞回上下文。比如搜索结果只保留标题和前 200 字摘要完整内容存到外部文件需要时再按需读取。这样能把单次工具返回的 Token 消耗降低 70% 以上。另外设置合理的max_iterations和单次工具返回长度上限也很重要。我一般限制工具返回不超过 1500 字超过就截断并提示模型“结果已截断如需完整内容请指定更精确的查询”。4.4 常见问题速查表问题现象可能原因排查方法解决思路JSON 解析失败模型输出格式不规范打印原始返回内容加格式约束提示词换结构化输出模型工具调用参数错误工具描述不清晰检查 Schema 和 description细化参数说明加示例循环调用同一工具结果无新信息查看工具返回内容加调用次数限制优化返回摘要上下文超长工具返回内容过多统计 Token 消耗摘要后再入上下文设长度上限任务未完成就退出模型误判完成检查最终输出在提示词中明确完成条件响应延迟高迭代次数过多记录每轮耗时减少迭代并行化独立步骤4.5 几个让我少走弯路的实操心得第一先写测试用例再写 Agent。把典型输入和期望输出列出来每次改完提示词或工具定义就跑一遍。没有测试用例的 Agent 开发就是盲人摸象。第二日志要打全。每一轮的模型输入、输出、工具调用参数、工具返回结果都要记录。出问题的时候回看日志比瞎猜快十倍。第三工具宁少勿多。一开始只给 3 到 5 个核心工具跑通了再逐步加。工具越多模型选错的概率越大。第四系统提示词要短而精。我见过有人写 2000 字的系统提示结果模型把关键约束都忘了。核心约束放在最前面和最后面中间放示例。第五别追求一次完美。Agent 开发是迭代过程第一版能跑通主流程就行边界情况慢慢补。我第一个 Agent 只能处理三种固定问法但跑通之后扩展起来就快了。5. 进阶方向从能跑到好用5.1 加入人工确认环节完全自主的 Agent 在生产环境里风险很高。我的做法是在关键操作前加人工确认。比如 Agent 要发邮件、改数据库、执行支付先弹一个确认框让用户点“同意”再继续。这样既保留了自动化效率又避免了误操作。实现上就是在 Workflow 里插入一个human_approval节点Agent 执行到这个节点时暂停把待确认内容展示给用户用户确认后继续拒绝则走回退分支。5.2 多 Agent 协作复杂任务可以拆给多个专职 Agent。比如一个“电商运营 Agent”可以拆成选品 Agent、定价 Agent、文案 Agent、客服 Agent。每个 Agent 有自己的工具集和提示词通过一个协调器来调度。这种架构的优点是每个 Agent 可以独立优化缺点是通信成本高而且协调器本身可能成为瓶颈。我的建议是只有当单个 Agent 的工具超过 10 个、提示词超过 1500 字时才考虑拆分。否则一个 Agent 加清晰的 Workflow 编排就够了。5.3 评估与监控Agent 上线只是开始持续监控才是关键。需要跟踪的指标包括任务完成率、平均迭代次数、工具调用成功率、Token 消耗、响应延迟。我一般会做一个简单的 Dashboard每天看一遍。如果发现完成率下降就去查日志看是哪类任务出了问题。如果 Token 消耗突然上升通常是某个工具返回内容变长了或者模型开始频繁重试。5.4 关于框架选择的个人看法LangChain 生态最全但抽象层太厚出问题不好排查。LlamaIndex 在 RAG 场景下很好用但 Agent 编排能力偏弱。CrewAI 的多 Agent 协作设计很优雅但定制化空间有限。Spring AI 适合 Java 技术栈的团队跟 Spring Cloud 集成很顺。我的选择是核心逻辑手写辅助功能用库。比如工具调用的解析和重试逻辑自己写向量检索用 LlamaIndexWeb 服务用 FastAPI。这样既保持了可控性又不用重复造轮子。6. 一个完整的最小可运行示例6.1 项目结构mini-agent/ ├── main.py # 入口 ├── agent.py # ReAct 循环 ├── tools.py # 工具定义与实现 ├── memory.py # 记忆管理 └── config.py # 配置6.2 核心代码串联config.py放模型配置和 API KeyMODEL gpt-4o MAX_ITERATIONS 10 MAX_TOOL_RESULT_LENGTH 1500tools.py定义工具def search_web(query, max_results5): # 实际实现调用搜索 API results do_search(query, max_results) # 截断过长内容 return truncate(results, MAX_TOOL_RESULT_LENGTH) def run_code(code): # 在沙箱中执行代码 return execute_in_sandbox(code)agent.py是核心循环就是前面 3.3 节的代码加上日志和错误处理。main.py启动if __name__ __main__: while True: user_input input(你: ) if user_input exit: break result run_agent(user_input) print(fAgent: {result})这个最小版本大概 200 行代码能处理“搜索信息并总结”这类任务。跑通之后你可以逐步加工具、加记忆、加 Workflow 分支慢慢扩展成完整的系统。6.3 测试与验证跑通之后先做三组测试。第一组是正常任务比如“搜索今天 AI 领域的重要新闻并总结”。第二组是边界情况比如“搜索一个不存在的公司”。第三组是异常情况比如故意让搜索 API 返回错误看 Agent 能不能优雅处理。每组测试记录是否完成任务、迭代了几轮、消耗多少 Token、有没有报错。这些数据是你后续优化的基准。7. 关于成本与性能的平衡7.1 Token 消耗的主要来源一个典型的多轮 Agent 任务Token 消耗分布大概是系统提示词占 10%用户输入占 5%模型思考输出占 20%工具调用参数占 10%工具返回结果占 55%。可以看到工具返回结果是最大的消耗源。优化方向很明确压缩工具返回内容。搜索类工具只返回摘要代码执行类工具只返回关键输出数据库查询类工具限制返回行数。我一般会把工具返回控制在 500 到 1500 字之间具体看任务复杂度。7.2 模型选择的性价比考量不是所有环节都需要用最贵的模型。我的做法是分层规划任务分解用强模型执行具体工具调用用中等模型结果摘要用便宜模型。这样整体成本能降 40% 到 60%而效果下降不明显。具体来说任务规划用 GPT-4o 或 Claude 3.5 Sonnet工具调用用 GPT-4o-mini 或 Claude 3 Haiku摘要用更便宜的模型。当然这需要你的 Workflow 支持多模型切换代码编排模式下很容易实现。7.3 缓存策略很多 Agent 任务有重复性。比如每天早上查同样的数据源、生成同样格式的报告。这种场景可以加缓存把工具调用参数做哈希如果相同参数在有效期内调用过直接返回缓存结果。我实测下来在日报生成场景下缓存能减少 60% 以上的工具调用次数Token 消耗直接砍半。缓存有效期根据数据更新频率来定新闻类设 1 小时统计数据设 1 天。8. 我踩过的三个印象最深的坑8.1 工具描述里的一个错别字导致整个流程崩溃有一次我写了一个send_email工具描述里把“收件人”写成了“收件入”。结果模型在调用时死活传不对参数因为它从描述里学到的就是错的。排查了两个小时才发现是描述里的错别字。从那以后我每次改完工具定义都会让另一个同事帮忙读一遍。8.2 忘记设最大迭代次数导致账单暴涨早期做的一个 Agent 没设迭代上限结果遇到一个模型无法处理的任务它连续调用了 200 多次搜索工具一晚上烧掉了几十美元。第二天看到账单的时候心都在滴血。现在我的所有 Agent 都强制设max_iterations默认 10最多不超过 20。8.3 上下文截断把关键信息截掉了为了控制 Token我一开始简单粗暴地按消息数量截断保留最近 10 条。结果有一次 Agent 在第 3 轮拿到了关键数据到第 12 轮需要用时已经被截掉了导致任务失败。后来改成按 Token 数动态截断并且优先保留包含工具调用结果的消息问题才解决。9. 后续可以继续深挖的方向如果你已经跑通了一个基础 Agent接下来可以往这几个方向深入。评估体系建立自动化的评估流水线每次修改提示词或工具定义后自动跑测试集量化对比效果变化。这是从“能跑”到“可靠”的关键一步。多模态能力让 Agent 能处理图片、PDF、表格等非文本输入。很多真实业务场景的数据不是纯文本比如发票识别、图表分析。领域知识注入通过 RAG 或微调把行业知识灌进 Agent。通用模型在专业领域往往不够准注入领域知识后效果提升很明显。LLM Wiki这类结构化知识库在这方面有天然优势。安全与权限给 Agent 加上操作权限控制不同用户能调用的工具不同敏感操作需要审批。这在企业环境里是必须的。可观测性接入 LangSmith 或自己搭一套追踪系统把每一轮的输入输出、耗时、成本都可视化。出了问题能快速定位优化也有数据支撑。Agent 这个方向变化很快每隔几个月就有新工具和新模式出来。但底层逻辑是不变的清晰的工具定义、可控的编排流程、合理的记忆管理、持续的评估优化。把这四件事做好不管用什么框架都能搭出好用的 Agent。
返回列表