Agent + Skills + MCP 的测试体系

6 阅读12分钟

从 0 到 1:我如何为 ai-robot 设计一套基于 Agent + Skills + MCP 的测试体系

一、为什么我想写这套方案

最近我在整理自己的 ai-robot 项目时,发现一个很典型的问题:

传统 Web 项目的测试思路,放到 AI Web 项目里,经常只够用一半。

为什么这么说?

因为 ai-robot 不是单纯的 CRUD 系统,它同时包含:

  • 普通聊天
  • SSE 流式输出
  • 联网搜索增强
  • RAG 智能客服
  • Markdown 分片上传
  • 异步向量化
  • PostgreSQL + pgvector

如果还按传统方式去做测试,通常只能测到:

  • 接口有没有通
  • 状态码是不是 200
  • 某个字段有没有返回

但 AI 项目真正容易出问题的地方,其实不是这些。

真正难测的是:

  • SSE 流有没有完整结束
  • Advisor 是否真的注入了记忆 / 联网 / RAG 上下文
  • 文件上传、分片合并、异步向量化有没有形成闭环
  • 大模型输出能不能稳定断言
  • 失败之后能不能快速定位到底是 Controller、Service、数据库、向量化还是外部依赖的问题

所以我没有继续堆一堆零散接口脚本,而是尝试把 ai-robot 的测试设计成一套更像“产品”的体系:

Agent + Skills + MCP/Tools

这篇文章就完整记录一下这套方案的设计思路、落地过程,以及最后跑出来的效果。


二、项目背景:ai-robot 到底是什么

先简单交代一下项目背景。

ai-robot 是一个基于 Spring Boot 3 + Spring AI 的 AI Web 项目,核心能力有两类:

1. 通用聊天

  • 支持普通聊天
  • 支持 SSE 流式输出
  • 支持对话记忆
  • 支持联网搜索增强
  • 支持消息落库

2. 智能客服

  • 支持 Markdown 知识库上传
  • 支持分片上传和断点续传
  • 支持文件合并
  • 支持异步向量化
  • 支持基于 pgvector 的 RAG 问答

换句话说,这是一个典型的 AI 应用型 Web 项目。

而这类项目的测试,不仅要测“接口”,更要测“链路”。


三、传统测试思路为什么不够

如果只是用传统接口自动化去测这个项目,通常会遇到几个明显问题。

1. 只能测到接口,测不到增强链路

比如:

  • /chat/completion 返回了 200,不代表记忆增强真的生效
  • /customer-service/completion 返回了内容,不代表 RAG 检索真的命中了知识库

也就是说,你能测到“结果返回了”,但测不到“为什么返回这个结果”。

2. AI 输出不能逐字断言

AI 项目很难像普通接口那样直接写:

expect(response.text).toBe("xxx")

因为只要模型输出语气稍微变一点,测试就会抖。

所以 AI 测试更适合:

  • 结构化断言
  • 关键词断言
  • 规则断言
  • 状态机断言

3. 文件和异步链路很容易被忽略

知识库上传这一条链路其实很长:

file/check -> upload-chunk -> merge-chunk -> event -> vectorize -> completion

如果你只测最终的 /completion,很多中间问题会被掩盖掉。

比如:

  • 分片没清理
  • 状态机没流转
  • 文件落盘失败
  • 向量化失败
  • 删除时清理不彻底

4. 缺少统一编排

很多项目最后会变成:

  • 一个脚本测聊天
  • 一个脚本测上传
  • 一个脚本测数据库
  • 一个脚本测客服

最后脚本越来越多,但没有统一入口,也没有统一质量门禁。

所以我想做的不是“再补几个脚本”,而是做一套完整测试代理。


四、核心设计:为什么是 Agent + Skills + MCP

这套方案的核心思想可以概括成一句话:

把测试从“脚本集合”升级成“可编排的测试系统”。

我把它拆成三层:

1. Agent:负责任务编排

Agent 不直接执行具体测试动作,而是负责:

  • 接收测试任务
  • 决定当前要跑哪个阶段
  • 调用对应的 Skill
  • 汇总结果
  • 生成最终报告

你可以把它理解成测试编排器。

2. Skills:负责能力模块化

每个 Skill 只做一类明确的事情。

例如:

  • 场景识别
  • 用例清单生成
  • 本地门禁
  • 在线冒烟
  • 文件链路回归
  • 聊天 + RAG 回归
  • 全量回归与质量门禁

这样做的好处是:

  • 结构清晰
  • 易复用
  • 易扩展
  • 出问题容易定位

3. MCP / Tools:负责连接外部能力

这里的 MCP / Tools 不一定是严格意义上的 MCP Server, 更重要的是它承担了“连接外部能力”的职责。

