Datadog 的 Stream Router 团队最近干了一件事:把一套跑在 FoundationDB 上的 KV 路由系统迁移到了 PostgreSQL。你可能觉得这没什么特别的。

但他们用了一个你可能没试过的方法——让 Claude 在测试的约束下写代码。AI 不决定做什么、不决定怎么做,它只负责在测试已经定义好的轨道上执行。

你可能也在想:「用 AI 做代码迁移?不就是给 prompt 让它写吗?」

Datadog 的经历告诉你:不是这样写的。一次关键的生产迁移,操作耗时从 45 分钟降到约 1 秒,存储缩小 40 倍,数据库成本降低 90%。

这组数据来自 Datadog 工程师 Arnold Wakim 最近分享的内部实践。整个迁移的关键不是用了多强的模型——Claude 而已。真正让项目成功的,是他们设计的一套测试驱动 AI 重构的三阶段方法论

一、先看问题:Stream Router 卡在哪了

Stream Router 是 Datadog 指标管线的路由 API,最初基于 FoundationDB 实现 KV 模型。初期跑得挺好,但随着路由表膨胀,问题开始冒出来:

  • KV 数据库开始触及事务大小限制
  • 最耗时的操作因数千次顺序往返,跑到 45 分钟
  • 代码里不得不用应用层逻辑模拟关系数据库的 foreign key 行为——拉几万条 entry 到进程里自己拼

这不是小修小补能解决的了。团队决定重设计 Schema,从 KV 模型迁移到 PostgreSQL 关系模型。

但问题来了:这是一套正在线上的生产系统,新 Schema 定了,旧代码几千行,全手动重写?还是全扔给 AI?

两种都不靠谱。他们选了第三条路。

# Datadog 的三阶段输入模式(伪代码)
def refactor_with_ai(method_name, old_code, new_schema):
    # Phase 1: 让 AI 描述意图
    intent = claude.describe(f"这个 {method_name} 函数的目的是什么?")

    # Phase 2: 测试驱动生成
    failing_test = test_framework.make_test(method_name, new_schema)
    attempts = 0
    while not failing_test.passed and attempts < 3:
        new_code = claude.generate(
            old_impl=old_code,
            new_schema=new_schema,
            failing_test=failing_test
        )
        failing_test.run(new_code)
        attempts += 1
    return new_code

    # Phase 3: Blue/Green 验证交给 infra 层

二、三阶段方法论:不是让 AI 自主编程,是用测试约束 AI

从 Wakim 的分享看,这三个阶段的设计很精准。每一阶段都有明确产出、有检验标准、有人类介入点。

Phase 1:让 Claude 描述意图

第一个阶段不是写代码,而是写描述。对 Stream Router 中每个关键函数,团队先让 Claude 读取旧代码,输出一份自然语言的行为描述——这个函数做什么、输入输出是什么、边界条件有哪些。

这个阶段的价值在于显性化隐性知识。很多函数写了好几年,功能早被人遗忘了。Claude 生成的描述文档充当了后续重构的「蓝图」。

Phase 2:测试驱动代码生成

这是整个方法论的核心。对每个需要重构的方法,团队构造了一个三件套输入:

旧实现          —— 原来的代码,告诉 Claude 当前逻辑
新 Schema       —— PostgreSQL 的表结构定义
一个会失败的测试  —— 用新 Schema 的预期行为写测试

Claude 根据这三个输入写新代码。然后跑测试。通过了?下一个。没通过?调整 prompt 重来。

注意一个关键设计:测试失败不是意外,是工作流的一部分。 团队刻意构造「会失败的测试」作为输入——不是让 Claude 一次写对,而是让测试说话,告诉 Claude 哪里不对。

这跟大多数「给一个 prompt 让 AI 全量生成」的做法完全不同。测试在这里充当了 AI 行为的边界控制器——AI 可以自由发挥,但测试决定了它的输出是否被接受。

Phase 3:Blue/Green 双跑 + 对比验证

代码改完了,但是改对了吗?在传统重构里,这个问题靠人工 Code Review 回答。在 Datadog,答案靠并行验证

两套 Stream Router 实例同时运行——旧的 FoundationDB 版和新的 PostgreSQL 版。同一个请求打到两套系统,各自产生路由响应。

然后一个专门的 Validator 服务在每个集群中周期性地比对新旧两个实例的输出。发现不一致?立刻告警。

Feature Flag 控制客户端流量路由,灰度切流。有问题的切回去修好再切。

