现代系统很少从零开始。一个看似清晰的服务架构,往往仍依赖十年前的接口、无人维护的批处理任务,或者只有少数工程师知道如何调用的内部服务。真正危险的不是“旧”,而是团队不知道它的输入、输出、副作用和故障边界。
AI 编码智能体适合处理这类知识缺口:它可以跨文件检索调用点、归纳接口行为、生成测试草案,并把零散发现整理成架构文档。但它不能替代运行时证据和工程师判断。更稳妥的定位,是把智能体当作一名速度很快、但所有结论都需要复核的架构调查助手。
1. 从调用点反推遗留服务的真实边界
文档描述的是“设计时的系统”,代码和配置暴露的则是“正在运行的系统”。可以让智能体扫描以下信息:
- HTTP、RPC、消息队列和数据库调用点;
- 环境变量、服务地址、超时和重试配置;
- 请求参数、响应字段及错误处理分支;
- 定时任务、补偿逻辑和人工操作脚本;
- 哪些业务模块直接依赖遗留服务。
不要只问“这个服务做什么”。更有效的任务应要求智能体给出证据位置:
请调查仓库中对 legacy-billing 服务的全部依赖。
输出:
1. 调用文件和行号;
2. 使用的协议、路径与配置项;
3. 请求和响应字段;
4. 超时、重试、降级及异常处理;
5. 无法由代码确认的假设,单独列为“待验证”;
6. 不要修改代码。
这种输出可以形成依赖清单,但不能证明某个调用仍会在生产环境触发。还需要结合访问日志、链路追踪和配置中心进行验证。
2. 把代码考古结果变成可维护的接口契约
找到调用点后,下一步不是立即重构,而是把隐含契约显式化。智能体可以根据客户端模型、序列化逻辑和样例响应,起草 OpenAPI、JSON Schema 或消息格式说明。
建议为每个字段标注证据等级:
- 已验证:来自生产流量、服务实现或集成测试;
- 代码推断:从调用方代码推导,但尚未通过运行验证;
- 未知:错误码、空值规则或边界行为仍不清楚。
下面是一份可以改造的契约草案。它是假设性示例,不代表任何特定遗留服务的真实 API:
openapi: 3.0.3
info:
title: Legacy Billing Adapter
version: 0.1.0-draft
paths:
/v1/accounts/{accountId}/balance:
get:
parameters:
- name: accountId
in: path
required: true
schema:
type: string
responses:
'200':
description: Balance returned
content:
application/json:
schema:
type: object
required: [accountId, amount, currency]
properties:
accountId:
type: string
amount:
type: string
description: Decimal value; representation must be verified
currency:
type: string
minLength: 3
maxLength: 3
'404':
description: Account not found; error body remains to be verified
草案应进入版本控制,并由服务维护者和真实调用方共同审查。智能体可以提高整理速度,但不能凭几个客户端模型就确定服务端的全部行为。
3. 先生成特征测试,再考虑替换实现
遗留系统经常没有完整规格。此时最有价值的测试不是证明其行为“正确”,而是记录它“现在如何工作”。这类特征测试可以覆盖:
- 常见输入与典型响应;
- 空值、重复请求和超大数据;
- 超时、限流及部分失败;
- 字段顺序、日期格式和金额精度;
- 调用是否产生写库、发消息等副作用。
可以让智能体从调用方夹具、日志样本和现有测试中生成测试草案,再由工程师删除敏感数据、补充断言并在隔离环境运行。不要让智能体直接拿生产凭据探测旧服务。
如果必须记录真实响应,应先脱敏,并区分稳定契约与偶然数据。例如,订单状态可能属于契约,而请求时间戳通常不应被写死在快照里。
4. 让智能体比较架构选项,而不是直接决定架构
当依赖和行为逐渐清楚后,智能体可以协助比较多个改造方案:
- 保持现状,只补文档与监控;
- 增加适配器或反腐层,隔离遗留数据模型;
- 使用绞杀者模式逐步替换能力;
- 将共享数据库访问收敛为明确的服务接口;
- 暂缓迁移,先降低单点故障和运维风险。
让智能体生成架构决策记录(ADR)时,输入中必须包含约束,例如迁移窗口、合规要求、调用量、延迟预算、团队能力和回滚条件。否则,它很容易提出技术上优雅、组织上无法落地的方案。
一个有效的 ADR 至少应回答:为什么现在要改、有哪些备选方案、选择依据是什么、会引入哪些新风险,以及出现什么信号时需要撤销决定。
5. 用智能体持续检查架构漂移
一次性文档很快会过期。更有价值的做法,是把调查规则放进 CI:新增遗留依赖、绕过适配层、使用已废弃端点时自动生成报告或阻止合并。
下面的 Python 脚本只使用标准库,可以扫描仓库中常见的遗留服务标记。运行前请按项目修改 needles 和 allowed_suffixes:
#!/usr/bin/env python3
import json
import sys
from pathlib import Path
SKIP_DIRS = {'.git', '.idea', '.venv', 'node_modules', 'dist', 'build'}
def main() -> None:
root = Path(sys.argv[1] if len(sys.argv) > 1 else '.').resolve()
needles = ['LEGACY_BASE_URL', 'legacy.internal', '/v1/legacy/']
allowed_suffixes = {'.py', '.js', '.ts', '.java', '.go', '.yaml', '.yml', '.json', '.env'}
findings = []
for path in root.rglob('*'):
if not path.is_file() or path.suffix not in allowed_suffixes:
continue
if any(part in SKIP_DIRS for part in path.parts):
continue
try:
lines = path.read_text(encoding='utf-8').splitlines()
except (UnicodeDecodeError, OSError):
continue
for line_number, line in enumerate(lines, start=1):
matches = [item for item in needles if item.lower() in line.lower()]
if matches:
findings.append({
'file': str(path.relative_to(root)),
'line': line_number,
'matches': matches,
'text': line.strip()[:240],
})
print(json.dumps({'root': str(root), 'findings': findings}, indent=2, ensure_ascii=False))
if __name__ == '__main__':
main()
保存为 tools/legacy_inventory.py 后运行:
python tools/legacy_inventory.py . > legacy-usage.json
随后可以把 legacy-usage.json 交给编码智能体分类,但应避免上传令牌、连接串或客户数据。实际 CI 中还可以保存一份基线,只在新增依赖时失败,避免历史问题一次性阻塞所有交付。
落地时守住三条边界
引入 AI 编码智能体时,可以从一个风险可控的遗留服务开始,并遵循三条原则:
- 证据优先:每项结论都要能指向代码、配置、测试、日志或负责人确认;
- 只读起步:先允许搜索和生成报告,再逐步开放修改代码、执行测试等权限;
- 小步闭环:依赖清单、契约草案、特征测试、ADR 和 CI 规则应形成连续链路。
衡量成效时,不要只看智能体生成了多少文档。更值得关注的是:未知依赖是否减少、故障定位是否更快、迁移是否可以回滚,以及架构决策是否拥有可验证的依据。AI 能加快理解遗留系统的过程,但架构责任仍然属于团队。