AI 项目上线就停:一次事件循环阻塞的完整排查过程

AI 项目上线就停:一次事件循环阻塞的完整排查过程

工信部在 2026 年 8 月 31 日印发了《关于开展人工智能应用服务商培育专项行动的通知》(工信厅科函〔2026〕414号),四类服务里专门列了一项「运营管理服务」。政策解读里有一句话值得工程师记住:技术方案落地难,症结往往不在算法,而在落地环节由谁承接、如何持续服务。

我把这句话在自己项目上验证了一遍。下面是一次真实的排查记录,含报错原文、定位过程和修复代码。

现象:长时运行 7 分钟后数字人掉线

给客户做的 AI 客服演示系统,带数字人。压测时连续跑长片,跑到第 7 分钟左右:

  • 数字人画面消失,界面弹横幅:数字人未能开启
  • 同时对话区出现 Failed to fetch
  • 但后端进程活着 :/api/health 返回 200,审计日志持续写入,没有任何崩溃记录

真的不是网络问题。

注意这里的第一个坑:界面报的原因和真正的原因不是一回事。横幅说是「数字人未能开启」,看起来像 SDK 或网络问题,实际根因在后端。别信横幅。

短测不会暴露。跑 30 秒,一切正常。测不出来。跑 30 秒一切正常------验收当天客户通常只会让你跑五分钟。

定位:先分清「进程挂了」和「事件循环被堵了」

判据很简单:

bash 复制代码
# 后端还活着吗
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8011/api/health
# 200 → 进程没挂

# 但前端为什么 Failed to fetch?看审计日志时间戳是否连续
tail -f app/audit.jsonl | jq -r '.ts + " " + .kind'
# 日志在写,但每次请求的间隔出现 20 秒以上的空洞 → 事件循环被同步调用堵住

Failed to fetch + 后端 200 + 日志有空洞,三个信号。

一起出现,基本可以锁定:异步事件循环里有同步阻塞调用。

根因:async def 里用了同步 httpx.Client

出问题的写法(网关代理,简化后):

python 复制代码
@app.api_route("/api/xmov/gateway/{path:path}", methods=["GET", "POST"])
async def xmov_gateway_proxy(path: str, request: Request):
    # ❌ 同步客户端:await 不到,直接把事件循环占住
    with httpx.Client(timeout=25) as c:
        r = c.request(request.method, url, content=await request.body(), headers=hdrs)
    return Response(r.content, status_code=r.status_code)

单进程 uvicorn 下,httpx.Client.request() 是同步阻塞 的,timeout=25 意味着最坏情况事件循环被占住 25 秒。这期间前端所有请求排队,数字人 SDK 的后续调用也拿不到响应,会话被判失败。

顺带一提,识别这类问题的另一个信号在访问日志里:我们自己发起的请求 UA 是 Python-urllib/3.13 ,而浏览器请求的 UA 是 Mozilla/...。看到代理链路里出现 Python UA,说明它在自己调自己,这一跳就是排查重点。先看它。

修复很简单。

python 复制代码
@app.api_route("/api/xmov/gateway/{path:path}", methods=["GET", "POST"])
async def xmov_gateway_proxy(path: str, request: Request):
    body = await request.body()
    # ✅ 异步客户端:让出控制权,其它请求照常处理
    async with httpx.AsyncClient(timeout=25) as c:
        r = await c.request(request.method, url, content=body, headers=hdrs)
    return Response(r.content, status_code=r.status_code)

另一处同类问题:会话结束时的同步 HTTP 调用,挪进后台线程即可,不要放在请求链路里。

python 复制代码
import anyio
anyio.from_thread.run_sync  # 或在 FastAPI 里用 BackgroundTasks

同一批修复里的另外两处(也都在工程侧,不在模型侧)

① 播报分段必须在调用方串行化。 SDK 不提供「播报结束」回调时,同一个 tick 里连调 speak() 会被厂商判为「上一轮未结束」:

js 复制代码
// ❌ 同 tick 全发
const segs = splitSentences(text, 60);
for (let i = 0; i < segs.length; i++) AGENT.speak(buildSsml(segs[i], opts), first, last);

// ✅ 按字数估时,上一段播完再发下一段
const EST_MS_PER_CHAR = 190, BUFFER_MS = 500;
(async () => {
  for (let i = 0; i < segs.length; i++) {
    AGENT.speak(buildSsml(segs[i], opts), i === 0, i === segs.length - 1);
    await sleep(segs[i].length * EST_MS_PER_CHAR + BUFFER_MS);
  }
})();

② 厂商消息要分级,不能一票判死。 把任何厂商消息都当成致命错误,会让一次解码抖动就把整个会话拆掉:

js 复制代码
// 只有会话 / 鉴权 / 素材类错误才判死;解码抖动等记一笔并尝试重连
const FATAL = /session|auth|token|asset|not\s*found/i;
onMessage((msg) => { FATAL.test(msg.text) ? failAvatar(msg) : logOnce(msg); });

修复后的实测

项 修复前 修复后
连续运行 第 7 分钟掉线 170 秒连续跑全程正常
前端错误 稳定复现 Failed to fetch 无
事件循环阻塞 最长 25 秒 无阻塞

给做交付的同行三句话

  1. 验收当天跑五分钟,测不出这类问题。 长时运行是唯一的暴露方式,把「连续跑 10 分钟」写进交付前必跑清单。
  2. 界面报错和真因经常不是一回事。 先把「进程活着没有」和「事件循环通不通」分开判断,再去看业务逻辑。
  3. 政策提到的「运营管理服务」,落到代码上就是这些事:监控空窗、解码抖动、会话回收。它们不性感,但决定了第 91 天系统还在不在。

AI 参与说明:本文的排查记录、命令与实测数据来自作者现场操作;文字由作者与 AI 辅助整理,事实与观点经作者核实。

信息来源:① 工业和信息化部办公厅《关于开展人工智能应用服务商培育专项行动的通知》(工信厅科函〔2026〕414号,2026-08-31);② 南方都市报《到年底破两千家!工信部专项行动:打造 AI 应用服务商资源池》(2026-09-02)。

我们专注小微企业知识库与 AI 客服落地(Apache-2.0 开源,含国标 61 项自查清单)。

相关推荐
yichengerp1 小时前
电子行业常用erp系统有哪些?推荐适合中小电子厂的易呈erp软件,操作简单,易落地
大数据·运维·人工智能·云计算·制造
染指11101 小时前
142.Agent-多Agent框架-通过Skills实现多Agent
开发语言·人工智能·python·langchain·agents
薛定谔的猫-菜鸟程序员1 小时前
上传试卷、打Boss,玩游戏:我用 TextIn xParse 做了一套“会解析试卷的刷题游戏“
人工智能·游戏·大模型·textin·ai数据层基础设施
量子-Alex1 小时前
【大模型后训练】Does Fine-Tuning LLMs on New Knowledge Encourage Hallucinations
人工智能·语言模型·自然语言处理
天国梦1 小时前
国密门禁品牌怎么选?2026年最新3个避坑要点
运维·服务器·数据库·python
空 白II1 小时前
10.11 大语言模型研究简报:OpenAI 公布 AI 数学研究新进展
人工智能·语言模型·openai
蓝瑟1 小时前
苏格拉底式提问法,也许是AI时代最稀缺的能力
人工智能
Csvn1 小时前
延迟别再看平均值了:AI 应用指标与告警实战(O03)
人工智能·aigc·agent
Re_zero1 小时前
一次 SSE 断流排查:PrintWriter 吞掉了我的 IOException
java·后端