如果你正在运营 AI API 中转站,最怕的不是用户问“模型怎么接”,而是用户把 Agent 接上以后反馈:联网搜索不稳定、网页总结有时全失败、明明只是一两个网页超时却整轮任务没有结果。Hermes Agent 最近关闭的一个 GitHub issue 就很适合作为 API 中转站排查教程:tools/web_tools.py 里多处 asyncio.gather() 没有启用 return_exceptions=True,导致只要其中一个网页抓取或总结任务失败,其他已经成功的结果也会被一起丢掉。
这篇文章的重点不是单纯复述 GitHub issue,而是面向 DeepAI API 中转站的真实转化场景:当用户把 Hermes Agent、Claude Code、Codex、OpenClaw 这类 Agent 接入 OpenAI Compatible API 后,如何判断问题出在模型、API 中转站、上游供应商,还是 Agent 自己的工具并发逻辑。
> 参考 GitHub 已解决问题:Hermes Agent issue #2744「asyncio.gather without return_exceptions discards results on failure」,由 PR #26244 修复并关闭。相关链接见文末。
搜索场景:Hermes Agent 接 API 中转站后联网工具不稳定
会搜到这类文章的人,通常不是在学习 Python 教程,而是正在配置 API 中转站或 AI Agent。更真实的搜索词包括:
- Hermes Agent web_extract 为什么一个网页失败后全部没结果?
- asyncio.gather 没有 return_exceptions 会发生什么?
- AI Agent 批量抓网页时如何避免单点失败拖垮整批任务?
- Hermes Agent 接 OpenAI Compatible API 后搜索总结不稳定怎么排查?
- DeepAI API 中转站用于 Agent 工具调用时如何定位失败?
- API 中转站能不能判断是模型失败还是工具失败?
- AI Agent 联网搜索失败是不是 Base URL 配错?
这些问题最后都会回到一个核心:API 中转站能帮你统一 Base URL、API Key、模型和日志,但 Agent 工具层也必须允许局部失败,不能把一个网页异常升级成整轮任务失败。
为什么这篇文章适合 API 中转站用户看
DeepAI API 中转站的核心价值,是把不同上游模型统一成更容易接入的 OpenAI Compatible API,让用户在 Hermes Agent、OpenClaw、Cline、Dify、Cherry Studio 等工具里少折腾 Base URL、API Key 和模型 ID。
但 Agent 类工具和普通聊天客户端不一样:
- 普通聊天客户端主要是一次模型请求;
- Agent 会同时调用搜索、网页抓取、摘要、文件、MCP、模型推理;
- 用户看到“失败”时,原因可能不在 API 中转站,而在工具链某个子任务;
- 如果没有日志和分层排查,用户很容易误以为“中转站不稳定”。
所以这类 GitHub 已解决 issue 的价值在于:它能变成 API 中转站用户的排错内容,帮助他们理解“什么问题该查 DeepAI 控制台,什么问题该查 Agent 工具日志”。
现象:一个 URL 超时,整批 web_extract 结果都没了
在 Hermes Agent 的 web_tools.py 场景里,工具可能会并行处理多个页面,例如:
- 对多个搜索结果做 Firecrawl 处理;
- 对 Tavily 返回的多个页面做 crawl;
- 对长网页切块后并行总结;
- 对多个提取结果做 LLM 摘要。
如果其中一个页面遇到超时、限流、解析失败、模型返回异常,用户期望通常是:
> 失败的那一个跳过,其他成功页面继续返回。
但 issue #2744 描述的问题是:多处 asyncio.gather() 没有设置 return_exceptions=True。Python 默认行为是,只要任意一个 awaitable 抛出异常,gather() 就会向外抛异常。对于 Agent 工具调用来说,这会造成一个非常糟糕的体验:
- 页面 A、B、C 已经抓取成功;
- 页面 D 发生网络错误或摘要失败;
- 最终工具层抛异常;
- A、B、C 的有效结果也无法交给上层模型使用。
这就是“局部失败拖垮全局结果”。
已解决方案:return_exceptions=True + 过滤异常结果
Hermes Agent PR #26244 的修复方向很直接:在 tools/web_tools.py 的多个 asyncio.gather() 调用点增加 return_exceptions=True,然后过滤掉 BaseException 结果并记录 warning 日志。
伪代码可以理解为:
results = await asyncio.gather(*tasks, return_exceptions=True)
valid_results = []
for item in results:
if isinstance(item, BaseException):
logger.warning("web tool task failed: %s", item)
continue
valid_results.append(item)
这背后的设计取舍是:
- 不隐藏失败:异常仍然被记录到日志;
- 不扩大失败:单个页面失败不影响其他页面结果;
- 不改变成功路径:全部任务成功时,行为基本不变;
- 更适合 Agent:模型可以基于部分结果继续回答,而不是直接中断。
对于 AI Agent 来说,这种“可降级”的工具设计非常重要。用户搜索资料、抓网页、总结报告时,宁可看到“5 个来源里 1 个失败”,也不希望看到“全部失败”。
为什么这对 Hermes Agent、Claude Code、Codex 都重要
虽然这次修复发生在 Hermes Agent,但问题并不只属于 Hermes。任何具备工具调用、网页检索、批量 API 请求能力的 Agent 都会遇到类似情况:
| 场景 | 常见失败 | 好的处理方式 |
| 批量网页抓取 | 某个 URL 超时 | 返回其他 URL 结果,并标记失败项 |
| 多模型参考答案 | 某个模型 429 | 保留其他模型输出,提示该模型限流 |
| OpenAI Compatible API 调用 | 某个 endpoint 格式不兼容 | 记录响应体、模型 ID、Base URL |
| Agent 工具链 | 某个工具异常 | 上层继续基于可用工具结果推理 |
| 长文分块总结 | 某个 chunk 失败 | 保留其他 chunk 摘要,允许重试失败块 |
这也是为什么在 Claude Code、Codex、OpenClaw、Hermes 这类项目里,工具层容错和日志可观测性往往比“提示词怎么写”更影响稳定性。
接入 DeepAI API 中转站时,应该这样分层排查
如果你用 Hermes Agent 或其他 Agent 接入 DeepAI API 中转站,建议把问题分成三层,而不是一出错就换模型。常见配置通常会涉及:
- Base URL;
- API Key;
- Model ID;
- OpenAI Compatible API 格式;
- streaming / non-streaming;
- 工具调用或网页总结链路。
当你遇到“搜索总结不完整”“网页工具偶发失败”“模型有时返回空内容”时,不要只怀疑模型。建议按下面顺序排查:
1. 先区分模型失败还是工具失败
如果 Agent 报错发生在 web_extract、web_search、crawl、summarize chunks,优先检查工具层日志。模型 API 可能没有问题,真正失败的是某个网页请求或某个 chunk 的处理。
2. 检查并发任务是否允许局部失败
如果你的自定义工具里也用了 asyncio.gather(),确认是否需要:
return_exceptions=True
并且不要只加参数,还要对异常结果做过滤和日志记录。否则后续代码可能把异常对象当正常结果处理。
3. 记录关键请求信息,但不要泄露密钥
排查 DeepAI API 或 OpenAI Compatible API 时,日志至少保留:
- Base URL 的域名和路径;
- Model ID;
- HTTP status code;
- request id(如果有);
- 截断后的错误响应体;
- 工具名称和任务编号。
不要把完整 API Key 写进日志、文章、GitHub issue 或群聊。
4. 对 429、timeout、502 做可恢复处理
Agent 工具层建议把常见临时错误归类为“可重试/可降级”:
- 429:限流,等待后重试或降低并发;
- timeout:跳过当前 URL,保留其他结果;
- 502/503:短暂服务异常,重试一次;
- JSON parse error:记录原始片段,避免吞错。
DeepAI API 中转站这类统一入口的价值之一,就是让不同客户端用相似的 OpenAI Compatible API 方式接入,并通过统一日志帮助你判断请求是否到达、模型是否返回、状态码是什么;但 Agent 端的并发工具、网页抓取和异常恢复,仍然需要在 Agent 自己的工具层处理。
5. 用 DeepAI 控制台把“模型问题”和“工具问题”拆开
如果 DeepAI 控制台里能看到请求正常到达、状态码正常、模型也返回了内容,但 Agent 仍然报 web tools 失败,那就优先查 Agent 的工具链。反过来,如果控制台里出现 401、404、429、5xx,再回到 API Key、Base URL、模型 ID、额度和限流去查。
这就是 API 中转站对 Agent 用户的实际价值:不是承诺所有工具问题都由中转站解决,而是给你一个统一入口,把“请求有没有到模型层”这件事先查清楚。
对 API 中转站运营者的三个启发
1. Agent 不是聊天框,而是分布式小系统
一次用户请求可能触发搜索、抓取、摘要、模型调用、文件写入、消息发送。任何一个环节都可能失败。因此 Agent 代码要像后端服务一样考虑超时、重试、日志和降级。
2. “沉默失败”比显式报错更难排查
这次 issue #2744 的问题是结果被丢弃;同一批修复附近还有 Hermes Agent 对本地模型自动检测异常日志的改进。它们共同说明:Agent 运行时最怕的不是失败,而是失败没有证据。
3. OpenAI Compatible API 生态需要统一排错语言
无论你接的是 DeepAI、OpenAI、Claude Code 周边工具、Codex CLI,还是 Hermes Agent,自定义模型接入时都绕不开几个关键词:Base URL、API Key、Model ID、streaming、tool call、response format。把这些信息标准化记录下来,排查效率会高很多。
给 DeepAI API 中转站用户的实用检查清单
如果你正在搭建自己的 AI Agent 工作流,可以按这个清单检查:
- 工具批量任务是否允许单项失败?
- 失败项是否会写入 warning/debug 日志?
- API Key 是否被脱敏?
- Base URL 和 Model ID 是否能在日志中定位?
- 429/timeout/502 是否有重试或降级策略?
- Web 搜索结果是否能返回“部分成功”?
- 模型输出为空时,是模型问题、网络问题,还是工具层丢结果?
- DeepAI 控制台里能不能看到对应请求、状态码和消耗?
- 是否为 Agent 单独创建了 API Key,方便和普通聊天流量区分?
如果你只是想快速把 Hermes Agent、OpenClaw、Dify、Cherry Studio、Cline 这类客户端接到统一的 OpenAI Compatible API,可以优先使用 DeepAI API 中转站这类兼容接口,再把精力放到 Agent 工具链容错和业务流程上。
FAQ
Hermes Agent asyncio.gather 报错全丢结果是什么原因?
原因是默认 asyncio.gather() 在任意子任务抛异常时会向外抛错,导致其他已经成功的任务结果无法继续使用。Hermes Agent issue #2744 已经通过 PR #26244 修复。
return_exceptions=True 会不会隐藏错误?
不会,前提是你要显式过滤异常并记录日志。正确做法不是忽略异常,而是把异常作为一个结果项处理:成功项继续用,失败项写日志。
DeepAI API 中转站能解决工具层异常吗?
DeepAI API 中转站主要解决模型接入、OpenAI Compatible API、统一 Base URL、API Key 管理、日志和模型调用的问题。工具层的并发、网页抓取、异常过滤仍然需要 Agent 自己处理。
Claude Code、Codex、OpenClaw 也需要关注这个问题吗?
需要。只要涉及并发工具调用、批量网页读取、多模型请求或长文分块总结,就应该考虑局部失败和结果保留策略。
遇到 Agent 联网总结不稳定,第一步该查什么?
先查工具层日志,确认是网页抓取失败、模型 API 失败、还是并发异常导致结果被丢弃。不要一上来就更换模型。
参考链接
- Hermes Agent issue #2744:
https://github.com/NousResearch/hermes-agent/issues/2744 - Hermes Agent PR #26244:
https://github.com/NousResearch/hermes-agent/pull/26244 - 相关 PR #26243:本地模型自动检测失败增加 debug 日志
- 相关 PR #26240:统一 MCP 环境变量插值 regex
总结
Hermes Agent 这次已关闭 issue 的价值不在于“加了一个参数”这么简单,而是提醒所有 AI Agent 开发者:工具调用链路必须具备部分成功、部分失败、可观测、可重试的能力。
对于使用 DeepAI API 中转站或 OpenAI Compatible API 的用户来说,模型接入只是第一步。DeepAI 负责把入口、Key、模型和日志统一起来;真正稳定的 Agent,还需要在工具层、日志层和错误恢复层一起下功夫。否则,一个网页超时,就可能让整轮任务看起来像“API 中转站坏了”,但实际问题可能只是 Agent 没有正确保留部分成功结果。