大概半年前,我们团队接手了一套接近“考古级”的订单管理系统。代码老、文档少、业务规则绕,自动化测试覆盖率勉强卡在40%,每次版本迭代,测试同学最怕的就是回归时不知道哪些功能又悄悄变了。我们当时做过一轮尝试:直接用AI生成全部测试用例,结果能跑通、也能跑出报告,但没人敢信——因为AI生成的断言逻辑偶尔是错的,它甚至会自信地把一个“应该失败”的用例标成通过。
后来我们换了个思路,不再把AI当成“能写全套测试的超级工程师”,而是把它的能力拆开用:Copilot负责翻译,MCP负责调度,本地模型负责兜底,人负责审核。这套组合跑下来,自动化测试用例维护成本降了一大截,新增接口测试的产出速度大概提了3倍。今天就把这套“AI生成本地跑”的务实方案拆开聊一聊。
1. 为什么是这三样:Copilot、MCP与本地模型
1.1 先交代业务背景和痛点
我们面对的系统常年没有专职测试开发,测试团队以手工和半自动为主。原来那套自动化脚本,是用Selenium + 测试平台自带的录制工具拼出来的,录一遍能跑,改一次前端样式就碎一半。接口层虽然有Postman集合,但几乎没有做断言和参数化,上线前靠人肉点一遍。
在这种背景下,最痛的不是“没有自动化”,而是“没有可持续维护的自动化”。我们试过让AI直接全自动生成脚本,速度快得惊人,但生成完才发现:
- 部分用例定位元素太脆弱,一次前端改版就大面积失效;
- 断言逻辑“想当然”,比如接口返回的成功标志变了,AI还在按旧字段判断;
- 测试数据全靠硬编码,跑过一次之后第二次直接失败。
后来我们达成的共识是:AI生成本地跑,但不能把AI的输出当作最终产物。AI应该当一个“翻译官”和“调度员”,它把人话翻译成代码,把人和工具连接起来,但每一步关键决策都要有人审核。这个认知是我们整套方案的起点——AI解决效率问题,人解决信任问题。
1.2 方案定位:分工明确的AI协作链
既然不让AI大包大揽,那就要重新划分职责。我们把AI能力拆成了三层:
- Copilot——翻译层:负责把业务需求、接口文档、失败日志“翻译”成可读可改的测试代码和排查建议,它的强项就是代码语境理解,非常适合做测试用例的初稿生成和代码解释;
- MCP——调度层:负责把AI的“意图”翻译成真正的工具调用,比如让AI去测试平台拉取一条失败用例、去数据库查一条测试数据、去缺陷系统登记一个Bug。MCP在这里的角色更像司机,AI说想去哪,司机负责开车到目的地;
- 本地大模型——兜底层:负责处理不能出内网的数据和需求,做脱敏后的文本理解、本地知识库问答和轻量级的语义分类。
这三层不是叠加关系,而是互相配合的协作链:本地模型做初步的信息理解,Copilot生成代码草稿,MCP执行真正的落地动作,测试人员负责最后审批。这样既不浪费AI的能力,又不会失控。
如果你所在的团队也遇到过“AI生成的测试脚本不敢用”“AI叫得动但跑不对”的情况,这套分工思路其实可以直接抄走。
2. 整体架构:翻译、司机、底盘怎么分工
2.1 三层协作模型
一句话概括我们最终跑通的架构:Copilot是我们和代码之间的翻译,MCP是我们和系统之间的桥梁,本地模型是处理敏感信息的保险盒。
具体执行时,我们跑出了一条比较顺的链路(打个比方,有点像外包团队协作):
- 测试同学写一句话需求,例如“新增订单创建接口,字段有客户ID、商品ID、数量,校验非法数量返回400”——这是人的输入;
- Copilot Chat根据这个需求生成pytest接口测试骨架,包含参数化、断言框架和基础数据构造逻辑;
- 人把骨架里的业务断言核对一遍,修正AI理解的偏差,比如确认“数量不可为负数”这个规则在产品里是服务端校验还是前端校验;
- MCP Server在本地运行,暴露出可被AI调用的工具——比如“获取测试环境配置”“查询数据库表结构”“向测试平台提交测试结果”;
- AI Agent根据人的指令,通过MCP调用这些工具,把测试数据准备好、把测试执行起来、把失败原因汇总回传到群里;
- 本地模型单独处理涉敏的需求文档,例如脱敏后的用户协议、专利材料、内部设计文档,用来生成测试要点和边界条件清单。
用这套链路,AI参与度很高,但每一个可能出问题的节点(尤其是断言和期望值)都被人卡了一道。
2.2 MCP与Copilot的边界
很多人问我们:“既然Copilot都能写代码了,为什么还要加一个MCP?直接用Copilot去执行不行吗?”
这个问题我们一开始也困惑。实际用下来发现,Copilot和MCP是两种完全不同的能力:
- Copilot理解的是“代码语境”:你给它一段代码,它能解释、补全、重构;你让它根据自然语言生成代码,它也能做,但它没有主动去操作系统里查数据的能力。它更像一个坐在工位上等你递资料的专家;
- MCP解决的是“工具连接”:MCP Server定义了AI可以调用的工具,每个工具有明确的输入输出格式,比如“获取订单详情”“查询测试环境配置”“创建Bug”。AI通过这些工具,才能真正把意图变成操作。
换句话说,Copilot负责出主意,MCP负责跑腿。如果只让Copilot写代码、然后人手动去跑,效率提升很有限;如果只接MCP没有Copilot辅助翻译和生成,那AI能调用的工具再多,也不知道怎么把一条业务描述变成一段完整的用例脚本。
我们在实际项目里,一般让Copilot承担60%的代码生成量,MCP承担剩下的流程自动化,人只做审核和决策。这个比例可以根据团队情况调整,但“翻译+调度”的组合方式我建议保留。
2.3 本地模型扮演的“底盘”角色
再来说本地模型。我们选择本地跑一个7B参数的开源模型,部署在一台闲置的GPU服务器上,用的是Ollama。选择7B而不是更大的模型,原因有两点:
第一,OCR和文本理解任务不追求极致的生成能力,7B模型做中文总结、实体提取、分类完全够用;第二,本地模型要承载的是开发人员自己的笔记本也能连接的轻量服务,太大的模型不仅部署麻烦,推理速度也拖慢节奏。
本地模型的典型场景:
- 对一份几十页的需求PDF做摘要,提取出“对测试有影响的功能点”,比如新增状态流转、变更字段类型、移除入口等;
- 对脱敏后的接口日志做错误信息分类,把常见异常类型(超时、数据库约束冲突、空指针)归组,减少人工翻日志的时间;
- 做测试数据生成的辅助,比如给一批脱敏用户数据生成合法的姓名、地址、手机号,避免直接在生产库上操作。
这里要特别说一句:本地模型不要试图取代Copilot。我们试过让本地模型写pytest代码,效果比Copilot差不少。术业有专攻,本地模型老老实实负责“不能出内网”的文本处理和轻量分类,Copilot负责代码生成,这个搭配最舒服。
3. 工程落地:从零搭一套能够干活的MCP Server
3.1 选定工具链:Python + FastMCP
MCP全称Model Context Protocol,本质上是一套规范,定义AI客户端如何发现、调用外部的能力。相对常见的做法是把MCP Server当成本地服务,通过stdio或HTTP跟AI客户端通信。
官方SDK有TypeScript和Python版本。我们团队Python是主语言,所以选了Python生态里的FastMCP,它把协议细节封装得很好,几行代码就能定义出一个可调用的工具。
先装依赖:
pip install fastmcp然后写一个最简单的MCP Server,暴露两个工具:一个返回测试环境配置,一个查数据库表结构。这一步先把“AI能调用工具”的链路打通,后面再慢慢增加能力。
from fastmcp import FastMCP mcp = FastMCP("test-toolkit") @mcp.tool() def get_test_env(env_name: str) -> str: """获取指定测试环境的基础配置信息""" configs = { "dev": "http://dev.example.com", "test": "http://test.example.com", "staging": "http://staging.example.com", } return configs.get(env_name, "unknown") @mcp.tool() def get_table_schema(table_name: str) -> str: """查询指定数据表的结构信息,返回字段名和类型列表""" # 这里实际会连接内部数据库的information_schema,此处为示例 fake_schema = { "orders": "id INT, customer_id INT, goods_id INT, quantity INT, created_at DATETIME", "users": "id INT, name VARCHAR(100), phone VARCHAR(20)", } return fake_schema.get(table_name, "table not found") if __name__ == "__main__": mcp.run(transport="stdio")跑起来很简单:
python mcp_server.py但这只是第一步,真正的价值在于把企业内部的各种系统“塞”进MCP里。我们后来陆续加了几类工具:
- 测试平台工具:根据测试用例ID查询历史执行记录、获取失败日志、触发指定测试套件运行;
- 缺陷系统工具:根据错误信息自动创建Bug草稿,标题、复现步骤、堆栈信息自动填充;
- 数据库工具:在指定的测试库执行只读SQL,例如查出最新订单号、统计某个状态的数据量;
- 消息通知工具:把测试结果以摘要形式发到团队群。
每一类工具都是独立的Python函数,入参出参都定义得比较明确。因为MCP协议本身不限制工具数量,理论上你想暴露多少能力都行,只要注意别把生产库的写权限挂上去。
3.2 把MCP Server接入Agent客户端
Server写好了,还要让AI客户端能发现它。当前主流的做法是在AI客户端的配置文件里声明mcpServers。以我们的实测为例,在支持MCP的客户端(比如Cline、Claude Desktop,以及现在很多企业内部的Agent平台)里,配置文件一般长这样:
{ "mcpServers": { "test-toolkit": { "command": "python", "args": ["/path/to/mcp_server.py"], "env": { "DB_CONN_STR": "mysql://readonly:****@10.0.0.8:3306/test_db", "TEST_PLATFORM_TOKEN": "****" } } } }配置好之后,AI客户端启动时会自动拉起这个MCP Server进程,然后扫描它暴露的工具列表。现在你在对话里就能说“查一下订单表的结构”,AI会调用get_table_schema这个工具,把结果返回给你,再根据这些信息继续往下做。
这个环节我们踩的第一个坑是环境变量。MCP Server进程从AI客户端继承环境变量,如果Python依赖装在了某个虚拟环境里,直接在配置里写python可能找不到依赖。解决办法有两个:要么把MCP Server的依赖装到全局环境,要么在配置里指向虚拟环境的python绝对路径。我们后来统一用conda环境,路径写死,问题才消停。
3.3 本地大模型:Ollama的部署与调用
再回来补一下本地模型的部署细节。之前说我们用Ollama,这里给出具体操作。
在GPU服务器上安装Ollama很简单:
curl -fsSL https://ollama.com/install.sh | sh然后拉取模型:
ollama pull qwen2.5-coder:7bOllama默认启动后会监听11434端口,通过HTTP API对外提供服务。我们写了一个Python封装,用来调用本地模型做文本总结和分类:
import requests OLLAMA_URL = "http://localhost:11434/api/generate" def summarize_text(text: str) -> str: """调用本地模型对长文本做摘要""" prompt = f"请对以下内容做一个不超过200字的要点总结,只输出要点,不要解释:\n{text}" resp = requests.post(OLLAMA_URL, json={ "model": "qwen2.5-coder:7b", "prompt": prompt, "stream": False, "options": {"temperature": 0.2} }) return resp.json().get("response", "")实际调用时,temperature我习惯设低一点,0.2左右,保证输出稳定。和那些动辄几十B并发的云端API比,7B模型跑在本地确实慢不少,但胜在数据不出内网,而且对“摘要、分类”这类任务完全够用。
我们有一个流程是这样的:需求文档进到内部系统后,先自动去敏感信息(比如用户真实姓名、手机号),再调用本地模型生成“测试关注点清单”,最后由测试负责人人工补充遗漏的边界条件。这个流程跑了一个季度,比之前纯人工阅读文档至少省了40%的时间。
4. 自动化测试中的实际用法
4.1 翻译式用例生成:让Copilot当真正的翻译
聊完基建,来说最核心的部分——Copilot怎么在自动化测试里当“翻译”。
我们的标准用法是这样的:测试同学先把业务规则用口语写出来,不要求写代码,然后让Copilot生成测试用例骨架。关键点是先把规则写清楚,越接近人话越好。比如:
请生成一个pytest接口测试用例,针对创建订单接口 POST /api/orders: 1. 正常场景:传入customer_id=1001, goods_id=88, quantity=2,期望返回200且订单号非空; 2. 边界场景:quantity=0,期望返回400; 3. 异常场景:customer_id不存在,期望返回404; 4. 断言期望值字段为code和message。 请用requests库实现,参数化格式为pytest.mark.parametrize。这段描述虽然也是中文,但把预期值、接口路径、断言字段都给了,Copilot翻译出来的代码准确率非常高。反过来,如果你的需求描述很模糊,只写一句“测一下创建订单接口”,那Copilot生成的东西基本只能算“样子货”,改起来比你从零写还费劲。
这就是“Copilot当翻译”的真实含义:你不是让AI自己去理解业务,而是让它把你已经拆解好的思路转成代码。翻译任务里,人类负责说“人话”,AI负责输出“机器话”。
实测下来,接口测试用例的初稿准确率可以到80%左右,剩下的20%主要集中在边界条件缺失和字段类型处理不当。UI测试会差一些,主要因为元素定位本身就依赖前端现状,Copilot看不见页面渲染结果,只能靠猜测。所以我们给的策略是:接口测试大胆用Copilot生成,UI测试让Copilot生成骨架、人再补定位逻辑。
4.2 让Agent通过MCP自动排查失败用例
测试跑完总会有失败用例,过去我们花大量时间打开报告、翻日志、定位问题。现在我们用MCP把这个流程自动化了一部分。
大致链路是:
- 测试任务跑完后,结果回传到测试平台;
- 一个定时触发的Agent脚本主动去测试平台拉取“最近一次执行失败的用例列表”;
- Agent通过MCP调用get_failed_case_detail工具,获取用例的错误日志;
- 日志被截断后发给本地模型做一次粗分类,分“可能是代码问题”“可能是数据问题”“可能是环境问题”;
- 分类结果附上日志摘要,自动在缺陷系统创建Bug草稿,并通知对应的开发负责人。
这个流程里,MCP的角色就是那个“司机”,AI让它去测试平台拉数据,它就去拉;让它去缺陷系统建单,它就建单。它不负责判断,只负责执行。
单个环节都没什么高深的技术,但串起来之后,我们排障平均时间从40分钟降到了15分钟,因为很多环境问题(比如测试库被谁写入脏数据导致断言失败)在人工介入前就已经被分类识别出来。
4.3 测试数据准备与清理的自动化
自动化测试最难受的往往是测试数据。登录态、订单状态、优惠券有效期,任何一个数据不对,用例就会挂。我们之前是一个人手动维护一批测试账号和订单,崩溃点是:只要有人跑了一遍破坏了数据,后面所有人都跟着红。
现在我们把测试数据准备也交给MCP来做。我们写了一个数据工厂工具,变成一个MCP工具暴露出去:
@mcp.tool() def create_test_order(customer_id: int, goods_id: int, quantity: int, status: str = "PENDING") -> dict: """创建一条指定状态的测试订单,返回订单ID""" # 这里调用内部的数据工厂服务,实际会往测试库插入数据并返回 return {"order_id": 2025040112345, "status": status}同时还有配套的清理工具:
@mcp.tool() def clean_test_order(order_id: int) -> bool: """清理指定测试订单,用于用例结束后的数据回收""" ...测试脚本执行前后,通过MCP把数据“安排”好,不再依赖手工维护。尤其在跑批量回归时,数据每次都干净一致,稳定性提高了很多。
当然,这里有个必须注意的点:数据工厂这类工具只能连测试库,绝不能连生产库。我们在这个MCP Server的代码里硬编码了数据库连接的地址校验,如果发现连的不是测试环境就拒绝执行。这种“硬保护”建议一定要做在代码层面,而不是靠人自觉。
5. 踩过的坑和避坑经验
5.1 Copilot生成了“对的错代码”
Copilot生成的代码语法上完全正确,逻辑上却有一个隐蔽错误:它误以为订单状态字段是字符串"open",而实际上系统里是整数1。这类问题在接口测试里最常见,因为Copilot只能基于训练数据里的常识去猜字段值,无法感知你们系统的具体字段枚举。
我们的对策是:把系统里稳定的字段枚举、状态码、常用错误提示整理一份“测试规范说明”,在让Copilot生成用例时,把这部分内容作为上下文粘贴进去。AI能利用多长的上下文,我们就塞多长的规范,实测下来准确率能提升不少。
5.2 MCP Server进程“悄悄退掉”
有段时间AI频繁报“tool not found”,查了半天发现是MCP Server进程崩溃退出了,但AI客户端没有自动重启。后来我们用一个简单的supervisor配置拉起MCP Server,保证进程退出后能自动重启。
[program:mcp-test-toolkit] command=/opt/conda/envs/agent/bin/python /opt/mcp_servers/mcp_server.py autorestart=true stdout_logfile=/var/log/mcp_test_toolkit.log stderr_logfile=/var/log/mcp_test_toolkit_err.log另外要给MCP Server设置超时时间。如果某个工具执行超过了30秒,客户端那边很容易一直转圈,有时候甚至会重复调用,造成测试库里出现重复数据。工具设计时也要尽量保持“轻量”,只读操作优先,写操作要加幂等控制。
5.3 本地模型被“长文本”拖垮
我们刚开始用本地模型做文档摘要时,直接把几十页PDF原文塞进去,结果不是报错就是输出质量很差。后来才意识到,7B模型的上下文窗口有限,处理长文本必须分段。
我们的办法是:先按章节切分文本,每段控制在1000字以内,分段摘要,最后再把分段摘要合并成整体摘要。虽然多了一步,但输出质量稳定得多。
另外GPU显存不足也是个高频问题。7B模型量化版大概需要6GB左右显存,但如果同时跑多个请求,内存占用会往上飙。我们后来限制同时请求数最多2个,排在后面的请求排队处理,实测下来基本稳定。
5.4 常见问题速查表
| 问题 | 可能原因 | 解决建议 |
|---|---|---|
| Copilot生成的用例断言字段错误 | AI无法感知业务字段枚举 | 把字段规范粘贴进上下文,生成后人工核对关键断言 |
| MCP Server无响应 | 进程崩溃或超时未处理 | 用supervisor守护进程,工具内设置合理超时 |
| 本地模型摘要质量差 | 输入文本过长、未分段 | 按章节分段摘要,再合并汇总 |
| Agent调用数据库工具返回乱码 | 字符集配置不一致 | 连接串里显式指定utf8mb4 |
| 测试数据重复创建 | MCP工具没有幂等 | 写操作增加唯一键校验和重复尝试过滤 |
| 本地模型推理太慢 | 模型过大或并发过高 | 换小参数量化版,限制并发数 |
5.5 权限和安全的底线
最后一定要提醒一句:MCP Server虽然方便,但它等于给AI开了一串“手”出去,权限控制必须收紧。
我们内部的规范有三条:
- 所有MCP工具连接数据库一律使用只读账号,写操作必须经过单独申请的写专用账号,并且每次写操作都要记审计日志;
- 工具暴露范围遵循最小权限原则,AI只能调用完成当前任务必需的工具,不暴露生产环境任何能力;
- 涉及敏感信息的字段脱敏后才允许进入大模型上下文,包括Copilot的上下文,防止业务数据进入不可控的环节。
这三点不是技术问题,而是流程红线。如果你们也想把MCP大规模接入自动化测试体系,我建议先在公司内部把这几条安全规范定下来。
这套方案跑下来,我最深的体会是:AI在自动化测试里最好的定位不是“替代者”,而是“放大器”。它把人的意图快速翻译成代码、把工具调用自动化、把信息从漫长链路里捞出来,但它判断不了业务逻辑、给不了系统真实的期望行为。Copilot当翻译、MCP当司机、本地模型当保险盒,人站在中间做裁判——这个分工,是目前我们团队效率和数据安全之间最平衡的一个点。最后再分享一个小经验:一开始别想着把所有工具都接进MCP,先接一两个真正难受的流程,比如失败日志拉取或者测试数据准备,跑通了再逐步扩大,这样团队接受度和维护成本都会可控很多。