---
layout: post.njk
source: https://blog.qiaomu.ai/ai-assisted-coding
speaker: 向阳乔木
title: 用 AI 造了一个等了 8 年的工具，他想说点真话 · 乔木博客
date: '2026-04-21'
summary: 本文记录了 Lalit Maganti 如何利用 AI 历时八年完成 SQLite/PerfettoSQL 开发工具的构建。文章深入探讨了 AI 辅助编程的优势（加速开发、重构）与劣势（成瘾性、代码感知丢失、设计决策推迟），并强调 AI 是实现层面的强大助力，但不能替代人类的设计判断和历史上下文理解。
area: tech-engineering
category: software-development
tags:
  - ai-assisted-development
  - developer-tools
  - sql
  - code-generation
  - developer-workflow
people:
  - Lalit Maganti
  - Andrej Karpathy
companies_orgs:
  - Google
products_models:
  - Perfetto
  - PerfettoSQL
  - syntaqlite
  - Claude Code
  - SQLite
media_books: []
draft: true
status: evergreen
---

乔木博客

全部

AI工具

AI教程

AI生成

AI资讯

健脑房

播客解读

论文学习

# 用 AI 造了一个等了 8 年的工具，他想说点真话

AI教程

·

2026年4月21日

·

856 次阅读

·

约 20 分钟

Lalit Maganti 在 Google 做 Perfetto 项目，维护一个叫 PerfettoSQL 的查询语言。

> Perfetto 是 Google 开发的性能分析平台，用来追踪 Android、Chrome 等系统的运行状态。

PerfettoSQL 是在它上面跑的查询语言，基本上就是 SQLite 加了一些扩展，让工程师能用 SQL 的方式去分析性能数据。

这个语言在 Google 内部有超过十万行代码，被各种团队广泛使用。

用的人多了，自然就有需求：格式化工具、代码检查、编辑器插件。

他去找开源社区的 SQLite 工具，结果一个能用的都没有，要么不够准确，要么太慢，要么根本没法扩展到 PerfettoSQL 的方言。

这个遗憾在他脑子里压了整整八年。

今年三月，他终于发布了 syntaqlite。

用了三个月，250 小时，全靠 AI 编程工具才做到。

他写了一篇很长的复盘，没有吹嘘，也没有装清醒。

这是目前关于 AI 辅助编程最诚实的一篇文章之一。

> 原文：https://lalitm.com/post/building-syntaqlite-ai/

## 为什么 SQLite 的开发工具一直是空白

SQLite 是世界上部署最广泛的数据库，没有之一。

每一部智能手机、每一个主流浏览器、无数嵌入式系统里都跑着它。

但围绕它的开发者工具，一直是个令人困惑的空白地带。

devtools（开发者工具）在这里具体指三样东西：

formatter（格式化器）：自动把 SQL 代码排版整齐，就像 Prettier 对 JavaScript 做的事

linter（代码检查器）：静态分析代码，找出潜在的错误或不规范写法

language server / LSP（语言服务器）：让编辑器能提供自动补全、跳转定义、错误提示等智能功能，TypeScript 在 VS Code 里的那种体验

Lalit 找过市面上的工具，要么格式化器会"吃掉"注释，要么 linter 不支持 SQLite 特有的语法，要么语言服务器功能残缺。

根本原因在于，这些工具的解析器都是"近似"SQLite 语法，而不是精确还原它。

为什么精确解析 SQLite 这么难？

通常一门语言要做开发工具，第一步是拿到它的正式语法规范，然后按规范写解析器。

但 SQLite 没有正式规范，它也不暴露解析器的 API 给外部使用。

更奇特的是，SQLite 内部实现根本不生成语法树，它直接从 SQL 文本编译成字节码，就像跳过了中间步骤。

这意味着，想做一个真正高质量的 SQLite 解析器，唯一合理的路是：钻进 SQLite 的 C 源码，把相关部分挖出来，重新组装成一个能生成语法树的解析器。

具体来说分三步：

从 SQLite 源码中提取词法分析器（tokenizer，负责把 SQL 文本切成一个个词）

