e2e自定义executor完全指南:替换内置智能体执行器
【免费下载链接】e2eNext generation e2e testing framework for web and mobile apps.项目地址: https://gitcode.com/GitHub_Trending/e2e6/e2e
e2e 是面向 Web 和移动端的下一代端到端测试框架,它内置了一个 AI 智能体执行器(agent executor),让测试用自然语言驱动界面。当内置智能体不够用——你想换一套工具词表、接入自己的"大脑"、甚至完全不用大模型时,就可以通过e2e 自定义 executor替换内置智能体执行器。本文用通俗的方式讲清楚:为什么要换、怎么换、以及替换后你能拿到什么。
先搞懂:executor 是什么,为什么要替换
e2e 的智能体步骤(agent.act()/agent.assert())由两部分协作完成,理解这个分工是理解自定义 executor 的关键:
| 角色 | 职责 | 是否可替换 |
|---|---|---|
| 运行器(runner) | 脱敏、动作授权、预算、超时、录制、报告 | ❌ 固定 |
| 执行器(executor) | 思考:读屏幕、决定做哪个动作、给出结论 | ✅ 可替换 |
源码注释里有一句点睛之笔:"Swapping executors changes the thinking, never safety, budgets, or the report"——换执行器只换"思考",安全、预算和报告永远由运行器把关(见 executor.ts)。
所以替换内置智能体执行器是安全的:你的自定义 executor 拿到的是已脱敏的屏幕观察和受检查的动作方法,无论里面跑的是哪家大模型、还是纯脚本逻辑,预算、死线和判定规则都不变。
什么情况下需要替换?常见场景有三类:
- 🛠️ 内置动作词表不合用:比如只允许"读屏幕 + 点节点"的最小工具集
- 🧠 想接入自己的模型或决策逻辑(含非 AI SDK 的模型)
- 📜 根本不需要模型:用确定性脚本代替 AI 决策
两条官方路线:保留循环 或 完全接管
官方文档 executors.mdx 给出了两条路线,按需选择:
路线一:createToolLoopExecutor—— 保留内置循环,只换工具词表
如果你还想要大模型驱动,但想控制它"能说什么话",选这条路。它会原样保留内置循环的全部纪律:
- 预算(模型调用次数、动作次数)
- 重复调用检测(防死循环,见 tool-loop.ts 中的 loop guards)
- 结论工具
complete_step、用量记账、调试转录
你只需要提供三样东西:system提示词、buildPrompt开场提示、tools工具集。循环会自动补上complete_step结论工具。
路线二:StepExecutor—— 完全自定义,模型可选
自己实现runStep(ctx)方法,一个步骤进、一个结论出。模型和 AI SDK 都是可选的——不装ai包,类型照样能编译。适合:
- 确定性脚本:只处理特定的
assert断言,其他指令直接返回blocked - 用自己的模型、自己的推理框架
- 需要把历史/记忆作为"事实来源"的执行器(此时把
cache设为'off',每个步骤都真实执行)
三步把自定义 executor 挂进配置
替换内置智能体执行器只需在e2e.config.ts的agents条目里加一个executor字段。以路线二为例,最小可用写法:
import type { E2EConfig, StepExecutor } from 'e2e'; import { web } from '@e2e-dev/web'; const scripted: StepExecutor = { name: 'scripted', version: '1', cache: 'off', async runStep(ctx) { const screen = await ctx.observe(); const ready = screen.text.includes('Ready'); return ready ? { status: 'passed', summary: 'The screen says Ready.' } : { status: 'failed', summary: 'Ready is absent.' }; }, }; export default { targets: [{ engine: web(), app: { url: 'http://localhost:3000' } }], agents: { default: { executor: scripted } }, } satisfies E2EConfig;配置规则(详见 config.mdx):
executor与其他字段互斥:同一条目里再写system或tools会报INVALID_CONFIG——执行器自带提示词和工具,把它们传给createToolLoopExecutor即可- 仍然生效的选项:
model、judge、context和各类预算照常工作 - 模型一致性:条目和 executor 各自带了
model时必须指向同一模型,否则配置加载失败
被测试的应用长这样——智能体(内置或自定义)都在这类界面上工作:
替换后你能拿到什么:执行器上下文与结论
自定义 executor 的runStep(ctx)会收到一个内容丰富的上下文(完整定义见 StepExecutorContext),核心成员:
| 成员 | 用途 |
|---|---|
ctx.step | 步骤指令、参数、序号;秘密值只会以<secret:name>占位符出现 |
ctx.observe({ tree, pixels }) | 脱敏后的屏幕文本,可选节点树和打码截图 |
ctx.actions | 受检查、受记账的动作:tap、type、scrollUntil、upload等二十多个动词 |
ctx.target | 目标平台与它支持的动词集合——只给模型提供它能做到的 |
ctx.signal | 取消、死线或其他硬停止时触发,收到就该立刻停 |
ctx.budgets | 动作/模型调用记账;自定义工具包在runTool里执行 |
ctx.replayedPrefix | 缓存重放已执行过的动作,继续时别重做 |
ctx.attachScreenshot/attachTurns | 把截图、模型回合附到步骤报告上 |
步骤结束时返回三态结论StepVerdict:
- ✅
passed:目标达成,不携带错误码 - ❌
failed:应用行为不符合要求 - 🚫
blocked:环境/凭据/预算阻断了判断,必须携带可阻断的错误码
注意:STEP_TIMEOUT、CANCELLED这类运行器专属错误码不能由执行器"发明",乱返回会被以MODEL_OUTPUT_INVALID拒收(见 agent-steps.mdx)。
缓存、预算与常见坑
- 重放缓存:
cache决定act步骤如何参与缓存——'inherit'(默认)跟随配置模式,'off'永不重放、每步都进runStep。assert步骤从不缓存。条目按"agent + 上下文"为键,一个 agent 录制的条目不会在另一个 agent 上重放 - 记账要用
ctx.budgets.runTool:自定义工具要占动作槽、被记录,就包在runTool里;但不要在runTool内部再调ctx.actions或ctx.observe,会死锁 - 直连页面 API 要谨慎:用
surfaceOf(handle)拿到 Playwright 页面直接操作会绕过动作授权和重放缓存,运行器仍会执行死线和记录结论 - 工具体保持短小并支持取消:步骤死线无法取消一个无视信号的底层操作
- 模型缺失会明确报错:路线一要求有模型,条目没配
model时抛MODEL_UNAVAILABLE,错误信息会告诉你去配哪里
选型清单:我该选哪条路?
| 你的需求 | 推荐方案 |
|---|---|
| 仍用大模型,但想收紧工具词表、自定义提示词 | createToolLoopExecutor |
| 零模型、确定性脚本断言 | 手写StepExecutor+cache: 'off' |
| 用自己的模型/推理框架驱动界面 | StepExecutor自带model |
| 直接操控浏览器(Playwright 风格) | StepExecutor+surfaceOf |
换执行器 = 换大脑,不换安全底线。想动手的话,从官方示例页 executors.mdx 的两个完整例子起步,再对照 executor 接口源码 逐字段阅读,半小时内就能跑起第一个自定义 executor。
延伸阅读:内置智能体步骤机制、agents 配置参考、引擎编写指南、项目工具 defineTool
【免费下载链接】e2eNext generation e2e testing framework for web and mobile apps.项目地址: https://gitcode.com/GitHub_Trending/e2e6/e2e
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考