生产级异步工具:用 async def 打造高性能 Agent 摘要当 Agent 需要调用外部 API、查询数据库时同步工具会阻塞整个事件循环。本文教你用async def编写生产级异步工具实现并发执行、结构化错误处理和优雅降级让 Agent 性能提升数倍。引言你有没有遇到过这样的场景Agent 需要同时查询三个新闻源的信息结果工具一个接一个地串行执行每个 API 调用等待 2 秒三个就是 6 秒。用户盯着屏幕干等体验极差。问题的根源在于I/O 密集型操作API 调用、数据库查询、文件读写使用了同步方式。在同步模式下CPU 在等待网络响应时完全空闲事件循环被阻塞其他任务无法执行。解决方案就是异步工具——用async def定义工具让 Agent 在等待 I/O 时切换执行其他任务甚至并发调用多个工具。核心概念同步 vs 异步一张表说清维度同步工具 (def)异步工具 (async def)定义方式def tool_func(...)async def tool_func(...)I/O 等待时阻塞事件循环CPU 空闲释放控制权执行其他任务调用方式tool.invoke({...})await tool.ainvoke({...})并发能力串行执行asyncio.gather并发适用场景CPU 密集型计算API 调用、DB 查询、文件读写tool识别自动识别为同步工具自动识别为异步工具关键一点tool装饰器会自动检测函数是否为async def无需额外配置。为什么异步工具如此重要同步执行 3 个 API 调用每个 2 秒 ├── API 1: ████████ 2s ├── API 2: ████████ 2s ├── API 3: ████████ 2s 总耗时: 6s 异步并发执行 3 个 API 调用每个 2 秒 ├── API 1: ████████ 2s ├── API 2: ████████ 2s ├── API 3: ████████ 2s 总耗时: 2s性能提升3 倍而且 API 调用越多差距越大。代码示例1. 基础异步工具用async def定义异步工具tool自动识别importasyncioimportloggingfromlangchain_core.toolsimporttool loggerlogging.getLogger(__name__)toolasyncdeffetch_news_articles(topic:str,max_results:int5)-list:Fetch latest news articles about a topic. Use this to stay updated on: - Industry trends and news - Company announcements - Market developments Args: topic: News topic or keyword max_results: Maximum number of articles (default: 5, max: 20) Returns: List of article dictionaries with title, source, published_date try:logger.info(fFetching news for topic:{topic})awaitasyncio.sleep(0.5)# 模拟网络延迟# 限制最大结果数防止数据过载max_resultsmin(max_results,20)articles[{title:fArticle{i}about{topic},source:News Source,published_date:2026-06-22}foriinrange(max_results)]returnarticlesexceptasyncio.TimeoutError:logger.error(fTimeout fetching news for:{topic})return[{error:Request timeout, please try again}]exceptExceptionase:logger.error(fError fetching news:{str(e)})return[{error:fFailed to fetch news:{str(e)}}]注意三个关键点async def—tool自动识别为异步工具ainvoke调用—await fetch_news_articles.ainvoke({topic: AI})结构化错误返回— 返回[{error: ...}]而非抛出异常2. 并发执行多个工具用asyncio.gather同时调用多个工具性能翻倍importasyncioimporttimefromlangchain_core.toolsimporttooltoolasyncdefsearch_weather(city:str)-str:查询城市天气awaitasyncio.sleep(1)# 模拟 1 秒 API 延迟returnf{city}: 晴, 25°Ctoolasyncdefsearch_stock(symbol:str)-str:查询股票价格awaitasyncio.sleep(1)# 模拟 1 秒 API 延迟returnf{symbol}: ¥150.00 (2.3%)toolasyncdefsearch_news(keyword:str)-str:搜索新闻awaitasyncio.sleep(1)# 模拟 1 秒 API 延迟returnf关于{keyword}的最新新闻AI 行业持续升温...# 串行执行慢asyncdefrun_sequential():starttime.time()r1awaitsearch_weather.ainvoke({city:北京})r2awaitsearch_stock.ainvoke({symbol:AAPL})r3awaitsearch_news.ainvoke({keyword:AI})elapsedtime.time()-startprint(f串行耗时:{elapsed:.1f}s)# ≈ 3.0s# 并发执行快asyncdefrun_concurrent():starttime.time()resultsawaitasyncio.gather(search_weather.ainvoke({city:北京}),search_stock.ainvoke({symbol:AAPL}),search_news.ainvoke({keyword:AI}),)elapsedtime.time()-startprint(f并发耗时:{elapsed:.1f}s)# ≈ 1.0sforrinresults:print(r)asyncio.run(run_sequential())asyncio.run(run_concurrent())输出串行耗时: 3.0s 并发耗时: 1.0s 北京: 晴, 25°C AAPL: ¥150.00 (2.3%) 关于 AI 的最新新闻AI 行业持续升温...3 个工具各需 1 秒串行 3 秒并发只需1 秒。3. 生产级错误分类生产环境中异步工具需要精细的错误处理。不同类型的异常应该有不同的降级策略importasyncioimportaiohttpimportloggingfromlangchain_core.toolsimporttool loggerlogging.getLogger(__name__)toolasyncdeffetch_web_content(url:str)-dict:Fetch and extract main content from a web page. Args: url: Target web page URL Returns: Dict with content, title on success, or error on failure try:asyncwithaiohttp.ClientSession(timeoutaiohttp.ClientTimeout(total10))assession:asyncwithsession.get(url)asresponse:ifresponse.status200:htmlawaitresponse.text()return{content:html[:1000],status:success}else:return{error:fHTTP{response.status},status:failed}exceptasyncio.TimeoutError:# 超时建议重试return{error:请求超时10s建议稍后重试,status:timeout,retryable:True}exceptaiohttp.ClientErrorase:# 网络错误可能是 DNS、连接等问题return{error:f网络错误:{str(e)},status:network_error,retryable:True}exceptExceptionase:# 未知错误记录日志返回通用信息logger.error(fUnexpected error fetching{url}:{e})return{error:内容获取失败请稍后重试,status:unknown_error,retryable:False}错误分类的价值在于Agent 可以根据retryable字段决定是否重试根据status选择替代策略。4. 性能对比实测用一个完整的对比脚本直观感受同步与异步的差距importasyncioimporttimefromlangchain_core.toolsimporttool# 同步工具tooldefsync_api_call(name:str)-str:同步 API 调用time.sleep(1)# 模拟 I/O 阻塞returnfResult from{name}# 异步工具toolasyncdefasync_api_call(name:str)-str:异步 API 调用awaitasyncio.sleep(1)# 非阻塞等待returnfResult from{name}# 测试同步deftest_sync():starttime.time()fornamein[API-1,API-2,API-3]:sync_api_call.invoke({name:name})print(f同步 3 次调用:{time.time()-start:.1f}s)# ≈ 3.0s# 测试异步asyncdeftest_async():starttime.time()awaitasyncio.gather(async_api_call.ainvoke({name:API-1}),async_api_call.ainvoke({name:API-2}),async_api_call.ainvoke({name:API-3}),)print(f异步 3 次调用:{time.time()-start:.1f}s)# ≈ 1.0stest_sync()asyncio.run(test_async())调用次数同步耗时异步耗时性能提升1 次1.0s1.0s无差异3 次3.0s1.0s3x5 次5.0s1.0s5x10 次10.0s1.0s10x调用次数越多异步的优势越明显。最佳实践1. I/O 密集型工具一律用async def判断标准很简单工具内部是否有网络请求、数据库查询、文件读写如果有就用异步。# ✅ 异步调用外部 APItoolasyncdefsearch_web(query:str)-str:awaitaiohttp.get(fhttps://api.example.com/search?q{query})...# ❌ 同步CPU 密集型计算不需要异步tooldefcalculate_fibonacci(n:int)-str:# 纯计算没有 I/O...2. 捕获特定异常返回结构化错误不要只写一个笼统的except Exception。针对不同异常返回不同信息让 Agent 能做出更聪明的决策try:resultawaitapi_call()exceptasyncio.TimeoutError:return{error:超时,retryable:True}# Agent 知道可以重试exceptValueError:return{error:参数错误,retryable:False}# Agent 知道该换参数exceptExceptionase:return{error:str(e),retryable:False}# 兜底3. 添加日志方便调试异步工具的问题往往难以复现日志是排查问题的关键importlogging loggerlogging.getLogger(__name__)toolasyncdeffetch_data(url:str)-dict:logger.info(f开始请求:{url})try:resultawaitdo_fetch(url)logger.info(f请求成功返回{len(result)}条数据)returnresultexceptExceptionase:logger.error(f请求失败:{url}, 错误:{e})return{error:str(e)}4. 限制返回结果数量不限制结果数一次返回上千条数据不仅浪费 Token还会拖慢 Agent 推理。用min()设置上限max_resultsmin(max_results,20)# 硬上限 20 条5. 用ainvoke调用异步工具异步工具必须通过ainvoke调用不能用invoke# ✅ 正确resultawaitfetch_news_articles.ainvoke({topic:AI,max_results:5})# ❌ 错误invoke 无法正确执行异步工具resultfetch_news_articles.invoke({topic:AI})# 可能报错或行为异常总结异步工具是构建高性能 Agent 的基础设施。核心要点回顾要点说明何时用异步I/O 密集型操作API、DB、文件定义方式async deftool自动识别调用方式await tool.ainvoke({...})并发执行asyncio.gather同时调用多个工具错误处理捕获特定异常返回结构化错误信息日志记录logger.info/error便于调试结果限制min(max_results, N)防止数据过载记住一个原则能用async def就用async def。在 Agent 需要同时调用多个工具的场景下异步带来的性能提升是数量级的。下一篇我们将探讨 Agent 的工具编排策略——如何让多个工具协同工作完成复杂的端到端任务。

