:从工具调用理解 Agent 原理)
Agent 不是一个“更会聊天”的模型而是模型、工具、状态与控制循环组成的软件系统。最小闭环是观察输入、决定动作、执行工具、读取结果再决定回答或继续。一、痛点先定义 Agent 的可验收边界业务方说“让 Agent 自动处理”时必须追问自动到哪一步、可访问哪些数据、谁承担最终决定。一个可验收任务要写清输入、成功产物、禁止动作、最大步数、时间与费用预算。例如“处理客户请求”太宽“读取一条已脱敏工单给出分类、引用政策条款并生成不外发的回复草稿”才可测试。工具调用的首要价值是把自然语言的不确定性包在确定性软件边界内。设计时把失败也纳入契约工具无结果时是拒答、转人工还是换查询信息冲突时谁有优先级达到预算时保存什么状态。不要以“模型通常会判断”为验收标准。可观测的终止原因、工具参数和证据引用才让开发者复盘错误。所有写操作默认关闭先用内存假实现或沙箱跑通轨迹再逐级开放权限。二、原理模型提议程序裁决把模型输出视为不可信的计划而不是已经执行的命令。模型擅长从自然语言选择动作宿主程序擅长权限检查、类型校验和确定性计算。二者分开才能重放每一步也能在模型选错工具时拒绝执行。下面程序把三种方案放进相同门槛。它演示的不是模型能力排名而是“先过硬约束、再在合格项中择优”的决策函数。生产中可把 score 拆为任务成功率、安全违规率、p95 延迟和单次成本并保存原始样本不能只存平均分。fromdataclassesimportdataclassdataclass(frozenTrue)classCandidate:name:strscore:floatcandidates[Candidate(直接回答,0.45),Candidate(单次工具,0.78),Candidate(观察后再决策,0.92),]threshold0.80eligible[]foritemincandidates:accepteditem.scorethresholdprint(f{item.name}: score{item.score:.2f}accepted{accepted})ifaccepted:eligible.append(item)ifnoteligible:raiseSystemExit(no eligible design)selectedmax(eligible,keylambdaitem:item.score)print(fselected{selected.name})print(fmargin{selected.score-threshold:.2f})运行输出直接回答: score0.45 acceptedFalse 单次工具: score0.78 acceptedFalse 观察后再决策: score0.92 acceptedTrue selected观察后再决策 margin0.12阈值必须在实验前确定否则团队容易看到结果后移动球门。对高风险动作应使用一票否决哪怕综合分高只要出现越权写入或泄露敏感字段就不能发布。对低风险辅助功能则可接受较低自动化率用拒答和转人工换取精确率。三、实现把状态、工具与终止条件接起来最小实现需要工具注册表和运行状态。注册表只暴露允许的名字不让模型导入模块或拼接命令状态保存目标、预算、历史与状态码。每次动作按固定顺序经过解析、Schema 校验、授权、执行、结果裁剪和日志记录。工具结果同样不可信网页可能包含提示注入数据库文本可能过长因此只回传任务需要的字段并标注来源。以下脚本独立可运行用固定动作模拟 calculator、lookup_policy、send_notice。把模拟决策替换为模型响应时执行器不需要改变这正是把概率模型与业务副作用解耦的收益。fromdataclassesimportdataclass,fielddataclassclassRunState:goal:strbudget:int4history:list[str]field(default_factorylist)status:strrunningdefexecute(state:RunState,action:str)-str:allowed{calculator,lookup_policy,send_notice}ifactionnotinallowed:raiseValueError(fblocked action:{action})state.budget-1observationf{action}:okstate.history.append(observation)ifactionsend_notice:state.statuscompletedelifstate.budget0:state.statusbudget_exhaustedreturnobservation stateRunState(goal完成可审计任务)foractionin[calculator,lookup_policy,send_notice]:resultexecute(state,action)print(fstep{len(state.history)}result{result}budget{state.budget})ifstate.status!running:breakprint(fstatus{state.status})print(fhistory{,.join(state.history)})运行输出step1 resultcalculator:ok budget3 step2 resultlookup_policy:ok budget2 step3 resultsend_notice:ok budget1 statuscompleted historycalculator:ok,lookup_policy:ok,send_notice:ok真实服务还应给每次 run 分配不可猜测的 ID日志记录 action、参数摘要、耗时、结果摘要和错误类别。不要记录访问令牌、完整个人信息或未经脱敏的提示。历史应追加而非覆盖关键状态落到事务型存储这样进程退出后能够判断某个副作用是否已经完成。四、踩坑把“能跑”误当成“可托管”第一类坑是授权过宽。工具名称看似安全参数却可能扩大范围例如查询接口接受任意用户 ID或通知接口接受任意收件人。授权必须结合当前用户、资源和动作在服务端判断。第二类坑是把工具报错原样塞回上下文既浪费窗口也可能暴露栈、SQL 和密钥应转换成稳定错误码与经过裁剪的说明。第三类坑是缺少停止条件。模型可能重复相同动作、在两个工具间振荡或因为观察为空而不断改写查询。可用规范化后的“工具名 参数哈希”检测重复并同时限制轮数、墙钟时间和费用。第四类坑是把测试数据与线上分布混为一谈评测必须覆盖空结果、中文别名、超长输入、权限不足、下游超时以及提示注入。取舍上不是步骤越智能越好。确定的字段转换、金额计算、规则路由应该写普通函数只有分类、信息抽取、证据综合等语义任务才值得调用模型。模型调用增加延迟、成本与不确定性显式工作流增加代码量却换来可预测性。先选择最简单的可用结构再依据失败轨迹增加 Agent 自主性。五、验证用轨迹而不是演示视频验收为每个案例保存初始状态、每步动作、工具观察、最终产物和终止原因。至少检查五项任务是否完成是否只用了允许工具参数是否满足类型和业务约束结论能否追溯证据是否在预算内停止。回归时固定模型版本、提示版本、工具契约版本和随机参数否则分数变化无法归因。上线顺序采用离线回放、影子流量、小比例灰度、有限自治。影子阶段让 Agent 读取真实输入但不产生副作用与人工结果比较灰度阶段保留即时关闭开关只有连续满足质量与安全门槛才扩大范围。一次失败应能定位到规划、参数、工具、上下文或策略层而不是笼统归咎于“模型幻觉”。本篇可交付物包括一份边界说明、一组工具契约、可重放轨迹、失败分类表和发布门。下一篇将用 function calling 让模型输出可校验的工具参数继续复用本篇的预算、白名单和审计轨迹。参考来源OpenAI Function callingReAct 论文JSON Schema 觉得有用就点个赞 收藏方便回头查阅有疑问直接在评论区留言我看到都会回。 本文属于《AI Agent 应用实战》系列持续更新关注不迷路。 文章里的代码都能直接跑。想要可直接 clone 的完整工程 配套部署脚本 / 踩坑清单评论一声或发邮件到cj2664qq.com我免费发你。如果你正好在做类似系统、或有工程化难题想找人做也欢迎邮件聊一句——我按实际情况评估能落地的就接单或出方案。评论和邮件都能直接找到我不用跳别的平台。—进阶学习想把 AI 从“能用”调到“好用”我的付费专栏《提示词工程实战》10 篇 ¥19.9第 1 篇免费试读https://blog.csdn.net/weixin_67153745/article/details/163650483 姊妹篇免费专栏《RAG 知识库问答实战》也在博客主页 https://blog.csdn.net/weixin_67153745 问题欢迎评论区交流。