从 MDC 到 Agent:我手搓的文档路由协议,在 Spring AI Alibaba 里找到了正式实现
原创 · 鸣潮牛逼 | 本文同步发布:GitHub (nbhhdd/mdc-workflow) · CSDN
前言:一个让我纠结很久的问题
我用 AI 辅助开发已经两年了。踩过最大的坑不是模型不够聪明,而是------文档过期。
场景很常见:我用 AI 改了某个模块的接口,忘了更新文档。下次让 AI 写新功能时,它读到我几个月前写的旧文档,用过期的方法名、错误的参数结构,生成一堆和项目架构不一致的代码。改代码的时间比写代码还多。
传统的解决办法是"靠人自觉"------但人总会忘。我自己就忘过无数次。
后来我悟了:既然 AI 是概率模型,输入模糊就会概率发散,那就用规范的结构化约束去收窄它的概率分布。 于是有了 MDC(Multi-Document Co-driven)多文档协同工作流。
一、MDC 方法论:用纯文本手搓一个"编排器"
1.1 核心思想
把项目知识拆成 8 类独立文档,通过一个核心调度文档做路由:
┌─── 核心调度文档 (Router) ───┐
│ TS-Protocol 时间戳看门狗 │
└────────────┬───────────────┘
▼
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ 【全局规范与设计蓝图】 │ │ 【执行与动态反馈】 │
│ 01 技术架构 / 02 功能规划 │ │ 03 错误档案 / 04 文件规范 │
│ 05 测试策略 / 06 代码规范 │ │ ... │
└─────────────────────────────┘ └─────────────────────────────┘
关键机制 :AI 修 Bug 时只读错误档案+技术架构,写新功能时只读功能规划+代码规范------高内聚低耦合,上下文污染降低约 60%。
1.2 TS-Protocol 时间戳闭环(最核心的创新)
每份文档带 last_updated 时间戳(格式 YYYYMMDD-HHMM),AI 改完代码后必须:
- 更新调度文档中的时间戳索引
- 同步重写对应文档章节
- 然后才能输出生产代码
这实现了"从人动到 AI 动":AI 写代码 → AI 自动维护文档,人只需审查结果。
1.3 一个关键认知
做 MDC 的时候,我隐隐觉得自己在搭一个什么东西------有路由、有状态、有校验。但当时我只把它当"提示词工程的高级玩法"。
直到我开始学 Agent 框架,才恍然大悟。
二、学习 Spring AI Alibaba:我看到了自己的方法论
2.1 发现:工具路由 = 我的文档路由
学 Spring AI Alibaba 的 ReactAgent 时,我发现 Agent 的核心机制和我的 MDC 惊人地同构:
| 我的 MDC(纯文本) | Agent 框架(代码) |
|---|---|
| 核心调度文档(Router) | ReactAgent + 工具路由 |
| 8 类文档模块 | 工具列表 + 系统提示词 |
| TS-Protocol 时间戳闭环 | 上下文管理 + Checkpoint |
| "修 Bug 只读 D12+D03" | 按工具描述决定调哪个 |
| 自反思清单 | finish_reason / 迭代上限 |
同一个思想:给 AI 决策路径。 我相当于用纯文本手搓了 Agent 的路由+记忆机制,只是当时不知道它叫这个名字。
2.2 认知升级:从"软建议"到"硬约束"
MDC 方法论有个天然缺陷:它是靠提示词约束 AI 的。"你改完代码必须更新文档"------AI 可听可不听,上下文一长就忘。
而 Agent 的工具调用是代码级强制 :Agent 不调用 updateDoc 工具,就无法完成任务。流程从"软建议"变成了"硬约束"。
这就是"方法论产品化"的价值。
三、实战:把 MDC 做成一个 Agent
3.1 项目结构
基于 Spring AI Alibaba(Java 17 + Spring Boot 3.5),核心代码 4 个文件:
mdc-agent/
├── MdcAgentApplication.java # 启动类
├── MdcAgentConfig.java # Agent 定义(ReactAgent + 工具)
├── MdcAgentStaticLoader.java # 注册到 Studio
└── tools/
└── MdcDocTools.java # 4 个核心工具
3.2 4 个工具 = MDC 四大机制的代码化
java
@Tool(description = "根据任务类型读取对应文档。任务类型: tech/feature/error/file/test/code/router")
public String readDoc(String taskType) { ... }
@Tool(description = "校验指定文档的时间戳是否过期(TS-Protocol 看门狗)")
public String checkTsProtocol(String taskType) { ... }
@Tool(description = "更新指定文档内容并刷新时间戳(写代码后必须执行)")
public String updateDoc(String taskType, String content) { ... }
@Tool(description = "在所有 MDC 文档中搜索关键词")
public String searchDocs(String keyword) { ... }
3.3 Agent 系统提示词:把 MDC 规则注入
java
private static final String INSTRUCTION = """
你是 MDC 文档协同智能体,负责维护项目的多文档工作流。
1. 用户提出开发任务时,先调用 read_doc 按任务类型读取对应文档
- 修改核心业务逻辑 → 读 技术架构文档
- 修正重大 Bug → 读 错误档案文档
- ...
2. 改代码前调用 check_ts_protocol 校验文档时间戳是否过期
3. 改完代码后调用 update_doc 同步更新文档并刷新时间戳
禁止:不读文档就写代码;改完代码不更新文档。
""";
3.4 运行效果:Agent 完整执行 MDC 闭环
实测对话(用户说"我修好了登录 NPE bug"):
工具调用序列: readDoc(error) → checkTsProtocol(error) → updateDoc(error)
Agent 的行为:
- ✅ 先读错误档案 → 发现文档不存在
- ✅ 校验时间戳 → 警告"文档不存在,建议先创建再写代码"
- ✅ 更新文档 → 真实创建了结构完整的错误档案:
markdown
# 03-错误档案.md
> last_updated: 20260803-1812
### ERR-001:登录接口空指针异常(NPE)
- **状态**:✅ 已修复
- **模块**:登录模块(Login)
- **严重级别**:P1(高,阻塞登录主流程)
- **根因分析**:用户信息组装逻辑中,存在未做空值判定的字段访问...
验证结果:ALL PASS(应用存活 / Agent 注册 / 工具调用序列 / 文档真实写入 / 时间戳刷新)
3.5 真实测验:6 类任务全覆盖
我写了测验脚本,模拟面试官会问的 6 类任务,逐个检查 Agent 的实际工具调用行为:
| 任务 | 输入示例 | 预期工具 | 结果 |
|---|---|---|---|
| 1. 普通问答 | "What tools do you have?" | 不调工具,直接回答 | ✅ 工具调用为空 |
| 2. 新增功能 | "Add a new export feature, read feature doc first" | readDoc(feature) | ✅ readDoc + checkTsProtocol |
| 3. 修Bug | "Fix a critical payment bug, read error archive" | readDoc(error) + checkTsProtocol | ✅ 触发错误档案读取+校验 |
| 4. 完整闭环 | "Fixed payment bug, update error archive" | readDoc → checkTsProtocol → updateDoc | ✅ 三步完整执行 |
| 5. 搜索文档 | "Search docs for 'login'" | searchDocs | ✅ 多次检索 |
| 6. 写码前检查 | "Check code standards before writing" | readDoc(code) + checkTsProtocol | ✅ 规范读取+时间戳校验 |
结果:6/6 全部通过。 Agent 能根据任务类型自主决定调用哪些工具,完整执行"文档路由 → 时间戳校验 → 文档更新"的 MDC 闭环。
四、踩坑记录:Spring AI Alibaba 接入 DeepSeek 的 6 个坑
给后来人省时间,这 6 个坑我全踩过:
坑 1:默认模型是 gpt-4o-mini,配置不生效
Spring AI 1.1.2 的模型配置前缀变了:
yaml
# ❌ 错误(旧版写法)
spring.ai.openai.chat.model: deepseek-v4-flash
# ✅ 正确(1.1.2 写法)
spring.ai.openai.chat.options.model: deepseek-v4-flash
坑 2:base-url 重复 /v1
Spring AI 会自动拼 /v1/chat/completions:
yaml
# ❌ 会变成 /v1/v1/chat/completions
base-url: https://api.deepseek.com/v1
# ✅ 正确
base-url: https://api.deepseek.com
坑 3:ChatModel Bean 冲突
dashscope 自动配置和 openai 自动配置同时存在,报 "required a single bean, but 2 were found":
java
// 方法参数加 @Qualifier
public ReactAgent xxx(@Qualifier("openAiChatModel") ChatModel chatModel) { ... }
坑 4:91MB 的 GraalVM Python 依赖
官方 chatbot 示例带 Python 执行工具,依赖 91MB 且网络不稳定会下载失败。不需要就删掉,Agent 核心功能不受影响。
坑 5:中文 JSON 400
Windows 下 curl 发中文默认 GBK 编码,服务端按 UTF-8 解析报 "Invalid UTF-8 middle byte":
bash
# 用文件方式发送,避免 shell 转义和编码问题
curl -X POST ... --data-binary @payload.json
坑 6:Studio 接口字段
/run_sse 接口的 newMessage 必须带 messageType 字段(多态类型标识):
json
{"newMessage": {"messageType": "user", "content": "..."}}
五、总结与展望
这趟学习最大的收获
不是学会了某个框架,而是验证了一个认知:
我的 MDC 方法论和 Agent 是同一个思想的两个实现------一个用纯文本,一个用代码。方法论是"道",框架是"术"。先有了"道",学"术"的时候才能一眼看穿本质。
下一步计划
- MCP 集成:让 Agent 能连接真实项目文件系统
- 多 Agent 化:主管 Agent + 文档子Agent + 代码子Agent
- 真实项目验证:在开源项目上跑通完整闭环
给读者的建议
如果你也在用 AI 辅助开发,强烈建议试试文档驱动的工作流。不用一开始就上 Agent 框架------先在提示词层面把"任务类型 → 文档路由"的结构搭起来,你会发现 AI 的输出质量立刻上一个台阶。等你熟悉了,再升级成 Agent 化实现。
附录:资源链接
- MDC 工作流开源仓库:https://github.com/nbhhdd/mdc-workflow
- Spring AI Alibaba:https://github.com/alibaba/spring-ai-alibaba
- 本文配套代码:mdc-agent 示例(基于 spring-ai-alibaba examples 改造)
版权声明:本文为原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。