相关新闻

最新新闻

C++实现HDLC协议栈:从原理到嵌入式工业通信实战

C++实现HDLC协议栈:从原理到嵌入式工业通信实战

1. 项目概述:为什么要在C里折腾HDLC?如果你在嵌入式、工业通信或者一些老牌通信设备公司的代码里翻过,大概率会碰到HDLC(高级数据链路控制)协议。乍一看,这协议名字里带个“高级”,但其实是上个…

2026/7/16 5:45:43
PCB设计工程师核心技能与学习路径:从入门到进阶

PCB设计工程师核心技能与学习路径:从入门到进阶

这次我们来聊聊PCB设计工程师这个岗位到底需要掌握哪些技能,哪些内容可以暂时放一放。对于刚入行的工程师来说,最头疼的就是不知道学习重点在哪里,担心学了一堆用不上的东西,反而错过了核心技能。PCB设计工程师主要负责电路板的设…

2026/7/16 5:45:43
【AI总结】2026年6月 主流国内外大模型总结

【AI总结】2026年6月 主流国内外大模型总结

目录 引言一、 国际主流模型 1. OpenAI GPT 系列2. Anthropic Claude 系列3. Google Gemini 系列4. Meta Llama 系列5. xAI Grok 系列6. 其他值得关注的国际模型 二、 国内主流模型 1. 百度 文心大模型2. 阿里 通义千问3. 腾讯 混元大模型4. 字节跳动 豆包大模型 / 扣子5. 智谱…

