Opening Statement Hook: 你是否厌倦了那些“运行一次就抛弃”的 AI 脚本?在追求智能自动化的道路上,我们常常忽略了一个最基本的问题:AI 代码是否足够健壮,能否像人类工程师编写的代码一样,具备参数化、错误处理、环境预检和资源回收的能力? 本文将带你深入一个顶级 AI Agent 任务的内部结构,揭示如何将一个简单的 “Ping Test” 升级为一套具备交互式修复能力、CI/CD 兼容性、且能安全管理系统资源的专业级“AI 技能”。我们的目标是:从“Prompting”阶段,彻底迈向“Programming” AI Agent 的工程化实践。


Part I: 范式转变:从简单提示到工程化 AI Agent 技能

1.1. 导言:AI 自动化中的“工程化”缺失

在过去的一年里,大语言模型(LLM)驱动的 AI Agent 已经从科幻走进了工程实践。但当前大多数 Agent 的应用场景仍停留在“一次性脚本”的层面:用户给出一个自然语言提示,Agent 生成并执行一段代码(通常是 Python 或 Shell),完成任务后便退出。

这种模式存在致命的工程缺陷:

  1. 缺乏鲁棒性(Fragility):代码没有错误处理,环境稍有变化即失败。
  2. 不可重用性(Non-Reusability):每次任务都需要重新提示,浪费 LLM 资源。
  3. 资源泄露(Resource Leakage):没有原子级的清理机制,容易在后台留下僵尸进程或未释放的资源。
  4. 非交互性(Non-Interactive):CI/CD 模式和本地调试模式无法兼容。

真正的工程实践要求自动化工具像人类工程师一样:预先检查环境、安全启动和终止进程、处理异常情况,并能根据环境(本地调试或 CI)自动切换模式。这正是“AI 技能工程化”的核心价值。

1.2. 什么是“AI 技能”?AI Agent 自动化模型的三个进化阶段

我们将 AI Agent 的自动化能力进化划分为三个阶段:

阶段 模型名称 核心特征 应用场景 工程缺陷
1 提示即代码 (Prompt-as-Code) 一次性、非结构化提示,直接生成代码执行。 快速原型设计、简单数据查询。 鲁棒性极低,无法处理复杂环境。
2 工具调用 (Tool-as-Function) Agent 能调用预定义工具(Function Calling),但工具逻辑在外部。 外部 API 集成、简单系统操作。 Agent 仍是执行者,缺乏对复杂流程的控制能力。
3 AI 技能工程化 (Engineered AI Skill) 将复杂流程封装成结构化、参数化、自带鲁棒逻辑的“技能文件”。 复杂的 Dev/Ops、QA 自动化、高可靠性任务。 -

AI 技能(AI Skill):一个可版本控制、参数化、具备明确输入、输出、执行流程、以及内置错误处理和清理逻辑的结构化任务定义文件。它将 Agent 从一个临时的代码生成器,提升为能够执行复杂、多步骤、高可靠性流程的专业化角色。

1.3. 引入 BMAD 技能管理框架:一个面向生产环境的 Agent 治理体系

为了有效地管理这些复杂的“AI 技能”,我们引入一个概念性的组织和治理框架:BMAD

  • B - Build (构建):定义和编写技能文件(如 .md.yaml 格式),明确输入、输出和执行步骤。
  • M - Manage (管理):通过 Git 或其他版本控制系统进行管理,并以层级目录结构组织(如 .claude/commands/BMad/tasks/...)。
  • A - Agent-Execute (Agent 执行):Agent 解析技能文件,结合 LLM 的规划能力,在沙盒环境中执行流程。
  • D - Deploy (部署):将技能集成到 CI/CD 流程或开发者 CLI 中,实现大规模应用。

我们提供的 run-e2e-ping-test.md 文件正是 BMAD 框架下,一个面向 qa 代理的高度工程化的 B - Build 阶段的杰出产物。


Part II: 蓝图剖析:深度解析 E2E Ping 测试任务

2.1. 任务的宏观目标与价值

任务文件: .claude/commands/BMad/tasks/run-e2e-ping-test.md

该任务的核心目标是自动化一个完整的、模拟用户行为的端到端(E2E)测试,以验证前后端服务的联通性。

传统 E2E 测试 vs. Agent 驱动 E2E 测试

