Agent驱动的测试变更管理系统设计实录

Agent驱动的测试变更管理系统设计实录

叫我EC就好

引言:一个看似简单的需求

“帮我为项目补充测试用例。”

这个需求听起来很简单,对吧?我最初也这么认为。让AI Agent分析代码,生成测试用例,编译运行,发现问题就修复——听起来就是一个标准的自动化流程。

但当我真正开始设计这个系统时,才发现真正的挑战根本不在代码生成本身,而在于一个更基本的问题:如何管理这些不断产生的变更?

想象一下这个场景:一个月后,当你看到代码库里多了几十个测试用例,你会问自己:

  • 这些测试用例是为什么写的?
  • 它们测试了什么功能?
  • 哪些是必要的,哪些可能是冗余的?
  • 如果要修改框架API,会影响哪些测试?

如果这些问题没有答案,那么即使AI生成的代码再完美,整个系统也会逐渐走向混乱。

这篇文章想和大家分享我在设计TestSpec系统时的一些思考——从10节点工作流到4阶段设计的演进,从索引文档到规范体系的转变,以及在这个过程中对”什么是真正需要管控的”这个问题的重新理解。

第一次尝试:10节点工作流的诞生

从问题开始的设计

最初的想法很直接:既然测试开发有固定的流程,那就把这个流程标准化、自动化。我梳理了一个典型的测试开发过程:

  1. 理解需求 → 确定测试覆盖点
  2. 选择测试策略 → 设计测试用例
  3. 编写测试代码 → 配置构建系统
  4. 编译验证 → 修复编译错误
  5. 运行测试 → 分析测试结果
  6. 修复问题 → 重新验证

看起来很合理,于是我设计了一个10节点的工作流:

1
2
3
4
5
6
7
8
9
节点0A: 环境检查 → 节点0B: 中断任务恢复

节点1: 需求澄清 → 节点2: 代码定位

节点3A: 集成测试设计 → 节点3B: 单元测试设计

节点4: 代码实现 → 节点5: 编译执行

节点6: 日志分析与问题诊断 → 节点7: 任务总结

每个节点都有明确的职责,输入输出都定义清楚,节点之间的依赖关系也很清晰。从工程角度看,这是一个相当完整的设计。

实践中暴露的问题

但在实际使用中,问题很快就暴露出来了。

有一次,团队成员反馈:”我只是想快速查一下某个项目已有哪些测试用例,但Agent坚持要走完整个流程,还创建了一堆我不需要的文档。”

还有一次,另一个同事说:”我需要重构一个API,这会影响大量现有测试。但10节点流程是为’新增测试’设计的,根本不适合这种批量修改的场景。”

更让我困扰的是产物文档的管理。每次执行工作流都会在discuss/目录下生成一堆文档:

  • requirements/task_001.md
  • design/task_001_integration_design.md
  • execution/task_001_compile.log
  • summary/task_001_summary.md

但这些文档就像流水账,你很难从中理解:

  • 为什么要补充这个测试?
  • 这个测试验证的是什么需求?
  • 测试的历史演进是怎样的?

我开始意识到,流程的标准化并不等于变更的可管理性

更深层的反思

有一天,我坐下来重新审视整个设计,问了自己几个问题:

  1. 并非所有任务都需要完整流程。查询现有测试覆盖是只读操作,为什么要创建那么多产物文档?
  2. 不同场景的需求差异很大。新增测试、修复bug、重构代码——这些场景的复杂度和关注点完全不同,却用同一套流程处理。
  3. 缺少”当前真相”层。我们有大量的产物文档记录”做了什么”,但缺少一个权威的地方告诉你”现在是什么状态”。

这些问题的根源在于:我把关注点放在了”如何执行任务”上,而忽略了”如何管理知识和变更”

重新思考:什么是真正需要管控的

OpenSpec的启发

周末在看开源项目时,偶然发现了一个叫OpenSpec的项目。它的设计理念让我眼前一亮:

1
2
3
specs/           # 当前真相层(The Source of Truth)
changes/ # 变更提案层(Proposed Changes)
changes/archive/ # 历史归档层(Change History)

这个简单的三层结构背后,有一个很深刻的洞察:系统的演进本质上是”当前状态”和”变更历史”的交互

