diff 只告诉你 agent 改了什么,没告诉你它漏了什么

小岛AI 2026 / 07 / 13

一座深夜的城市,大部分街区泡在黑暗里,只有几片地方亮着灯。有的泛着苔藓一样的绿,有的亮成月光的白,还有几小块烧成暖琥珀色。

这不是哪座城市的卫星图。这是一个代码仓库,亮着的地方,是编码 agent 刚才摸过的文件。

这两天 Hacker News 上刷到一个开源项目,叫 Mindwalk,干的就是上面这件事,把 Claude Code 和 Codex 的会话日志,回放到你代码库的 3D 地图上。作者 cosmtrek,写 Go 的朋友对这个 ID 应该不陌生,那个几乎人手一份的热重载工具 air 就是他做的。仓库 7 月 9 号才建,四天 369 个 star,冲上了 HN 热门。

我跟你说,这个项目戳中的那个痛点,可能比它的 demo 还值得聊。

先把痛点摆出来。你让 Claude Code 或者 Codex 干一个活,改个 bug,加个接口,全程你能看到什么。它刷刷刷地调工具,读文件,跑命令,滚动条一路往下飞,最后甩给你一个 diff。你 review 这个 diff,逻辑没毛病,测试也绿了,合并。

但有个问题一直悬在那儿,它改这几行代码之前,到底看了多少东西。

它是把整个模块摸了一遍才动的手,还是 grep 到第一个匹配就开改。你以为它理解了整条鉴权链路,也许它只读了那个函数上下十行。你以为它检查过调用方,也许有个藏在另一个目录里的调用点,它压根不知道存在。diff 只告诉你结果,不告诉你理解。你验收的是货,看不见航线。

有人会说,会话日志不是全都记着吗。对,~/.claude/projects 底下一堆 JSONL(一种一行一条 JSON 记录的日志格式),agent 的每次搜索、每次读文件、每次编辑都在里面,一个字不落。但你自己想想看,你真的会一行一行去读那玩意吗。一个稍微复杂点的任务,日志几千行起步,工具调用套着子 agent,读起来跟盯着别人家的 strace 输出差不多。记录是全的,可读性是零。

我的日常工作是给大模型搭脚手架,就是让 agent 真正能干活的那层工程,工具怎么接,上下文怎么管,跑挂了怎么重试。这种活干久了会落下职业病,特别在意 agent 的行为轨迹,而不只是产出。产出可以蒙对,轨迹蒙不了。所以刷到 Mindwalk 的时候,我第一反应是,好家伙,这个方向终于有人动手做了。

Mindwalk 的思路一句话能讲完。把仓库画成一张夜景地图,把 agent 的会话当成光,在地图上放出来。它搜过、读过、改过的地方会亮,没碰过的地方保持黑暗。任务结束,你看一眼光斑的形状,agent 对这个任务的理解范围,就成了一个肉眼可见的东西。

具体的亮法是有讲究的。每个文件记住它被碰过的最深一层状态。只在搜索结果里露过脸的,亮苔藓绿。内容真的被读过的,亮月白色。被动手改过的,烧成暖琥珀。从头到尾没被理会的,黑着。四种状态叠在同一张图上,你扫一眼就知道,这次任务 agent 的脚印踩到了哪里,哪些地方它自以为不用去。

地图本身有两种画法。一种是径向树,仓库目录像年轮一样一圈圈铺开。另一种是 treemap 平原(把树形结构画成嵌套矩形、面积对应体量的可视化,Ben Shneiderman 九十年代发明的老手艺),整个仓库摊成一片地形。前端是 React 加 Three.js,后端一个 Go 二进制,装完什么参数都不带跑一下,它自己扫描本地的会话目录,起一个本地端口,浏览器就打开了。所有数据都在本机处理,一个字节都不出网。这个年头,一个读你全部会话日志的工具,肯把「fully local」写进 README 第一屏,算是基本礼貌了。

Mindwalk 的 terrain 视图,橙色是被改过的文件,蓝白是读过的,大片深色是 agent 从没去过的地方

光会亮还只是第一层。往下玩,底部有一条播放条,整个会话被切成一格一格的直方图,颜色排在一条冷暖光谱上。观察类的动作是冷色,搜索、读文件、跑命令都算。动手改代码是暖色。你按下空格,光开始在地图上流动,agent 先在哪儿转悠,转了多久才下手,改完又跑去哪儿确认,节奏全在里面。一个健康的会话,冷色打底,暖色一小撮。要是通篇暖色,上来就一顿猛改,你心里就该咯噔一下了。