这个验证体系的意义在于:它把「AI 写的代码对不对」的判断从人的责任变成了系统的责任。 人只需要在 Validator 告警时介入。其他时候,让系统自己验证。

三、三个使能要素

Wakim 在分享中特别强调了,如果不是这三个要素都已到位,这套方法论跑不起来。

强代码模块化。 Stream Router 在 PostgreSQL 上实现了一套和 FoundationDB 版完全相同的 API 接口。这意味着修改一个后端实现时,调用方代码一行都不需要改。没有这个条件,测试驱动 AI 重构的 scope 会扩大很多倍——改一个方法要牵出一串上下游,测试用例的写法和验证难度都指数上升。

完整测试套件。 这是整个方法论的基石。没有测试,AI 生成代码的「正确性」就只能靠人工审查,退回到了最慢的方式。Wakim 在最后总结时直接说:测试套件的强壮程度,决定了你有多大把握信任 AI 生成的代码。

并行基础设施。 Blue/Green 双跑听起来贵——两套系统同时跑,硬件翻倍。但对一次关键生产迁移来说,这套基础设施省掉的「上线后发现问题→回滚→排查→重试」的成本,远比多跑一套实例高。

四、Claude 做不到的:人类仍然不可替代

这可能是整篇文章里最有价值的部分 —— Datadog 团队坦诚地记录了 Claude 的短板。

「Niche optimizations such as batching, UNNEST tricks, and common table expressions required human input. The AI-generated queries returned the right results but issued far more round trips than necessary.」

翻译成人话:AI 写出来的代码逻辑上是对的,但性能上不行。

Claude 能写出正确的 JOIN、正确的 WHERE 过滤,但不会主动优化查询——不会用 UNNEST 替代逐行处理、不会写 CTE 减少子查询、不会做批量操作减少往返。这些优化需要人类来写第一版。

但好消息是:一旦人类示范过一次优化模式,Claude 能在后续的方法中复现同样的模式。 团队发现,他们手动写完一个优化版后,Claude 在后续类似方法中开始模仿这个模式。

这印证了当前 AI 编码工具的一个普遍规律:AI 是优秀的「模仿者」,但不是「发现者」。 人类负责发现优化模式、设计架构边界、定义验收标准。AI 负责在划定范围内高效执行。

还有一个实用的教训:Token 消耗。 团队把完整的测试输出 dump 喂给 Claude,Token 消耗非常高。Wakim 建议裁剪测试输出后再提交,只保留关键差异部分。

# 迁移效果对比
# 指标              迁移前(FoundationDB)  迁移后(PostgreSQL)
# 操作耗时             45 分钟               ~1 秒
# P99 延迟             数百毫秒              个位数毫秒
# 存储占用              基准                   1/40
# 数据库成本            基准                   1/10
# CPU/内存             高                    显著下降

五、这些经验对你有用吗?

你所在的公司大概率没有 Datadog 那个级别的路由表和 45 分钟的查询。但这套方法论的价值在于它的可迁移性

场景 能借用什么
日常代码重构 给 AI 输入「旧代码 + 新接口 + 失败测试」,让测试当裁判
数据库迁移 Blue/Green 对比验证,Validator 服务比对输出
新项目启模 先测试后代码,不写测试就不让 AI 写代码
代码审查 用测试结果替代主观判断,「通过了就 OK」

三条可以直接抄进团队技术方案的原则:

第一,测试不是验收环节,是执行环节。 大多数人写测试是「验证写完的代码对不对」。Datadog 是先写测试,再让 AI 填代码,测试是 AI 的「工作指令」。

第二,AI 不自主决策。 他们会做什么、要做到什么标准,由人类定义。AI 只在划定好的轨道里执行。这个「人类在环内」的设计,才是生产级 AI 编码的正确姿态。

第三,并行验证是最好的保险。 新系统上线前,新旧双跑一段时间,让系统替你发现差异。不要事后才对比——要在上线前就有对比基准。


这让我想起之前写过的 Spotify 73% PR 由 AI 生成那篇。两篇结合起来看,你会发现一个共同的模式:高效的 AI 编码不是让 AI「干活」,而是让 AI「在测试的约束下执行」。 成功的团队都在做同一件事——把 AI 的「创造力」缩小、把 AI 的「执行力」放大。

如果你所在的团队也在尝试用 AI 做代码重构或生产迁移,不妨试试这套三阶段方法论。先写一个会失败的测试,再把代码交给 AI——让测试说话,你只做裁判。

更多推荐