提取语法规则，用 SQLite 自带的 Lemon 解析器生成工具，造出自己的解析器

手动处理超过 400 条语法规则，逐一决定每条规则在语法树里对应什么节点

SQLite 的源码是出了名的难读，用极其紧凑的 C 风格写成。

Lalit 说他光是理解虚拟表 API（virtual table API，一种让 SQLite 能查询外部数据源的机制）就花了好几天，而他已经用这个 API 做了八年 Perfetto 了。

这种项目最可怕的地方在于：它同时满足"太难"和"太无聊"两个条件。

任何一个单独存在都还好，两个加在一起，动力就彻底死了。

还有一个额外的复杂性：他不想只做一个服务 Perfetto 的工具，他想让它对所有 SQLite 用户都有用，同时还要支持 PerfettoSQL 这样的方言扩展，而不需要 fork 整个项目。

这个设计目标让架构难度又上了一个台阶。

## 三个月的过程，分两个截然不同的阶段

### 第一阶段：一个月的 vibe coding 实验

2025 年底，他观察到 AI 模型的质量似乎有了一次明显的跃升。

Andrej Karpathy（OpenAI 联合创始人之一）当时说过一句话，他觉得说得很准：

> "编程 Agent 在十二月之前基本上不能用。模型的质量、长期连贯性和执行力有了显著提升，能够完成大型、长周期的任务，对默认的编程工作流造成了极大冲击。"

圣诞节期间，他给自己出了一道题：能不能用最极端的方式，完全靠 AI 把这个项目做出来？

他订了 Claude Code 的 Max 计划（每月 200 英镑），把自己定位成"半技术经理"，几乎把所有设计和实现都委托给 Claude。

整个一月，他就这么干。

功能上最终到了一个还算能用的地方：一个用 Python 脚本从 SQLite 源码提取的 C 解析器，一个建在上面的格式化器，同时支持 SQLite 和 PerfettoSQL，还有一个网页演示环境。

但一月底，他仔细审查了整个代码库，结论很直接：完全是意大利面条代码。

他在项目日志里写道：

> "我很快就精疲力竭，开始接受太多随机代码。一旦搞乱了，不把它扔掉就很难恢复。"

Python 提取流水线的大部分他自己都看不懂，函数散落在各个随机文件里没有清晰结构，有几个文件膨胀到了好几千行。

代码解决了眼前的问题，但永远不可能支撑他更大的愿景，更别说集成进 Perfetto 的工具链了。

唯一的收获：证明了这条路走得通，以及 500 多个可以复用的测试用例。

### 第二阶段：全部推倒，换语言，换角色

他做了两个决定。

第一，把所有代码扔掉，从零重写。

第二，把大部分代码库切换到 Rust。

原因很实际：C 语言会让格式化器、验证器、语言服务器这些上层组件很难写，而 Rust 可以让提取流水线和运行时用同一种语言，不用再在 C 和 Python 之间来回切换。

（词法分析器和解析器本身仍然保留 C，因为它们直接从 SQLite 源码提取。）

更重要的是，他完全改变了自己在项目里的角色。

他在和 Claude 的对话记录里，开头第一句话是：

> "我想要的工作方式是：我负责所有决策和方向，我来告诉你做什么。我不想让你规划，不想让你独立行动。清楚了吗？"

他把 AI 从"项目负责人"变成了"超级自动补全"，套在一个更严格的流程里：

先做有主见的设计，每次改动都仔细审查，发现问题立刻修，投入精力建脚手架（linting、验证、非平凡的测试）来自动检查 AI 的输出。

核心功能在二月完成，最后的收尾阶段（上游测试验证、编辑器插件、打包、文档）在三月中旬完成，发布了 0.1 版本。

## AI 真正做到了什么

### 打破了第一步的惯性

Lalit 承认自己有一个老毛病：面对大项目容易拖延。

他在日志里写道：

> "用它来超快速地原型化改动，然后回来把所有代码删掉，再以更结构化的方式重新构建。"

AI 改变了这件事的方式很有意思。

