0%

把 AI 编码工具改造成研发工作台——基于 Pi 的 Extension 实践

最近几个月,AI 编码工具已经成了日常开发的一部分。Claude Code、Cursor、Copilot——它们在代码生成和重构上的表现越来越好。

但用得越久,越觉得有一个断层:AI 在终端里帮我写代码,但我自己却要频繁切出终端去做别的事。查数据库切到 DataGrip,看日志 SSH 上服务器,构造测试数据打开另一个脚本。AI 离我的实际工作环境,其实还很远。

这个问题让我开始想一件事:能不能让 AI 编码工具直接触达数据库、服务器、日志——把它从一个「代码助手」变成一个真正的「研发工作台」?


一、一个典型的排查场景

假设 QA 提了一个 bug:订单状态在某些情况下没有正确更新。

这时候我们需要放下手上的代码,开始排查:

1
2
3
4
1. 切到 DataGrip → SELECT * FROM orders WHERE id = 12345
2. 看到 user_id = 67890 → SELECT * FROM users WHERE id = 67890
3. 想查这个用户相关的操作记录 → SSH 上服务器 → tail -n 500 /opt/logs/app.log | grep 67890
4. 日志里有一条可疑的 MQ 消息 → 切回代码,定位到消费者逻辑

整个过程,我切换了 3 次工具。每次切换都是一次心流中断。

AI 编码工具能帮我写代码、重构代码,但它碰不到第 1、2、3 步——它不知道数据库里有什么,不知道日志里写了什么。它只能基于我告诉它的信息来推理。而「告诉它」这个动作本身,又回到了手动查数据的老路。

所以核心问题不是 AI 不够聪明,而是 AI 的工具集太窄。它只有读文件、写文件、执行 bash。它需要一套能连接到实际开发环境的工具箱。


二、我想要的不是更强的 AI,而是更宽的工具集

理想状态不是一个「更强的 AI」,而是一个 AI 能触达所有日常工具的环境:

  • 数据库查询就在终端里,写 SQL → 出结果,不用切 DataGrip
  • 日志搜索直接 tail 远程日志,不用手动 SSH
  • 跳板机自动穿透,AI 的 bash 能落到目标机器上
  • 测试数据读表结构自动生成,不用手写 INSERT
  • 接口 Mock 本地起一个 mock server,描述接口即用

这些东西 DataGrip、Kibana、Postman 都能做,但它们分散在不同的窗口里。我要的不是更好的数据库客户端,而是把它们装进同一个终端——那个 AI 已经在帮我写代码的终端。排查问题时,查数据库、看日志、改代码,在同一次对话里完成。

所以我需要的不是「功能更多的 AI」,而是一个能让我自己给它装工具的 AI 编码助手。这导向了技术选型:Pi。这篇文章聚焦数据库能力——日志、SSH、Mock 等后续再展开。


三、为什么是 Pi

Pi 是一个 MIT 开源的 AI 编码 harness——你可以把它理解成 AI 模型和操作系统之间的桥梁:给 AI 读文件、写文件、执行命令的能力,但不过度封装。Claude Code 的子代理、计划模式、权限弹窗在通用编码场景下很有用,但对于「我只想快速查数据、看日志」的工作台来说反而增加了摩擦。Pi 默认只启用 readwriteeditbash 四个工具(另有 grepfindls 可按需开启),其他一切通过 extension 自己造。

Extension API 很克制:

1
2
3
4
5
export default function (pi: ExtensionAPI) {
pi.registerTool({...}); // 注册 AI 可调用的工具
pi.registerCommand({...}); // 注册 / 命令
pi.on("tool_call", ...); // 拦截工具调用
}

我需要的是一个干净的画布,不是一艘已经装了 80% 我用不上的功能的宇宙飞船。Pi 刚好是前者。


四、数据库工作区:/db 命令 + AI 工具双通道

实现的 extension 叫 devops-toolsGitHub)。经过几轮迭代,它现在有两条通道:给人用的 /db 命令,和给 AI 用的 7 个 tool。

命令体系:

1
2
3
4
5
6
7
8
/db                     显示工作区面板
/db add 交互式添加连接
/db switch 选择环境 → 连接 → 数据库
/db tables / schema 列出表 / 查看表结构
/db query [表名|SQL] 执行查询(交互选表 / 表名+WHERE / 直接 SQL)
/db history / favorite 搜索查询历史 / 管理收藏 SQL
/db relations / related 管理表关系 / 浏览关联查询结果
/db on / off 会话内启用 / 禁用扩展

