AI多Agent协作系统实战(十七):凌晨4点,我的AI系统在“假装工作“——3个bug同时爆炸的5小时

系列第17篇 | 一个bug不可怕,三个同时来才致命

凌晨4点的飞书

2026年7月17日,凌晨4点。

我睡不着,打开飞书看了一眼小密(我的AI统筹Agent)的消息。然后我愣住了:

复制代码
【小密统筹报告 07-17 04:04】
【小密统筹报告 07-17 04:34】
【小密统筹报告 07-17 05:04】
【小密统筹报告 07-17 05:34】
【小密统筹报告 07-17 06:04】
【小密统筹报告 07-17 06:34】
【小密统筹报告 07-17 07:04】

7条消息,每条都只有一个标题,没有任何内容。没有任务表格,没有进度,没有状态。

就像一个员工每半小时给你发一封邮件,标题写"工作汇报",打开里面是空白的。

他没在偷懒------他一直在发邮件。但他也没在工作------邮件里什么都没有。

我发了条消息:"有什么问题,一直在空转。"

然后我开始排查,发现不是一个bug,是三个。它们来自三个完全不同的系统层,互相不知道对方的存在,但效果叠加在一起------整个心跳系统"假装工作"了整整5个小时。

第一个炸弹:空报告

现象:心跳每30分钟发一条报告到飞书,从凌晨2点开始正常,4点开始变成只有标题的空消息。

排查过程

我打开format_report.py,看到了这个函数:

python 复制代码
def has_content(notes, timeout_tasks):
    if notes:        # ← 问题在这里
        return True
    if timeout_tasks:
        return True
    return False

看起来没毛病?但问题在于notes里装了什么。

当所有任务都处理完了,脚本会往notes里写一句"无待复核任务"。bool("无待复核任务")返回True,所以has_content说"有内容!",继续生成报告。

但后面有个过滤器:

python 复制代码
filtered_notes = [n for n in notes if not n.startswith("无")]

"无待复核任务"以"无"开头,被过滤掉了。filtered_notes变成空列表。

has_content看的是过滤前的notes ,不是过滤后的filtered_notes

就像你在厨房检查食材有没有过期,但没检查做出来的菜有没有变质。

最终效果:脚本说"有内容"→生成报告→内容被过滤→只剩标题→发送空报告。

修复

python 复制代码
def has_content(notes, timeout_tasks):
    # 不再检查原始notes,检查最终输出
    lines = format_lines(notes, timeout_tasks)
    content_lines = [l for l in lines if l.strip() 
                     and not l.startswith('【') 
                     and not l.startswith('|')]
    return len(content_lines) > 0

教训:判断"有没有内容",要在出口看输出,不要在入口看输入。

第二个炸弹:手机白屏

现象:手机浏览器一片白,控制台没报错,Vue完全没渲染。

排查过程

第一层:资源路径混乱。

mobile/index.html引用了/assets/xxx.js,但文件实际部署在/mobile/assets/下。浏览器请求404,JS不加载,Vue不启动。

但这个修好后,还有第二层------更隐蔽的。

localStorage跨设备污染

我之前在PC端访问系统,点了侧边栏折叠按钮。JS把状态存进localStorage

javascript 复制代码
localStorage.setItem('sidebarCollapsed', 'true')

localStorage按域名存储 的,跟设备无关。同一个域名(nasioe.cc.cd),PC端和手机端共享同一份localStorage

我用手机打开同一个域名,浏览器读到sidebarCollapsed = 'true',JS把侧边栏宽度设成60px。手机屏幕375px宽,60px侧边栏+主内容区,布局全乱。

你以为localStorage是"本地"的,其实它是"本域名"的。

就像你在家里的冰箱贴了一张"今晚吃火锅"的便条,结果你出差住酒店,酒店冰箱里也有一张同样的便条------因为你们用的是同一个美团账号。

修复

javascript 复制代码
// 只在PC端恢复折叠状态
if (window.innerWidth > 768) {
    const saved = localStorage.getItem('sidebarCollapsed');
    if (saved === 'true') {
        sidebar.classList.add('collapsed');
    }
}

第三个炸弹:CSS幽灵

现象:PC端侧边栏折叠按钮被遮挡,折叠后菜单文字没隐藏。

排查过程

我grep了CSS,找到了这段:

css 复制代码
.sidebar.collapsed span:not(.menu-icon) {
    display: none !important;
}

选择器匹配的是span:not(.menu-icon)------也就是隐藏非图标的span

但实际HTML是这样的:

html 复制代码
<a href="/dashboard.html" class="menu-item">
    <span class="menu-icon">📊</span>
    数据看板    <!-- ← 文字直接在<a>里,不在<span>里 -->
</a>

文字不在<span>里,直接写在<a>标签里。CSS选择器根本匹配不到它。

CSS不会报错。它只是静静地失效,看着你的页面一团糟。

就像你给门配了一把钥匙,但门锁已经换了。钥匙插进去,转不动,但门看起来还是那扇门。

修复

css 复制代码
.sidebar.collapsed a {
    font-size: 0;      /* 隐藏<a>内的文字 */
}
.sidebar.collapsed .menu-icon {
    font-size: 18px;   /* 强制显示图标 */
}

三个bug的"完美风暴"

Bug 影响 持续时间
空报告 飞书消息全是空白标题 5小时
手机白屏 手机端完全无法访问 直到修复
CSS幽灵 PC端侧边栏折叠失效 直到修复

三个bug单独看都不致命。但叠加在一起:

  1. 空报告→用户看不到系统在干什么("一直在空转")
  2. 手机白屏→移动端完全不可用
  3. CSS幽灵→PC端UI也有问题

从用户视角看:飞书里一串空消息,手机打不开,电脑侧边栏也是坏的。整个系统似乎瘫痪了。

但实际上,核心逻辑(任务派发、Agent调度、心跳监控)一直在正常运行。出问题的全是展示层

一个"内部正常但外部表现异常"的系统,在用户眼里跟"完全坏掉"没有区别。

三个教训

1. 判断"有没有内容"要看最终输出

has_content检查原始notes,但notes在后面被过滤了。入口看到的和出口输出的不是同一回事。

2. localStorage是域名级别的,不是设备级别的

多设备共用的Web应用,UI状态必须考虑跨设备兼容。用window.innerWidth判断设备类型是最简单的方案。

3. HTML结构改了,CSS选择器必须同步grep

CSS选择器是"盲"的------DOM结构变了,选择器失效,样式静默丢失。改HTML后第一件事:grep所有引用该class的CSS文件。

相关推荐
gaolei_eit1 小时前
Java+Ai+vue
java·spring·maven
qq_2518364571 小时前
基于java Web 动漫视频网站毕业论文
java·开发语言·前端
LayZhangStrive2 小时前
JUC相关的函数、注解、变量杂记
java·面试·多线程·juc
未秃头的程序猿2 小时前
给公司做了个AI客服Agent,用的Spring AI 1.0,3天上线领导拍板了
java·后端·ai编程
曹牧2 小时前
Eclipse 批量文本替换
java·ide·eclipse
an317422 小时前
6MB 组织树大文件性能优化全流程
前端·javascript·vue.js
程序员清风2 小时前
OpenAI官方发布最新提示词技巧!
java·后端·面试
梅头脑2 小时前
写了3年CRUD,volatile和synchronized的区别还是答不清——直到我画出了这张三性两锁边界图
java
暮暮祈安2 小时前
Celery 新手入门指南
java·数据库·python·flask·httpx