他不再需要坐在那里想"我该怎么理解 SQLite 的解析机制"，而是变成"让 AI 先给我一个方案，我来看哪里不对"。

有个具体的东西可以批评，比对着空气思考要容易太多。

AI 生成的原型，哪怕最后全扔掉，也把抽象的不确定性变成了具体的东西可以反应，证明了这条路走得通。

### 写"显而易见的代码"比人快

他的原话是：如果能把问题拆解成"写一个有这个行为和参数的函数"，AI 会比他写得更快，而且风格可能对未来的读者更直觉友好。

AI 会写他懒得写的注释，会保持代码风格和项目其他部分一致，会用语言的"标准写法"。

他在日志里提到，他既让 AI 完整生成整个模块，也会在需要的时候亲手写 SIMD 指令并在 Compiler Explorer 里看汇编输出，完全取决于具体问题。

标准代码是绝大多数，手写的是例外。

但这个"标准化"是双刃剑。

对于项目里大多数普通代码，标准化是好事。

但每个项目都有它的核心难点，那些需要做非显而易见决策的地方，AI 的本能是把它"正常化"，反而有害。syntaqlite 的提取流水线和解析器架构就是这样，Lalit 最后选择自己设计、自己写。

### 重构和生成一样快

他在日志里反复强调这一点：

> "如果你用 AI 在工业规模上生成代码，你必须持续不断地重构。如果不这样做，事情会立刻失控。"

> "每次大量生成代码之后，值得作为人类停下来问'这个丑吗'，如果是，就做点什么。"

有时候 AI 能自己清理。有时候有一个大规模的抽象层 AI 看不到，但他能看到，他给出方向，让 AI 执行。

他的日志里写道："审计加重构，两者配合效果惊人。"

如果你有品味，犯错的代价会大幅降低，因为你能快速重构。

### 大幅降低了学习新领域的成本

他举了一个很典型的例子：做格式化器的时候，他需要了解一种叫 Wadler-Lindig 的算法。

Wadler-Lindig 是一种"漂亮打印"（pretty-printing）算法，让你能声明式地描述文档的排版方式，由打印器自动决定在哪里换行，而不是手动计算每行的宽度。

在格式化器设计的对话记录里，Claude 主动提出了"从一开始就用 Wadler-Lindig 文档模型做宽度感知格式化"，Lalit 能立刻参与权衡讨论，而不是先花好几天才发现这个方法的存在。

他对这类跨领域切换的总结是：

> "我对 C++/Android 性能非常熟悉，但对 Python/Go/Rust 工具完全不了解。有了 AI，这不是问题：基础是一样的，术语是相似的。我现在能在领域之间切换得非常快。"

VS Code 插件也是类似的情况。

他对这套 API 完全陌生，但一小时内就有了一个能跑的扩展。

### 让 AI 充当代码库的"即时顾问"

他在日志里描述了一种很实用的用法：

> "你可以控制深入程度：表层概览用于快速复习，详细线性讲解用于深入了解，定向审计用于追查问题。"

当他切换上下文太多、忘了某个模块是怎么工作的，他可以直接问 AI："给我讲讲这个组件"，或者"审计这个 repo 里所有 unsafe 的用法"。

这种按需获取上下文的能力，在频繁切换任务的业余项目里格外有价值。

### 让项目变得更完整

没有 AI，他大概会发布一个核心功能可用、但边角料全缺的工具。

有了 AI，这些东西都做出来了：VS Code 插件、文档网站、crates.io（Rust 包）、PyPI（Python 包）、npm（JavaScript 包）、Homebrew（macOS 包管理器）发布、Zed 编辑器插件。

每一个单独拿出来都是一个周末项目。

更重要的是，他有了余力去思考用户体验。 他在日志里写道：

> "不只是'我应该解决什么问题'，还有'什么错误提示最有用'和'怎么让这个真的简单易用'。"

具体落地的例子：类似 rustc 风格的多错误诊断（带"你是不是想写……"的建议）、快速修复代码操作、syntaqlite.toml 配置文件（让用户不用每次都写命令行参数）。

AI 没有只是让同一个项目变快，它改变了这个项目是什么。