当前状态(specs/)告诉你”系统现在是什么样子”。
变更历史(changes/archive/)告诉你”系统是如何变成现在这个样子的”。
而变更提案(changes/)是连接两者的桥梁。

这让我重新思考我们的测试管理系统应该是什么样子。

核心洞察:索引文档也是一种”规格”

在梳理系统架构时,我发现了一个有趣的现象。我们有一个索引系统,记录了测试框架的所有能力:

  • 框架支持哪些通信协议
  • 有哪些虚拟设备可用
  • 支持哪些时序控制机制

这些索引文档原本是为了让AI Agent快速了解框架能力。但当我尝试用OpenSpec的思维重新审视时,发现:这些索引文档本质上也是一种”规格”——框架规格

举个例子:当我们要添加一个新的通信指令时,

  • 这是”框架能力变更”,需要更新索引文档
  • 但这个变更也需要:提案、评审、实现、测试、归档
  • 为什么框架变更和测试变更要用不同的管理方式?

再看一个更复杂的场景:重构一个核心API

  • 这既是”框架规格变更”,也会导致”所有相关测试变更”
  • 如果框架变更和测试变更分离管理,很容易出现不一致

我开始意识到,我们需要的不是两套系统,而是一个统一的规范管理体系

重新定义”变更”的边界

基于这个洞察,我重新梳理了变更的分类:

只读任务(不需要管控):

  • 查询框架能力:”系统支持哪些通信协议?”
  • 检查测试覆盖:”项目X已有哪些测试用例?”
  • 分析编译日志:”这个编译错误是什么原因?”
  • 定位代码位置:”某个测试用例在哪个文件?”

这些任务不修改任何东西,不需要创建提案,不需要历史追溯。它们就像查字典,快速查询就好。

变更任务(需要严格管控):

  • 补充测试用例:”为新功能添加测试”
  • 修改测试用例:”修复测试中的错误”
  • 重构测试代码:”简化测试代码结构”
  • 框架能力变更:”添加新的虚拟设备”
  • 框架API重构:”简化时序控制接口”

这些任务会改变系统状态,需要:

  • 清晰的动机(为什么要改?)
  • 明确的范围(改了什么?)
  • 可追溯的历史(什么时候改的?)

关键发现:并非所有的”工作”都需要用同样的流程来管理

演进:从10节点到4阶段

简化的哲学

有了对”什么需要管控”的清晰认识后,我开始重新设计工作流。

10个节点太多了,记不住,也不够灵活。我需要找到一个更高层次的抽象——不是具体的”节点”,而是”阶段”。

思考测试开发的本质流程,其实就四个阶段:

1
2
3
4
5
6
7
8
9
10
11
Phase 1: 准备(Preparation)
了解现状 → 分析需求 → 制定计划

Phase 2: 执行(Execution)
设计方案 → 编写代码 → 实现变更

Phase 3: 验证(Verification)
编译测试 → 运行验证 → 问题诊断

Phase 4: 总结(Summary)
整理产物 → 生成报告 → 准备归档

每个阶段内部可以灵活组合不同的”技能”(Skills)。比如:

  • Phase 1可能需要”规范分析”+”代码定位”
  • 也可能只需要”规范分析”
  • 甚至可以完全跳过(对于简单任务)

这种设计的核心思想是:提供结构,但不限制灵活性

关键设计决策

在新设计中,有几个关键的决策点:

决策1:只读与变更严格分离

操作类型 需要提案 可单独执行 修改文件
只读操作
变更操作

这个分离让系统的行为变得可预测。当你执行只读操作时,不用担心会产生副作用。当你要做变更时,系统会强制要求你创建提案。

决策2:阶段内的灵活性

4个阶段只是大的结构框架,具体执行时可以根据场景灵活调整:

简单场景(补充单个测试用例):

1
2
3
4
Phase 1: 规范分析(跳过代码定位)
Phase 2: 直接实现(跳过设计文档)
Phase 3: 编译验证
Phase 4: 快速总结

复杂场景(重构API,影响大量测试):