比如我这里实际接入了:

  • 源码结构扫描
  • HTTP / SSE 请求
  • JDBC 直连 PostgreSQL
  • 文件系统校验

后续如果再扩展,也可以继续接:

  • 向量库校验
  • Mock SearXNG
  • Mock 模型服务
  • CI 系统

所以这套架构的本质不是某个具体技术名词,而是职责边界清晰。


五、我把 ai-robot 的测试拆成了 5 个阶段

为了让这套方案可逐步落地,而不是一上来就做成大而全,我把它分成了 5 个阶段。


第一阶段:离线分析

这一阶段不依赖运行中的后端服务,只做“结构级理解”。

目标是回答两个问题:

  1. 这个项目到底有哪些核心测试场景?
  2. 当前代码结构是否已经具备支撑这些测试场景的基本条件?

这一阶段我实现了三个核心能力:

1. 场景盘点

自动识别项目中的核心场景:

  • 普通聊天与记忆增强
  • 联网搜索与 SSE 输出
  • RAG 智能客服
  • 知识库上传与异步向量化

输出文件:

  • scene_inventory.json
2. 用例清单生成

根据场景生成结构化测试清单,而不是自然语言说明。

输出文件:

  • case_manifest.json
3. 本地门禁

检查:

  • Controller 是否存在
  • Advisor 是否存在
  • Service 是否存在
  • 关键端点是否覆盖

输出文件:

  • local_gate.json
  • summary.json

这一阶段最大的价值是:

即使后端没跑起来,也能快速发现“测试对象是否就绪”。


第二阶段:在线冒烟

第二阶段开始真正连运行中的后端。

但我没有一上来就测复杂模型输出,而是选择了一个非常稳定的策略:

直接利用项目里已有的“时间类问题后端兜底”能力。

为什么这样做?

因为它有两个优点:

  1. 不依赖真实模型波动
  2. 能稳定验证 HTTP + SSE 链路本身

这一阶段验证两个接口:

  • /chat/completion
  • /customer-service/completion

输出文件:

  • online_smoke.json

这一阶段关注的是:

  • 服务是不是在线
  • SSE 能不能返回
  • 链路是不是通的

第三阶段:知识库文件回归

第三阶段是我觉得最有价值的一步,因为它开始进入真正的“业务闭环测试”。

这里我没有只测一个接口,而是把整个知识库文件链路串起来:

  1. file/check
  2. upload-chunk
  3. merge-chunk
  4. file/list
  5. JDBC 查数据库
  6. 文件系统校验
  7. file/delete

这一阶段我验证了:

  • 文件初始不存在
  • 分片上传成功
  • uploadedChunks 正常返回
  • 数据库里 t_ai_customer_service_file_storage 状态正确
  • 数据库里 t_file_chunk_info 记录正确
  • 合并后分片目录被清理
  • 最终文件真正落盘
  • 删除之后数据库和文件系统都被清理

输出文件:

  • knowledge_file_regression.json

这一阶段还帮我测出了一个真实 bug:

删除知识库文件时,后端还会尝试再次删除已经被 mergeChunk() 清理掉的分片目录, 导致 FileNotFoundException,返回 10000

我顺手把这个 bug 修掉了:

  • 分片目录不存在时,删除逻辑应当幂等跳过,而不是抛异常

这个细节其实非常适合写进博客,因为它体现了测试不仅“验证”,还“推动修复”。


第四阶段:聊天落库 + RAG 回归

第四阶段我把两条高价值链路合到了一起:

1. 聊天链路

完整验证:

chat/new -> chat/completion -> 数据库落库 -> chat/delete

这里验证的不是“模型回答是否完美”,而是:

  • 是否创建了对话 UUID
  • t_chat 是否写入
  • t_chat_message 是否真的落入 user + assistant 两条消息
  • 删除对话后主表和消息表是否都清理干净
2. RAG 问答链路

完整验证:

上传知识库 -> 等待向量化完成 -> customer-service/completion -> 删除知识库

这里我特意设计了一个稳定问题:

小哈 AI 机器人支持哪些核心能力?

因为 fixture 里本来就写了:

  • 普通聊天
  • 联网搜索
  • 智能客服

所以我可以用关键词断言来判断回答是否命中知识库。

输出文件:

  • chat_rag_regression.json

这个阶段的意义在于:

它第一次把“落库正确”和“RAG 命中正确”都纳入测试范围。


第五阶段:全量回归与质量门禁

如果前四个阶段解决的是“各模块怎么测”, 那第五阶段解决的就是:

“能不能一条命令把整套测试体系跑完,并给出最终门禁结论?”

所以我实现了一个总编排器:

  • 依次执行前四个阶段
  • 聚合通过率
  • 汇总失败项
  • 输出 JSON 报告
  • 输出 Markdown 报告

