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

自定义工具开发实战:把任意Python函数变成AI Agent可用的工具

自定义工具开发,把任意Python函数变成Agent工具

内置工具只能解决通用问题。真正做项目的时候,你肯定需要写自己的工具。

比如对接公司内部的API,操作特定的业务系统,调用内部的数据库。这些都得自己写。

好消息是,在LangChain里写自定义工具特别简单。把一个普通的Python函数装饰一下,Agent就能调用了。

这一篇我们从最简单的开始,一步步讲怎么写工具、怎么写好工具描述、怎么处理异常,以及实际项目里的一些经验。


最简单的写法

用@tool装饰器,是最简单的方式。

fromlangchain.toolsimporttool@tooldefadd_numbers(a:int,b:int)->str:"""把两个数字相加,返回相加的结果。"""returnf"结果是{a+b}"

就这么简单。一个普通的函数,加上@tool装饰器,就变成了Agent能用的工具。

函数名就是工具名。函数的文档字符串就是工具的描述。函数的参数类型注解,就是参数的类型说明。

这三样东西都很重要。Agent靠它们来理解这个工具是干什么的、什么时候该用、参数怎么传。

写的时候注意几点。

函数名要直观。一看就知道这个工具做什么的。别起太抽象的名字。

文档字符串要写详细。别只写一句话。说清楚功能、参数含义、什么时候用、举个例子。后面会专门讲怎么写好描述。

参数类型要标清楚。int、str、float这些基本类型直接写就行。复杂类型用Pydantic模型。


用Pydantic定义输入

参数简单的时候,直接写类型注解就行。参数多了,或者参数有嵌套结构,最好用Pydantic模型来定义。

fromlangchain.toolsimporttoolfrompydanticimportBaseModel,FieldclassWeatherInput(BaseModel):city:str=Field(description="城市名称,比如北京、上海、广州")date:str=Field(description="查询的日期,格式为YYYY-MM-DD,比如2026-08-06")@tool(args_schema=WeatherInput)defget_weather(city:str,date:str)->str:"""查询指定城市指定日期的天气情况。 返回天气状况、温度、湿度、风力等信息。 例如用户问'明天北京天气怎么样'的时候可以调用这个工具。 """# 实际项目中这里调用天气APIreturnf"{city}{date}的天气是晴,25度。"

用Pydantic的好处是,你可以给每个参数加description,还可以加校验规则。Agent能更准确地理解参数的含义,参数传错的概率会降低。

参数超过两个的时候,我建议都用Pydantic来定义。多写几行代码,省很多调试的时间。


工具描述怎么写才好用

工具能不能用好,描述占了八成。

描述写得好,Agent用得准。描述写得烂,Agent经常选错工具、填错参数。

我自己总结了几个写工具描述的经验。

第一,说清楚能做什么,也说清楚不能做什么。边界清楚了,Agent才知道什么时候该调用、什么时候不该调用。

第二,举例子。在描述里加一两个使用场景的例子。比如"当用户问’某某城市天气怎么样’的时候,可以调用这个工具"。例子对大模型特别有效。

第三,参数说明要具体。每个参数是什么意思、什么格式、有什么限制,都写清楚。有可选值就列出来。日期格式、数字范围、单位,都说明白。

第四,说明返回值的格式。告诉Agent工具会返回什么样的结果,它拿到结果以后知道怎么处理。

举个反例和正例对比一下。

反面教材。

@tooldefsearch(query:str)->str:"""搜索工具。"""...

这种描述等于没写。Agent根本不知道什么时候该用、参数怎么传。

正面教材。

@tooldefsearch(query:str)->str:"""通过搜索引擎查询互联网上的最新信息。 当你需要回答以下类型的问题时使用这个工具: - 实时新闻和热点事件 - 最新的产品价格、发布日期 - 不确定的知识,或者你的训练数据里可能没有的信息 - 具体的事实核查 参数说明: query: 搜索关键词。用中文或英文都可以。不要太长,20个字以内效果最好。 返回:搜索结果的摘要,包含标题、摘要和链接。 """...

这样写,Agent就很清楚什么时候该调用、怎么传参数。


处理异常和错误

工具调用总会出错。网络断了,API限流了,参数不对,数据库连不上。各种情况都可能发生。

出错了怎么办。两个原则。

第一,工具内部要捕获异常,不要直接抛出去。Agent拿到异常信息也不知道怎么处理。

第二,返回给Agent的错误信息要有意义。告诉它哪里错了、可能的原因、建议的处理方式。它才能决定是重试、换个方式,还是告诉用户。

比如这样。

@tooldefget_weather(city:str)->str:"""查询城市天气。"""try:result=call_weather_api(city)returnresultexceptNetworkError:return"网络连接失败,无法查询天气。请稍后再试。"exceptCityNotFoundError:returnf"找不到{city}的天气数据。请确认城市名称是否正确,或者换一个城市试试。"exceptExceptionase:returnf"查询天气时出现未知错误,{e}。"

