AI
给 AI 发工具的一周:从浏览器桥到表格打印
最近一周连续做了五个小项目:browser-bridge、mcp-coding、ai-sessions、ai-models、printable。主线只有一个——与其替 AI 写流程,不如给 AI 发趁手的工具。
翻了下 GitHub 的提交记录,8 月中下旬这十来天,我几乎每天都在往不同的仓库推代码,粗看很散:浏览器扩展、MCP 服务器、Go CLI、Python 性能优化。但串起来其实只有一条主线:
与其替 AI 写流程,不如给 AI 发趁手的工具。
具体就是五个项目,正好构成一个小闭环:AI 用 browser-bridge 看真实网页,用 mcp-coding 改代码;我用 ai-sessions 复盘 AI 干得怎么样,用 ai-models 挑该用哪个模型;最后所有输出交给 printable 打印得整整齐齐。
一、browser-bridge:把我的浏览器借给 AI
这个项目的深层成果是,知道了如何从外部和浏览器通信交互,不再让浏览器成为不可触碰的孤岛。
普通的爬虫:
- 没有登录态,每个站点都得想办法塞 cookie;
- 反爬一抓一个准,Cloudflare 盾页都过不去;
- 验证码只能干瞪眼。
换个思路呢?别造假浏览器,直接用我正在用的这个。 登录态天然就有,验证码我顺手点一下就行,指纹就是真人的指纹。
于是有了 browser-bridge,三层结构:
- 浏览器扩展:注入页面拿 DOM 快照,监听指令;
- Native Host:扩展和本机进程之间的桥,Chrome官方开的口子;
- MCP Server:对上暴露标准 MCP 协议,任何 MCP 客户端(Claude Code、Codex、curl)都能连。
AI 拿到的是 browser_snapshot / browser_click / browser_type / browser_extract 这样一组工具,操作的就是我眼前这个真实的浏览器标签页。
之前 Claude、Codex的浏览器扩展配合 App工作,估计也是这个原理,但是它不开放呀,只能它自己用。
设计里我最得意的是跟随模式:不指定目标时,AI 自动控制当前激活的标签页。我在哪个页面上,AI 就在哪个页面上,零配置。想让它去别的页,切过去就行——控制权和知情权始终在我手里。
两个省 token 的细节:
browser_extract把正文抽出来转成 Markdown,读文章比全量 snapshot 便宜一个量级;- 截图落到本地缓存目录返回路径,AI 按需再读,而不是每步都塞一张图进上下文。
为了便于其他可能感兴趣的用户,配置 Github CI 矩阵出各平台压缩包,用户解压跑一个 install-host.sh 就完事。目前 v0.1.2,开源在 GitHub。
二、mcp-coding:一次调用改十个文件
第二个项目解决的是另一个日常摩擦:AI 改代码太"碎"。
内置的编辑工具基本是"一次一处",跨五个文件的重构就是五轮工具调用,五次往返、五次上下文膨胀。更难受的是失败恢复——改到第三个文件发现第一处匹配错了,前面已经落盘的怎么办?
mcp-coding 是我的答案:一个 MCP 服务器,只暴露一个工具 edit_files,吃一种自定义的行导向文本协议:
! src/legacy.go # 删除文件,位置无关,写在哪都行
> src/main.rs => src/app.rs # 移动/重命名,后面还能接着编辑
@func main() { # 锚点:从这行之后开始匹配
- x := compute(1) # - 定位并删除(前导空格是缩进)
+x := compute(1) * 2 # 紧跟 - 的 + = 替换该行
- println("done")
~"done"|->|"all done" # 行内替换,原行保留不删
> impls.rs
pub struct Queue { # 空格开头 = 上下文行:参与匹配但保留,用于消歧
- fn push(&self) {}
+ fn push(&self) -> bool {}
> src/config.go
:42 # 行号定位:直接跳到第 42 行
-timeout = 30
+timeout = 60
$ # EOF 锚点
+// appended at end # $ 后的 + = 追加到文件尾
> CHANGELOG.md # 文件不存在则创建
* # 全文重写,其后所有 + 行为新内容
+# v0.2.0 # 内容以 # 开头,用 + 转义
+- edit_files 协议化 # 同理,+- 插入 "- edit_files 协议化"
一个 patch 同时覆盖:删文件(!)、移动重命名(=>)、文本锚点(@)、行号跳转(:42)、删改块(-/+)、上下文消歧行(空格开头)、行内替换(~)、尾部追加($ 后接 +)、新建并全文重写(*)。关键性质有三条:
- 原子性:整个 patch 先全部验证,任何一行匹配失败就整体拒绝、零修改,报错里带文件名、行号和当前内容;
- 模糊降级:auto 模式下精确匹配失败会依次尝试忽略尾空白、忽略首尾空白、Unicode 归一,降级了会明说,膨胀行直接拒绝;
- 歧义拒绝:锚点命中多处时不猜,列出所有候选行号让你消歧。
协议本身写了 ABNF 规范,配了单元、回归和 stdio 冒烟测试。现在我日常写代码就挂着它。
三、ai-sessions:随时查看 agent 对话历史
工具发出去之后,新问题来了:AI 用这些工具干活的完整过程,散落在各家客户端自己的存储里——Codex 是 sqlite,Claude 和 Qoder 是 JSONL,格式互不相通,出了问题根本没法回看。
ai-sessions 把它们统一解析掉:
ai-sessions # 列出今天的会话索引
ai-sessions -q tantivy # 全文过滤:哪次对话提过这个词
ai-sessions -i 019abc -t 2 # 某个会话第 2 问的完整详情
ai-sessions -i 019abc --think # 连中间思考过程一起看
最有用的其实是 token 统计:Claude/Qoder 从 usage 字段汇总,Codex 能算出缓存命中率。哪类任务烧钱、哪个 prompt 让 AI 绕了远路,数据说话。
四、ai-models:选模型不拍脑袋
复盘之后自然要选型。新模型层出不穷,榜单满天飞,但榜单和我实际的编程场景经常对不上。
ai-models 直接拉 OpenRouter 的实时数据,按编程评分(coding_index)筛:
ai-models -free # 免费模型里能打的
ai-models -trend -limit 30 # 最近一周大家实际在用什么
ai-models -model deepseek/deepseek-v4-flash-0731 # 同一个模型在各渠道的价格对比
-aa 选项还可以拉 artificialanalysis.ai 的评分交叉验证。选模型从"听说很强"变成"查一下再定"。
亮点是,我让 AI 设计了公式来计算总分,用于排名。其中有些常量,我用 ai-sessions 输出我的日常使用统计,喂给 AI 之后定出来的,也算更贴近真实使用情况。
这个命令的表格输出,使用了 go-column,和接下我要讲的 printable 共享了c底层实现。
五、printable:老项目焕发新春
前四个都是新项目,最后这个是个老朋友:printable,一个打印表格数据的 Python 库 + CLI(pip install printable),支持中英文混排对齐。
这周回头性能优化了一波。思路是把宽度计算和渲染下沉到 C,编成共享库:
| engine | input | median (ms) | speedup |
|---|---|---|---|
| Python | rows | 80.32 | 1.00x |
| Python + C width | rows | 28.37 | 2.83x |
| Go column | []byte |
14.10 | 5.70x |
5000×6 中英混合行,纯 Python 80ms,Go 走 C 实现只要 14ms。有意思的地方在于一份 C 实现喂三家人:Python 走 ctypes,Go 通过 cgo binding 复用同一个 .so,谁也不用重新实现一遍 UTF-8 宽度计算。
而不带线框的表格渲染使用的 linux 上的 column 命令底层实现 util-linux,借力打力。
打包也顺带清理了:wheel 里不再带 .c/.h 源码、输入走内存文件、为各个平台输出单独的更小体积的 wheel 包。现在 PyPI printable v0.5.0。
效果如下,
$ printable -f samples/klines-qqq.json
date open high low close volume dividends stock_splits capital_gains
2026-07-06T00:00:00-04:00 719.93 726.08 718.45 722.82 30220400 0.0 0.0 0.0
2026-07-07T00:00:00-04:00 714.17 716.35 704.9 709.43 42483100 0.0 0.0 0.0
2026-07-08T00:00:00-04:00 704.95 712.26 700.91 711.44 35603200 0.0 0.0 0.0
2026-07-09T00:00:00-04:00 718.33 724.23 715.13 723.28 33654700 0.0 0.0 0.0
2026-07-10T00:00:00-04:00 720.7 726.39 717.0 725.51 26415900 0.0 0.0 0.0
2026-07-13T00:00:00-04:00 717.72 718.74 710.08 711.74 36552400 0.0 0.0 0.0
2026-07-14T00:00:00-04:00 720.22 722.29 714.34 719.69 29448100 0.0 0.0 0.0
2026-07-15T00:00:00-04:00 723.85 724.36 710.23 717.74 32627600 0.0 0.0 0.0
$ printable -f samples/klines-qqq.json --grid full
┌───────────────────────────┬─────────┬────────┬────────┬────────┬──────────┬───────────┬──────────────┬───────────────┐
│ date │ open │ high │ low │ close │ volume │ dividends │ stock_splits │ capital_gains │
├───────────────────────────┼─────────┼────────┼────────┼────────┼──────────┼───────────┼──────────────┼───────────────┤
│ 2026-07-06T00:00:00-04:00 │ 719.93 │ 726.08 │ 718.45 │ 722.82 │ 30220400 │ 0.0 │ 0.0 │ 0.0 │
├───────────────────────────┼─────────┼────────┼────────┼────────┼──────────┼───────────┼──────────────┼───────────────┤
│ 2026-07-07T00:00:00-04:00 │ 714.17 │ 716.35 │ 704.9 │ 709.43 │ 42483100 │ 0.0 │ 0.0 │ 0.0 │
├───────────────────────────┼─────────┼────────┼────────┼────────┼──────────┼───────────┼──────────────┼───────────────┤
│ 2026-07-08T00:00:00-04:00 │ 704.95 │ 712.26 │ 700.91 │ 711.44 │ 35603200 │ 0.0 │ 0.0 │ 0.0 │
├───────────────────────────┼─────────┼────────┼────────┼────────┼──────────┼───────────┼──────────────┼───────────────┤
│ 2026-07-14T00:00:00-04:00 │ 720.22 │ 722.29 │ 714.34 │ 719.69 │ 29448100 │ 0.0 │ 0.0 │ 0.0 │
├───────────────────────────┼─────────┼────────┼────────┼────────┼──────────┼───────────┼──────────────┼───────────────┤
│ 2026-07-31T00:00:00-04:00 │ 692.11 │ 695.77 │ 680.05 │ 687.99 │ 50540500 │ 0.0 │ 0.0 │ 0.0 │
├───────────────────────────┼─────────┼────────┼────────┼────────┼──────────┼───────────┼──────────────┼───────────────┤
│ 2026-08-03T00:00:00-04:00 │ 688.3 │ 701.59 │ 685.82 │ 700.07 │ 44814900 │ 0.0 │ 0.0 │ 0.0 │
├───────────────────────────┼─────────┼────────┼────────┼────────┼──────────┼───────────┼──────────────┼───────────────┤
│ 2026-08-04T00:00:00-04:00 │ 708.205 │ 720.37 │ 707.59 │ 720.36 │ 30269963 │ 0.0 │ 0.0 │ 0.0 │
└───────────────────────────┴─────────┴────────┴────────┴────────┴──────────┴───────────┴──────────────┴───────────────┘
写在最后
回头看这五个项目,没有一个是"AI 应用"——没有 prompt 工程,没有 agent 框架,全是朴素的小工具。但它们共同回答了一个问题:怎么让 AI 在我的环境里干活更顺手?
- 它要看网页 → 给它 browser-bridge;
- 它要改代码 → 给它 mcp-coding;
- 我要检查它的活 → ai-sessions;
- 我要挑模型 → ai-models;
- 结果要给人看 → printable。
AI 的能力上限是模型厂商的事,我能做的是把它脚下的路铺平一点。工具配置对了,同样的模型干出的活就会不一样。