特征 传统脚本 (e.g., Playwright/Cypress) Agent 驱动任务 (BMAD Skill)
测试目标 关注业务逻辑或 UI 交互。 关注环境准备、进程管理、原子清理
执行载体 预编写的 JS/TS 代码。 AI 动态生成、结合系统工具、执行流程
健壮性 依赖工程师编写的错误捕获。 内置预检逻辑、交互式用户决策回路。
启动方式 需手动或外部 CI 脚本启动服务。 将服务启动/停止纳入任务流程内,实现自包含。

Agent 任务将环境准备和清理视为测试本身不可分割的一部分,从而极大提高了测试的可靠性和隔离性。

2.2. Agents and Delegation: 为什么是 qa 代理?

负责人qa 代理

在 BMAD 框架下,我们倡导“代理角色专业化”。就像人类团队中的 Dev、Ops、QA 一样,Agent 也应具备专业职能边界:

  • developer 代理:专注于功能代码的编写、重构和单元测试。
  • devops 代理:专注于基础设施、部署脚本、CI/CD 流程。
  • qa 代理:专注于系统联通性、集成测试、E2E 流程,并对测试环境的隔离性负责。

将 E2E 测试指派给 qa 代理,意味着:

  1. 职责分离:确保测试的独立性和客观性。
  2. 专业工具集qa 代理将默认配备 Playwright MCP、Chrome DevTools MCP、系统端口工具等,无需在核心 developer 代理中冗余。
  3. 权限控制:可以对 qa 代理施加更严格的系统资源(进程管理、网络访问)使用权限限制。

2.3. Parameters and NL-CLI: 如何将自然语言转化为结构化指令?

任务定义清晰地列出了三个输入参数:backendPortfrontendPortciMode。这赋予了任务高度的灵活性和可重用性。

深度解析:NL-CLI (Natural Language Command Line Interface)

这是 Agent 工程化中最具颠覆性的机制之一。它解决了传统 CLI 的两大痛点:难以记忆和输入繁琐。

传统 CLI: run-e2e-ping-test --backendPort 8080 --frontendPort 3000
NL-CLI: 运行端到端 ping 测试,但后端使用 8080 端口,前端使用 3000 端口。

AI Agent 内部必须执行以下关键步骤:

  1. 意图识别: 识别用户请求的核心任务是“运行端到端 ping 测试”。
  2. 参数提取:
    • 通过自然语言处理和槽位填充(Slot Filling)技术,从句子中提取数值:“8080”、“3000”。
    • 识别关键词“后端使用”和“前端使用”,将其与任务定义的参数 backendPortfrontendPort 进行语义匹配。
  3. 模式推断: 根据语句中未提及“交互”或“CI”,判断 ciMode 为默认值 false
  4. 结构化输出: 将结果转化为内部执行环境可识别的 JSON 结构:{ "task": "run-e2e-ping-test", "backendPort": 8080, "frontendPort": 3000, "ciMode": false }

Pro-Tip: NL-CLI 的鲁棒性要求 Agent 能够处理同义表达(如“后端使用 8080 端口”与“服务在 8080 上跑”)和不完整信息(只指定一个端口)。


Part III: 鲁棒性支柱 (I):预检和交互式修复

3.1. 自动化任务的致命弱点:环境依赖与资源冲突

E2E 测试最常见的失败原因不是代码 Bug,而是环境问题。特别是端口冲突,如果测试脚本无法处理,CI/CD 流水线将立即中断,耗费宝贵的构建时间。

run-e2e-ping-test 任务通过 第 1 步:预检 - 端口验证 机制,将环境问题从“致命错误”降级为“可修复异常”,是工程化 Agent 的一个核心标志。

3.2. 核心机制 1: 预检 - 端口可用性验证

技术细节:跨平台端口检测的抽象与执行

Agent 在执行预检时,不能简单地尝试连接端口,而必须使用操作系统级的命令来确定端口被占用的具体原因(即哪个进程 ID 占用)。

操作系统 端口检查命令 (抽象前) 抽象目标
Linux/macOS lsof -i :<端口> 检查并返回 PID
Windows netstat -ano | findstr :<端口> 检查并返回 PID

Agent 的执行逻辑:LLM 会首先识别当前操作系统,然后选择正确的系统工具,并封装成一个原子工具调用,其输出必须包含 端口状态(可用/占用)占用进程 PID

