当前位置: 首页 > news >正文

手搓生产级 AI Agent 系统(2):工具系统深度实战——从参数校验到沙箱安全

前言:Agent 翻车,90% 死在工具系统上

上一篇我们搭好了 Agent 的骨架(ReAct 循环 + 记忆架构 + 反思机制)。但真正让 Agent 从"能说"变成"能做"的,是工具系统。

我在三个真实项目中追踪了 Agent 的故障原因分布:

故障类型占比根因
工具调用死循环31%工具返回格式不一致,Agent 反复重试
参数错误28%Schema 定义模糊,LLM 传了错误参数
工具不存在12%工具注册名和 LLM 理解的功能对不上
危险操作9%没有沙箱,Agent 直接执行了 rm -rf
其他20%API 超时、网络错误等

71% 的故障可以通过改进工具系统设计来避免。这篇文章把工具系统的每一个环节拆开,给出一套生产级的实现方案。


一、工具系统的设计目标

一个靠谱的工具系统需要满足六条要求:

目标说明做不到的后果
通用注册任何函数一行代码就能注册为工具每加一个工具都要改 Agent 代码
自动校验参数类型、必填、枚举值自动检查LLM 传了错误参数,执行失败
精准描述工具描述直接影响 LLM 调用准确率工具误调用率高达 30%
安全隔离危险操作拦截 + 用户确认机制Agent 执行破坏性命令
失败恢复超时重试、错误提示、降级策略一个工具失败,整个任务挂掉
可观测每次调用的输入/输出/耗时/费用出问题不知道是哪一步

二、工具注册框架:一个装饰器搞定

2.1 为什么不用 LangChain 的 Tool 类?

LangChain 定义一个工具需要继承BaseTool,重写_run_arun,然后注册到ToolRegistry。一个发邮件的工具要写 40 行样板代码。

我们用一个装饰器,一行@register_tool搞定:

importinspectimportjsonimporttimeimportsignalimportrefromtypingimportCallable,Any,Optional,get_type_hintsfromdataclassesimportdataclass,fieldfromfunctoolsimportwraps# ====== 全局工具注册表 ======TOOL_REGISTRY:dict[str,'ToolDefinition']={}@dataclassclassToolParameter:"""工具参数定义——给 LLM 看的描述直接决定调用准确率"""name:strtype:str# string / number / boolean / objectdescription:str# 这个描述是给 LLM 看的,写清楚传什么required:bool=Truedefault:Any=Noneenum:Optional[list]=None# 限定可选值,大幅降低参数错误率@dataclassclassToolDefinition:"""工具的完整定义"""name:strdescription:str# 包含"做什么"和"不要做什么"parameters:list[ToolParameter]func:Callable category:str="general"# 工具分类,方便组织require_confirmation:bool=False# 危险操作需用户确认timeout:int=30# 超时秒数max_retries:int=1# 失败重试次数risk_level:str="safe"# safe / dangerous / destructivedefregister_tool(name:str,description:str,parameters:list[dict]=None,category:str="general",require_confirmation:bool=False,timeout:int=30,max_retries:int=1,risk_level:str="safe",):"""装饰器:将任意 Python 函数注册为 Agent 工具。 用法: @register_tool( , description="发送邮件。参数 to 为收件人邮箱...", parameters=[ {"name": "to", "type": "string", "description": "收件人邮箱地址", "required": True}, {"name": "subject", "type": "string", "description": "邮件主题", "required": True}, {"name": "body", "type": "string", "description": "邮件正文(支持 Markdown)", "required": True}, ], category="communication", require_confirmation=True, risk_level="dangerous", ) def send_email(to: str, subject: str, body: str) -> str: ... """ifparametersisNone:parameters=[]defdecorator(func:Callable)->Callable:# 从函数签名自动推断参数类型(如果没在 parameters 里显式声明)hints=get_type_hints(func)ifhasattr(func,'__annotations__')else{}param_list=[]forpinparameters:param_type=p.get("type","string")# 如果类型没指定,从 type hints 推断if"type"notinporp["type"]=="string":py_type=hints.get(p["name"])ifpy_type==int:param_type="number"elifpy_type==bool:param_type="boolean"elifpy_typein(list,dict):param_type="object"param_list.append(ToolParameter(name=p["name"],type=param_type,description=p.get("description",""),required=p.get("required",True),default=p.get("default"),enum=p.get("enum"),))tool_def=ToolDefinition(name=name,description=description,parameters=param_list,func=func,category=category,require_confirmation=require_confirmation,timeout=timeout,max_retries=max_retries,risk_level=risk_level,)TOOL_REGISTRY[name]=tool_defreturnfuncreturndecoratordefget_tools_for_llm(category:str=None)->str:"""生成给 LLM 看的工具描述。格式直接影响调用准确率。"""tools=TOOL_REGISTRY.values()ifcategory:tools=[tfortintoolsift.category==category]lines=[
http://www.jsqmd.com/news/1191832/

相关文章:

  • Unity XLua热更新报错:Span与ReadOnlySpan类型缺失的深度解析与解决方案
  • GCC警告与优化协同配置:解决C++发布版本崩溃难题
  • Claude Code到底能不能干活?别只看 Demo 和跑分
  • 2026年7月最新南宁卡地亚官方售后维修服务网点地址与客服电话 - 卡地亚服务中心
  • Claude Code高效协作指南:claude.md编写规范与工程实践
  • 2026加密算法全景解析:从AES到后量子密码的实战指南
  • 零代码自动化:从重复操作到AI增强工作流的实践指南
  • 2026年苏州线切割设备靠谱生产服务商介绍:线切割机、放电切割机、阳极切割机设备制造企业 - 海棠依旧大
  • Armadillo预编译版在Windows+VS2022下的实战配置与性能优化
  • SpringCloud生态下的新选择:深入剖析PowerJob的分布式调度核心机制
  • STM32(三):外部中断实战避坑指南(标准库函数)
  • SpringBoot+Vue实战:从零构建一个课堂管理系统
  • 可行性研究实战:从经典习题到现代系统分析的思维跃迁
  • Unreal Engine模块加载失败全解析:从原理到排查的完整指南
  • C++ BOOST库实战指南:从智能指针到异步网络编程
  • 《AI辅助前端开发-10:避坑与进阶篇》
  • 2026 年 7 月新发布:揭西靠谱的止回式风帽订做厂家格局重塑与选型新思路,别等屋顶漏水才后悔!这玩意儿可能正让你家霉菌肆虐 - 实业推荐官【官方】
  • C++性能优化进阶:从代码技巧到工程体系的7个核心秘诀
  • C++浮点数输出精度控制:std::cout与<iomanip>实战指南
  • MySQL 崩溃恢复过程分析-元一软件
  • 2026年7月最新徐州格拉苏蒂官方售后维修服务网点地址与客服电话 - 亨得利钟表维修中心
  • (实战指南)STM32自定义通信协议:从帧结构设计到代码移植详解
  • VS Code原生AI编程:Cline插件深度集成Kimi k2实战指南
  • Unity URP汽车展览Demo实战:从场景搭建到交互实现
  • CandyForum / CandyBook
  • 把团队带废的5个坏习惯
  • 从道路边沿拟合到模型泛化:最小二乘与正则化的工程实践
  • 小米智能音箱Pro评测:300元价位如何实现千元音质与智能体验
  • 基于ObjectARX的AutoCAD楼梯参数化自定义实体开发实战
  • C++共享内存实战:从零构建带同步的生产者-消费者模型