## AI 带来了什么代价

### 像老虎机一样让人上瘾

他用了一个很准确的比喻：发一个 prompt，等待，要么得到很好的东西，要么得到废物。

这个随机性本身就让人上瘾。

他在日志里写道：

> "我在某些时候感到上瘾，沉迷于它的'老虎机'特性，耗尽时间，从长远来看也耗损了健康。"

他发现自己会在深夜"再试一个 prompt"，即使知道大概率没用。

沉没成本效应也在发挥作用：已经在这个任务上花了这么多时间，再试一次吧，换个说法也许就行了。

疲劳会让这个循环变得更糟。 他的日志里写道：

> "我对 AI 的精确度与我的疲劳程度成正比。当我精力充沛时，我能非常精确，效率很高。但当我疲惫时，我开始说'做 X 事情'而没有太多细节，AI 的输出会变得糟糕很多很多很多。"

在这种状态下，AI 其实比他自己写还慢，但很难从这个循环里跳出来。

### 失去对代码库的感知

他多次描述了一种感觉：突然意识到自己不知道代码里发生了什么。

不是不懂整体架构，而是那些日常细节，函数在哪里，谁调用谁，那些小决策是怎么积累成现在这个样子的。

他在日志里写道：

> "有好几次我'失去了'对代码库的感知，出现了令人惊讶的问题，我只能说'AI，请帮我调试'，我讨厌那种感觉。"

更深的问题是：失去感知之后，你没法有效地和 AI 沟通。 他的日志里写道：

> "你失去了'正在发生什么'的心理线索，就无法有意义地、清晰地沟通，每次交流都变得更长更冗长，需要 Agent 做更多工作。"

本来可以说"把 FooClass 改成做 X"，现在只能说"把那个做 Bar 的东西改成做 X"。

AI 要先猜 Bar 是什么，再猜它对应哪个类，有时候猜错了，问题变得更复杂。

他说这和工程师们抱怨"不懂代码的管理者提需求"是完全一样的问题，只是现在那个不懂代码的管理者变成了你自己。

他的解决方法是：每次 AI 实现完一段代码，立刻自己读一遍，主动问自己"我会怎么写这个"。

有一点值得注意：这个问题和"几个月前自己写的代码也会忘"有些类似，但 AI 让这个漂移发生得快得多，因为你没有经历最初打出那些代码时建立的肌肉记忆。

### 推迟了真正重要的决策

因为重构很便宜，他总是可以说"这个问题以后再处理"。

但推迟设计决策有一个隐性代价：代码库一直处于混乱状态，这会持续消耗他理清思路的能力。

他在日志里写道：

> "AI 让我拖延真正做关键设计决策，因为重构很容易，有好几次我能说'我以后再处理这个'。但与此同时，它腐蚀了我清晰思考的能力，因为代码库一直很混乱。"

vibe coding 那个月是最极端的版本。

他理解问题所在，但如果他更早、更果断地做出艰难的设计决策，他本可以更快收敛到正确的架构。

### 测试带来的虚假安全感

500 多个测试让他感觉很踏实，AI 也让生成更多测试变得很容易。但他在日志里写道：

> "人类和 AI 都没有足够的创造力来预见你未来可能遇到的那些奇怪情况。如果你没有某种基本的基础，你将永远追着 bug 跑。"

vibe coding 阶段的原型有 500 多个测试，照样彻底崩了。

重写时，他换了策略：投入精力做幂等性测试（同样的输入总是产生同样的输出），以及一个更关键的验证机制，写了一个 TCL 驱动程序，把 SQLite 自己的约 1390 个上游测试文件接进来，每条 SQL 语句同时跑真实 SQLite（sqlite3_prepare_v2）和 syntaqlite 的解析器做对比，SQLite 接受的语句 syntaqlite 必须接受，SQLite 拒绝的 syntaqlite 必须拒绝。这能抓住手写测试永远发现不了的一类 bug。

### AI 没有时间感

这是他观察到的一个更深层的问题。他在日志里写道：