错误处理架构:可恢复性设计

预检流程体现了分层错误处理的高级架构:

  1. 一级检查: 端口占用。
  2. 二级决策: 根据 ciMode 决定处理方式。

3.3. 交互式修复与人机协作 (ciMode=false 流程解析)

当在本地开发环境 (ciMode=false) 运行时,Agent 并不急于失败,而是进入一个“用户决策回路”,寻求人类的帮助以修复环境。这极大地提升了开发体验。

用户决策回路:[K]ill - 强制终止

如果用户选择 [K]ill - 终止,Agent 的执行流程将是:

  1. 解析 PID: 从预检结果中提取冲突进程的 PID。
  2. 系统级终止: 执行 kill -9 <PID> (或 Windows 对应命令 taskkill /F /PID <PID>)。
  3. 二次验证: 重新回到预检流程的第 1 步,再次检查端口是否已释放。

在这里插入图片描述

用户决策回路:[R]etry - 动态重试

如果用户选择 [R]etry - 重试

  1. 参数重置: Agent 必须询问新的端口号,并通过内部机制动态更新任务的 backendPortfrontendPort 参数。
  2. 流程回溯: 任务流程回溯到“预检 - 端口验证”的起点,使用新参数重新执行第 1 步。

这体现了 Agent 不仅是执行者,更是故障排除助手的价值,将原本需要人工执行的诊断、终止、重试流程自动化。

3.4. CI/CD 的 Fail-Fast 原则 (ciMode=true 流程解析)

当在 CI/CD 环境 (ciMode=true) 中运行时,环境修复的成本太高,人机交互是不允许的。因此,Agent 必须遵循 Fail-Fast 原则。

  • 逻辑: 如果端口被占用,Agent 必须立即以非零状态码(表示失败)中止任务。
  • 工程价值: 确保流水线快速失败,避免浪费后续的构建、部署或长时间测试时间。

Part IV: 执行引擎:并发、MCPs 与原子操作

一旦环境预检通过,Agent 即可进入高并发、高精度的执行阶段。

4.1. 并发启动与 PID 追踪的艺术

E2E 测试要求前后端服务同时运行。Agent 必须安全地将它们转为后台进程,并在 Shell 环境中实现并发。

关键挑战: 如何在后台运行进程的同时,捕获其 PID?

步骤 命令行(抽象) 目的
1 npm run dev:server -- --port ${backendPort} & echo $! > backend.pid 启动后端服务,并立即将后台进程 ID 写入 backend.pid 文件。
2 npm run dev:client -- --port ${frontendPort} & echo $! > frontend.pid 启动前端服务,并将 PID 写入 frontend.pid 文件。
3 wait <Time> 暂停执行,确保服务完全初始化。

工程关键点& 符号实现了后台运行,echo $! 在 POSIX Shell 中用于捕获上一个后台进程的 PID。**记录这些 PID(在第 2 步中被要求)**是确保任务原子性的生命线。

4.2. Playwright MCP: 浏览器控制与前端访问