2026/7/16 5:45:43
Java循环控制进阶:while与do..while的实战抉择与break/continue的精准调控

Java循环控制进阶:while与do..while的实战抉择与break/continue的精准调控

1. 为什么需要while和do..while循环?在日常编程中,我们经常遇到需要重复执行某段代码的场景。比如读取用户输入直到输入合法、处理文件中的每一行数据、或者游戏中的主循环。这时候,循环结构就派上用场了。Java提供了三种主要的循环结构&…

2026/7/16 5:45:43
【2014-01-27】cocos2dx学习笔记:CCNode回调流程

【2014-01-27】cocos2dx学习笔记:CCNode回调流程

[历史归档] 本文原发布于 cstriker1407.info 个人博客,内容为历史存档,仅供参考。 发布时间: 2014-01-27 | 标题:cocos2dx学习笔记:CCNode回调流程 | 分类: 编程 / C &&…

2026/7/16 5:45:43
Inno Setup多语言配置实战:从界面翻译到运行时语言切换

Inno Setup多语言配置实战:从界面翻译到运行时语言切换

1. Inno Setup多语言配置的核心价值 当你开发的软件需要面向全球用户时,安装包的多语言支持就成为了必备功能。想象一下,一个日本用户打开全是中文的安装界面,或者德国用户面对英文安装指引时的困惑——这些体验细节往往决定了用户对产品的第…

2026/7/16 5:40:33

月新闻