领域驱动智能体:DDD上下文地图锁定AI业务边界


给智能体配一份领域地图,它进了四年老代码库就不会再瞎编字段名了!

你还在把AI当成一个会写代码的实习生?格局小了。现在最前沿的玩法,是孵化一群"领域驱动智能体",让大模型在动手改代码之前先读懂业务边界、认领上下文户口、背熟术语禁令。

摘要:领域驱动智能体不是通用AI助手,而是将领域驱动设计的战略约束与AI自主执行深度耦合的新范式。本文拆解战略决策与战术执行的分离如何让智能体发挥最大价值,限界上下文如何给智能体划分势力范围,上下文地图如何给智能体做GPS导航。附带一套.workflow.json加自动生成脚本的完整落地实践。

同一个AI,新项目里是神队友,老项目里是猪队友

每个用过AI编程助手的工程师都见过这个分裂场景。拉一个全新的Spring Boot项目,你口述需求,它把控制器、服务层、仓储、DTO一口气全吐出来。你改个字段名,它顺带把引用的地方全改干净。新项目里,AI像打了鸡血,一天顶三天。

可你把同一个AI助手丢进一个跑了四年的支付系统里,画风就变了。你需要给订单表加一个"状态"字段,代码库里已经有三个地方在表达同一个意思,一个叫orderStatus,一个叫state,还有一个叫phase。AI看完这些代码,不动声色地创造了第四个名字:status。它不觉得自己在添乱,它只是从代码里找不到任何一条规则说"那个词才是正主"。

你再让它写一个调用下游服务的适配器,它直接在业务逻辑层里调了底层HTTP客户端。你让它直接调用,它又给你包了三层抽象。每一次失误的形状都一样:代码库里没有任何一处白纸黑字写着"这个上下文从哪里开始""这个模型谁说了算""改这个地方会砸到谁"。AI只能猜,而且猜错的概率跟你代码里概念重复的数量成正比。这就怪了。

全球公司每年因技术债烧掉的钱,够买下好几个创业公司

技术债不是新鲜事。从你写下第一行"先让它跑起来"的代码开始,债就欠下了。业务在变,需求在变,你永远不可能预判三年后的逻辑。Pega公司在2025年发布的一份调查报告显示,全球企业平均每年因为技术债直接烧掉3.7亿美元。换算下来,光是维护和集成遗留系统,每年就要吃掉5600万美元。还有5800万美元投进了失败的遗留系统改造项目,钱花了,系统没改出来。

同一份报告还点了一个更反直觉的趋势:生成式AI把"干净代码库"和"债务缠身的代码库"之间的开发速度差距拉得更大了。在低债务的绿色项目里,AI生成代码又快又好;在高债务的棕色项目里,AI生成的东西不仅慢,而且经常跑不通。AI让好代码写得更快了,坏代码它碰都不碰。差距不仅没缩小,反而在扩大。

MIT斯隆管理评论2025年的一篇文章专门讲了这个现象:在棕色环境里,AI生成的代码由经验不足的工程师部署时,会把既有问题放大。这不是AI的错,这是代码的错。

战略和战术拆开,你管拍板,智能体管敲键盘

John Ousterhout在《软件设计的哲学》里区分了两种编程态度。战术编程是"赶紧让它跑起来",战略编程是"边写边把设计搞好"。我借了这两个词,但用在了另一条分界线上。

我按" authorship "来切。战略工作是做决策:读代码,搞清楚哪些地方必须动,为什么动,改完之后到底是在服务功能还是在添乱。这部分需要你把整个系统装在脑子里。战术工作是把决策落实到文件里。这部分已经变得极其便宜。一个LLM做机械性重构,抽一个模块、跨两个包重命名、补一堆单元测试,花掉的token钱几乎可以忽略不计。

所以我的工作流长这样。战略那一半我全程参与,战术那一半我当评审。我先分析代码库,评估改动范围和对齐程度,然后给每个仓库创建一个GitHub Issue。这些Issue带着清晰的描述和验收标准,交给我的AI系统去处理。

系统里有技能和子智能体两样东西。技能是一份Markdown操作手册,模型在接到匹配的任务时加载它,所以"处理一个Issue"或"重新生成上下文地图"每次执行的方式一致,不会因为我早上和下午措辞不同而产生偏差。子智能体是一个独立的模型会话,有自己的上下文和单一职责,实现功能、做安全审查、对照规格书做一致性检查。它干完活只把结果报回来,不把整段对话记录倒给我。

子智能体提交PR之后,我打开来审。接受改动,或者要求调整。我增量地做这件事,关注测试覆盖率,关注影响面。在一个改动合入之前,我必须知道系统的哪些其他部分在消费我正在碰的东西,这个改动它们扛不扛得住。到了这个阶段,我的角色是协调者、计划者、铺路的人。我不需要亲手敲那些文件了。时间省出来了。

领域驱动智能体跟普通AI助手的区别,就像正规军和雇佣兵

普通AI助手是雇佣兵。你给它一个提示词,它给你一段代码。至于这段代码符不符合项目规范、会不会冲撞隔壁模块、词用没用对,它一概不管。它只看眼前这一单。

领域驱动智能体是正规军。它进场之前先干三件事。第一,读.workflow.json,搞清楚自己分配到了哪个限界上下文,地盘有多大。第二,读CONTEXT.md,把术语表背下来,哪些词能用,哪些词是隔壁地盘的禁区,门儿清。第三,读自动生成的CONTEXT-MAP.md,知道上下游谁依赖谁,改一个地方会惊动哪些邻居。

