{"id":"2000733","slug":"rss-39d4b4e80178ce","title":"如何在“不能出错”的系统里使用 AI Coding？分布式存储实践与边界","summary":"AI 能让代码写得更快，但在「不能出错」的分布式存储系统里，如何确保提效不变成风险？本文结合美团基础技术部在 AI 评审、问题排查和自动化开发中的真实实践，分享 AI 能帮上什么忙、容易在哪些地方犯错，以及哪些地方仍需要人来把关。比「多写代码」更重要的，是让代码和结论经得起验证。希望这些经验能为复杂系统中的 AI 应用提供参考，在享受效率提升的同时，守住质量与稳定性的底线。\n\n1. 背景：为什么分","topic":"大厂分享","kind":"doc","language":"zh-CN","source":"美团技术团队","source_url":"https://tech.meituan.com/2026/10/29/AI-Coding-IN-Distributed-Storage-System.html","license":"原文版权，转载需授权","updated_at":"2026-11-07T13:55:30.266Z","word_count":4079,"url":"https://knowledgehub.wujiss.com/a/rss-39d4b4e80178ce","sections":[{"heading":"","text":"AI 能让代码写得更快，但在「不能出错」的分布式存储系统里，如何确保提效不变成风险？本文结合美团基础技术部在 AI 评审、问题排查和自动化开发中的真实实践，分享 AI 能帮上什么忙、容易在哪些地方犯错，以及哪些地方仍需要人来把关。比「多写代码」更重要的，是让代码和结论经得起验证。希望这些经验能为复杂系统中的 AI 应用提供参考，在享受效率提升的同时，守住质量与稳定性的底线。 1. 背景：为什么分布式存储需要更审慎地使用 AI Coding 今年年初以来，随着Agent的普及，AI Coding 在功能开发、测试生成、脚本编写和执行、问题排查这些场景里都已经用得上了：读代码更快，实现和测试可以先让它写一版，研发之外的一部分杂活也能交给它去跑。 效率上去了，质量上的账也要重新算。同样的人力，一个版本里能交付的功能更多，改动的代码也更多，就算 AI 写的代码千行缺陷率和人写的持平，一个版本累计引入的缺陷绝对数量照样会涨。所以 AI Coding 的目标不能只是更快地写代码，提速的同时，代码质量和验证充分性还得比常规研发要求得更高。 分布式存储把这个问题放大了。代码规模大，模块之间关系复杂，一致性、并发、持久化、故障恢复和性能每一项都碰得到。一处看上去很局部的改动，平时可能一切正常，等到节点重启、磁盘异常、网络抖动或者高并发的时候才暴露出来。出了问题，受影响的也不会只是某一个功能，而是上层业务的数据可用性和系统稳定性，严重时还会波及数据正确性。存储服务支撑着大量上层业务，故障影响面大，修复也困难，对缺陷的容忍度极低。 要满足这样的质量要求，光让 AI 生成代码不够，AI 评审（Code Review）、AI 测试与验证、AI Debug 和受控自动化也得一起建起来，AI 生成的代码才能放心地进入研发流程。本文结合存储团队在 AI 评审、AI Debug 和 AI 自动化上的实践，讨论在分布式存储这类复杂度高、容错低的系统里，怎样一边用 AI 提速，一边靠更严格的评审、测试、调试和自动化验证守住稳定性与数据正确性，希望对其他类似系统落地 AI Coding 也有参考价值。 2. AI 评审（Code Review）：有益补充，但不能替代人对设计背景的判断 例：ENABLE_UNITTEST 在三处调用点控制测试 mock 变体的编译分支，但 CMake 迁移把这个名字换成了 WITH_UNITTEST，旧名字再也没被赋过值。单看任何一个文件都挑不出毛病，这个 bug 只存在于文件和文件之间的落差里。 例：AI 指出“这里没做边界检查”之后没有停下，接着构造了一个声明 1 GiB 数值、实际包体只有 5 字节的畸形包，打到真实的解码入口，把崩溃现场抓了出来。 例：一处疑似的并发竞态，AI 只能靠代码走读找到可疑路径。它明确说，要证实这段交错时序需要 ThreadSanitizer，而当前的工具链跑不了，于是把这条标成“未验证”，没有直接定性为缺陷。 例：一处“先读校验、再写推进”、中间没有互斥的更新，多次评审都稳定地识别了出来，给出的修复方向也一致（合并成单个原子操作）。这类常见的并发模式识别得很稳，可以固化成固定检查项。 例：一次重构把某个接口合并成单次 RPC，顺手删掉了成功后清理本地缓存的旧逻辑。AI 指出这会留下一个短暂的时间窗口，期间可能读到过期的旧数据。而人对被删掉的行，本来就最不敏感。 例：评审之前，AI 会先分析存量代码。改动较大的 PR 里，新代码可能顺手修掉了一个原有问题，人工评审容易把这种顺带修复当成新问题反馈；AI 则会把“原本就有、这次已顺手修掉”的问题单独列出来，并声明不作为问题上报。 例：某个 PR 里，三个仓库的构建文件互相用 feature 分支名引用对方，没有固定版本，合入顺序不对或者分支被清理，主干构建就断了。这属于“合并编排”层面的问题，只看 PR 页面的人恰好最容易漏掉，而 AI 把构建文件也当成了评审对象。 AI 的误判多数是因为看不到代码之外的东西，比如运维流程、设计决策和团队约定。我们的实践中也看到了AI 评审在修复建议、信噪比、定级和证据取舍上的问题。 例：报告把一处过期 epoch 的代码路径标成了现实风险。人工复核时没有质疑这段代码本身，质疑的是周围的系统到底会不会产生走到这个分支的输入：\"EPOCH_NOT_MATCH 只会在迁移分裂+1，分裂之后老的region就不存在了，迁移之后再迁移，src也不存在了，所以 EPOCH_NOT_MATCH 理论上走不到这个分支。\" 同样的情况也出现在被报告标成竞态窗口的一天过期时间的问题上：“迁移是人工操作，线上不会存在迁移发起一天还没有成功的，需要人工介入，一天的过期时间就是解决这个问题的”。AI 能建模那个计时器，建模不了包在它外面的人工流程。 例：报告把在生产环境里直接调用 abort() 的一致性检查标成了正确性风险，建议改成记录 Error 日志，不要崩溃。实际我们选择了abort，因为存储系统是正确性高于可用性的，在特定场景下，我们宁可 abort，也不能让这个请求继续而产生非常难处理的脏数据。 3. AI 评审附带的修复建议，本身也需要评审 例：AI 针对一个 32 位溢出给出的修复，是校验声明的 size 和实际收到的字节数是否一致。复核时发现 get_size() 返回的是 int，size 落在 2³¹ 到 2³² 之间会被截断成负数，这条校验本身就会静默失效。个例修好了，同一类问题并没有修好。 例：AI 评审把线程池默认值、重命名的配置项、被移除的二级缓存刷新开关都标成了“待确认”。每一条最后得到的回复，依据的都是团队自己压测得出的历史数据，和代码缺陷无关：\"根据压测调整的，后台线程数调低是为了降低对前台的影响。\" AI 缺少一道界限明确的质量门槛：同一类理论上可能的问题，这次被标成最高级，下次又可能被标成不重要。拿到一份 AI 报告，定级没法完全信，为了保险只能把所有问题挨个审一遍，反而很难聚焦到真正高等级的问题上。 例：两份 AI 评审用的是同一个“场景 × 约束”框架，却给出了相反的结论。一份直接复述头文件里的断言判定实现是对的；另一份去核对了具体的实现，判定是错的。另一个例子是简单依赖设计文档，即迁移设计文档中要求的版本连续性校验，在代码里却没有任何引用。 两份评审看的代码没有区别，区别在于有没有去验证这些“说明”本身。 2.3 让评审结论可执行：构建测试、集成测试与运行时日志 静态评审只能说明“代码里存在这条路径”。这条路径是否真的会出错、已有的保护能不能拦住、线上有没有发生过，还需要另外三类证据来回答。 2.3.1 构建与单测：把推理变成红绿 实验：AI对一个项目全仓评审的 117 个疑似问题，逐条写 gtest 验证，测试在 master 上失败即视为确认。结果：36 条红测试确认，3 条被证伪（误报），41 条只能靠源码确认，37 条未验证。 判决确定。变红的测试集中在三类：输入触发 abort、错误被吞掉后仍然报成功、解码越界。严重度按失败现象来定就行，不用再看 AI 的措辞。 能证伪。有 3 条发现被测试推翻了，这是静态评审很难给出的结论。 能暴露 CI 自身的问题。比如测试报告里硬编码了 failures=\"0\"，失败用例也不进汇总，所以要让 AI 自己构建、看原始输出，不能只信 CI 的绿灯。 边界。竞态和 UAF 需要 sanitizer，时序问题需要调度控制，故障注入点、受限主机、时钟偏移这些条件也还有缺口，“未验证”那份清单其实就是测试基础设施要补的课。变红的测试也只能证明代码会出错，证明不了线上会产生那个输入：有一个数据迁移场景，测试确认会有数据过期问题，人工复核后发现，在人工操作的流程里，这个过期恰恰是有意设计的。 2.3.2 贴近运行时的集成测试：主要价值是降误报 比如我们有一个项目的类实现做了特殊考虑，使得我们可以在单进程里就拉起真实的 Raft 多节点集群，全仓验证所有需要“生产集群”的场景。 让已有保护参与验证。一个 AI 发现的问题称 leader 切换会导致删除丢数据，而已有的一条集成测试恰好在删除窗口切主，结果证明是安全的。 裁决分歧。比如“快照能否捕获 split 中间态”，两次 AI 评审的意见相反，走真实的 change_peer 入口、加同步点注入写一个测试，就能直接判定。 fake/mock 的边界就是验证的边界。fake 要走真实入口、用生产配置，并写明替换了什么。 例：分布式 KV 的 hang 告警 Bug 没被测出来，是因为测试用的设置和实际生产发生的不同；网络阶段的丢弃保护在单测里被手工喂了时间戳，线上路径却从来不设置。 2.3.3 运行时日志：从“可能发生”到“已经发生” 实验：把一台存储节点 11 天的 WARN 日志（67.8 万行、34 个调用点）交给 AI 映射回源码，找到 5 个缺陷，对应的同学人工确认全部属实，没有误报。 发现静态审查不会怀疑的问题。例：“fail times 1”11 天只出现一次，说明计数器卡住了，hang 告警永远不会触发。 证伪错误假设。例：一个长达 19 分钟的响应，各阶段耗时之和与总耗时的比值恒为 1.0，由此排除了时钟错误，进而定位到发送阶段缺少丢弃保护。 让定级有依据。例：实测阶段耗时已经达到 1,156 秒，离存储这个耗时的 int32 溢出已经不到 2 倍。 其中两个缺陷并不是日志直接触发的，而是 AI 为了解释日志去读相邻代码时发现的，同样属实，日志提供的真实配置和数量级，可能也让相邻代码的推理更准。这只是一个样本，不能说明总能零误报，但足以支持一个做法：能拿到运行时日志时，评审和 Debug 都应附上。日志的局限是只覆盖执行过的路径，行号也可能与部署版本不符（需按消息文本定位）。"}],"text":"AI 能让代码写得更快，但在「不能出错」的分布式存储系统里，如何确保提效不变成风险？本文结合美团基础技术部在 AI 评审、问题排查和自动化开发中的真实实践，分享 AI 能帮上什么忙、容易在哪些地方犯错，以及哪些地方仍需要人来把关。比「多写代码」更重要的，是让代码和结论经得起验证。希望这些经验能为复杂系统中的 AI 应用提供参考，在享受效率提升的同时，守住质量与稳定性的底线。 1. 背景：为什么分布式存储需要更审慎地使用 AI Coding 今年年初以来，随着Agent的普及，AI Coding 在功能开发、测试生成、脚本编写和执行、问题排查这些场景里都已经用得上了：读代码更快，实现和测试可以先让它写一版，研发之外的一部分杂活也能交给它去跑。 效率上去了，质量上的账也要重新算。同样的人力，一个版本里能交付的功能更多，改动的代码也更多，就算 AI 写的代码千行缺陷率和人写的持平，一个版本累计引入的缺陷绝对数量照样会涨。所以 AI Coding 的目标不能只是更快地写代码，提速的同时，代码质量和验证充分性还得比常规研发要求得更高。 分布式存储把这个问题放大了。代码规模大，模块之间关系复杂，一致性、并发、持久化、故障恢复和性能每一项都碰得到。一处看上去很局部的改动，平时可能一切正常，等到节点重启、磁盘异常、网络抖动或者高并发的时候才暴露出来。出了问题，受影响的也不会只是某一个功能，而是上层业务的数据可用性和系统稳定性，严重时还会波及数据正确性。存储服务支撑着大量上层业务，故障影响面大，修复也困难，对缺陷的容忍度极低。 要满足这样的质量要求，光让 AI 生成代码不够，AI 评审（Code Review）、AI 测试与验证、AI Debug 和受控自动化也得一起建起来，AI 生成的代码才能放心地进入研发流程。本文结合存储团队在 AI 评审、AI Debug 和 AI 自动化上的实践，讨论在分布式存储这类复杂度高、容错低的系统里，怎样一边用 AI 提速，一边靠更严格的评审、测试、调试和自动化验证守住稳定性与数据正确性，希望对其他类似系统落地 AI Coding 也有参考价值。 2. AI 评审（Code Review）：有益补充，但不能替代人对设计背景的判断 例：ENABLE_UNITTEST 在三处调用点控制测试 mock 变体的编译分支，但 CMake 迁移把这个名字换成了 WITH_UNITTEST，旧名字再也没被赋过值。单看任何一个文件都挑不出毛病，这个 bug 只存在于文件和文件之间的落差里。 例：AI 指出“这里没做边界检查”之后没有停下，接着构造了一个声明 1 GiB 数值、实际包体只有 5 字节的畸形包，打到真实的解码入口，把崩溃现场抓了出来。 例：一处疑似的并发竞态，AI 只能靠代码走读找到可疑路径。它明确说，要证实这段交错时序需要 ThreadSanitizer，而当前的工具链跑不了，于是把这条标成“未验证”，没有直接定性为缺陷。 例：一处“先读校验、再写推进”、中间没有互斥的更新，多次评审都稳定地识别了出来，给出的修复方向也一致（合并成单个原子操作）。这类常见的并发模式识别得很稳，可以固化成固定检查项。 例：一次重构把某个接口合并成单次 RPC，顺手删掉了成功后清理本地缓存的旧逻辑。AI 指出这会留下一个短暂的时间窗口，期间可能读到过期的旧数据。而人对被删掉的行，本来就最不敏感。 例：评审之前，AI 会先分析存量代码。改动较大的 PR 里，新代码可能顺手修掉了一个原有问题，人工评审容易把这种顺带修复当成新问题反馈；AI 则会把“原本就有、这次已顺手修掉”的问题单独列出来，并声明不作为问题上报。 例：某个 PR 里，三个仓库的构建文件互相用 feature 分支名引用对方，没有固定版本，合入顺序不对或者分支被清理，主干构建就断了。这属于“合并编排”层面的问题，只看 PR 页面的人恰好最容易漏掉，而 AI 把构建文件也当成了评审对象。 AI 的误判多数是因为看不到代码之外的东西，比如运维流程、设计决策和团队约定。我们的实践中也看到了AI 评审在修复建议、信噪比、定级和证据取舍上的问题。 例：报告把一处过期 epoch 的代码路径标成了现实风险。人工复核时没有质疑这段代码本身，质疑的是周围的系统到底会不会产生走到这个分支的输入：\"EPOCH_NOT_MATCH 只会在迁移分裂+1，分裂之后老的region就不存在了，迁移之后再迁移，src也不存在了，所以 EPOCH_NOT_MATCH 理论上走不到这个分支。\" 同样的情况也出现在被报告标成竞态窗口的一天过期时间的问题上：“迁移是人工操作，线上不会存在迁移发起一天还没有成功的，需要人工介入，一天的过期时间就是解决这个问题的”。AI 能建模那个计时器，建模不了包在它外面的人工流程。 例：报告把在生产环境里直接调用 abort() 的一致性检查标成了正确性风险，建议改成记录 Error 日志，不要崩溃。实际我们选择了abort，因为存储系统是正确性高于可用性的，在特定场景下，我们宁可 abort，也不能让这个请求继续而产生非常难处理的脏数据。 3. AI 评审附带的修复建议，本身也需要评审 例：AI 针对一个 32 位溢出给出的修复，是校验声明的 size 和实际收到的字节数是否一致。复核时发现 get_size() 返回的是 int，size 落在 2³¹ 到 2³² 之间会被截断成负数，这条校验本身就会静默失效。个例修好了，同一类问题并没有修好。 例：AI 评审把线程池默认值、重命名的配置项、被移除的二级缓存刷新开关都标成了“待确认”。每一条最后得到的回复，依据的都是团队自己压测得出的历史数据，和代码缺陷无关：\"根据压测调整的，后台线程数调低是为了降低对前台的影响。\" AI 缺少一道界限明确的质量门槛：同一类理论上可能的问题，这次被标成最高级，下次又可能被标成不重要。拿到一份 AI 报告，定级没法完全信，为了保险只能把所有问题挨个审一遍，反而很难聚焦到真正高等级的问题上。 例：两份 AI 评审用的是同一个“场景 × 约束”框架，却给出了相反的结论。一份直接复述头文件里的断言判定实现是对的；另一份去核对了具体的实现，判定是错的。另一个例子是简单依赖设计文档，即迁移设计文档中要求的版本连续性校验，在代码里却没有任何引用。 两份评审看的代码没有区别，区别在于有没有去验证这些“说明”本身。 2.3 让评审结论可执行：构建测试、集成测试与运行时日志 静态评审只能说明“代码里存在这条路径”。这条路径是否真的会出错、已有的保护能不能拦住、线上有没有发生过，还需要另外三类证据来回答。 2.3.1 构建与单测：把推理变成红绿 实验：AI对一个项目全仓评审的 117 个疑似问题，逐条写 gtest 验证，测试在 master 上失败即视为确认。结果：36 条红测试确认，3 条被证伪（误报），41 条只能靠源码确认，37 条未验证。 判决确定。变红的测试集中在三类：输入触发 abort、错误被吞掉后仍然报成功、解码越界。严重度按失败现象来定就行，不用再看 AI 的措辞。 能证伪。有 3 条发现被测试推翻了，这是静态评审很难给出的结论。 能暴露 CI 自身的问题。比如测试报告里硬编码了 failures=\"0\"，失败用例也不进汇总，所以要让 AI 自己构建、看原始输出，不能只信 CI 的绿灯。 边界。竞态和 UAF 需要 sanitizer，时序问题需要调度控制，故障注入点、受限主机、时钟偏移这些条件也还有缺口，“未验证”那份清单其实就是测试基础设施要补的课。变红的测试也只能证明代码会出错，证明不了线上会产生那个输入：有一个数据迁移场景，测试确认会有数据过期问题，人工复核后发现，在人工操作的流程里，这个过期恰恰是有意设计的。 2.3.2 贴近运行时的集成测试：主要价值是降误报 比如我们有一个项目的类实现做了特殊考虑，使得我们可以在单进程里就拉起真实的 Raft 多节点集群，全仓验证所有需要“生产集群”的场景。 让已有保护参与验证。一个 AI 发现的问题称 leader 切换会导致删除丢数据，而已有的一条集成测试恰好在删除窗口切主，结果证明是安全的。 裁决分歧。比如“快照能否捕获 split 中间态”，两次 AI 评审的意见相反，走真实的 change_peer 入口、加同步点注入写一个测试，就能直接判定。 fake/mock 的边界就是验证的边界。fake 要走真实入口、用生产配置，并写明替换了什么。 例：分布式 KV 的 hang 告警 Bug 没被测出来，是因为测试用的设置和实际生产发生的不同；网络阶段的丢弃保护在单测里被手工喂了时间戳，线上路径却从来不设置。 2.3.3 运行时日志：从“可能发生”到“已经发生” 实验：把一台存储节点 11 天的 WARN 日志（67.8 万行、34 个调用点）交给 AI 映射回源码，找到 5 个缺陷，对应的同学人工确认全部属实，没有误报。 发现静态审查不会怀疑的问题。例：“fail times 1”11 天只出现一次，说明计数器卡住了，hang 告警永远不会触发。 证伪错误假设。例：一个长达 19 分钟的响应，各阶段耗时之和与总耗时的比值恒为 1.0，由此排除了时钟错误，进而定位到发送阶段缺少丢弃保护。 让定级有依据。例：实测阶段耗时已经达到 1,156 秒，离存储这个耗时的 int32 溢出已经不到 2 倍。 其中两个缺陷并不是日志直接触发的，而是 AI 为了解释日志去读相邻代码时发现的，同样属实，日志提供的真实配置和数量级，可能也让相邻代码的推理更准。这只是一个样本，不能说明总能零误报，但足以支持一个做法：能拿到运行时日志时，评审和 Debug 都应附上。日志的局限是只覆盖执行过的路径，行号也可能与部署版本不符（需按消息文本定位）。"}