输出文件:

  • full_regression.json
  • full_regression.md

最后的质量门禁长这样:

  • 总检查数:44
  • 通过数:44
  • 失败数:0
  • Gate:PASS

这一阶段让整套测试体系真正具备了:

  • 一键执行
  • 可视化汇总
  • 可接 CI
  • 可做团队门禁

六、这套方案最终产出了什么

到目前为止,这套测试代理已经不只是“一个想法”,而是完整可运行的一套体系。

主要产物包括:

1. 测试代理代码

路径:

Resume/ai-robot/test-agent-mvp/

里面包括:

  • cli.py
  • runner.py
  • scene_inventory.py
  • case_manifest.py
  • local_gate.py
  • online_smoke.py
  • knowledge_file_regression.py
  • chat_rag_regression.py
  • full_regression.py
  • jdbc_snapshot.py
  • PostgresSnapshot.java

2. 测试报告

路径:

Resume/ai-robot/out/test-agent-mvp/

包括:

  • scene_inventory.json
  • case_manifest.json
  • local_gate.json
  • summary.json
  • online_smoke.json
  • knowledge_file_regression.json
  • chat_rag_regression.json
  • full_regression.json
  • full_regression.md

3. 技术方案与博客文档

路径:

  • ATestDocs/ai-robot-Agent化测试技术方案.md
  • ATestDocs/ai-robot-Agent测试方案-博客版.md

七、为什么这套方案值得写进博客

我觉得这套方案比较有意思的地方,不是“用了 Agent 这个词”,而是它确实解决了 AI 项目测试里的几个真实问题。

1. 它不是空谈架构,而是逐阶段落地

很多文章讲 Agent,最后都停留在概念层。

这套方案的特点是:

  • 第一阶段有产物
  • 第二阶段能跑接口
  • 第三阶段能测文件 + 数据库
  • 第四阶段能测聊天落库 + RAG
  • 第五阶段能做总回归与门禁

这是一条很清晰的落地路线。

2. 它适合 AI Web 项目,而不只是普通接口项目

因为它考虑了:

  • SSE
  • 流式响应
  • AI 输出不稳定
  • RAG 检索
  • 文件上传与异步链路
  • 向量化前后状态

这些都是 AI 应用常见但传统测试方案不太擅长覆盖的地方。

3. 它验证的不只是接口,而是完整链路

比如第三阶段和第四阶段,本质上都在做一件事:

从“接口是否成功”升级到“链路是否闭环”。

这类思路特别适合写博客,因为它体现了测试设计能力,而不是单纯脚本技巧。

4. 它还能反向发现和修复真实 bug

比如我在第三阶段就测出了删除逻辑里的幂等问题。

这说明测试体系不仅是验证工具,也是发现系统设计缺陷的放大镜。


八、如果继续演进,下一步可以做什么

虽然现在这套方案已经能跑完整 5 个阶段,但如果继续做,还有几个值得继续演进的方向。

1. 向量检索精细断言

目前第四阶段已经验证了“回答命中知识库关键词”, 但还没有继续下沉到:

  • TopK 命中文档校验
  • 向量表精细校验
  • metadata 过滤断言

2. Mock 外部依赖

目前很多回归是基于真实服务跑的。

如果后面接团队 CI,可以继续加入:

  • Mock SearXNG
  • Mock LLM
  • Mock Embedding

这样会让回归更稳定。

3. 失败样本归档

后续可以把失败时的:

  • 请求参数
  • SSE 结果
  • 数据库快照
  • 文件路径
  • 错误日志摘要

都沉淀成统一失败样本,方便复盘。

4. 接入 CI/CD

第五阶段已经具备质量门禁能力了, 下一步就可以直接接成:

  • GitHub Actions
  • Jenkins
  • 本地 pre-release 检查

九、我对这套方案的最终总结

如果让我用一句话总结这套方案,我会这样说:

我不是想给 ai-robot 再补几条测试脚本,而是想把它的测试体系设计成一个可编排、可扩展、可复用的测试代理系统。

这套系统的核心价值在于:

  • Agent 负责任务编排
  • Skills 负责测试能力模块化
  • MCP/Tools 负责连接代码、接口、数据库和文件系统

最终把测试从“单点脚本”升级成“多阶段回归体系”。

到现在为止,这套方案已经完成了 5 个阶段:

  1. 离线分析
  2. 在线冒烟
  3. 知识库文件回归
  4. 聊天落库 + RAG 回归
  5. 全量回归与质量门禁

并且已经跑到了:

  • 总检查数:44
  • 通过数:44
  • Gate:PASS

我觉得这不仅是一套适合 ai-robot 的测试方案,也是一套可以迁移到其他 AI Web 项目的测试设计思路。

如果以后我再做新的 AI 项目,我大概率还会沿着这条路线继续演化。