使用AI代理重构单体应用的经验教训
1Password分享了使用AI代理重构大型Go单体应用的经验。他们构建了代理工具链进行依赖分析和提取排序,在清理任务中实现了高效自动化,但在服务提取等复杂任务中,代理仅带来20-30%的效率提升,且需要严格的规范约束。关键教训包括:将非确定性控制在确定性工具内、提供明确的规格说明、确保并行修改的隔离性。
4月20日,1Password团队在博客中详细披露了他们利用AI代理重构大型Go单体应用(代号B5)的实践。该应用拥有数百万行代码,是1Password产品的基石,但随着Unified Access功能对高请求率和低延迟的需求,团队需要更清晰的服务边界和独立的扩展能力。他们决定使用AI代理来分析和规划系统的分解。
构建分析层是第一步。团队结合Go SSA分析、SQL解析和DataDog运行时耦合数据,构建了代理工具链,生成了领域所有权图、耦合图和优先级提取顺序。结果与资深工程师的判断一致:从Vault开始,然后是Billing、AuthN/AuthZ,最后是Identity。关键模式是:用代理构建确定性工具(如SSA分析器),而非依赖代理持续解释代码。这提供了稳定的基础,并且额外带来了端到端事务可见性的提升。
在寻找人工与代理最佳配比的过程中,团队处理了一个长期积压的清理任务:将Go服务器中用于启动数据库事务的MustBegin(失败时panic)替换为返回错误。他们生成了3000多个调用点的清单,分类为少数模式,定义了明确模板,并编写了详细的执行手册,包括常见失败模式和停止升级条件。多个代理通过git worktree并行执行,实际修改仅花费数小时。关键发现是:当任务被完全指定和约束时,代理既快又准;遇到超出规范的情况,系统会主动上报而非隐式猜测。
然而,在更复杂的服务提取任务中,代理的表现就不那么理想了。即使面对相对较小的服务,代理在顺序和不变量的处理上仍存在问题。例如,代理会在更新插入新行的代码之前尝试回填UUID列,导致静默数据丢失;或将共享表视为新服务独立拥有,造成部署冲突。团队还观察到“推测”行为:代理在缺乏上下文时用未验证的假设填补空白,比如错误推断标识符格式为ULID,最终导致整个会话回滚。这类任务的效率提升仅为20-30%,虽然可观,但无法替代人工协调和审查。
基于这些经验,1Password总结了四条关键教训:1. 代理重构的瓶颈不是代码生成,而是管理有顺序约束或难以逆转的决策(如模式变更、部署顺序)。2. 非确定性必须被仔细控制,最佳实践是用代理构建确定性工具,并将后续工作约束在这些输出上。3. 不完整的规格会导致代理隐式假设,唯一可靠的方法是提供明确的规格,包括不变性、顺序约束和升级路径。4. 并行性只在变更已隔离且冲突被结构性消除时才有效。
目前,1Password正在全工程组织推广代理工具,但明确其适用边界:代理在问题定义清晰时最有效,而工程师仍负责定义系统边界、建模依赖和确保顺序正确。这些经验将帮助团队将精力从编写代码或提示模型,转向设计可安全、可预测执行系统。