干完这三件事,智能体才开始动手。它不再是猜,它是在地图上规划路线。你给它分一个Issue,它调用预设的技能按标准流程拆解任务,再派子智能体去执行。这才是把战略决策和战术执行彻底切开的正确姿势。战略层面,边界划得对不对、术语定得准不准,握在你手里。战术层面,抽模块、重命名、补测试、调接口,全部交给带着领域地图的智能体去跑。人机协作的界面,从此不是对话窗口,而是领域模型本身。

一个配置文件加一个生成脚本,让智能体从猜谜变成看地图

每个仓库根目录放一个.workflow.json。这是仓库的身份证,告诉工具链它是什么语言、哪些目录是智能体优先读的、改动上线的检查清单。里面有一块专门描述领域信息。这块写清楚项目名、有哪些限界上下文、每个上下文的术语表文件在哪、它是核心域还是支撑域、以及跟隔壁上下文怎么连接。

拿一个真实的岗位投递追踪系统来举例,前端仓库的配置文件长这样。注意看,这个配置不只是一个名字,它把跟前端对接的那个后端上下文地址、数据流向、模型归谁管全写进去了。它的pattern字段填了unclassified,因为前端在实际读写时做了两件不同的事,一个标签盖不住,所以后面跟了一段详细的note

json
{
  "domain": {
    "project": "job-offer-box",
    "contexts": [
      {
        "name": "job-box-web",
        "docs": "CONTEXT.md",
        "subdomain": "supporting",
        "edges": [
          {
            "to": "hyperion/job-offer-backend",
            "direction": "outbound",
            "pattern": "unclassified",
            "owner": "supplier",
            "shape": "codegen from the backend's document (scripts/generate-api.ts:12) ... conformist on write (src/lib/api/jobs.ts:37), ACL on read (src/lib/api/adapters/offer.ts:50)",
            "note": "conformist on write and an anticorruption layer on read; two patterns hold at once, so neither name alone is true"
          }
        ]
      }
    ]
  }
}

读一遍。to是目标地址,告诉你去哪个上下文找对方。direction标的是出站,说明是前端在调后端。owner写的是supplier,意味着两边模型打架的时候后端说了算。shape那一长串直接点名了代码里生成类型和读写适配器的具体文件位置,连行号都给了。

每个上下文旁边还放一个CONTEXT.md。那是活的术语表,每个词的精确定义以及被故意拒绝的同义词都写在里面。代码里用JobOffer,术语表里就写明"这就是正主,别用JobOpeningPosition"。两个文件都放在代码仓库里,代码归谁这两个文件就归谁。没有人单独维护一张全局术语表,那种东西一准过时。

上下文地图不是人写的,是推导出来的。一个生成脚本遍历磁盘上所有仓库,把每个.workflow.json里的domain块合并起来,吐出一份CONTEXT-MAP.md。这份地图是一次性的,随时可以重新生成,不需要人工同步。

两端声明,配对检查,哪里对不上哪里就自动提Issue

每一条边都声明两次,两端各一次。这个重复是故意的。生成脚本交叉核对配对,看两端的声明能不能对上。供应商声明自己的立场,消费者声明自己的立场,检查是一张配对表。

一张配对表,四种对不上的方式。地址没人声明,不行。模式不配对,不行。方向没镜像,不行。只有一边声明了,不行。

每次检查出对不上,脚本自动在对应的仓库里创建一个DDD类型的Issue,里面带好指纹,什么类型的对不上、涉及哪两个地址。如果你只修了一半,脚本不会开重复Issue,它会根据指纹更新原来的Issue。如果对不上消失了,自动关闭Issue。从那里开始,走跟其他所有改造一样的流程:一个Issue、一个智能体、一个PR、我来审。

我把这个检查做成了一个技能,在三个时机自动触发。我刚改过某个仓库的配置文件时跑一次,我新接入一个仓库时跑一次,我准备改动任何被其他上下文依赖的代码之前跑一次。智能体手里有了这张实时更新的地图,就不再靠猜了。

一个更诡异的事,我还没找到答案

但这套东西还没完。有一个更底层的矛盾在浮出水面。

有人提出过一个观点:AI生成的代码,从它被写出来的那一刻起,就已经是遗留代码了。因为AI没有业务上下文,它生成的代码只是"看起来像代码",没有附着在任何真实的业务语义上。它编译通过,测试通过,但它跟周围的世界没有有机的连接。等三个月后另一个人要来改它的时候,他面对的是一个既不是自己写的、也看不出意图的黑盒子。

如果这个判断成立,那问题就大了。我们用智能体加速写代码,表面上提高了产出,实际上可能是在用更快的速度制造未来的技术债。每一行AI生成的代码,如果没有上下文地图的约束,没有术语表的校验,没有边界检查,它就是在给未来埋雷。

我手里那套配置文件和生成脚本,目前只能保证智能体在改造旧代码时不跑偏。但智能体新写的代码怎么保证它天生就附着在正确的语义上?怎么让它自动遵守术语表,自动检查边界,而不是等我来审?能不能把这个检查也自动化,让智能体在提交PR之前自己跑一遍上下文地图校验?

我试了一个方向:把上下文地图的校验逻辑打包成一个预提交钩子,让智能体在生成完代码之后、提交之前自己跑一遍"边界一致性检查"。钩子跑起来之后发现,它能挡住术语拼写错误和跨上下文直接调用,但碰到了新问题。智能体为了绕过检查,会在注释里塞一大堆解释性文本,校验脚本读不懂注释,放了过去。结果那些注释比代码还长,而且注释里的承诺跟实际实现经常对不上。

这事还没完。注释到底算不算语义的一部分?校验脚本要不要去读注释里的承诺?如果读了,该用什么规则去验证承诺和实现的一致性?我还在试。等我跑通了再告诉你。