1
2
3
4
Phase 1: 规范分析 + 代码定位 + 影响分析
Phase 2: 详细设计 + 分批实现
Phase 3: 全量编译 + 回归测试 + 深度诊断
Phase 4: 详细总结 + 生成迁移指南

决策3:强制提案关联

所有变更任务必须关联一个TestSpec提案:

1
2
3
4
5
testspec/changes/{change-id}/
├── proposal.md # 为什么改、改什么、影响范围
├── tasks.md # 实施清单
└── specs/ # 规范差异
└── {module}/spec.md # ADDED/MODIFIED/REMOVED

这个设计借鉴了Git的思想:每个变更都应该有清晰的commit message。但我们更进一步,不仅要说明”改了什么”,还要说明”为什么改”和”影响了什么”。

技能(Skills)的解耦设计

在新架构中,我把具体的执行能力抽象成可复用的”技能”(Skills):

只读技能(可自由调用):

  • spec-analyze: 查询规范内容
  • env-check: 检查环境状态
  • code-locate: 定位代码位置
  • log-analyze: 分析日志内容

变更技能(需要提案支持):

  • test-design: 设计测试用例
  • code-implement: 实现测试代码
  • compile: 编译构建
  • execute: 运行测试

每个技能都是独立的,可以在不同阶段灵活组合。就像乐高积木,你可以根据需要自由拼装。

统一规范体系的构建

三层规范架构

基于对”索引也是规格”的理解,我设计了一个统一的规范体系:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
testspec/
├── specs/ # 当前真相层
│ ├── framework/ # 框架规格
│ │ ├── core/
│ │ │ ├── spec.md # 核心能力规格
│ │ │ └── design.md # 设计文档
│ │ │
│ │ ├── communication/ # 通信子系统
│ │ │ ├── spec.md
│ │ │ └── design.md
│ │ │
│ │ └── simulation/ # 仿真子系统
│ │ ├── spec.md
│ │ └── design.md
│ │
│ └── projects/ # 项目测试规格
│ ├── project-a/
│ │ └── spec.md # 项目A的测试用例清单
│ └── project-b/
│ └── spec.md

├── changes/ # 变更提案层
│ ├── {change-id}/
│ │ ├── proposal.md
│ │ └── specs/ # 规格差异
│ │
│ └── archive/ # 历史归档
│ └── YYYY-MM-DD-{change-id}/

└── project.md # 项目约定

这个架构的关键在于:

  • specs/是权威的”当前真相”,回答”系统现在是什么状态”
  • changes/记录所有变更,回答”系统是如何演进的”
  • framework/projects/用统一的方式管理

规范文件的结构设计

每个spec.md都采用Requirement → Scenario的结构:

1
2
3
4
5
6
7
8
9
10
11
12
## Requirement: 时序控制能力

框架应提供基于虚拟时间的时序控制机制。

### Scenario: 在指定时间点执行操作

- **GIVEN** 仿真环境已初始化
- **WHEN** 设置在虚拟时间10ms时执行某操作
- **THEN** 该操作应在仿真时间到达10ms时精确执行
- **API**: `Stage()->Equal(10 * MS, [&]{ /* 操作 */ })`
- **添加时间**: 2024-05-10
- **添加原因**: 初始框架设计

这种格式有几个好处:

  1. 机器可读:AI Agent可以准确理解每个能力的语义
  2. 人类可读:工程师能快速了解功能的行为和用法
  3. 可追溯:记录了何时、为何添加这个能力

变更差异的表达方式

在创建变更提案时,规格差异采用ADDED/MODIFIED/REMOVED的方式表达:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# specs/framework/communication/spec.md 的差异

## ADDED Requirements

### Requirement: 新增指令XYZ

框架应支持XYZ指令...

## MODIFIED Requirements

### Requirement: 重构ABC指令 (原Requirement修改)

- **变更说明**: 简化参数结构,提升易用性
- **影响**: 需要迁移12个使用该指令的测试用例

## REMOVED Requirements

### Requirement: 废弃DEF指令

- **移除原因**: 该指令已被XYZ指令替代
- **迁移指南**: 使用XYZ指令的xxx方法替代

这种差异表达方式让变更的影响一目了然。

在规范与灵活之间寻找平衡

强制提案的权衡

