news 2026/9/9 13:16:34

让 AI Agent 交付可信代码:为 Novu 单体仓库设计 verifier 验证工作流

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
让 AI Agent 交付可信代码:为 Novu 单体仓库设计 verifier 验证工作流

让 AI Agent 交付可信代码:为 Novu 单体仓库设计 verifier 验证工作流

【免费下载链接】novuThe open-source communication infrastructure for agents and products项目地址: https://gitcode.com/GitHub_Trending/no/novu

导读

大型开源单体仓库(monorepo)中,由 AI 编码 Agent 提交代码的最大风险不是"写错",而是"声称写完了但实际跑不通"。Novu 在其 Cursor 协作体系中用一个名为verifier的 Agent(验证者)专门解决这个问题:它扮演"怀疑论者",在任何任务被标记为完成之后接管,通过"确认改动文件 → 运行受影响应用的真实测试 → 静态检查 → OpenAPI 规范校验 → 边缘情况扫描"这一串动作,把"声明完成"变成"证据驱动地验证完成"。本文围绕仓库中的 verifier Agent 定义,逐条拆解这套验证流程,并结合 apps/api/package.json、apps/worker/package.json、apps/dashboard/package.json 与 .cursor/rules/testing.mdc 中的真实脚本定义,说明每条命令背后的执行逻辑与适用边界。读完你既能理解如何复刻一个"验证者"角色的 Prompt 设计,也能掌握 Novu 仓库中单测、E2E 与 OpenAPI 校验的确切用法。

verifier 是什么:一个专职"唱反调"的编码 Agent

在 Cursor 中,Agent 通过 Markdown 文件顶部的 YAML frontmatter 进行声明式注册。verifier 的元数据定义了它的职责边界:

--- name: verifier description: Validates completed work. Use after tasks are marked done to confirm implementations are functional — runs tests, checks types, and verifies the OpenAPI spec where applicable. model: fast ---

三个字段的含义分别是:

  • name:Agent 的唯一标识,供 Cursor 对话中按名调用;
  • description:定义"何时该用我"。注意它把触发时机限定得非常精确——"after tasks are marked done"(任务被标记为完成之后),这与普通编码 Agent 形成职责互补;
  • model: fast:指定该 Agent 默认使用轻量快速模型执行。验证任务大多是机械的 grep、跑命令、核对产物,不需要重模型推理,fast模型能在降低延迟与成本的同时完成任务。

正文第一句直接给出角色内核:You are a skeptical validator. Your job is to verify that work claimed as complete actually works.(你是一个怀疑论验证者,你的工作就是核实那些"声称已完成"的工作是否真的可用)。这是一个刻意设计的对抗性角色定位——与"写代码"的 Agent 不同,verifier 的产出不是新功能,而是"通过与不通过的判定 + 待修复问题清单"。

在 .cursor/agents/impact-checker.md 中可以看到体系化的另一半:impact-checker在"改动前"评估共享代码的爆炸半径(blast radius),而 verifier 在"改动后"做功能验收。两者共同构成"改前评估风险、改后验证结果"的闭环。

六步验证流程拆解

verifier 被调用时按固定步骤执行,下面结合仓库中真实脚本逐一还原每步的执行内容与原理。

第一步:锁定"声称完成"的具体范围

  1. Identify what was claimed to be completed

验证不能从"你做了什么"开始,而应从"你声称做了什么"开始。verifier 先解析任务结论中的改动声明,明确验证对象(例如"新增了某个 UseCase""修改了某个 DTO""调整了某条路由"),再进入下一步去核对物理证据。这一步的价值在于把"笼统的完工"翻译成"可检验的断言清单",防止 Agent 自述式交付绕过检验。

第二步:确认实现文件真实存在且包含预期改动

  1. Confirm the implementation files exist and contain the expected changes

验证者须核对文件系统事实:改动涉及的文件是否真的存在、关键符号(类/函数/DTO/枚举)是否真的按声明被添加或修改。在 Novu 仓库中这意味着验证者要能区分几个"看似相似但互不相关"的代码库区域:

  • apps/api:NestJS 网关,承载 REST API、UseCase 编排与 OpenAPI 生成;
  • apps/worker:后台任务消费者(队列 worker),处理通知投递等异步逻辑;
  • apps/ws:WebSocket 网关;
  • apps/dashboard:Vite + React 管理面板;
  • 支撑库:libs/dal(数据访问)、libs/application-generic(业务逻辑)、packages/shared(共享类型/DTO/枚举)。

文件层核对通过后,才能进入"跑测试"环节。

第三步:运行受影响应用的真实测试套件

  1. Run the relevant test suite for the affected app
    • API/worker:cd apps/api && pnpm testorcd apps/worker && pnpm test
    • Dashboard:cd apps/dashboard && pnpm test:e2e(only if dashboard is running)

这是整个验证流程的中枢。命令选择遵循"按受影响应用匹配"原则,而非"全仓一把梭"。

API 单测cd apps/api && pnpm test在 apps/api/package.json 中展开为:

cross-env TS_NODE_PROJECT=tsconfig.spec.json TS_NODE_TRANSPILE_ONLY=true NODE_ENV=test \ NOVU_ENTERPRISE=true CLERK_ENABLED=true NODE_OPTIONS=--no-experimental-strip-types \ mocha --timeout 15000 --require ts-node/register --exit 'src/**/*.spec.ts'

细节值得注意:

  • 基于Mocha + ts-node,匹配src/**/*.spec.ts的单元测试文件(与 .cursor/rules/testing.mdc 中"Mocha for API/worker"的约定一致);
  • 通过NOVU_ENTERPRISE=trueCLERK_ENABLED=true把 Enterprise 与 Clerk 能力纳入测试环境(脚本中还声明了对@novu/ee-*等 workspace 包的依赖,见 apps/api/package.json);
  • --timeout 15000--exit保证长任务与进程都能被妥善收尾;
  • 还有配套的pretest钩子会先执行pnpm build:metadata生成元数据,再开始跑测试。

Worker 单测cd apps/worker && pnpm test对应 apps/worker/package.json 中基于 Mocha 的命令,测试文件 glob 为src/**/**/*.spec.ts,并在环境变量中关闭了strictNullChecks以匹配现有代码风格。若涉及端到端通知链路,.cursor/rules/testing.mdc 还提示 worker 需先启动(pnpm start:worker)。

Dashboard E2Ecd apps/dashboard && pnpm test:e2e实际是playwright test(见 apps/dashboard/package.json),测试目录约定在apps/dashboard/tests/。verifier 特别标注了前置条件——仅当 dashboard 正在运行时执行,因为 Playwright 需要真实页面。仓库中已有可参考的 Playwright 用例,例如 manage-workflows.e2e.ts 与 sync-workflow.e2e.ts,它们配合 page-object-models 与 utils 组织页面对象与公共操作。

第四步:用pnpm check做 lint 与类型卫生

  1. Runpnpm checkin the affected app to confirm no lint or type errors

check脚本在三个应用中都指向Biome

  • apps/api/package.json:"check": "biome check ."
  • apps/worker/package.json:"check": "biome check ."
  • apps/dashboard/package.json:"check": "biome check ."

Novu 以 biome.json 为根配置(规则集分散在 .cursor/rules 与 biome-plugins 下的.grit规则中),biome check会同时覆盖 lint 与格式两类问题,因此它充当 verifier 的"代码卫生门禁",确保改动不引入 lint 违规或格式化漂移。

第五步:涉及 API 端点改动时校验 OpenAPI 规范

  1. For API changes that touch endpoints: runnpm run lint:openapi(requires API running)

这一步属于"按需深度验证"。Novu 的 OpenAPI 文档由运行中的 API 服务实时暴露,命令在 apps/api/package.json 中定义为:

spectral lint http://127.0.0.1:${PORT:-3000}/openapi.yaml

解读:

  • 使用 StoplightSpectral对线上 OpenAPI 文档做规则校验(@stoplight/spectral-cli在 devDependencies 中声明,见 apps/api/package.json);
  • 目标来自正在运行的服务(默认127.0.0.1:3000,可用PORT环境变量覆盖);
  • 因此前置条件必须是API 正在运行——这解释了为什么它被单独列为一步而不是放进普通测试。

仓库中 OpenAPI 的构建链路佐证了"端点改动会波及规范":build:generate会执行generate:swagger(运行 exportOpenAPIJSON.ts)再执行generate:sdk重新生成内部 SDK(见 apps/api/package.json),产物包括 swagger-spec.json。也就是说,端点签名变更不仅影响服务,还会扩散到 SDK 层,verifier 的这一校验正是为了把"规范漂移"扼杀在验收阶段。

第六步:主动寻找遗漏的边缘情况

  1. Look for edge cases that may have been missed

测试全绿不代表正确。verifier 被要求在收尾时主动质疑:空数组、null/undefined输入、并发竞争、权限边界、环境差异、超出主流 happy path 的输入分支……这些仓库约定都有迹可循——例如 .cursor/agents/impact-checker.md 要求评估改动对下游消费者的影响,apps/api/migrations 里大量数据迁移脚本的存在也提醒验证者:涉及 MongoDB 模型或数据形态的改动,还要考虑历史数据与迁移影响。

报告输出:只陈述验证过的证据

verifier 的报告格式被刻意压缩为三类事实:

Report: - What was verified and passed # 已验证且通过的内容 - What was claimed but is incomplete or broken # 声称完成但实际缺失/损坏的内容 - Specific issues that need to be addressed # 需要解决的具体问题

这种三段式强制验证者把输出限定在"可验证事实"上:

  1. 通过的项必须能回溯到上文的某条命令(如"apps/apipnpm test通过,涉及 3 个 spec 文件");
  2. 未通过的项必须给出"声明 vs 现实"的落差(如"声称新增了XxxUsecase,但对应文件不存在");
  3. 问题清单要具体到可执行——指向具体文件、具体断言或具体命令输出,而不是空泛的"需要改进"。

模板之外还有一条总的心理纪律:Do not accept claims at face value. Test everything you can.(不要轻信任何声明,尽可能测试一切可测的)。这保证 Agent 的输出始终以工具执行结果为准,而非以被验证者的自述为准。

这一设计模式如何落地到其他工程团队

verifier 模式并不绑定 Cursor 或 Novu,它沉淀的是一套可复制的"AI 交付质检"方法论:

  1. 让"验证者"与"实现者"角色分离。写代码的 Agent 倾向于为自己的产出辩护,专职的 skeptical validator 则被授权唱反调,天然规避了"自己验证自己"的盲区。
  2. 把验证动作绑定到真实命令而非口头检查。verifier 清单里的每一步都对应仓库里真实存在的 npm/pnpm 脚本(testchecktest:e2elint:openapi),验证结果因此具有可复现性——这正是它与"看图说话式 Code Review"的本质区别。
  3. 按改动范围决定验证深度。不是每次改动都跑全量:普通 API 改动跑单测 +check;动端点再加 OpenAPI 校验;动 dashboard 才跑需要起服务的 Playwright E2E。验证成本与风险面匹配,才不会被团队弃用。
  4. 报告结构化、证据化。固定三段式输出,让开发者扫一眼就知道"哪些已确认、哪些被证伪、下一步修什么"。

对 Novu 仓库而言,这套工作流与仓库自身的工程底座深度咬合:单测约定见 .cursor/rules/testing.mdc,共享代码的爆炸半径评估见 .cursor/agents/impact-checker.md,顶层协作约束见 AGENTS.md(如"改动packages/需重新构建""Enterprise 改动需与社区版解耦"等边界)。verifier 正是把文档化约束翻译成可执行验证步骤的那个角色——它不负责让代码变得正确,而是负责让"正确"这件事变得可以被证明。

【免费下载链接】novuThe open-source communication infrastructure for agents and products项目地址: https://gitcode.com/GitHub_Trending/no/novu

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 13:16:25

遥感图像融合TIF算法:Python与MATLAB实战指南

简介:图像融合TIF算法(Transform Invariant Fusion)提供Python与MATLAB两种语言的实现代码,适合图像处理初学者与进阶开发者学习。该算法基于变换不变性设计,能在图像发生平移、缩放或旋转时仍保持稳定融合效果&#x…

作者头像 李华
网站建设 2026/9/9 13:15:19

从零搭建图像去雨Derain项目:数据合成、残差U-Net训练与调优实战

简介:一个基于Python实现的图像去雨(Deraining)项目,面向图像处理与计算机视觉学习者,旨在去除照片中的雨滴干扰,提升恶劣天气下拍摄图像的清晰度。项目围绕预处理、特征提取、雨滴建模与背景恢复等关键步骤…

作者头像 李华
网站建设 2026/9/9 13:13:25

Neokikoeru:端到端语音合成与声音克隆实战全解析

Neokikoeru这名字乍一看有点怪,如果拆开看就很有意思了:neo kikoeru,后面这个词在日语里是“聞こえる”,也就是“能听见”的意思。合在一起,就是“重新听见”或者说“用一种新方式去听”。做音频和语音相关的朋友应该能…

作者头像 李华
网站建设 2026/9/9 13:13:25

数字化转型总体方案设计:从信息化到数据闭环的落地指南

1. 先把“数字化”这个词拆清楚——别拿着信息化的旧地图找数字化的新大陆我这两年接触过不少企业管理者,一上来就说“我们想搞数字化转型”,再一聊,发现他们想的是“把ERP升级一下”“上个OA审批”“把Excel的活儿搬到系统里”。这其实不是转…

作者头像 李华
网站建设 2026/9/9 13:11:57

三张大头如何做到风格统一?批量稿件全流程拆解与实操指南

做稿件的同学应该都有这个感受:单张“大头”不算难画,真正让人头疼的是三张放在一起时,看起来不像同一批稿件。角色脸型跑偏、颜色冷暖不一致、背景光源方向不统一,这些在单张审核时很难发现,等三张拼在一起就特别明显…

作者头像 李华