ARTICLE DETAIL

资讯详情

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

从零手写生产级 Agent:ReAct 循环、工具注册与容错设计

从零手写生产级 Agent:ReAct 循环、工具注册与容错设计 从零手写生产级 AgentReAct 循环、工具注册与容错设计框架用多了容易产生一种错觉Agent 就是调一个库。但真正遇到框架解决不了的场景——比如需要深度定制工具协议、严格审计每一步动作、或者目标环境过于受限时——你就必须理解 Agent 内部到底在发生什么。这篇文章不推荐你生产环境手写 Agent而是通过从零实现一个带工具调用的 ReAct Agent把模型决策、工具执行、循环终止、容错恢复这些核心机制彻底讲透。读懂这些你再用任何框架都会觉得是在看自己的代码。一、ReAct 循环的本质思考、行动、观察ReActReason Act是目前绝大多数 Agent 的基础范式。它把问题求解过程拆成三步循环Thought思考模型分析当前状态决定下一步做什么。Action行动模型输出一个工具调用意图。Observation观察程序执行工具把结果回传给模型。循环往复直到模型认为任务完成。这个循环的每个环节都需要工程化处理。# 核心循环骨架defagent_loop(query,tools,llm,max_steps10):messages[{role:user,content:query}]forstepinrange(max_steps):responsellm.chat(messages)actionparse_action(response)# 解析模型输出的动作ifactionisNone:returnresponse# 模型认为完成直接返回resultexecute_tool(action,tools)# 执行工具messages.append({role:assistant,content:response})messages.append({role:tool,content:result})return达到最大步数任务未完成## 二、工具注册让模型知道你能做什么Agent 的工具系统由两部分组成**工具的元信息**让模型知道有什么工具、怎么用和**工具的执行器**程序真正干活的部分。 python TOOLS{}defregister_tool(name,description,params_schema):defdecorator(func):TOOLS[name]{func:func,description:description,params_schema:params_schema,}returnfuncreturndecoratorregister_tool(nameget_weather,description查询指定城市的当前天气城市用中文名称。,params_schema{city:string, 必填城市名},)defget_weather(city:str):# 实际项目里这里调用天气 APIreturnf{city}今天晴25 度register_tool(namecalculator,description执行四则运算表达式如 3 4 * 2。,params_schema{expr:string, 必填数学表达式},)defcalculator(expr:str):returnstr(eval(expr))# 生产环境严禁 eval仅作演示 模型怎么知道这些工具存在靠的是**工具描述注入**。把每个工具的 name、description、params 拼进系统提示词让模型看到工具箱 pythondefbuild_tool_prompt():lines[你可以使用以下工具,]forname,metainTOOLS.items():lines.append(f-{name}:{meta[description]}参数:{meta[params_schema]})lines.append( 使用工具时输出格式为 ACTION: 工具名 PARAMS: JSON 参数 任务完成或无法解决时输出 DONE: 最终答案 )return\n.join(lines) 这里有两个工程细节一是工具描述要写清楚**适用场景和参数格式**描述越模糊模型越容易调用错二是要明确输出协议——模型用固定格式声明它要调用的工具程序端解析这个格式并执行双方靠协议沟通而不是靠猜。## 三、动作解析与执行协议的两端模型的输出是自由文本必须解析成结构化的工具调用。生产级实现应该让模型直接输出 JSON用 response_format 强制约束再用try-except兜底 pythonimportjsondefparse_action(response):textresponse.strip()iftext.startswith(DONE):returnNone# 任务完成iftext.startswith(ACTION:):linestext.split(\n)tool_namelines[0].replace(ACTION:,).strip()params_rawtext.split(PARAMS:,1)[1].strip()ifPARAMS:intextelsetry:paramsjson.loads(params_raw)exceptjson.JSONDecodeError:params# 解析失败时降级为空参数return{tool:tool_name,params:params}returnNone 执行环节必须有完整的错误处理链 pythondefexecute_tool(action,tools,max_tool_retries1):tool_name,paramsaction[tool],action[params]iftool_namenotintools:returnf错误工具{tool_name}不存在可选工具{list(tools.keys())}functools[tool_name][func]try:returnstr(func(**params))exceptTypeErrorase:returnf错误参数不匹配{e}请参考参数规范重新调用exceptExceptionase:returnf错误工具执行失败{e} 注意**工具执行失败的信息要原样回传给模型**让模型根据错误信息自行修正。比如参数格式错了模型看到错误描述后会重新组织参数再次调用。这个失败反馈-自我修正机制是 Agent 比固定脚本强的地方。## 四、Function Calling更可靠的替代协议上面手写的 ACTION/PARAMS 协议教学意义完整但生产环境有更可靠的方案让模型原生支持 function calling。OpenAI 兼容接口提供 tools 参数模型会在响应里返回结构化的 tool_calls省去文本解析这一步——解析错误和格式漂移都消失了。 pythondefagent_with_function_calling(query,max_steps10):messages[{role:user,content:query}]tools_spec[{type:function,function:{name:name,description:meta[description],parameters:{type:object,properties:{expr:{type:string}}}}}forname,metainTOOLS.items()]forstepinrange(max_steps):respclient.chat.completions.create(modelgpt-4o-mini,messagesmessages,toolstools_spec,)msgresp.choices[0].messageifnotmsg.tool_calls:returnmsg.content# 没有工具调用说明任务完成messages.append(msg)fortcinmsg.tool_calls:resultexecute_tool({tool:tc.function.name,params:json.loads(tc.function.arguments)},TOOLS)messages.append({role:tool,tool_call_id:tc.id,content:result})return达到最大步数 从手写协议到 function calling是 Agent 工程里一次重要的协议升级手写协议让你理解原理function calling 让你上生产。两者并非二选一——理解前者能帮你诊断后者的问题比如模型不触发工具调用时往往是工具描述写得太含糊。## 五、容错与安全Agent 的底线设计生产级 Agent 和教学 Demo 的分水岭全在容错与安全设计上。以下几条是必须的**第一最大步数限制。**循环必须有硬上限通常8~15步防止模型陷入无限循环。每步之间记录耗时超过阈值强制终止。**第二工具白名单与权限隔离。**生产环境绝不把任意代码执行暴露给模型。文件读写、网络请求、数据库操作等敏感工具必须走权限校验最好在独立沙箱进程里执行。**第三敏感操作的人工审批。**对不可逆操作删除、支付、对外发送插入确认环节——执行前暂停把动作详情展示给人工批准后才真正执行。这也是现在各大框架都在强调人在回路的原因。**第四幂等与重试。**工具调用可能重复执行模型超时重试导致同一步跑两遍写工具时要保证幂等性——同样的参数执行两次结果一致不产生副作用。**第五可观测性。**每一步的 Thought、Action、Observation 都要落 trace。线上出问题时能看到完整的推理轨迹而不是一个孤立报错。建议记录step 序号、模型输入输出、工具名称与参数、执行耗时、返回结果摘要。## 六、评测一个 Agent光看结果远远不够最后补一个关键认知Agent 系统的评测比普通 LLM 应用难一个量级因为过程复杂、路径众多。推荐从三个层次建立评测1.**结果正确性**最终答案是否达到目标需要人工或 LLM-as-Judge 标注。2.2.**工具调用正确性**每一步是否调用了正确工具、传了正确参数——这能定位是模型决策错了还是工具实现错了。3.3.**路径合理性**是否走了冗余步骤、是否反复横跳、是否过早放弃。这类过程指标暴露的问题往往比结果指标更早。 pythondefevaluate_tool_usage(traces,expected_tools):检查 Agent 执行轨迹里是否按预期顺序调用了工具used[t[tool]fortintraces]correctall(einusedforeinexpected_tools)returncorrect,used ## 七、小结手写一遍 Agent 的价值不在于我有自己的 Agent而在于你彻底理解了那条循环里每一环的职责模型负责决策协议负责沟通工具负责执行循环负责推进容错负责兜底。有了这套心智模型你再去用 LangGraph、AutoGen 或任何新框架看到的就不再是黑盒 API而是一个你亲手搭过一遍的系统的封装。请记住框架可以帮你省掉脚手架但省不掉的是——你对循环之外那些工程问题的理解。
返回列表