1. 棕地 Agent 工程到底难在哪:从“能跑”到“敢改”的鸿沟
接手一个跑了七八年的老系统,老板突然说“给它加个 AI Agent 吧”,这大概是当下不少资深工程师最真实的处境。新项目从零搭 Agent 框架,网上教程一抓一大把,LangChain、LangGraph、各种主流架构的 Demo 半天就能跑通。可一旦把场景换成那种几十万行、没人敢动、注释停留在三年前、原作者已经离职的遗留代码库,事情就完全变了味道。棕地 Agent 工程这个词,说的就是这种在已有系统上做增量智能化的活儿——不是推倒重来,而是在活着的、还在产生业务价值的系统上动手术。
我先把结论摆在前面:在遗留代码库里做 AI Agent,最大的敌人从来不是模型能力不够,而是你对这套老系统的理解程度不够。很多人一上来就想着“我要接个大模型进去”,结果连这个系统里哪个模块负责什么、数据怎么流转、哪些接口是历史包袱都还没搞清楚,最后做出来的 Agent 要么是个花架子,要么一上线就把生产环境搞出问题。棕地工程的核心矛盾在于:遗留系统本身是脆弱的、隐性的、充满历史妥协的,而 AI Agent 是概率性的、需要试错的、行为不完全可预测的。把这两个东西捏在一起,难度不是加法,是乘法。
那为什么还要做?因为绝大多数企业真正的业务价值都沉淀在这些老系统里。你不可能让一家做了二十年 ERP 的公司把系统推倒重来去拥抱 AI,那不现实。真正有价值的场景,恰恰是在这些老系统上长出智能能力——比如让 Agent 自动处理那些重复的工单分类、自动生成报表解读、自动在多个老系统之间做数据搬运和校验。这些活儿人来做又慢又容易出错,Agent 来做刚好合适。所以棕地 Agent 工程不是一个可选项,而是大部分传统企业落地 AI 的必经之路。
这篇文章我想聊的不是“怎么搭一个 Agent”,而是“怎么在一个你不敢乱动的老系统里,安全地、可控地、可回滚地把 Agent 嵌进去”。我会结合自己在几个遗留系统上做 Agent 改造的实际经验,把那些反直觉的、跟常规教程完全相反的法则讲清楚。如果你手上正好有一个老系统要加 AI 能力,或者你是个架构师正在评估这件事的可行性,那接下来的内容应该能帮你少走不少弯路。适合有一定工程基础、对 AI Agent 有基本认知、但还没在真实遗留系统上踩过坑的读者。
2. 法则一:先给老系统做“特征测试”,再谈 Agent 接入
2.1 为什么特征测试是棕地 Agent 的第一道门槛
在绿地项目里,你写代码之前系统是空的,行为完全由你定义。但在棕地项目里,系统已经有一套运行了多年的行为逻辑,这套逻辑可能连文档都没有,全靠代码本身和运维经验在维持。这时候你如果直接往里塞 Agent,最危险的不是 Agent 本身出错,而是你根本不知道它触发了老系统里哪条隐藏的路径。
特征测试(Characterization Test)这个概念来自 Michael Feathers 的《修改代码的艺术》,核心思想是:在改动遗留代码之前,先写测试把当前行为“钉死”,不管这个行为看起来是对是错。它的目的不是验证正确性,而是建立一个行为基线。对棕地 Agent 工程来说,这一步的价值被严重低估了。因为 Agent 的输出是概率性的,你没法用传统的断言去测它,但你可以测它调用的那些老接口、老函数、老数据流在特定输入下是否还保持原来的行为。
我做过一个项目,老系统里有个订单状态计算函数,逻辑写得极其绕,嵌套了七八层 if-else,还有几个魔法数字。我们当时想用 Agent 来自动判断订单异常,结果测试阶段发现 Agent 给出的判断跟系统实际状态对不上。排查了两天才发现,那个函数里有个隐藏的分支:当订单金额恰好等于某个阈值时,会走一条特殊路径,而这条路径在代码注释里完全没提。如果没有特征测试把这个行为固定下来,Agent 上线后就会在这类边界订单上持续出错,而且很难定位。
2.2 特征测试在 Agent 场景下的具体做法
具体怎么做?我的经验是分三步走。第一步,找出 Agent 将要触碰的所有老系统入口点,包括 API、数据库读写、消息队列、定时任务。第二步,针对每个入口点,用生产环境的真实数据(脱敏后)跑一批样本,记录输入和输出,把这些记录变成回归测试用例。第三步,把这些测试用例接入 CI,每次 Agent 相关代码有改动就自动跑一遍,确保老系统的行为没有被意外改变。
这里有个关键细节:特征测试的样本要覆盖“正常路径”和“异常路径”两类。正常路径好办,异常路径才是坑最多的地方。比如老系统里对空值、超长字符串、特殊字符的处理,往往跟现代框架的默认行为不一样。Agent 生成的参数如果没做清洗,很容易触发这些老逻辑里的边界问题。我一般会专门构造一批“脏数据”样本,把老系统在各种奇怪输入下的反应都记录下来。
提示:特征测试不是一次性的工作。每次 Agent 迭代、每次老系统本身有变更,都要重新跑一遍基线测试。我见过太多团队做完一次就丢在一边,结果三个月后老系统被人改了一行代码,Agent 就开始出各种诡异问题。
2.3 测试覆盖率的取舍:别追求 100%
还有一点要提醒:在遗留系统上追求 100% 的特征测试覆盖率是不现实的,也没必要。你的目标是覆盖 Agent 实际会走到的那些路径,而不是整个老系统。我通常会把 Agent 的调用链路画出来,只对链路上的节点做特征测试,链路之外的代码暂时不管。这样能把工作量控制在可接受的范围内,同时保证 Agent 相关的行为是可控的。
这个取舍背后有个逻辑:棕地 Agent 工程是增量改造,不是全面重构。你不需要理解整个老系统,你只需要理解 Agent 会碰到的那部分。把有限的精力集中在关键路径上,比漫无目的地给整个系统补测试要高效得多。
3. 法则二:Agent 的“智能”要放在边缘,别往核心业务逻辑里塞
3.1 核心逻辑与智能逻辑的边界划分
这是我在第二个项目里用血泪换来的教训。当时我们的做法是:把 Agent 的判断逻辑直接嵌入到老系统的订单处理主流程里,让 Agent 在关键节点做决策。听起来很美好,实际上是一场灾难。因为老系统的核心流程是强事务、强一致的,而 Agent 的调用有延迟、有失败率、有不确定性。一旦 Agent 超时或者返回了意料之外的结果,整个订单流程就卡住了。
后来我们调整了架构:把 Agent 放在核心业务流程的“边缘”,让它做辅助决策而不是主决策。具体来说,老系统的核心流程保持不变,Agent 在旁路运行,它的输出作为“建议”写入一个独立的表或队列,由核心流程在合适的时机以非阻塞的方式读取。如果 Agent 挂了或者超时,核心流程照常走原来的逻辑,只是少了智能增强的部分。这样既保证了老系统的稳定性,又让 Agent 的能力能够逐步渗透。
这个原则可以总结成一句话:Agent 可以影响决策,但不能阻塞决策。在遗留系统里,任何可能阻塞主流程的东西都是高危的,因为老系统的容错设计往往很粗糙,一个环节卡住可能引发连锁反应。
3.2 旁路模式的三种落地形态
旁路模式具体怎么落地?我实践过三种形态,各有适用场景。
第一种是异步建议模式。Agent 在独立进程或独立服务里运行,消费老系统发出的消息或事件,处理后把结果写回一个建议表。老系统在需要的时候去查这个表,查到就用,查不到就走默认逻辑。这种模式对老系统侵入最小,适合那些主流程极其敏感、不能有任何额外延迟的场景。
第二种是同步旁路模式。Agent 作为一个独立的服务,老系统通过一个带超时和熔断的调用去问它。超时时间设得很短,比如 200 毫秒,超了就降级。这种模式适合那些需要实时智能判断、但又能接受偶尔降级的场景。关键是熔断和降级逻辑要写好,不能让 Agent 的故障传导到老系统。
第三种是影子模式。Agent 和老系统并行处理同一批数据,但 Agent 的结果只记录不生效,用来对比和验证。这种模式适合 Agent 刚上线、还在验证阶段的场景。跑一段时间,确认 Agent 的判断准确率达标了,再切换到生效模式。影子模式是我最推荐的上线策略,没有之一。
3.3 为什么“智能放边缘”反而效果更好
有人可能会问:把 Agent 放边缘,它不就发挥不了全部价值了吗?恰恰相反。在遗留系统里,Agent 的价值不在于替代核心逻辑,而在于处理那些核心逻辑处理不好的“模糊地带”。比如工单的语义分类、非结构化文本的提取、多系统之间的数据对账,这些活儿老系统做不了或者做得很差,Agent 来做刚好。而核心的金额计算、库存扣减、状态流转,这些有明确规则的事情,老系统已经做得很稳了,没必要让 Agent 去掺和。
把边界划清楚,Agent 和老系统各司其职,整体效果反而比让 Agent 大包大揽要好。这也是棕地工程和绿地工程思维上的一个根本差异:绿地工程追求的是端到端的智能,棕地工程追求的是在现有约束下的最优增量。
4. 法则三:迁移盲区比技术债更致命,得先画“雷区图”
4.1 什么是迁移盲区
迁移盲区这个词是我自己总结的,指的是那些在遗留系统里“看起来能用、实际上没人真正理解”的部分。它和技术债还不一样。技术债是你知道它有问题、知道欠了什么,只是暂时没还。迁移盲区是你根本不知道它有问题,甚至不知道它的存在。它可能是一个没人维护的定时脚本、一个硬编码在配置文件里的特殊规则、一个只有某个老员工才知道的运维操作。
在棕地 Agent 工程里,迁移盲区是最致命的东西。因为 Agent 的行为是数据驱动的,它会去读各种数据、调各种接口,很容易踩到这些盲区。我遇到过一个案例:老系统里有个每天凌晨跑的脚本,会把某些订单的状态批量改掉,这个脚本没有任何文档,也不在监控范围内。Agent 上线后,在凌晨时段读取订单状态时经常读到“中间态”,导致判断出错。排查了很久才发现是这个隐形脚本在作怪。
4.2 画雷区图的四个信息源
要发现迁移盲区,我一般从四个信息源入手。
第一个是代码考古。用静态分析工具扫一遍老代码,找出那些没有被任何测试覆盖、没有被最近修改过、但仍在被调用的函数和脚本。这些是盲区的高发地带。特别要关注那些带定时任务、带数据库直连、带文件读写的代码,它们往往游离在主干逻辑之外。
第二个是运维日志。去翻生产环境的日志、监控、告警记录,看看有没有一些“不明来源”的操作。比如某个表的数据在特定时间点被修改,但找不到对应的业务操作。这些异常往往是盲区的信号。
第三个是人肉访谈。找那些在老系统上工作多年的运维、DBA、业务人员聊,问他们“有没有什么系统行为是你知道但文档里没写的”。这个问题往往能挖出很多宝藏。我就从一个老运维那里得知,系统里有个隐藏的管理员入口,可以在特定条件下绕过某些校验,这个入口在代码里藏得很深。
第四个是数据血缘分析。追踪关键数据的来源和流向,看看有没有“断头路”或者“幽灵写入”。数据血缘能帮你发现那些不在正常业务链路上的数据操作。
4.3 雷区图怎么用
把盲区找出来之后,要画成一张“雷区图”,标注每个盲区的位置、影响范围、触发条件、风险等级。然后针对每个盲区,决定是绕开、是封装、还是先补测试再动。我的原则是:高风险盲区一律绕开,中风险盲区先封装再加监控,低风险盲区可以边用边观察。
绕开的意思是,Agent 的设计要主动避开这些区域。比如那个凌晨脚本,我们后来让 Agent 在读取订单状态时加了一个时间窗口判断,避开脚本运行的时间段。封装的意思是,给盲区加一层适配层,把它的行为固定下来,Agent 只跟适配层打交道。补测试的意思是,如果这个盲区必须被 Agent 用到,那就先写特征测试把它钉死,再让 Agent 接入。
这张雷区图不是画完就完了,它应该是一个活文档,随着你对系统理解的加深不断更新。我一般会把它放在项目 Wiki 的显眼位置,让所有参与 Agent 开发的人都能看到。
5. 法则四:别迷信“大模型什么都能干”,该写规则就写规则
5.1 大模型在遗留系统里的能力边界
现在有一种风气,好像什么问题都想用大模型解决。在绿地项目里这么想问题不大,但在遗留系统里,这种思维会害死人。大模型擅长的是语义理解、模糊匹配、文本生成这类任务,它不擅长的是精确计算、状态管理、事务控制。而遗留系统里大量的逻辑恰恰是后一类。
我见过一个团队,想用 Agent 来自动处理对账差异。他们的做法是把两边的数据都丢给大模型,让模型判断哪些是差异、差异原因是什么。结果准确率惨不忍睹,因为对账涉及大量的金额计算、时间窗口匹配、多字段组合判断,这些用规则引擎几行代码就能搞定的事情,大模型反而做不好。后来他们改成规则引擎做初筛、大模型只负责对差异原因做自然语言解释,效果立刻上来了。
这个案例的教训是:在遗留系统里,能用确定性规则解决的问题,就不要用概率性模型。规则引擎是确定的、可测试的、可解释的,而大模型是不确定的、难测试的、黑盒的。在棕地环境里,确定性是稀缺资源,能保留一点是一点。
5.2 规则与模型的混合架构
那什么时候用规则、什么时候用模型?我的经验是画一条线:输入和输出都是结构化数据、判断逻辑可以用明确的 if-else 表达的任务,用规则;输入是非结构化数据、或者判断逻辑涉及语义理解的,用模型。
比如订单金额校验、库存扣减、状态机流转,这些用规则。工单内容分类、客户意图识别、非结构化文本提取,这些用模型。两者结合的场景也很多,比如先用规则做粗筛,把明显正常的过滤掉,剩下的模糊案例交给模型做精细判断。这种混合架构在棕地 Agent 工程里特别实用,因为它把大部分流量挡在了确定性逻辑里,只有少量真正需要智能的请求才会走到模型,既保证了稳定性,又控制了成本。
5.3 规则的可维护性设计
用规则还有一个好处:可维护性。遗留系统本身就已经很难维护了,如果你再塞一堆模型调用进去,后面接手的人会更痛苦。规则至少是看得懂、改得动的。但规则也要设计好,不能写成一堆散落的 if-else。
我一般会把规则做成配置化的,用表格或者 DSL 来描述,而不是硬编码在代码里。这样业务人员也能参与维护,改规则不用改代码、不用重新部署。在遗留系统里,减少部署次数本身就是一种稳定性保障。规则引擎我推荐用成熟的、轻量的方案,不要自己造轮子,也不要用太重的东西,毕竟是在老系统上做增量。
6. 法则五:Agent 的可观测性要比老系统本身还强
6.1 为什么老系统的监控不够用
遗留系统的监控往往是薄弱的,可能只有基本的存活检测和错误日志。这在传统场景下勉强够用,但加了 Agent 之后完全不够。因为 Agent 的行为链路更长、更复杂,涉及模型调用、外部服务、数据读写多个环节,任何一个环节出问题都可能导致最终结果异常,而老系统的监控根本看不到这些。
我坚持一个原则:Agent 相关的每一个决策点都要有日志,每一次模型调用都要有记录,每一个降级和熔断都要有告警。这不是过度设计,而是棕地环境的必然要求。因为老系统本身就是一个黑盒,你再加一个黑盒进去,出了问题根本没法排查。可观测性是把 Agent 从黑盒变成灰盒的唯一手段。
6.2 可观测性的三个层次
具体来说,我会从三个层次建设可观测性。
第一个层次是调用链追踪。给每个 Agent 请求分配一个唯一 ID,把这个 ID 贯穿到所有相关的日志、模型调用、数据库操作里。这样出问题时,你可以用这个 ID 把整条链路串起来看。在微服务架构里这是标配,但在遗留系统改造场景里经常被忽略。我一般会用轻量的方案,比如在日志里打标记,不一定非要上全套的分布式追踪系统。
第二个层次是决策记录。Agent 每次做判断,都要记录它的输入、输出、置信度、以及它依据的规则或模型版本。这些记录在排查问题时极其有用。比如用户投诉 Agent 判断错了,你可以回放当时的决策过程,看到底是输入数据有问题、还是模型版本不对、还是规则配置错了。没有这些记录,你只能靠猜。
第三个层次是效果监控。Agent 上线后,要持续监控它的准确率、响应时间、降级率、异常率这些指标。这些指标要跟老系统的业务指标关联起来看,比如 Agent 的准确率下降是否导致了业务异常率的上升。我一般会做一个简单的看板,把这些指标放在一起,方便一眼看出问题。
6.3 日志的成本控制
可观测性做得好,日志量会很大,成本是个现实问题。我的做法是分级记录:关键决策点的日志全量保留,普通调用日志采样保留,调试日志只在需要时开启。另外,日志的存储要有生命周期管理,比如热数据保留 7 天、温数据保留 30 天、冷数据归档。在遗留系统里,存储资源往往也紧张,不能无节制地写日志。
注意:可观测性建设要在 Agent 上线之前完成,不能等出了问题再补。我见过太多团队上线时图快,监控没做好,结果出了问题排查了三天才定位到原因,业务损失远超过提前做监控的成本。
7. 法则六:上线策略比技术方案更重要,灰度是唯一正确答案
7.1 为什么棕地 Agent 不能一次性全量上线
绿地项目里,新功能全量上线风险相对可控,因为整个系统都是新的,出问题影响范围有限。但棕地项目不一样,你是在一个承载着真实业务的老系统上动刀,一旦出问题,影响的是正在跑的业务。所以棕地 Agent 的上线策略必须是渐进的、可回滚的。
灰度发布是唯一正确答案,没有之一。但灰度怎么做,有很多讲究。我一般会分四个阶段:影子阶段、小流量阶段、扩量阶段、全量阶段。每个阶段都有明确的准入和退出条件,不达标就不进入下一阶段。
7.2 四个阶段的具体操作
影子阶段:Agent 跟老系统并行跑,但结果不生效,只记录。这个阶段主要验证 Agent 的准确率和稳定性。准入条件是 Agent 的准确率达到预设阈值、没有严重错误。这个阶段一般跑一到两周,覆盖足够多的业务场景。
小流量阶段:选一小部分业务流量(比如 1%)让 Agent 的结果真正生效。这个阶段主要验证 Agent 在真实生效场景下的表现,以及跟老系统的交互是否正常。准入条件是小流量下没有业务异常、没有性能问题。这个阶段要密切监控,一旦有异常立即回滚。
扩量阶段:逐步扩大流量比例,比如 1% 到 5% 到 20% 到 50%。每个比例都要观察一段时间,确认稳定后再继续扩。这个阶段主要验证 Agent 在更大流量下的稳定性,以及是否有一些低频问题开始暴露。
全量阶段:流量到 100%。但即使全量了,也要保留快速回滚的能力。回滚开关要做得简单可靠,最好是一键操作,不需要重新部署。
7.3 回滚机制的设计要点
回滚机制是灰度发布的保险绳,必须设计好。我的经验是:回滚要能在分钟级完成,且回滚后系统状态要能恢复到 Agent 介入之前。这就要求 Agent 的所有写操作都是可逆的,或者至少是可补偿的。
具体做法上,我会给 Agent 的每个写操作设计一个对应的补偿操作。比如 Agent 修改了某个订单的状态,补偿操作就是把它改回去。这些补偿操作要预先写好、测试好,不能等回滚时才临时想。另外,回滚的触发条件要明确,可以是人工触发,也可以是自动触发(比如错误率超过阈值自动回滚)。自动回滚要谨慎,阈值设得太敏感容易误触发,设得太迟钝又起不到保护作用。我一般会设一个相对宽松的自动回滚阈值,同时配合人工监控,两者结合。
8. 法则七:团队能力结构比技术选型更决定成败
8.1 棕地 Agent 团队需要什么样的人
最后一个法则,也是我认为最重要的一个:棕地 Agent 工程的成败,很大程度上不取决于你选了什么框架、用了什么模型,而取决于团队的能力结构。这个活儿需要的人,跟纯 AI 团队或者纯后端团队都不一样。
你需要至少一个懂老系统的资深工程师。这个人不一定是架构师,但他必须对老系统的历史、坑、盲区有深入了解。他能告诉你哪些地方能碰、哪些地方不能碰、哪些地方碰了会出什么事。没有这个人,你就是在雷区里蒙眼狂奔。
你需要一个懂 AI Agent 的工程师。这个人要理解 Agent 的基本原理、主流架构、常见坑,知道怎么设计 prompt、怎么处理模型的不确定性、怎么做效果评估。他不一定要是算法专家,但要有实际的 Agent 落地经验。
你还需要一个懂运维和可观测性的工程师。这个人负责把 Agent 的运行状态变得可见、可控。在棕地环境里,这个角色的价值被严重低估。很多时候 Agent 出问题不是逻辑错了,而是环境问题、依赖问题、配置问题,这些都需要运维视角的人来排查。
8.2 团队协作模式的调整
除了能力结构,协作模式也要调整。传统的开发模式是“需求-开发-测试-上线”的线性流程,但棕地 Agent 工程更适合小步快跑、快速验证的模式。因为 Agent 的效果很难在开发阶段完全预测,必须尽早放到真实环境里验证。
我一般会组织一个小的“攻坚小组”,包含上面说的三类人,直接对 Agent 的效果负责。这个小组有较大的自主权,可以快速做决策、快速试错。同时,要跟老系统的维护团队保持密切沟通,任何可能影响老系统的改动都要提前对齐。
8.3 知识沉淀与传承
棕地 Agent 工程还有一个容易被忽略的点:知识沉淀。因为涉及老系统的隐性知识、Agent 的调优经验、踩过的坑,这些东西如果不沉淀下来,人员一变动就全丢了。我一般会要求团队维护三份文档:老系统的雷区图、Agent 的设计决策记录、踩坑与解决方案库。这三份文档要持续更新,成为团队的共同资产。
说到底,棕地 Agent 工程是一个系统工程,技术只是其中一部分。把人的问题、流程的问题、知识的问题解决好,技术方案才能真正落地。我在几个项目里最大的体会就是:那些失败的案例,往往不是技术不行,而是团队没准备好、协作没理顺、知识没沉淀。反过来,那些成功的案例,技术方案可能很朴素,但团队配合得好、节奏控制得好,最后效果反而超出预期。
如果你正准备在遗留系统上做 Agent,我的建议是先别急着选框架、调模型,先花时间把上面这七条法则过一遍,看看自己的团队和系统准备好了没有。准备好了再动手,比仓促上马然后反复返工要快得多。这个领域没有银弹,但有方法可循,希望这些经验能帮你少踩几个坑。