在设计中,最大的争议点是:是否所有变更都强制要求提案?

支持严格模式的理由:

  • 确保所有变更都有文档
  • 形成完整的历史追溯
  • 避免”快速修改”积累成技术债务

反对严格模式的担忧:

  • 可能影响开发效率
  • 简单修改也要走流程太繁琐
  • 团队可能抵触使用

我的最终决策是:严格模式 + 降低门槛

具体做法是:

  1. 自动生成提案草稿。当AI Agent识别到变更任务但缺少提案时,自动生成一个包含基本信息的草稿,而不是直接拒绝。
1
2
3
4
5
6
7
8
9
10
11
用户: "帮我补充项目X的功能Y测试"

Agent: "我理解你需要补充测试。这是一个变更任务,我已经为你生成了
提案草稿:add-project-x-feature-y-tests

提案预览:
- 为什么: 功能Y开发完成,需要补充测试验证
- 变更内容: 补充功能Y的集成测试用例
- 受影响规范: specs/projects/project-x/

现在帮你完善这个提案..."
  1. 智能查询辅助。提案创建过程中,自动查询现有规范,识别缺失的测试场景,让提案更加完整。

  2. 批准流程简化。对于简单变更,可以自动批准;对于影响范围大的变更,才需要人工审查。

产物文档的精简

另一个权衡是产物文档的详细程度。

10节点时代,每个节点都生成文档,导致产物过多。4阶段设计后,我重新定义了哪些产物是必要的:

必要产物(永久保留):

  • testspec/changes/{id}/proposal.md - 变更提案
  • testspec/changes/{id}/specs/*.md - 规格差异
  • testspec/changes/archive/{id}/ - 归档后的完整记录

临时产物(可选,discuss/目录):

  • discuss/preparation/ - 准备阶段的分析文档
  • discuss/design/ - 设计阶段的方案文档
  • discuss/verification/ - 验证阶段的日志
  • discuss/summary/ - 总结报告

临时产物在变更归档后可以选择保留或清理,不强制要求。

这样既保证了关键信息的可追溯,又避免了文档过载。

渐进式迁移策略

对于已有的索引系统,我没有选择”大爆炸”式的重构,而是设计了一个渐进式的迁移计划:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
阶段1(当前):双轨并行
- 保持原有索引系统不变
- 新建testspec/体系,开始试点
- 两个系统并存,互不干扰

阶段2(1-2月):逐步迁移
- 选择2个子系统先迁移到新格式
- 验证新格式的完整性和可用性
- AI Agent优先查询新系统,降级到旧系统

阶段3(3月后):完全切换
- 全部内容迁移完成
- 旧系统标记为deprecated
- 最终归档或删除旧系统

这种策略的好处是:

  • 风险可控,可以随时回退
  • 团队有充足的适应时间
  • 可以在实践中持续优化

实践中的演进

一次完整的变更流程

让我用一个真实的场景来展示新系统是如何工作的:

场景:项目A的新功能开发完成,需要补充测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
用户: "帮我为项目A补充功能X的测试"

↓ Agent分析

意图分类: 变更任务(补充测试)
检查提案: 不存在
触发提案生成...

↓ Agent响应

"我理解你需要为项目A补充功能X的测试。我已查询现有规范:

当前项目A的测试覆盖情况:
✓ 基础功能测试(已有10个用例)
✗ 功能X测试(缺失)

我为你生成了变更提案草稿:add-project-a-feature-x-tests

提案内容:
- 为什么: 功能X开发完成,需要测试验证
- 变更内容: 补充功能X的集成测试(预计3-5个场景)
- 受影响规范: specs/projects/project-a/spec.md

现在帮你完善规格差异..."

↓ 生成规格差异

testspec/changes/add-project-a-feature-x-tests/
├── proposal.md
└── specs/projects/project-a/spec.md
## ADDED Requirements

### Requirement: 功能X测试
验证功能X在不同场景下的行为...

#### Scenario: 正常场景测试
- GIVEN 系统已初始化
- WHEN 执行功能X操作
- THEN 应得到预期结果

#### Scenario: 异常场景测试
...

↓ 用户批准

用户: "看起来不错,开始实施吧"

↓ 执行4阶段工作流

Phase 1: 准备
- 规范分析 ✓ (已完成,在提案生成时)
- 代码定位 ✓ (找到测试文件位置)

Phase 2: 执行
- 测试设计 ✓ (设计3个测试场景)
- 代码实现 ✓ (编写测试代码)

Phase 3: 验证
- 编译 ✓ (编译通过)
- 执行 ✓ (测试全部通过)

Phase 4: 总结
- 生成总结报告 ✓
- 生成归档检查清单 ✓

"任务完成!共补充3个测试用例,全部通过。

归档检查清单:
✓ 提案文档完整
✓ 规格差异明确
✓ 测试代码已实现
✓ 编译和测试通过

执行归档:/testspec:archive add-project-a-feature-x-tests"

↓ 归档变更

归档后:
- specs/projects/project-a/spec.md 已更新(合并差异)
- changes/add-project-a-feature-x-tests/ →
archive/2025-10-21-add-project-a-feature-x-tests/
- discuss/ 临时产物已清理

整个流程既保证了规范性,又相对流畅。关键是提案生成的自动化降低了使用门槛。

处理复杂场景:框架API重构

新系统的真正价值在处理复杂变更时才体现出来。

场景:重构时序控制API,影响大量测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
用户需求: "时序控制API太复杂,想简化成更直观的形式"

↓ 变更分析

影响评估:
- 框架核心API变更(BREAKING)
- 影响150+测试用例
- 需要提供迁移指南

↓ 创建提案

testspec/changes/refactor-timing-api/
├── proposal.md
│ ## 变更类型: BREAKING
│ ## 为什么
│ 现有API学习曲线陡,团队反馈使用困难...

│ ## 变更内容
│ - 重构API设计,简化调用方式
│ - 保持语义不变,仅改变接口形式

│ ## 影响分析
│ - 框架规格: specs/framework/core/spec.md (MODIFIED)
│ - 项目测试: 150个测试用例需要迁移
│ - 兼容策略: 保留旧API 2个版本,提供自动迁移工具

└── specs/
├── framework/core/spec.md
│ ## MODIFIED Requirements

│ ### Requirement: 时序控制 (API重构)

│ 旧API:
│ Stage()->Equal(10 * MS, [&]{ /* ... */ })

