记录一下那天晚上的排查过程。工具里查第三方物流接口,对方偶发 30 秒不返回,Agent 整条链路卡住,用户端等到 60 秒超时,日志里没有任何工具级超时记录。
刚开始盯着「重试与超时叠加,实际等待时间翻倍」,折腾了半个多小时,排掉了。
真正麻烦的地方在于,几个原因的现象几乎一样。工具函数用 requests 默认无超时,连接一直挂着。少数情况下是Agent 层没有单步超时,只能等整体超时。
不容易想到的是,异常没被捕获,工具报错直接终止整轮。
给工具请求加显式超时
python -c "import requests;print(requests.get('http://127.0.0.1:9/',timeout=(2,5)))"
然后在 Agent 侧包一层超时控制
python -c "import concurrent.futures as f;print(f.ThreadPoolExecutor(1).submit(lambda:1).result(timeout=3))"
超时后返回结构化错误而不是抛异常
python -c "print({'ok':False,'error':'tool_timeout'})"
剩下的就是用一条慢接口复现看耗时
curl -s -o /dev/null -w "%{time_total}\n" --max-time 5 http://127.0.0.1:9/slow
别只看报错消失,验证要多做一步。慢接口场景下整轮在 8 秒内返回降级答案,日志里有 tool_timeout 记录,Agent 不会整条链路挂住。
工具超时要短于 Agent 超时,降级路径提前设计好,临时捕获异常只能换来一句看不懂的报错。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