所有状态跨会话保持——切换数据库后下次启动 Pi 还是同一个库。查询历史、收藏的 SQL、注册的表关系都存在本地 SQLite 里。

下面挑几个关键的设计决策展开。


五、命令 + Tool 双通道:分工的原则

自然语言查询最大的成本不是「AI 会不会写 SQL」,而是「AI 要在多大的 schema 里找表」。全量注入 schema 不现实,不注入又全靠猜。这里的解法是:通过 /db switch 选中数据库后,扩展向会话静默注入上下文,告诉 AI 当前的连接和数据库;AI 需要表结构时调 db_tables 实时查询 information_schema。范围被一个选中的库收窄之后,AI 找表、确认列名、生成 SQL 的链路非常短——本质上是把「在一个库里找数据」变成了和「在一个代码仓库里找文件」同构的问题,而后者正是 AI 编码工具最擅长的事。

展示工具内容:

当前注册的 7 个工具:

工具 类型 说明
db_query 只读·常驻 执行只读 SQL(与 /db query 相同的安全限制),默认作用于当前选中的库
db_tables 只读·常驻 列出所有表,或查看单表结构(实时查询,无缓存)
db_mutate ·常驻 执行 INSERT/UPDATE/DELETE/REPLACE,需人工确认(下节展开)
db_tools loader·常驻 按需启用下面 3 个懒加载工具
db_discover 只读·按需 发现可用的连接和数据库(返回脱敏信息)
db_list_relations 只读·按需 列出已注册的表关系,供 AI 自己写 JOIN
db_relation 写(本地 SQLite)·按需 注册 / 删除表关系

后 3 个不常驻是有意为之——全量注册每轮多消耗约 600 tokens,所以做成懒加载:AI 需要时先调 db_tools 启用,下一轮生效。日常查询用不上 db_discover,就不该为它付每轮的 token。

分工原则:

  • 条件明确、SQL 比描述快——走 /db query 命令,一次写完一次执行
  • 探索性的、需要边看边试的——走 tool,AI 自己探表、生成 SQL、执行、基于结果继续推理

「确定性操作走命令,构造性操作走 tool」——查数据在范围限定、schema 实时可获取的前提下,已经被归类为后者。


六、改数据:AI 生成 SQL,人来把关

查数据放开给 AI 之后,改数据是自然的下一步——但它必须有一道人工的门。

db_mutate 把这道门放在了工具自身的执行路径上,而不是依赖 AI 自觉或平台的权限配置:

  1. DML 白名单先过滤。 只放行 INSERT / UPDATE / DELETE / REPLACE,DDL(CREATE/DROP/ALTER/TRUNCATE)直接拒绝,连确认弹窗都不会出现。一个调用只接受一条 SQL,多条改动就多次调用、多次确认。
  2. 弹窗确认不可跳过。 每次调用都弹出 overlay 确认框:操作类型按颜色区分(INSERT 绿、UPDATE 黄、DELETE 红),标明目标 数据库 @ 连接,完整 SQL 逐行展示。Enter 确认,Esc 取消,其他按键全部忽略。UPDATE/DELETE 没带 WHERE 时会醒目警告「将影响表中所有行」——警告不阻止执行,这个判断留给人。
  3. 用户的决定不被缓存。 没有「本次会话不再询问」之类的开关,每条 SQL 独立确认。prompt 里还要求 AI 调用前先解释这次要改什么、为什么——用户看到弹窗时已经有预期,不会对着一条突兀的 SQL 做决定。

两个实现细节值得一提。一是用户拒绝是正常返回,不是异常:取消后工具回给 AI 的是一条普通消息「用户已拒绝变更」,AI 可以接着对话调整方案,而不是收到一个 error 之后不知所措。二是确认逻辑以回调形式注入——核心层不依赖 Pi 的 UI,测试时替换成 stub 即可,这让「每次必须过人」这条规则本身能被单元测试覆盖。

读写是双向分流的:db_query 拒写,db_mutate 拒读,不存在「AI 图省事用查询工具执行写操作」的旁路。


七、安全策略:入口不止一个,但门只有一道

数据库能力的底线从最初的「只能读,不能写」演进成了现在的「读默认安全,写必须过人」。规则不靠 AI 自觉——所有安全检查都在执行引擎的唯一入口处强制执行,AI 工具和人用的命令在底层汇入同一条路径,谁都绕不过。