│ 新API:
│ RunFor(10_ms).Then([&]{ /* ... */ })

│ 迁移影响: 150个测试用例

└── projects/*/spec.md (批量标记为MODIFIED)

↓ 分阶段实施

Stage 1: 实现新API,保持旧API兼容
Stage 2: 提供自动迁移工具
Stage 3: 批量迁移测试用例
Stage 4: 废弃旧API(2个版本后)

↓ 归档

归档时生成:
- 完整的变更记录
- 迁移指南
- 影响评估报告
- 回滚方案

这种复杂变更在旧系统中几乎无法管理,但在新系统中,所有信息都被结构化地记录下来。

意外的收获:机器可读的知识库

在设计过程中,我发现这个系统还带来了一些预期之外的价值。

AI Agent的学习能力

统一的规范体系让AI Agent可以更好地”学习”:

场景1:模式识别

当需要为新功能补充测试时,Agent可以:

  1. 查询specs/projects/,找到相似功能的测试规格
  2. 查询changes/archive/,学习类似变更的实现方式
  3. 基于历史模式,生成更准确的测试提案

场景2:缺失发现

定期分析规范,AI Agent可以主动发现:

  • 哪些功能只有代码,没有测试
  • 哪些测试覆盖了废弃的功能
  • 哪些模块的测试覆盖率明显低于平均水平

场景3:需求逆向

更有趣的是,从测试规格可以逆向生成需求文档:

1
2
3
4
5
6
测试规格: "当系统接收到信号X时,应在10ms内响应..."

↓ 逆向推导

功能需求: "系统应提供对信号X的实时响应能力,
响应时延不超过10ms..."

这为”文档与代码同步”提供了新的可能。

团队协作的改善

规范体系的建立也改善了团队协作:

评审更聚焦

1
2
3
4
5
传统评审: "你这个测试写得对不对?"
(需要理解代码逻辑)

新评审: "这个测试符合规格吗?"
(对照spec.md检查)

知识传递更容易

1
2
3
4
5
6
新人问题: "这个功能怎么测试?"

传统回答: "你去看XXX文件的YYY测试用例..."

新回答: "你看specs/framework/XXX/spec.md,
里面有所有场景的GIVEN-WHEN-THEN..."

变更影响更清晰

1
2
3
4
5
6
修改API前:
- 查询specs/,看哪些地方使用了这个API
- 评估影响范围
- 制定迁移计划

而不是靠"经验"和"grep搜索"

一些思考与启发

回顾整个设计过程,有几个感悟想和大家分享。

完美的系统是演进出来的

最初我想一次性设计一个完美的系统——10个节点覆盖所有场景,每个环节都标准化。但实践证明,这种”大而全”的设计往往很脆弱。

真正有生命力的系统是在使用中不断演进的:

  • 从10节点到4阶段,是因为发现固定流程不够灵活
  • 从索引文档到规范体系,是因为认识到两者本质相同
  • 从强制流程到降低门槛,是为了平衡规范性与易用性

不要追求一开始就做对,而要快速试错、持续改进

技术问题往往是管理问题

一开始我以为主要挑战是技术实现——如何让AI生成正确的测试代码。但深入下去发现,真正的难点在于:

  • 如何管理不断产生的变更
  • 如何维护知识的一致性
  • 如何让团队接受新的工作方式

很多看似技术的问题,本质上是工程管理问题

约束带来自由

“所有变更必须有提案”听起来是个约束,可能影响效率。但实际使用中,我发现这个约束反而带来了自由:

  • 有了规范,就不用每次都从头思考测试策略
  • 有了历史,就可以学习过往的最佳实践
  • 有了清晰的变更边界,就敢于重构和优化

适当的约束是创造力的前提

工具要符合人的思维

10节点工作流失败的一个重要原因是:它符合”机器执行的逻辑”,但不符合”人的思维方式”。

人在解决问题时,思维是跳跃的:

  • 有时需要快速查询
  • 有时需要深度思考
  • 有时需要试错迭代

4阶段设计之所以更好用,是因为它给出了结构(4个阶段),但允许灵活性(阶段内自由组合)。这更接近人的工作方式。

好的工具应该是人的延伸,而不是约束

文档即代码,代码即文档

在设计规范体系时,我逐渐意识到,规范文件spec.md和代码其实是一体的:

  • 规范描述”应该是什么样”
  • 代码实现”实际是什么样”
  • 测试验证”确实是这样”

当这三者同步时,开发效率最高。而同步的关键不是写更多文档,而是让文档成为工作流的一部分,在每次变更时自然地更新。

与其强调”文档很重要”,不如让文档成为工作流的副产品

写在最后

从10节点到4阶段,从索引文档到规范体系,这不仅仅是一次技术重构,更是一次对”如何管理复杂性”的深度思考。

我发现,很多时候我们过度关注”如何把事情做对”,而忽略了”如何把对的事情做好”。TestSpec系统的价值不在于它有多完善的流程,而在于它帮助团队建立了一个共同的语言——一个描述系统状态、变更意图和演进历史的语言。

有了这个语言,AI Agent可以更好地理解系统,人可以更好地协作,知识可以更好地传承。

当然,这个系统还远未完善。还有很多问题需要在实践中解决:

  • 如何让规范的编写更加自然
  • 如何自动检测规范与代码的不一致
  • 如何平衡文档详细程度与维护成本

但我相信,方向是对的。剩下的,就是在使用中不断打磨,让它真正成为团队工作方式的一部分。

技术的演进从来不是直线的,而是螺旋式上升的。每一次回归原点的反思,都是为了下一次更高的跃升。


系列文章导航

本文是”测试工程化实践”系列的第一篇,分享了TestSpec系统的设计与演进过程。

相关文章

  • Title: Agent驱动的测试变更管理系统设计实录
  • Author: 叫我EC就好
  • Created at : 2025-10-21 14:30:00
  • Updated at : 2025-10-21 16:30:53
  • Link: https://www.o0o0o.sbs/2025/10/21/Agent驱动的测试变更管理系统设计实录/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments