AI Agent 验证技能:像真实用户一样自动验证应用

AI Agent 验证技能:像真实用户一样自动验证应用 过去一年AI Agent 的能力边界一直在快速扩大它能写代码、能改文件、能调 API、能操作浏览器。但真正把它放进业务项目的开发者几乎都会遇到同一个尴尬时刻——Agent 把活干完了你却不敢让它上线因为你不知道它改对没有。这不是测试用例不够的问题而是整个验证链路没有跟上 Agent 的产出速度。代码生成已经变成越来越便宜的能力验证却依然是手工活人工回归、肉眼比对、反复点击页面。pstack 最近新增的“创建与维护验证技能”正是冲着这个痛点来的——让 Agent 像真实用户一样去验证应用而不是写完代码就甩手交付。这篇文章会从三个层面把这个更新讲透第一为什么验证会成为 Agent 应用的瓶颈第二pstack 的验证技能到底是什么和 MCP、传统自动化测试有什么区别第三从技能创建、运行到维护用一个完整的待办事项应用示例把整个流程跑通。如果你正在做 AI 应用开发或者准备把 Agent 接进自己的项目这篇文章应该能帮你少踩几个坑。1. 为什么 Agent 应用需要“验证技能”先看一个非常典型的开发场景。你让 Agent 给后台管理系统加一个导出功能。Agent 在几分钟内改完代码还顺手告诉你新增了 export.js修改了列表接口调整了权限配置。听起来很顺利但接下来才是真正的问题你怎么知道导出功能在真实浏览器里能用权限调整有没有影响原有的用户查询列表接口的改动有没有破坏分页在没有验证技能的情况下你只能把 Agent 改完的代码部署到测试环境然后自己打开页面一步步地点击、填写、提交、刷新。发现一个 bug反馈给 AgentAgent 再改你再去点。这个循环一旦跑起来你会发现一个残酷的事实Agent 写代码只要五分钟你验证它可能要五十分钟。当 Agent 的产出速度快于人的验证速度时整个开发流程的瓶颈就从“能不能写出来”变成了“能不能被确认是对的”。这背后有三层验证困境第一层单元测试和接口测试覆盖不到真实用户操作。很多 Agent 项目确实有测试用例但大量测试停留在函数级或接口级而用户真正关心的是页面能不能打开、按钮能不能点、流程能不能走通。一个接口返回 200不代表页面上的交互是正确的。第二层人工回归跟不上迭代节奏。传统项目里测试人员用自动化测试框架维护一套用例然后在发版前集中执行。但 Agent 的开发节奏是小时级的甚至分钟级的。每次让它改一个小需求都要求人工先回归一遍团队会变得极其疲惫。第三层Agent 修改的不确定性让测试维护更难。Agent 生成代码的模式和人不一样它可能为了一个需求重写了整个组件也可能悄悄替换了某个工具函数。旧的测试用例可能因为选择器变了、接口字段改了、页面结构换了而大面积失败。这时候维护测试本身又成了一项不亚于写业务代码的工作。所以在 Agent 时代验证正在从“保证质量的手段”变成“决定 Agent 能否交付的关键能力”。pstack 这次把“创建与维护验证技能”作为独立能力推出本质上是在承认一件事如果 Agent 只会干活不会验证那它写代码再快也只是把 bug 生产得更快。没有验证闭环的 Agent在真实项目里很难被信任也就很难真正落地。2. pstack 验证技能的核心概念与边界2.1 Skill、Agent 与验证技能在讨论验证技能之前需要先厘清几个基本概念。Agent指的是能够自主完成任务的智能体。它的工作方式通常是一个循环接收目标、拆解步骤、调用工具、观察结果、再决定下一步。这个循环被称为“规划-执行-观察”循环。一个成熟的 Agent 框架会在这个循环里加入记忆、工具调用、任务编排等能力用来处理复杂任务。Skill 在这个循环里扮演什么角色更准确地说Skill 是一个可以被 Agent 复用的“能力包”里面既包含一段可执行脚本也包含使用它的说明。打个比方Agent 是大脑负责思考和决策Skill 是肌肉记忆负责把某类动作稳定地做出来。没有 SkillAgent 每次都要从零摸索怎么做有了 SkillAgent 识别到匹配场景后直接调用效率和稳定性都会明显提升。从这次功能介绍看pstack 的定位是 AI 应用开发与智能体协作的工程平台它承接从需求描述、应用创建、代码生成到运行迭代的整条链路。开发者借助它管理 Agent 任务Agent 借助它调用应用资源和工具。这次新增的“创建与维护验证技能”是在 Agent 的技能体系里补上了一块明显的短板——验证。“验证技能”就是专门用于验证应用的 Skill 类型。“创建与维护”四个字是关键。创建指 Agent 能根据应用的结构和行为自动生成验证脚本和验证用例维护指当应用界面或接口发生变化后Agent 能跟着更新验证逻辑而不是把一堆过时脚本扔在那里。这正好回应用了前面提到的第三层困境验证技能不是一份静态的测试代码而是一套由 Agent 创建、又由 Agent 持续维护的动态能力。2.2 “像真实用户一样”到底是什么意思pstack 这次更新的描述里最有信息量的一句话是“像真实用户一样验证应用”。这句话背后的技术含义很具体验证层级从接口走向界面。真实用户的验证不是调用一个函数看返回值而是打开页面、点击按钮、填写表单、等待跳转、观察页面反馈。要做到这一点验证技能不能只停留在接口测试层面而要具备操作浏览器或客户端的能力同时还要能理解页面状态。比如一个登录功能接口测试只验证“用户名密码正确时返回 token”但真实用户验证要覆盖登录页是否正常渲染、输入框是否可填写、点击登录按钮后是否跳转到首页、错误密码时是否弹出提示、提示文案是否清晰。这意味着验证技能的设计需要包含几个关键要素可执行的操作步骤、对页面状态的识别能力、判定通过或失败的断言规则、以及出现问题时的错误信息输出。只有具备这套能力Agent 才能在自己修改完应用后主动执行一次完整的“用户视角”验证并把结果反馈到下一次迭代中。2.3 验证技能与 MCP、传统自动化测试的区别很多读者会问验证技能和 MCP 有什么关系和 Playwright、Selenium 这类自动化测试框架又有什么区别这三个概念常常被放在一起讨论但它们的层次完全不同。对比维度MCP传统自动化测试框架pstack 验证技能本质工具调用协议测试执行工具Agent 能力单元服务对象Agent 的工具访问测试人员Agent 的自主验证流程主要工作方式按需调用外部工具人工编写用例后执行由 Agent 创建、执行并持续维护典型场景Agent 读取文件、查数据库、操作浏览器发版前的接口回归、UI 回归Agent 交付修改前自动验证应用维护成本需要配置工具和权限需要人工维护脚本成本高支持跟踪应用变化自动更新MCP 解决的是“Agent 能不能调用某个工具”的问题它是一种标准化的协议让 Agent 可以访问文件系统、数据库、浏览器等外部资源。验证技能解决的是“Agent 怎么围绕一个验证目标组织多步操作并得出通过或失败结论”的问题。二者不是替代关系更常见的组合是验证技能在执行界面操作时通过 MCP 协议调用浏览器工具在读取测试配置时通过 MCP 调用文件接口。传统自动化测试框架则更偏向“工具”本身。它的核心价值是把人工点击转换成可重复执行的脚本但脚本的编写和维护仍然依赖人。验证技能把这一层也往前推进了一步它把验证目标、执行步骤、断言规则和失败处理打包成一个面向 Agent 的能力单元让 Agent 在规划任务时能主动选择和调用。这也是 Agent 应用开发和传统测试开发之间一个很重要的认知差异。3. 创建验证技能流程拆解与环境准备3.1 创建流程拆解从工程实践角度看创建一个可用的验证技能通常要经过五个步骤。第一步明确验证目标与核心路径。不要一上来就写脚本先定义清楚这个技能要验证哪些功能覆盖哪些核心用户路径是在应用每次变更后执行还是在发版前执行比如一个电商应用核心路径可能是“搜索商品—加入购物车—结算—支付”一个后台管理系统核心路径可能是“登录—列表加载—新建数据—编辑数据—删除数据”。第二步梳理或生成验证步骤。把核心路径拆成可执行的步骤序列每个步骤都要有明确的输入、操作和预期结果。这一步可以靠人对业务的理解来梳理也可以让 Agent 结合应用代码和页面结构自动生成再交给人工确认。pstack 的“创建”能力重点就在这一步。第三步编写技能元信息。一个技能要被 Agent 正确发现和调用光有脚本是不够的还需要描述清楚这个技能是做什么的、什么时候应该被调用、需要什么输入参数、会输出什么结果。这部分通常用 YAML 或 JSON 描述是整个技能是否“好用”的关键。第四步注册技能。把写好的技能注册到当前的项目或工作区中让 Agent 在执行任务时能检索到它。注册完成后可以先用自然语言给 Agent 下一个验证任务观察它能否准确识别并调用正确的技能。第五步联调验证并输出报告。执行一次真实验证检查输出结果是否可读、失败信息是否足够定位问题。如果失败信息只写“断言失败”对 Agent 和人都没有帮助好的输出应该包含失败步骤、实际响应、期望结果和可能的修复方向。3.2 环境准备本文后面的示例会用一个本地待办事项应用作为被验证对象。环境准备按以下清单进行操作系统Linux 或 macOS 都可以Windows 同样支持只是命令略有差异。运行环境Python 3.10 以上需要能执行 pip 安装依赖示例中用到的 requests 库是纯 Python 实现安装简单。被验证应用一个本地运行的 Web 应用提供待办事项的增删改查接口可访问地址为http://localhost:8080。Agent 与技能框架本文演示的是通用技能创建思路pstack 相关命令以你安装版本官方文档为准。先确认基础环境版本python3 --version node --version然后创建虚拟环境并安装依赖python3 -m venv .venv source .venv/bin/activate pip install requests如果实际项目中需要做界面级验证还可以安装 Playwright 这类浏览器自动化库并执行playwright install下载对应浏览器驱动。需要注意的是界面级验证对环境要求更高首次配置时要留意浏览器版本与驱动的匹配问题。4. 完整示例为待办事项应用实现一个验证技能这一节用一个最小但完整的示例演示验证技能的三个组成部分技能元信息、验证脚本、注册与触发。示例目标是一个待办事项应用它对外提供四个接口查询列表、新增待办、完成待办、删除待办。4.1 技能元信息定义技能元信息是整个技能让 Agent 能“看懂”的部分。它决定了 Agent 在什么场景下会调用这个技能、需要提供什么参数、结果如何解释。# 文件路径skills/todo-app/skill.yaml name: todo_app_smoke_verify description: 对待办事项应用执行冒烟验证覆盖新增待办、完成待办、删除待办、列表加载四类核心操作。 适合在应用版本发布前、Agent 修改页面或接口后使用。 trigger: - verify todo app - 验证待办应用 - 待办应用冒烟测试 input_schema: base_url: type: string description: 待验证应用访问地址例如 http://localhost:8080 output_schema: status: type: string description: pass 或 fail steps: type: array description: 每个验证步骤的结果明细这里有两个容易被忽视的细节。第一description不是写给文档看的而是写给 Agent 看的。Agent 在规划任务时会靠这段描述判断当前任务是否匹配这个技能所以描述里应该明确写清“何时使用”“覆盖什么操作”而不是简单地写“验证应用”。第二trigger是一项实用设计一些 Agent 框架支持通过触发词快速命中技能这能显著降低 Agent 选错技能的概率。4.2 验证脚本实现验证脚本是技能的执行核心。下面这段 Python 脚本按顺序执行列表加载、新增待办、完成待办、删除待办四个步骤每一步都有明确的断言。全部通过后输出结构化报告并设置不同退出码供上层判断。# 文件路径skills/todo-app/verifier.py 待办事项应用冒烟验证脚本 验证目标列表加载、新增待办、完成待办、删除待办 运行方式python verifier.py --base-url http://localhost:8080 --report report.json import argparse import json import sys import time import requests def call(method: str, url: str, **kwargs): 统一请求入口方便在超时、重试、日志层面做后续扩展。 kwargs.setdefault(timeout, 5) return requests.request(method, url, **kwargs) def verify_list_todo(base_url: str) - dict: resp call(GET, f{base_url}/api/todos) assert resp.status_code 200, f列表接口返回 {resp.status_code} assert isinstance(resp.json(), list), 列表接口返回格式不是数组 return {step: 列表加载, status: pass} def verify_add_todo(base_url: str) - dict: resp call(POST, f{base_url}/api/todos, json{title: pstack 验证技能测试}) assert resp.status_code 200, f新增待办接口返回 {resp.status_code} todo resp.json() assert todo.get(id), 新增待办响应缺少 id 字段 return {step: 新增待办, status: pass, todo_id: todo[id]} def verify_complete_todo(base_url: str, todo_id: str) - dict: resp call(PUT, f{base_url}/api/todos/{todo_id}, json{completed: True}) assert resp.status_code 200, f完成待办接口返回 {resp.status_code} todo resp.json() assert todo.get(completed) is True, 完成待办后 completed 字段未变为 true return {step: 完成待办, status: pass, todo_id: todo_id} def verify_delete_todo(base_url: str, todo_id: str) - dict: resp call(DELETE, f{base_url}/api/todos/{todo_id}) assert resp.status_code 200, f删除待办接口返回 {resp.status_code} resp call(GET, f{base_url}/api/todos/{todo_id}) assert resp.status_code 404, 删除待办后再次查询未返回 404 return {step: 删除待办, status: pass, todo_id: todo_id} def main(): parser argparse.ArgumentParser(description待办事项应用冒烟验证) parser.add_argument(--base-url, requiredTrue, help应用访问地址) parser.add_argument(--report, defaultreport.json, help结果报告输出路径) args parser.parse_args() base_url args.base_url.rstrip(/) results [] try: results.append(verify_list_todo(base_url)) todo_id verify_add_todo(base_url)[todo_id] results.append({step: 新增待办, status: pass, todo_id: todo_id}) results.append(verify_complete_todo(base_url, todo_id)) results.append(verify_delete_todo(base_url, todo_id)) except Exception as exc: results.append({step: 未完成步骤, status: fail, error: str(exc)}) status pass if all(r[status] pass for r in results) else fail report { skill: todo_app_smoke_verify, status: status, timestamp: time.time(), steps: results, } with open(args.report, w, encodingutf-8) as f: json.dump(report, f, ensure_asciiFalse, indent2) print(json.dumps(report, ensure_asciiFalse, indent2)) sys.exit(0 if status pass else 1) if __name__ __main__: main()这段脚本的关键逻辑有三处。第一所有请求都通过call()统一发送后续如果想加超时重试、请求日志只需要在这一处修改。第二断言紧跟在操作后面并且失败信息尽量具体比如“完成待办后 completed 字段未变为 true”而不是笼统的“断言失败”这样 Agent 拿到结果后能更快定位问题。第三最终结果同时输出到标准输出和 JSON 文件方便 Agent 读取结构化报告也方便人工查看历史记录。4.3 注册技能并触发验证脚本写完后需要把技能注册到当前项目然后让 Agent 在任务规划中识别并调用它。以下命令仅用于演示技能注册和触发的通用形态实际命令名以你使用的 pstack 版本官方文档为准。# 将技能注册到当前项目工作区 pstack skill add ./skills/todo-app # 让 Agent 执行验证任务 pstack run 对待办事项应用执行冒烟验证base_urlhttp://localhost:8080注册完成后Agent 会在自己的技能列表里检索到todo_app_smoke_verify。当它收到验证任务时会读取技能描述、匹配触发词、确认输入参数然后执行脚本、读取输出报告并根据status字段判断验证是否通过。5. 运行结果与效果验证手动执行一次验证脚本可以更清楚地看到整个验证技能的输出形态。运行命令如下python3 verifier.py --base-url http://localhost:8080 --report report.json如果应用运行正常预期输出是一份类似下面的 JSON 报告{ skill: todo_app_smoke_verify, status: pass, timestamp: 1737093600.0, steps: [ { step: 列表加载, status: pass }, { step: 新增待办, status: pass, todo_id: 1001 }, { step: 完成待办, status: pass, todo_id: 1001 }, { step: 删除待办, status: pass, todo_id: 1001 } ] }判断验证是否成功核心看两个地方一是报告顶层的status字段是否为pass二是每个step的status是否全部为pass。当某个步骤失败时报告会保留失败步骤的error信息比如“新增待办接口返回 500”“完成待办后 completed 字段未变为 true”这些信息既是给人看的也是给 Agent 看的。如果在 pstack 里通过 Agent 触发验证效果会更有意思。Agent 读完失败报告后可以继续执行一个“修复—再验证”的循环它先根据error字段定位代码问题修改代码然后再次调用同一个验证技能直到status变为pass。这就把“写代码”和“验证代码”两个环节真正闭环了。如果验证脚本失败时只输出一个含糊的“AssertionError”这个自动闭环就很难成立所以结构化输出和可读的错误信息是整个设计的生命线。6. 验证技能的维护应用变了技能如何跟着变创建验证技能只是开头更考验工程能力的是维护。传统自动化测试之所以在快速迭代的项目里经常被放弃就是因为维护成本太高接口改了字段、页面换了按钮文案、业务流程新增了步骤测试脚本就要跟着改改着改着测试就变成了负担。pstack 把“维护”写进功能名说明它把维护当成了一等公民。应用的每次变化都可能触发验证技能的更新。比较常见的维护场景有三种第一种接口契约变化。比如待办事项接口新增了priority字段旧脚本断言不涉及这个字段通常不会失败但如果你想验证新字段就需要在verify_add_todo里补充断言。更麻烦的是字段改名比如title改成name那新增待办和列表加载的断言都要同步调整。第二种页面结构或交互变化。如果在界面级验证中使用了 CSS 选择器或 XPath按钮文案变化、页面层级调整、异步加载逻辑修改都可能导致选择器失效。这类问题在真实项目中非常常见也是维护成本的大头。第三种业务流程扩展。应用从“只支持新增和删除”扩展到“支持编辑、批量操作、搜索筛选”原来的冒烟验证技能覆盖范围就不够了。这时候需要新增验证步骤技能描述也要同步更新否则 Agent 依然只会执行旧的那套验证。维护验证技能时有三条经验值得借鉴。第一把验证技能看成应用的一部分而不是外部附属品。应用迭代时验证逻辑的更新要同需求一起评审、一起排期。第二失败报告要按“应用 bug”和“验证脚本过期”分类。如果 Agent 每次验证失败都只看到“断言失败”而没有上下文它很难判断是该改应用还是该改脚本。第三验证技能的变更要保留记录尤其是自动更新后的断言改动最好经过人工确认避免 Agent 为了“通过验证”而把断言越改越松最后验证流于形式。说到底验证技能维护的本质是让 Agent 持续理解“应用当前应该是什么样”。应用的业务逻辑在演进验证技能也要跟着演进否则它就只是一堆过时的、看起来还在运行却没有任何护城河价值的脚本。7. 常见问题与排查思路在落地验证技能的过程中团队遇到最多的问题有六类。下面用表格做一个快速索引。问题现象可能原因排查方式解决方案Agent 不调用验证技能技能描述不清晰、触发词不匹配查看 Agent 规划日志和技能检索结果补充更精准的 description 和 trigger增加示例任务验证脚本频繁失败接口字段变更或页面选择器失效查看失败步骤的错误信息和响应体更新脚本断言或选择器必要时重新生成技能验证通过但应用上线后仍有问题覆盖范围不足只验证了主路径分析线上问题集中在哪类场景增加边界场景、异常场景和权限场景的验证步骤验证脚本污染了测试数据脚本没有做数据清理重复执行积累垃圾数据检查数据库中技能产生的测试数据设计幂等脚本执行前后清理测试数据高并发或慢接口导致超时误报超时设置过短没有重试机制查看超时时间和接口实际响应时间合理调整 timeout增加有限次数的重试自动维护后断言被改松Agent 为了通过验证而放宽断言审查技能变更记录比较新旧断言差异对自动更新设置人工审批门槛排查时建议按“先分面再分点”的顺序先确认问题发生在技能发现阶段、执行阶段还是结果解释阶段。技能发现阶段的问题看 Agent 规划日志执行阶段的问题直接跑一次脚本看原始输出结果解释阶段的问题看报告里的 status 判断逻辑和退出码。大多数问题在跑一次脚本、看一遍 JSON 报告之后就能定位到具体环节。8. 最佳实践与工程建议验证技能不是写一个脚本就有用它要真正融入 Agent 应用开发的流程需要遵循一系列工程规范。以下八条建议是我认为在这个领域最值得关注的底线和技巧。第一验证脚本必须幂等。Agent 可能会重复执行同一个验证技能脚本应该做到无论执行多少次都不会产生重复数据和副作用。最简单的做法是新增数据时带上可识别的测试前缀验证结束后清理数据如果清理失败下一次执行也能正常继续。第二输出必须是结构化且可被 Agent 消费的。JSON 要比纯文本好一万倍。报告里除了 pass/fail还应该有失败步骤、实际值、期望值、错误上下文。Agent 读取这份报告后才能做下一步决策而不是靠猜。第三超时与重试要单独设计。真实的接口和页面不会永远 200ms 内响应。超时时间设置太短会造成误报设置太长会拖慢整个验证链路。更好的做法是把网络超时和断言超时分离开并对非确定性操作实现有限次重试。第四数据隔离和安全边界。验证技能如果连的是测试环境问题不大一旦连到预发甚至生产环境就必须设计独立测试账号、独立测试数据集和最小权限。验证技能能操作应用它本身也是 Agent 能力的延伸权限边界要和写业务的 Agent 一样严格。第五验证技能要纳入版本管理。技能元信息、验证脚本、预期结果报告模板都应该放进 Git 仓库随应用代码一起走版本。这样当验证结果出现回归你可以快速定位是哪次提交改变了行为。第六把验证技能接入 CI/CD 流程。即使不用 Agent 触发也应该在应用构建或部署流水线中自动执行关键验证技能让回归在代码合并阶段就暴露问题。pstack 这类平台的好处就在于验证技能可以被 Agent 调用也可以被流水线调用一套脚本多处使用。第七失败信息里带上修复线索。好的失败报告不只是一句“断言失败”而是附上实际响应、相关接口文档或页面截图。现在很多 Agent 具备自我修复能力但前提是它能看到足够的信息。验证技能的设计者要把失败报告当成 Agent 的诊断书来写。第八命名与组织规范。技能名建议采用“应用名_场景名_验证类型”的格式比如todo_app_smoke_verify、order_flow_e2e_verify。技能目录按应用或业务模块划分避免所有技能堆在一个目录里。Agent 的技能检索效率会直接影响它能不能在正确的时机选中正确的技能。9. 总结与后续学习方向这篇内容把 pstack 新增“创建与维护验证技能”这件事从背景、概念、实现到维护完整过了一遍。核心判断可以浓缩成一句在 AI Agent 应用开发里验证能力不是锦上添花而是决定 Agent 能不能被信任、能不能上线的关键一环。代码生成越便宜验证就越值钱Agent 干活越快验证闭环就必须越自动。对读者的建议是不要停留在“读概念”这一步。你可以先把手头的一个小应用拿出来给它写一个最简单的冒烟验证技能覆盖两条核心用户路径然后让 Agent 在每次修改后自动执行它。先跑通再优化再扩展到更多场景。这个最小闭环建立起来之后你才算是真正体验到了“Agent 自己验证自己”的工作方式。后续值得继续深入的方向有三个一是技能市场的沉淀把针对不同应用的验证技能抽象成可复用模板让同一个技能在不同项目里快速落地二是界面级验证的深化结合更智能的页面状态识别减少选择器维护成本三是多 Agent 协作验证一个 Agent 写代码另一个 Agent 负责验证两个角色互相监督。验证技能的边界还很宽但这个方向已经足够清晰地指出来了Agent 不仅要会干活更要会证明自己干对了。如果你正在做 Agent 应用开发建议把“验证技能”作为一个独立的工作项纳入计划。它能帮你把对 Agent 的信任从“感觉还行”变成“验证通过”。