四道安全检查:

  1. SQL 白名单:只读放行 SELECT/SHOW/DESCRIBE/EXPLAIN,写操作放行 INSERT/UPDATE/DELETE/REPLACE,其他一律拒绝。
  2. LIMIT 自动注入:无 LIMIT 的 SELECT 自动追加 LIMIT 100(可按连接配置)。追加后的 SQL 原样展示,LIMIT 是可感知的,不是隐藏行为。
  3. 密码保护:密码用 ${ENV_VAR} 占位符,启动时从环境变量替换,真实密码不落盘。db_discover 返回脱敏信息,工具描述里明确禁止 AI 读配置文件——密码不进上下文。
  4. 写操作人工门控:上一节的确认机制——每次确认、不可跳过、不缓存决定。

入口不止一个,但门只有一道。


八、自动关联查询:让表关系在查询时生效

多数业务系统已经不设物理外键了——性能考虑、分库分表、历史债务,原因很多。但表之间的逻辑关系仍然存在:orders.user_id 指向 users.idorder_items.order_id 指向 orders.id

这引出了一个常见的开发场景:我查一张表,往往需要同时看几张关联表的数据。

/db relations 子命令解决了这个问题。你只需要注册一次表之间的关系:

1
2
3
4
/db relations add
→ 选择源表:orders,选择源列:user_id
→ 选择关联表:users,选择关联列:id
→ 关系类型:MANY_TO_ONE

之后查询时选择"查询关联表",它就会沿着注册的关系做 BFS 自动联查,主表和关联表分开展示,关联路径一目了然:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/db query orders (勾选"一起查询关联表")

结果:
═══ 查询 — order_db ═══
SQL:SELECT * FROM orders LIMIT 100
行数:12(0.023s)

| id | user_id | amount | status |
|----|---------|--------|----------|
| 1 | 101 | 99.00 | paid |
| 2 | 102 | 150.00 | pending |
...

────── 关联表 ──────

### order_db.users
关联路径:orders.user_id → users.id
行数:2(0.012s)

关联查询结果还可以随时用 /db related 打开一个悬浮层浏览器逐表翻看(←→ 切表、↑↓ 滚动、Esc 关闭),完整的关联数据同时进入 AI 上下文供分析。

关系的来源有三种:手动注册(/db relations add),从 MySQL 的 information_schema 自动发现残留的物理外键(/db relations discover),以及让 AI 分析后补充那些靠列名约定隐含的关系(比如所有叫 user_id 的列大概率指向 users.id)——对应上面的 db_relation 工具。注册过的关系 AI 也能消费:db_list_relations 把关系列表交给 AI,它写 JOIN 时就不需要猜列名约定了。


九、当前状态和后续扩展

目前 devops-tools 实现了数据库的查询和修改(写操作带人工确认),单元测试 241 个用例,另有一套 AI 自动执行 + 人工逐项确认的端到端验证流程。但更重要的是,它验证了一件事:Pi 的 extension 机制足够灵活,可以用来搭建一个完整的研发工作台。

接下来计划扩展的方向,按场景区分操作模式:

工具 状态 模式 说明
数据库查询 ✅ 已实现 命令 + Tool 人写 SQL 或自然语言,范围限定在选中的库
数据库修改 ✅ 已实现 Tool AI 生成 DML,人工确认后执行
日志查询 计划中 命令 SSH tail/grep,人指定过滤条件
跳板机登录 计划中 命令 /ssh <host>,AI 的 bash 自动走 ProxyJump
测试数据构造 计划中 Tool AI 读表结构 → 生成数据 → 批量插入(走确认门控)
接口 Mock 计划中 Tool AI 根据接口描述启动本地 mock server

每个新增的工具共享同一套配置体系和门面接口,可以独立实现、渐进扩展。

这个方案适合日常开发中的快速排查和辅助决策——你不必在所有场景下都用它。大规模数据分析、需要可视化的报表、多人协作的数据探索,DataGrip 之类的专用工具仍然更合适。工作台的意义不是替代专业工具,而是减少切换次数。

如果你也在用 AI 编码工具,而且总觉得有些地方「不连贯」——可能不是你的问题,是工具的设计假设和你的工作流不匹配。Pi 给了你一个机会,让你自己来调这个匹配度。