> "模型没有时间感。它们看到代码库处于某种状态，是的，它们可以通过上下文/文档/记忆获得一些感觉。但它们感受不到时间，方式和人类不同。比如，我能告诉你使用一个 API 是什么感觉，以及它随时间的演变，以及为什么事情是现在这个样子。模型只能通过明确的记录来获得这些，而这样做的成本非常高。"

这和失去一个资深工程师很像。

他们携带的历史和上下文不存在于任何文档里，是真正的隐性知识，指导着周围所有人。

理论上可以把这些都写进文档，但这件事本身极其昂贵。

AI 可以帮起草这些文档，但因为没有办法自动验证它准确捕捉到了真正重要的东西，人还是要手动审查，依然耗时。

还有一个上下文污染问题：你永远不知道关于 API A 的设计笔记什么时候会影响到 API B。

代码库的一致性需要的不只是当前工作的上下文，还需要其他以类似方式设计的东西的上下文。

判断什么是相关的，恰恰需要机构知识本身才能提供的那种判断力。

## 什么时候 AI 好用，什么时候不好用

他总结出了一个很清晰的规律，沿着两个维度展开。

第一个维度：你对这件事的理解有多深。

当他对一件事已经理解很深时，AI 表现出色。他能立刻判断输出对不对，能快速迭代。

语法规则生成就是最清楚的例子，他在日志里写道："Agent 团队的成功超出了我最疯狂的想象，能够在一个晚上完成所有工作。"

但前提是他先做了脚手架工程：重构项目结构让 Agent 能在不同文件上并行工作，写了一个差异比较脚本把错误分组成可操作的反馈。

然后还有不可避免的手动检查："需要逐一检查每一个测试，发现了一堆问题（标志没有正确格式化，缺少字段名等）。"

当他能描述想要什么但还不完全懂时，AI 有用但需要更多投入。

学 Wadler-Lindig 算法就是这种情况，他能判断方向对不对，能从解释里学到东西，但不能完全放手。

当他连自己想要什么都不清楚时，AI 从无用到有害。

项目架构设计就是最典型的例子。

他在早期花了好几周跟着 AI 走进死胡同，探索那些看起来有进展但经不起推敲的设计。

他说他有时候会想，那段时间如果完全不用 AI，直接自己想清楚，说不定反而更快。

第二个维度：答案能不能被客观验证。

他在日志里写道：

> "一个属性对于人类或 AI 来说越容易验证正确性，AI 就越擅长处理那些任务。"

代码实现有客观标准：编译通过，测试通过，输出符合预期。

API 设计没有。"这个 API 用起来舒不舒服"、"这个 API 能不能帮用户解决他们的问题"，没有测试能回答这两个问题，所以 AI 在这里表现很差。

他在三月初花了好几天专门做 API 重构，手动修复任何有经验的工程师都会本能避开、但 AI 搞得一团糟的东西。

他用了一个物理学的比喻来总结这一切：在局部小范围内，物理定律看起来简单，符合牛顿力学。

但放大来看，时空会以你从局部图景里预测不到的方式弯曲。

代码也一样，在函数或类的层面，通常有清晰的正确答案，AI 在这里很强。

但架构是所有局部组件相互作用的结果，你没法靠把局部正确的部分拼在一起得到全局正确的系统。

知道自己在这两个维度上处于什么位置，是有效使用 AI 的核心技能。

## 最后

八年的念头，三个月做出来了。

但这个过程不是那种干净的成功故事。

他浪费了一整个月在 vibe coding 上，掉进了管理一个自己根本不理解的代码库的陷阱，最后付出了全部重写的代价。

他希望看到更多这样的文章：诚实的、有细节的、关于用 AI 构建真实软件的记录。

不是周末玩具，是那种要经历用户、bug 报告、以及你自己不断变化的想法的软件。

他的结论很简单：AI 是实现层面的力量倍增器，但是设计层面的危险替代品。

它能给你一个具体技术问题的正确答案，但它没有历史感，没有品味，不知道一个真实的人用你的 API 会有什么感受。

如果你把软件的"灵魂"外包给它，你只是会更快地撞墙。

© 2026

·

向阳乔木