一旦服务启动,Agent 必须使用其专有工具 Playwright Modular Control Plane (MCP) 来模拟用户行为。

  • 浏览器启动: const browser = await playwright.launch({ headless: true })
  • 导航: 访问经过验证的 frontendPort 上的 URL:await page.goto(http://localhost:${frontendPort})

无头模式(headless: true)是 CI/CD 和自动化任务的标准配置,它消除了对图形界面的依赖,提高了执行速度和稳定性。

4.3. Chrome DevTools MCP 与深度网络捕获

Agent 驱动测试的优势在于其超越表层 UI 的深度洞察力。通过 Chrome DevTools MCP 的能力(通常通过 Playwright 的底层 API 实现),Agent 可以进行网络级别的断言。

传统 E2E:可能只断言页面上显示了某些文本。
高级 E2E 任务:必须断言底层数据流是否正确。

执行流程

  1. 激活网络监听: await page.route('**/api/ping', route => { /* handler */ })
  2. 等待请求: const [response] = await Promise.all([ page.waitForResponse(response => response.url().endsWith('/api/ping')), page.click('#pingButton') // 触发前端请求的动作 ])
  3. 捕获与验证: 在捕获到 /api/ping 的响应后,Agent 对其执行严格的校验。

4.4. 原子断言 (Atomic Assertion):API 响应的精确校验

第 4 步要求满足三个原子条件:

  1. 存在性验证: 检查是否捕获到了 /api/ping 的请求。
  2. 状态码验证: 响应状态码是否严格等于 200
  3. 内容精确验证: JSON 响应体是否完全等于 { "msg": "pong" }

任何一个条件不满足,整个任务即告失败。这种精确度是高级测试的必备条件。


Part V: 产物管理与原子清理

5.1. Proof of Execution: 自动化产物的标准与价值

成功的 Agent 任务不仅仅是“代码能跑”,更重要的是能提供可审计、可追溯的执行证据。

  1. test-report.json (结构化数据):
    • 价值: 供 CI/CD 报告系统或 Agent 自身的学习系统使用。它包含测试时间、持续时间、断言结果、以及 ping 请求和响应的详细元数据。
    • Agent 行为: 必须在断言完成后,将捕获到的请求/响应对象结构化并序列化为 JSON 格式。
  2. ping.png (视觉证据):
    • 价值: 提供测试瞬间的页面视觉状态,对于 UI 调试和非预期渲染场景至关重要。

5.2. 核心机制 2: 终局清理与资源回收 (Atomic Cleanup)

这是该任务中最能体现“工程化”精神的关键一步。一个不安全的自动化脚本执行后,可能在系统上留下:

  • 孤立的后端服务进程(占用 backendPort
  • 孤立的前端开发服务器进程(占用 frontendPort
  • Playwright 启动的浏览器实例残留。
为什么必须使用 PID?

直接使用 killall node 是危险的,它会终止系统中所有的 Node.js 进程,包括开发者可能正在运行的其他项目。

原子清理 的核心原则是:只清理由本任务启动的进程。

  • Agent 必须读取 backend.pidfrontend.pid 文件,获取到在 4.1 节中记录的精确 PID。
  • 然后,执行:kill <backend_PID>kill <frontend_PID>

健壮性要求: 清理步骤必须被设计为无论任务成功还是失败,都必须执行(类似于编程中的 finally 块)。这保证了系统资源的绝对释放。

Part VI: 工程最佳实践和未来方向

6.1. 总结:AI Agent 技能工程化的五大核心原则

通过对 run-e2e-ping-test.md 任务的深度解析,我们提炼出 AI Agent 技能工程化的五大核心原则:

  1. PFC (Pre-flight Check) 原则: 在执行任何资源操作之前,必须执行全面的环境预检。
  2. Atomic (原子性) 原则: 任务必须是自包含的,要么完全成功,要么能安全回滚/清理,确保对系统状态的净影响为零(零资源泄露)。
  3. Parameterized (参数化) 原则: 任务的所有关键变量必须能够通过参数控制,以实现最大的重用性。
  4. Specialized (专业化) 原则: 任务必须被分配给具备专业工具集和职责的 Agent 角色(如 qa)。
  5. Managed (可管理性) 原则: 任务定义必须是结构化的、可版本控制的(BMAD 框架),而非一次性的非结构化提示。

6.2. 拓展应用:将此模型推广到更复杂的 Dev/Ops 任务

run-e2e-ping-test 只是一个起点。这套工程化方法论可以应用于任何复杂的 Dev/Ops 任务:

复杂任务 核心挑战 Agent 技能工程化应用
数据库 Schema 迁移 1. 权限与连接性检查;2. 无法回滚的致命性。 PFC 检查:连接性、备份状态。Atomic 清理:迁移失败时自动执行回滚脚本。
蓝绿部署 (Blue/Green) 1. 并发启动新环境;2. 流量切换前的健康检查。 PFC 检查:目标端口和路由可用性。并发启动:同时管理新旧环境 PID。中断逻辑:健康检查失败,终止新环境 PID,不切换流量。
依赖升级 (e.g., Node.js Major Version) 1. 兼容性检查;2. 依赖安装与测试。 PFC 检查:现有版本与目标版本兼容性报告。交互式:兼容性问题时,询问用户“忽略/降级/修复”。

6.3. 结论:自动化与智能的融合

“智能”的价值,最终要由“工程”的质量来衡量。一个能够解析复杂意图、执行环境预检、在 CI/CD 中保持静默、在本地调试时与用户交互、安全地管理系统进程、并最终清理所有残留的 AI Agent 任务,才是真正值得信赖、可以部署到生产环境的自动化资产。

run-e2e-ping-test 的蓝图不仅提供了一个 E2E 测试的解决方案,它更提供了一张通往 AI Agent 工程化时代的路线图。从今天起,让我们告别低效的“脚本”,开始构建专业的“AI 技能”。


附录:BMAD 任务文件——run-e2e-ping-test.md 完整结构

为了确保报告的完整独立性,再次附上作为本文核心案例的 BMAD 任务定义文件。

.claude/commands/BMad/tasks/run-e2e-ping-test.md

## 任务:运行端到端 Ping 测试

**负责人**:`qa` 代理
**描述**:自动化一个完整的前后端交互测试,包括启动服务、运行浏览器测试以验证 API 端点,并生成最终报告。该任务是交互式的,并包含预检步骤以确保环境就绪。

### 输入参数

此任务接受可选参数。如果未提供,将使用默认值。

| 参数           | 描述                                             | 默认值  |
| :------------- | :----------------------------------------------- | :------ |
| `backendPort`  | 后端服务所需端口。                               | `3001`  |
| `frontendPort` | 前端开发服务器所需端口。                         | `5173`  |
| `ciMode`       | 若为 `true`,则以非交互模式运行(例如在 CI/CD 中)。 | `false` |

---

### 执行流程

#### 第 1 步:预检 - 端口验证

在启动任何服务之前,你必须验证所需端口是否可用。

-   **目标**:确定最终可用的 `backendPort` 和 `frontendPort`。
-   **流程**:对每一个目标端口(先处理 `backendPort`,再处理 `frontendPort`)执行以下操作:
    1.  执行系统级检查,确认端口当前是否被占用(例如,使用 `lsof -i :<端口>` 或 `netstat` 命令)。
    2.  **如果端口被占用**:
        -   明确告知用户哪个端口被占用,以及(如果可能)是哪个进程在使用它。
        -   **当 `ciMode` 为 `true` 时**,立即以清晰的错误信息中止任务。
        -   **当 `ciMode` 为 `false` 时**,向用户提供两个明确的选项:
            -   **[K]ill - 终止**:强制终止占用端口的进程。
            -   **[R]etry - 重试**:指定一个新端口号重试。
        -   如果用户选择**终止**,执行必要的系统命令来结束冲突进程,然后再次验证端口是否已释放。
        -   如果用户选择**重试**,询问新的端口号,并使用新端口号回到本预检流程的第 1 步。
    3.  **如果端口可用**:
        -   确认此端口为最终将要使用的端口。
        -   继续验证下一个端口。

#### 第 2 步:并发启动服务

一旦所有端口都验证并确认无误:

-   启动后端服务,确保它在最终确定的 `backendPort` 上监听。你可能需要通过环境变量(`PORT=${backendPort} npm run dev:server`)或命令行参数(`npm run dev:server -- --port ${backendPort}`)来传递端口号。
-   启动前端开发服务器,确保它在最终确定的 `frontendPort` 上监听。
-   这两个进程必须在后台运行。**必须记录每个服务的进程 ID (PID),以便在清理步骤中使用。**

#### 第 3 步:等待并启动浏览器

-   等待一段足够的时间(例如 5-10 秒),以确保两个服务都已完全初始化并准备好接受连接。
-   使用 **Playwright MCP**,启动一个无头模式的 Chromium 浏览器实例。
-   访问 `http://localhost:${frontendPort}`。注意,这里使用的是经过验证的 `frontendPort`。

#### 第 4 步:网络捕获与断言

-   利用 **Chrome DevTools MCP** 的能力(通过 Playwright 的网络拦截功能),主动监控网络请求。
-   等待访问 `/api/ping` 端点的网络请求出现。
-   **断言以下条件必须满足**:
    -   存在对 `/api/ping` 的请求。
    -   响应状态码为 `200`。
    -   JSON 响应体内容完全等于 `{ "msg": "pong" }`。

#### 第 5 步:生成产物(Artifacts)

-   将测试结果(成功/失败,以及 ping 请求/响应的详情)保存到一个名为 `test-report.json` 的文件中。
-   对最终的页面状态进行截图,并保存为 `ping.png`。

#### 第 6 步:清理环境

-   平稳地关闭 Playwright 浏览器实例。
-   **使用在第 2 步中记录的 PID**,平稳地终止后端和前端服务进程,确保没有留下任何孤立进程。
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