不同的错误返回不同的提示。Agent能根据提示决定下一步怎么做。城市找不到就换个名字,网络错了就重试。

如果只返回"出错了"三个字,Agent也不知道该怎么办,任务就卡住了。


同步和异步

默认的工具是同步的。如果你的工具里有IO操作,比如网络请求、数据库查询,可以写成异步的,性能更好。

@toolasyncdefasync_get_weather(city:str)->str:"""异步查询天气。"""result=awaitasync_weather_api(city)returnresult

用的时候,调用ainvoke而不是invoke。

简单的工具无所谓同步异步。IO密集型的工具,做成异步的,并发调用的时候速度会快很多。


完整示例

最后给一个完整的自定义工具例子,你可以照着写。

fromlangchain.toolsimporttoolfrompydanticimportBaseModel,FieldimportrequestsclassTranslateInput(BaseModel):text:str=Field(description="要翻译的文本,可以是中文或英文")target_lang:str=Field(description="目标语言,可选值:zh(中文)、en(英文)、ja(日文)",)@tool(args_schema=TranslateInput)deftranslate(text:str,target_lang:str)->str:"""文本翻译工具。支持中文、英文、日文互译。 当用户要求翻译文本,或者用户说的语言和默认语言不同时,可以使用这个工具。 例如用户说'把这句话翻译成英文'、'这个日语是什么意思'的时候。 参数说明: text: 要翻译的原文内容,长度不超过5000字 target_lang: 翻译后的目标语言代码 返回:翻译后的文本内容。 """try:# 这里替换成实际的翻译API调用response=requests.post("https://api.translation.example.com/translate",json={"text":text,"target":target_lang},timeout=10,)response.raise_for_status()result=response.json()returnf"翻译结果:{result['translated_text']}"exceptrequests.Timeout:return"翻译服务超时了,请稍后重试。"exceptrequests.HTTPErrorase:ife.response.status_code==429:return"翻译请求太频繁了,等一下再试。"returnf"翻译服务出错了,状态码{e.response.status_code}。"exceptExceptionase:returnf"翻译时出现未知错误,{e}。"

这个例子包含了Pydantic参数定义、详细的工具描述、异常处理。可以作为你写自定义工具的模板。


下一篇我们讲搜索引擎接入。搜索是Agent最重要的能力之一,我们深入讲一讲怎么接、怎么用好。

http://www.cnnetsun.cn/news/3884018.html

相关文章:

  • LLM文件编写:从Prompt工程到Agent工作流的实战指南
  • 郴州建设工程信息网站:为每一块基石注入透明与诚信的力量,寻找本地项目真相
  • 3ds Max新手入门到精通:从软件安装、核心建模到渲染输出的全流程避坑指南
  • 网站建设项目内控单全流程深度解析:避坑指南、风险管控与高效执行策略全攻略
  • Unity游戏数据持久化实战:Save Game Free插件核心应用与避坑指南
  • 计算机专业实测:哪款 AI 工具最适合撰写毕业设计论文?四大主流平台效率、深度、专业度全面测评
  • Stable Diffusion 2实战:用ControlNet打造角色一致的AI动物足球队
  • 华为eNSP实战指南:从零搭建网络实验环境与高频错误排查
  • OpenClaw智能体本地部署与飞书集成实战指南
  • 基于Python与Django的动漫数据分析系统:从爬虫到可视化实战
  • SPI信号串联电阻布局策略:从传输线理论到PCB工程实践
  • 衡阳网站建设qiandu1揭秘如何让你的本地企业网站不再只是摆设而是真正赚钱的销售员
  • Unity拉普拉斯变形实战:从原理到实现,提升角色皮肤真实感
  • Windows 10/11默认禁用SMBv1:安全风险、检测方法与迁移指南
  • 线性配置文件:从RAW原始数据到极致影调控制的底层工作流
  • 汽车电子HIL测试:VT2004模块模拟输入仿真与故障注入实战
  • 从旧协议到新基准:系统协议重构实战指南
  • 功率电感选型实战:从核心参数到调试技巧,解决DC-DC电源设计难题
  • 语音识别技术选型实战指南:从云服务到开源自研的六维对比
  • 从入门到企业级:AutoGen多智能体系统架构与实战指南
  • 开源项目健康度评估工具开发全攻略
  • 工业设备采购实战:从型号解析到安全集成的全流程指南
  • 佛山网站建设拓客科技:拒绝花架子,用真实业绩说话,这才是企业搞流量的小心机
  • Android应用加固逆向实战:梆梆加固脱壳与Sign算法还原
  • Java游戏开发实战:面向对象设计实现《大鱼吃小鱼》核心机制
  • Amber分子动力学模拟入门:从tleap前处理到cpptraj分析全流程详解
  • HTTP头注入漏洞实战:从UA/Referer注入到防御方案
  • C++实现ADB双向通信:匿名管道技术实战与Windows进程通信详解
  • CANable固件改造:模拟PCAN-USB实现低成本CAN总线调试
  • 甘特图实战指南:从原理到工具,60个模板提升项目管理效率