一个开源小工具,通过分析 Git 提交、Agent 日志、DevLake 数据来回答「团队是否真的因 AI 提速了」这类棘手问题。
每隔几个月,我都会发现自己处于某种版本相同的对话之中。
一个团队使用 AI 编程工具已经有一段时间了。兴奋之情已经冷却为一个更实际的问题:我们到底从中得到了什么?
这是一个合理的问题。领导者已经购买了许可证,团队已经改变了习惯,最终有人必须解释这是否有帮助。尴尬的是,常见的答案并不能让人满意。席位数量说明谁有权限。调查说明人们的感受。供应商仪表盘说明某个工具被打开了。
这些都不能告诉你代码库里实际发生了什么。
这就是我构建 whodunit 的原因。它是一个小型开源工具,用于从已有证据回答 AI 采用问题:git 提交、本地 agent 日志,以及如果你想要共享视图,还可以使用 DevLake 的交付数据。
目标不是让 AI 看起来更好。而是让那些说法更难被滥用。
人们实际会问的问题
这些是我从客户和工程领导者那里不断听到的问题。
我喜欢这个列表,因为它是诚实的。这不是一个精心包装的战略演示文稿。这是人们在尝试理解一项真实投资时会问的问题。
这些问题中,有些是可以回答的。有些是部分可回答的。其中那个关于生产力百分比的问题,是我在处理时最谨慎的一个。
whodunit 添加的小东西
whodunit 在提交中添加了一个简单的 git trailer:
AI-Attribution: v=1; status=assisted; method=intersected; agent=claude-code; agent_version=2.1.228; ratio=0.62; model=claude-opus-5; session=a3f9e21c
这个格式没有什么神奇之处。这正是重点。它只是 git 元数据,任何能读取提交信息的工具都可以读取。
trailer 记录了提交是否由 AI 辅助、涉及哪个 agent、报告了哪个模型,以及证据有多强。最强的方法是 intersected,意味着 agent 产生的文本存活到了暂存区。
当证据缺失时,whodunit 也会记录下来。它使用 undetermined 而不是悄悄地决定"没有使用 AI"。缺失和零之间的区别是整个工具建立的基础。这个区别比听起来更重要。缺失的信号不是零。它只是缺失。
一屏答案

执行仪表盘是给那些不会打开其他页面的人看的。它在一个地方显示辅助提交、覆盖率、接受率、活跃会话和交付对比。
那个页面上最重要的数字不是最耀眼的那个。是覆盖率。
覆盖率告诉你有多少提交历史有有效的归属 trailer。采用率告诉你有多少被覆盖的历史是辅助的。这是不同的说法,混淆它们是糟糕的 AI 指标的起点。
一个团队可能覆盖率很高但采用率很低。这是一个有效的发现。这意味着仪表正在工作,而证据表明 AI 在已提交的工作中并没有出现太多。
一个团队也可能覆盖率很低但采用率数字很漂亮。这个应该让你暂停思考。
采用率是一个分布,不是一句口号

当有人问"团队是否在采用这个?"时,团队平均值是不够的。
我想知道采用率是在整个团队中分布的还是仅由两个人支撑的。我想知道谁完全没有辅助提交。我想知道数据是否覆盖了足够的仓库区域以信任这个答案。
这就是为什么采用率视图在覆盖率旁边显示贡献者分布。贡献者身份来自提交中已有的 git 提交者邮箱。whodunit 不是在监视开发者。它是在让现有的提交元数据更容易阅读。
有一个值得温和但明确指出的问题:时钟从仪表安装时开始计时。
如果你的团队在安装钩子之前已经使用 AI 六个月了,那六个月并不能神奇地恢复。whodunit 可以告诉你 trailer 开始出现后发生了什么。要获得真正的"前后"故事,请在推广前使用 dun baseline capture 捕获基线。
错过了那个窗口,你仍然可以学到很多东西。只是你要对测量从哪里开始保持诚实。
"他们用得好吗?"只有部分可衡量

这个问题很快就会变得不舒服。
人们问开发者是否了解压缩、是否选择了正确的模型、是否使用了 skills 和 sub-agents、是否将日常工作变成了好的 AI 工作流。我理解他们为什么问。培训预算取决于此。
但我不认为仪表盘应该假装从记录中读取能力。
whodunit 能展示的是会话形态。会话只涉及对话吗?它调用工具了吗?它编辑文件了吗?它使用了很多工具还是 MCP 调用?使用了哪些模型?会话有压缩吗?
这给你提供了一个有用的代理指标,用于区分"只是在聊天"和"使用 agent 工作"。它不能告诉你开发者是否擅长使用 AI。那仍然需要人工上下文:配对、辅导、代码审查和对话。
我宁愿让那个边界保持可见,而不是构建一个不该被信任的置信分数。
AI 在工作中出现在哪里

对于"AI 是用于功能、测试、文档还是修复?"这类问题,whodunit 依赖提交前缀和路径启发式。
这很有用,但前提是你的仓库给了工具一些像样的东西来处理。如果你的团队使用 Conventional Commits,一个 feat: 提交是一个很好的信号。如果你的团队不使用,即使人们整周都在交付功能,功能面板也会看起来空荡荡的。
所以我把目的当作一个标签,而不是一个观察。
这是项目中反复出现的主题:图表应该说它知道的,同样重要的是,它不知道什么。
自主权改变了会话的形态
自主权比我预期的更有趣。
不同的工具有不同的权限词汇。Codex 可能报告像 never 和 on-request 这样的模式。Claude Code 可能报告 acceptEdits、default 或 auto。whodunit 保留这些名称,而不是假装它们都能整齐地映射到同一个阶梯上。
有用的问题不仅是"人们给予自主权的频率是多少?"还有"一旦给予了,发生了什么?"
根据我的数据,高自主权会话更少,但密度更高。每个会话的工具调用数比原始会话数更好地捕捉了这一点。不过,我在解读时要小心。允许更多操作的模式自然会生成更多操作。工具调用是活动,不是交付的价值。
每个人都想要的生产力数字

