如果你是个程序员,大概做过这种噩梦:构建失败了,你需要从几亿行日志里找出原因。
上周,Mendral 团队的 Agent 干了一件让人类工程师汗流浃背的事。它追溯了一个 "Flaky test"(不稳定测试)的根因,发现这问题竟然源于三周前的一次依赖版本升级。
整个过程,它自己写 SQL,自己扫数据,自己关联线索。
耗时:几秒钟。
这听起来有点科幻,但他们真的把 TB 级的 CI 日志直接喂给了 LLM。更有意思的是,他们没有给 Agent 预设什么复杂的工具 API,而是直接扔给了它一个 SQL 接口。
结果证明,LLM 可能是世界上最擅长写 SQL 的生物。
别教 Agent 怎么做事,给它数据
老实讲,很多 AI Agent 项目死就死在 "过度设计" 上。
开发者总想替 AI 把路铺好,搞一堆 get_failure_rate(workflow, days) 这种预设函数。想法很好,但这限制了 Agent 的上限——它只能回答你预设好的问题。
Mendral 换了个思路。
他们给 Agent 开放了一个 SQL 接口,权限范围限定在当前组织内。Agent 想问什么,自己写查询语句。
这招很险,但也极妙。SQL 的训练数据在互联网上浩如烟海,LLM 对这种结构化查询语言有着天然的亲近感。而且,自然语言转 SQL 的映射关系,比任何复杂的 API 调用都要直接。
Agent 的查询逻辑像极了一个老练的侦探。
它通常先用 "广撒网" 的方式查元数据:“这个工作流的失败率是多少?”、“哪些 Job 最慢?”。这类查询占了 63%,通常扫描几十万行数据,毫秒级返回。
一旦发现蛛丝马迹,它立刻 "深挖掘" 进原始日志:“给我看看这个 Job 的报错堆栈”、“这个报错信息第一次出现是什么时候?”。
这套组合拳下来,哪怕是最棘手的 "幽灵故障" 也无所遁形。
43 亿行数据,一场疯狂的 "数据赌博"
为了支撑这种玩法,Mendral 在底层架构上赌了一把大的。
他们的系统每周要处理 15 亿行 CI 日志,涉及 70 万个 Job。如果是传统数据库,光是存这些数据就能把 DBA 逼疯。
但他们做了一个极其大胆的决定:反范式化。
简单说,就是把所有上下文信息(Commit SHA、作者、分支、PR 标题、Job 名字等 48 列元数据),直接拍在每一行日志上。
这在传统行式存储里是自杀行为。但在 ClickHouse 这种列式数据库里,这简直是天才。
因为同一个 CI Run 产生的几千行日志,它们的元数据(比如 commit_message)是完全一样的。ClickHouse 的压缩算法看到这种重复数据,简直乐开了花。
看这组数据,真的有点离谱:
| 列名 | 压缩比 | 原因 |
|---|---|---|
commit_message |
301:1 | 同一个 Run 内几千行日志内容完全一致 |
display_title |
160:1 | PR 标题全一样 |
workflow_path |
79:1 | 工作流路径全一样 |
最终结果是什么?
原始日志文本 664 GiB,加上那 48 列元数据,未压缩前高达 5.31 TiB。但实际落盘后,只有 154 GiB。
压缩比 35:1。
也就是说,每行日志连同它所有的上下文信息,在硬盘上只占 21 字节。这甚至比很多原始日志文本本身都要小。
这不仅仅是省钱,这是给 Agent 赋予了 "上帝视角"。它不需要做任何 Join 操作,想按作者筛选?按分支筛选?还是按 Runner 标签筛选?都是单列查询,快得飞起。
在 GitHub 的 "红线" 上跳舞
有了数据和 Agent,还不够。现实世界有个更麻烦的制约:API 限流。
GitHub 的 API 并不是无限畅饮的。每小时 15,000 次请求(企业版),听起来很多,但对于一个要实时抓取几十个仓库日志、还要读取 PR Diff、还要发评论的 Agent 来说,这点额度瞬间就会烧光。
这就陷入了一个死循环:
- 摄入太猛,API 额度耗尽,Agent 没法干活。
- 摄入太慢,数据陈旧,Agent 看的是一小时前的日志,查了也白查。
Mendral 早期就踩了这个坑。摄入程序疯狂请求,撞到限流墙后被挂起一小时。等它缓过来,日志已经是 30 分钟前的 "旧闻" 了。
对于排查故障来说,这不可接受。
他们最后搞了一套精细的 "节流策略":把请求均匀铺在时间轴上,死死卡在每秒 3 个请求,给 Agent 留出 4000 次的机动额度。
看这张图,这就是他们的生存状态:
这就是那张著名的 "锯齿图"。每一次向下倾斜是消耗额度,每一次垂直跳升是小时重置。
他们甚至用了 Inngest 这种持久化执行引擎。一旦撞到限流,程序不是崩溃重试,而是 "挂起"。系统读出 GitHub 告诉你的等待时间,加个 10% 的抖动,然后暂停进程。
等时间到了,再从断点接着跑。
这就像在高速公路上开车,油门踩到底肯定要撞车,但如果你能精准控制车速,就能在车流中丝滑穿行。
43 亿行扫描,只要 31 秒
这套系统的性能数据,确实有点吓人。
他们分析了 52,000 次查询,发现 Agent 的 "胃口" 大得惊人。
- 中位数查询: 扫描 33.5 万行,耗时 20-110 毫秒。
- P95 级别查询: 扫描 9.4 亿行。
- 最重口味查询: 扫描 43 亿行。
即使是扫描 43 亿行这种 "核弹级" 查询,中位数耗时也才 31 秒。
说实话,让一个人类工程师在 GitHub Actions 的日志查看器里翻 43 亿行日志,他大概会先翻白眼,再提离职。
但 Agent 不在乎。它会先问 "失败率多少?"(查元数据,20ms),发现异常后再问 "这个报错啥时候开始的?"(查原始日志,110ms),然后一步步逼近真相。
这就是 Mendral 所谓的 "搜索模式":从宽泛到具体,从元数据到原始文本。
真的有那么神吗?
文章发出来后,评论区并没有一边倒地跪舔,反而吵得很凶。
这也正常,毕竟 "给 LLM 直接写 SQL" 听起来就像是把核按钮交给了实习生。
有人质疑幻觉问题:
"我也用过 LLM 分析日志,它们经常编造理由。因果关系的距离往往超过了上下文窗口,而且很多良性问题也会抛出吓人的报错。"
这确实是痛点。LLM 擅长找关联,但不一定懂因果。
还有人担心 Token 成本:
"文章没提用了什么模型和成本。如果用 ChatGPT,这 Token 消耗谁顶得住?"
更有意思的是,有人觉得这文章本身就是 AI 写的:
"这文章读起来完全是 LLM 生成的。就是堆砌了一堆听起来很牛的数字。"
我个人觉得,这些质疑都有道理。Mendral 展示了工程上的极致优化(ClickHouse 的使用、限流策略),但并没有完全解决 "噪音" 问题。
毕竟,正如一位评论者所说:
"你可能拥有 10 TB 的日志,但真正有趣的只有几行。如果你的准确率是 99.9999%,在亿级数据面前,误报依然能把人淹死。"
但这依然是一个极具启发性的尝试。
很多时候,我们以为 AI 需要的是 "更聪明的算法",但 Mendral 证明了,给 AI "更锋利的刀"(SQL)和 "更宽广的视野"(全量元数据),可能比教它怎么切菜更有效。
在这个数据爆炸的时代,也许我们不需要 AI 帮我们 "读" 每一行日志,我们需要的是 AI 帮我们 "问" 对问题。
至于它会不会问错?反正查一次只要 20 毫秒,多问几次就是了。
参考链接:
https://www.mendral.com/blog/llms-are-good-at-sql