再往下还有一层。时间轴上撒着几种记号。菱形是上下文压缩,就是 agent 聊太久,记忆装不下了,把前面的对话压成一份摘要接着干,压缩前后它对任务的记忆可能悄悄变形,这是老 agent 用户都懂的暗坑。圆圈是子 agent 启动,箭头是用户插话。每个记号都能点,点了播放头直接跳到那个时刻。还有快捷键,按 E 跳到下一次编辑,按 X 跳到下一个报错。X 这个键怎么说呢,有点子牛逼,等于给会话日志装了个「直接快进到事故现场」的按钮。

界面角上还折着一条 review 带,把几个摩擦信号收在一起,错误率,被反复改动的文件,还有最后一次验证之后又发生的修改。最后这个信号我愿意单独夸一句。跑完测试再手痒改两行,不重新跑就交货,写代码的都知道这是事故高发区。现在 agent 也会犯一模一样的毛病,而这个信号在 diff 里是完全隐形的,你只有回放时间线才能看见。

炫酷的部分说完了,拆开看看里面。Mindwalk 内部刻意分成两个独立的抽象,一个叫 trace,一个叫 citymap。

trace 是把会话日志规范化成一条有序的文件触碰事件流。Claude Code 的日志格式一个适配器,Codex 的格式一个适配器,进来之后长一个样。这层设计的意思是,明天再冒出来一个新的编码 agent,写个适配器就能接进来,可视化那头一行不用改。

citymap 是仓库的确定性布局。同一棵目录树,永远画出同一张地图。

我觉得这个「确定性」是整个设计里最值钱的一笔,比 3D 效果值钱。地图不变,光才有得比。同一个任务,你换个 prompt 再跑一遍,或者换个模型再跑一遍,两次的光斑印在同一张地图上,形状一对比,理解范围的差异直接浮出来。哪个模型摸得广,哪个 prompt 让它漏掉了整个目录,不用再靠体感争论,看图。这一步等于把「agent 理解了什么」从一种玄学感受,变成了一个可以比较的形状。

做评测的朋友应该已经闻到味了。这玩意往前再走一步就是回归测试。光斑覆盖率,触碰深度,观察和修改的比例,压缩发生的次数,全都可以变成指标进 CI。作者把两份 JSON 的 schema 都公开在仓库里,摆明了欢迎别人拿去接自己的管子。

顺着这个再聊聊,为什么我觉得 agent 可观测性这个方向,接下来会从「有意思」变成「刚需」。

前两天刚出过一档子事,xAI 官方的 Grok CLI 被安全研究者抓包,每轮任务前后把用户整个工作目录打包上传。先不谈那件事本身的是非,它暴露的底层现实更扎心,agent 在你机器上干了什么,默认状态下你是不知道的。你给了它读写权限,给了它网络,然后只验收结果。中间那一大段,全靠信。

我们这个行业花了几十年给代码建可观测性。日志,指标,分布式追踪,一个请求穿过十几个微服务都能还原现场,出了事故有 timeline 可以复盘。现在,写代码这个动作本身正在交给 agent,而对应的可观测性,几乎是零。大家盯着跑分看模型能力,盯着 diff 看产出质量,中间那层「它是怎么工作的」,长期处于没人看也没法看的状态。Mindwalk 补的就是这一块,而且姿势很聪明,它没有发明新的埋点,日志本来就在你磁盘上躺着,它只是让这些日志第一次变得能看。

光走过的地方是航线,黑着的地方是它没去过的海域

说实话,我还没装。README 里那个三十秒的 demo 我看完了,文档和仓库结构也翻了一遍,但自己机器上的会话还没喂进去。周末打算把最近几个 Claude Code 干的活回放出来,看看它在我那些仓库里到底是精读还是跳读,这段等我真跑过再写,不编。

也得说句丑话,这东西的命运有可能是当三天玩具。3D 可视化项目多少都有这个宿命,demo 惊艳,装上玩两个晚上,然后再也没打开过。飞线图、词云、代码城市,前辈们的坟头草都挺高了。但 Mindwalk 让我愿意多看两眼的地方在于,就算那个夜景 UI 最后落了灰,trace 和 citymap 这两个抽象也值得留下来。schema 是公开的,确定性布局是可复用的,换个人拿去做成 CI 里一个不起眼的检查项,价值一点不少。工具会腻,数据不会。

回到开头那张深夜的地图。光走过的地方,是 agent 的航线,黑着的地方,是它没去过的海域。以前我们只能检查船带回来的货,现在终于能看见航线本身了。

你天天让 agent 出海,是时候看看它的航线了。