如果你是个程序员,大概做过这种噩梦:构建失败了,你需要从几亿行日志里找出原因。

上周,Mendral 团队的 Agent 干了一件让人类工程师汗流浃背的事。它追溯了一个 "Flaky test"(不稳定测试)的根因,发现这问题竟然源于三周前的一次依赖版本升级。

整个过程,它自己写 SQL,自己扫数据,自己关联线索。

耗时:几秒钟。

这听起来有点科幻,但他们真的把 TB 级的 CI 日志直接喂给了 LLM。更有意思的是,他们没有给 Agent 预设什么复杂的工具 API,而是直接扔给了它一个 SQL 接口。

结果证明,LLM 可能是世界上最擅长写 SQL 的生物。

别教 Agent 怎么做事,给它数据

老实讲,很多 AI Agent 项目死就死在 "过度设计" 上。

开发者总想替 AI 把路铺好,搞一堆 get_failure_rate(workflow, days) 这种预设函数。想法很好,但这限制了 Agent 的上限——它只能回答你预设好的问题。

Mendral 换了个思路。

AI配图

他们给 Agent 开放了一个 SQL 接口,权限范围限定在当前组织内。Agent 想问什么,自己写查询语句。

这招很险,但也极妙。SQL 的训练数据在互联网上浩如烟海,LLM 对这种结构化查询语言有着天然的亲近感。而且,自然语言转 SQL 的映射关系,比任何复杂的 API 调用都要直接。

Agent 的查询逻辑像极了一个老练的侦探。

它通常先用 "广撒网" 的方式查元数据:“这个工作流的失败率是多少?”“哪些 Job 最慢?”。这类查询占了 63%,通常扫描几十万行数据,毫秒级返回。

一旦发现蛛丝马迹,它立刻 "深挖掘" 进原始日志:“给我看看这个 Job 的报错堆栈”“这个报错信息第一次出现是什么时候?”

这套组合拳下来,哪怕是最棘手的 "幽灵故障" 也无所遁形。

43 亿行数据,一场疯狂的 "数据赌博"

为了支撑这种玩法,Mendral 在底层架构上赌了一把大的。

他们的系统每周要处理 15 亿行 CI 日志,涉及 70 万个 Job。如果是传统数据库,光是存这些数据就能把 DBA 逼疯。

AI配图

但他们做了一个极其大胆的决定:反范式化

简单说,就是把所有上下文信息(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 次的机动额度。

看这张图,这就是他们的生存状态:

Image 1: GitHub API requests per second, steady at ~3 req/s with periodic rate-limit pauses

这就是那张著名的 "锯齿图"。每一次向下倾斜是消耗额度,每一次垂直跳升是小时重置。

他们甚至用了 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 所谓的 "搜索模式":从宽泛到具体,从元数据到原始文本。

真的有那么神吗?

文章发出来后,评论区并没有一边倒地跪舔,反而吵得很凶。

AI配图

这也正常,毕竟 "给 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