这是启动整个事情的问题:
告诉我采用 AI 后的生产力提升。
我希望这个数字能够更诚实地产生。那会让会议更短。
问题是有辅助和无辅助的工作不是随机分组。开发者选择何时使用 agent。他们可能用它来处理更大的变更、重复的迁移、不熟悉的代码、测试或他们已经知道如何委托的工作。
所以如果有辅助的提交更大,这证明了什么?
也许是 AI 帮助人们承担了更大的工作。也许是它鼓励了更大的差异。也许人们只是在不同类型的任务上使用了它。同一个图表支持所有三种说法。
这就是为什么 whodunit 显示比较,而不是生产力增益。当交付数据连接时,它可以显示变更大小、变更率、接受率、目的、采用率和周期时间差异。它不应该把这些变成一个百分比然后称之为 ROI。
基线有帮助。如果在安装钩子之前捕获了采用前的窗口,dun delta 可以将那个时期与后期进行比较。这比在同一时期内比较有辅助和无辅助的提交要强得多。
这仍然是观察性的。团队会变,代码库会变,项目会变。基线给你一个更好的对话,而不是实验室实验。
这听起来可能不令人满意。在实践中,我认为这是一种解脱。它让你可以说:"这是移动了的,这是没有移动的,这是我们不能诚实声称的。"
我试图避免的错误
最大的指标错误通常是奉承性的。
空不是零。如果 agent 没有报告令牌使用量,显示零会使它看起来是免费的。如果提交没有归属证据,将其视为"非 AI"会使采用率看起来比证据允许的更干净。
令牌不是美元。记录不知道某人是在使用订阅、企业合约还是 API 计费。whodunit 报告令牌和缓存行为。它不会捏造价格。
缓存写入要计数。缓存读取比率应该包括未缓存输入、缓存写入和缓存读取。漏掉写入让我早期的一个分析看起来比实际好得多。
修复率不是缺陷率。标记为 fix 的提交是重新工作的代理。它们有用,但不能证明 AI 导致了或防止了缺陷。
差异不是增益。这是我一直回顾的一点。如果组是自选择的,比较可以有用但不是因果的。
这些都不会使工具变得不那么有用。它使工具更安全地使用。
有两个部分。

在高层面上,whodunit 将敏感工作保持在本地。开发者机器读取 git 和本地 agent 日志,将归属戳入提交,并保留本地日志。只有在有人选择将 whodunit_* 表同步到可选的 DevLake 层时,团队才能获得共享仪表盘。
第一部分是 dun,一个在本地运行的 Go CLI:
cd your-repo
dun init # 安装 git hooks
git commit ... # trailer 自动被戳入
dun status # 覆盖率和方法的混合
dun report # 本地 HTML 报告
收集是本地的。hooks、守护进程和 ingest 命令读取 git 加本地 agent 记录,并写入本地 SQLite 日志。dun report 渲染一个独立的 HTML 文件,不需要服务器或网络调用。
第二部分是可选的:对于想要共享视图的团队,使用 DevLake 和 Grafana 层。whodunit 写入自己的 whodunit_* 表,并保持 DevLake 的领域表不变。如果 DevLake 已经是你交付指标的所在地,这可以让归属位于它们旁边,而不是创建另一个技术栈。
目前支持的适配器是 Claude Code、Codex CLI 和来自 Antigravity 的 agy。每个 agent 记录不同的内容,whodunit 保持这些差异可见,而不是将它们平滑掉。
收集路径不进行网络调用。
有两个值得命名的身份信息:
文件路径,因为它们揭示了某人工作了什么。
提交者邮箱,因为共享仪表盘需要将工作归属给贡献者。
两者都已经存在于开发工作流程中或周围。除非你配置了同步,否则两者都保持在本地。
日志没有 prompt 文本、消息内容、文件内容、主机名或远程 URL 的字段。这不是一个过滤承诺。这是一个架构选择。那些值没有地方可放。
我构建 whodunit 是因为我想在会议室里有一个更好的答案。
不是一个更大的答案。不是一个更漂亮的答案。是一个更诚实的答案。
十一个问题中的大部分都可以从提交和本地记录中回答。采用分布、模型组合、接受率、自主权、变更率、目的和覆盖率都可以用真实的分母来衡量。当交付数据连接时,周期时间也可以衡量。
但开发者是否真正理解压缩或模型选择,数据中是没有的。人们想要的干净的生产力百分比,除非你愿意悄悄地做出假设,否则是不存在的。
我不愿意悄悄地做出假设。
所以工具显示差异,打印分母,并留出争论的空间。这是我最在乎的部分。如果指标逻辑是错误的,我想知道。如果 1.25 倍的缓存写入盈亏平衡点是错误的,告诉我。如果有更好的处理选择偏差的方法,我真的很想听听。
重点不是赢得 AI 采用的故事。
重点是让故事足够健壮以至于可信。
代码:github.com/navjyotnishant/whodunit 文档:navjyotnishant.github.io/whodunit