☰
A2UI 0.8 评估框架实战指南:用 Genkit 评测 LLM 的 UI 生成能力
2026/10/16 3:33:39 网站建设 项目流程
  • 人工智能
  • 大模型
  • LLM 网关
  • AI Agent
  • 即时通讯

【免费下载链接】openclaw-zero-token

OpenClaw: Use All Major AI Models NO API Token! Claude/ChatGPT/Gemini/DeepSeek/Doubao/Grok/Qwen/Manus/Kimi

项目地址:https://gitcode.com/gh_mirrors/op/openclaw-zero-token
点击查看免费下载

本文基于 openclaw-zero-token 仓库内vendor/a2ui/specification/0.8/eval目录的官方评估框架,完整讲解其环境配置、命令用法、模型与提示词管理、输出控制以及底层校验原理。读完本文,你将能直接运行pnpm run evalAll对 Gemini / GPT / Claude 三系模型进行 A2UI 消息生成的批量评测,并能深入理解 matcher 校验体系与 summary 报告生成机制。

概述:为什么需要专门评估 A2UI 的 UI 生成

A2UI(Agent-to-User Interface)是一种声明式 JSON 协议,让 Agent 用数据来描述 UI 的"意图",再由客户端用自己的原生组件库渲染,做到"像数据一样安全,像代码一样富有表现力"(见 vendor/a2ui/README.md)。要让不同的大语言模型稳定地输出符合 A2UI v0.8 规范(四种消息类型:beginRendering、surfaceUpdate、dataModelUpdate、deleteSurface)的 JSON 消息,不能只靠人工抽查——需要一套可复现、可量化的评估流水线。

vendor/a2ui/specification/0.8/eval 正是这样一套基于Genkit的评估框架(Genkit Eval Framework for UI generation),它实现了:

  1. 多模型批量推理:内置 8 个模型配置(GPT、Gemini、Claude 三系);
  2. 多提示词评测集:内置 18 个覆盖常见 UI 场景的测试提示词;
  3. 结构化输出约束:通过 Genkit 的jsonSchema让模型直接产出符合 A2UI 协议的 JSON;
  4. 多层级校验:JSON Schema 级校验 + 语义 matcher 校验;
  5. 汇总报告:自动生成按模型、按提示词分组的 Markdown 评估摘要。

环境准备与安装

API Key 配置

框架通过三个环境变量读取各家模型的 API Key(见 eval/README.md):

环境变量对应模型厂商
GEMINI_API_KEYGoogle Gemini
OPENAI_API_KEYOpenAI GPT
ANTHROPIC_API_KEYAnthropic Claude

在 eval/src/flows.ts 中,框架会按环境变量存在性动态初始化插件:只配置了GEMINI_API_KEY就只注册 Google AI 插件,只配置OPENAI_API_KEY就只注册 OpenAI 插件(openAI()),只配置ANTHROPIC_API_KEY就只注册 Anthropic 插件。也就是说,你可以只评测你有 API Key 的模型,不会因为没有其他 Key 而报错。

配置方式有两种:

  • 在项目根目录(此处为vendor/a2ui/specification/0.8/eval)创建.env文件;
  • 或在 shell 配置文件(.bashrc、.zshrc)中 export。

示例.env:

GEMINI_API_KEY=your_gemini_key OPENAI_API_KEY=your_openai_key ANTHROPIC_API_KEY=your_anthropic_key

注意:pnpm run eval脚本使用dotenv -- tsx src/index.ts(见 package.json),dotenv-cli会自动加载.env文件,所以.env是首选方式。

安装依赖

pnpm install

框架依赖(见 package.json):

  • genkit(核心运行时)与@genkit-ai/google-genai、@genkit-ai/compat-oai、genkitx-anthropic三个模型插件;
  • @genkit-ai/vertexai(Gemini Vertex AI 通道,按需使用);
  • tsx(直接运行 TypeScript)、yargs(命令行参数解析)、dotenv-cli(加载.env)。

从源码运行无需额外编译步骤:tsx src/index.ts直接执行 TS。

运行评估

运行全部评测

pnpm run evalAll

⚠️ 官方 README 特别警告:全量运行会消耗大量模型配额(can use *lots* of model quota)。原因从源码可见:默认情况下evalAll会跑8 个模型 × 18 个提示词 = 144 个推理任务,且每个模型/提示词组合都会调用一次真实的 LLM API。

运行单个评测

快速调试单个模型 + 单个提示词,使用--model与--prompt两个命令行参数:

pnpm run eval -- --model='<model_name>' --prompt=<prompt_name>

官方示例——用gpt-5-mini (reasoning: minimal)模型跑generateDogUIs提示词:

pnpm run eval -- --model='gpt-5-mini (reasoning: minimal)' --prompt=generateDogUIs

注意:README 示例中的模型名gpt-5-mini (reasoning: minimal)是文档写作时的命名习惯;当前仓库 eval/src/models.ts 中的模型名是gpt-5-mini(推理配置通过config: { reasoning_effort: "minimal" }注入,不体现在名字里)。运行时请以models.ts中name字段的准确值为准。

命令行参数详解

eval/src/index.ts中通过yargs定义了完整的参数体系(见 eval/src/index.ts):

参数类型默认值说明
--verbose/-vbooleanfalse打印每次成功生成的完整 JSON 输出
--keep=<dir>string无保留每次调用的输入/输出到独立文件;不带路径时自动创建临时目录
--runs-per-prompt=<n>number1每个提示词重复运行次数
--model=<name>string[]全部模型按精确名称过滤模型,可选值必须是models.ts中定义的名称,可传多次
--prompt=<name>string全部提示词按前缀过滤提示词(startsWith匹配)

几个关键行为(源码佐证):

  • --model过滤用的是精确匹配,--prompt用的是前缀匹配(index.ts),因此--prompt=login会匹配loginForm等以login开头的提示词;
  • 若过滤后无匹配,程序会打印No models found matching: ...或No prompt found with prefix "..."并以退出码 1 终止;
  • 默认情况下(不加--verbose),控制台只打印汇总表和生成过程中的错误,成功结果不打印(index.ts);
  • 结果全部完成后,若指定了--keep,汇总报告会额外写入<output_dir>/summary.md。

三个内置快捷脚本

package.json 预置了三个快捷命令,方便快速对比三家模型(提示词均为travelItinerary):

pnpm run evalGemini # --model=gemini-2.5-flash --prompt=travelItinerary pnpm run evalGpt # --model=gpt-5-mini --prompt=travelItinerary pnpm run evalClaude # --model=claude-4-sonnet --prompt=travelItinerary

控制输出与保留运行产物

--verbose:查看完整 JSON

pnpm run evalAll -- --verbose

此时每个成功生成的结果会打印Model / Query (run N)、校验失败列表以及完整 JSON(JSON.stringify(component, null, 2)格式化输出)。注意:即使没有--verbose,校验失败和运行时错误也始终会打印,方便第一时间定位问题。

--keep:保留每次调用的输入输出

pnpm run evalAll -- --keep=output

会在output/下按模型名建子目录(模型名中的/、:会被替换为_,见 index.ts),每个提示词生成三类文件:

  • <prompt>.input.txt:发送给模型的提示词原文;
  • <prompt>.output.json:成功时模型生成的 A2UI JSON;
  • <prompt>.error.json:失败时写入{message, stack, ...error}错误详情。

若--keep不带路径(--keep单独使用),会通过fs.mkdtempSync自动创建a2ui-eval-*临时目录(index.ts)。指定目录时文件按<output_dir>/<模型名>/<prompt>.*的层级存放,同时汇总报告写入<output_dir>/summary.md。这套产物结构非常适合做回归对比:同一提示词在不同模型间的输出可以直接 diff。

模型配置:如何添加 / 调整被测模型

所有被测模型集中定义在 eval/src/models.ts 的modelsToTest数组中,每个条目是一个ModelConfiguration:

export interface ModelConfiguration { model: any; // 由 Genkit 插件工厂创建的模型实例 name: string; // 命令行 --model 过滤使用的名称 config?: any; // 传给 ai.generate 的推理配置 }

当前仓库内置的 8 个模型配置:

name底层模型关键 config
gpt-5openAI.model("gpt-5"){ reasoning_effort: "minimal" }
gpt-5-miniopenAI.model("gpt-5-mini"){ reasoning_effort: "minimal" }
gpt-4.1openAI.model("gpt-4.1"){}
gemini-2.5-pro-thinkinggoogleAI.model("gemini-2.5-pro"){ thinkingConfig: { thinkingBudget: 1000 } }
gemini-2.5-flashgoogleAI.model("gemini-2.5-flash"){ thinkingConfig: { thinkingBudget: 0 } }
gemini-2.5-flash-litegoogleAI.model("gemini-2.5-flash-lite"){ thinkingConfig: { thinkingBudget: 0 } }
claude-4-sonnetclaude4Sonnet{}
claude-35-haikuclaude35Haiku{}

从配置可以看出评测设计者的对比意图:同一系列内对比不同规格(gpt-5vsgpt-5-minivsgpt-4.1;gemini-2.5-provsflashvsflash-lite),跨系列对比三家头部模型,并刻意把 Gemini 的thinkingBudget拉开(pro 用 1000 token 深度思考,flash 系用 0 关闭思考)以考察推理预算对 UI 生成质量的影响。

新增模型的步骤(例如接入其他厂商或新版本):

  1. 在文件顶部 import 对应 Genkit 插件工厂;
  2. 在modelsToTest追加一个ModelConfiguration条目;
  3. 重启评估即可通过--model=<name>单独评测该模型,yargs的choices会自动同步新名称。

提示词评测集:18 个场景全覆盖

所有测试提示词定义在 eval/src/prompts.ts。每个TestPrompt包含四要素:

export interface TestPrompt { name: string; // 提示词名称(--prompt 按此前缀匹配) description: string; // 场景说明 schemaPath: string; // 使用的 JSON Schema 路径 promptText: string; // 发送给模型的提示词正文 matchers: SchemaMatcher[]; // 该校验器(见下一节) }

全部提示词统一使用../../json/server_to_client_with_standard_catalog.json(相对 eval/src 的路径,实际文件为 vendor/a2ui/specification/0.8/json/server_to_client_with_standard_catalog.json)。该 Schema 是官方把server_to_client.json与standard_catalog_definition.json合并后生成的"LLM 友好版":把通用的component对象替换为对标准目录中每个组件的严格oneOf定义,让模型在生成时不产生歧义(见 vendor/a2ui/specification/0.8/json/README.md)。

内置 18 个提示词覆盖四类消息与常见 UI 场景:

消息类型覆盖

  • surfaceUpdate(绝大多数提示词):dogBreedGenerator、loginForm、productGallery、settingsPage、animalKingdomExplorer、recipeCard、musicPlayer、weatherForecast、surveyForm、flightBooker、dashboard、contactCard、calendarEventCreator、checkoutPage、socialMediaPost、eCommerceProductPage、interactiveDashboard、travelItinerary;
  • dataModelUpdate:productGalleryData(填充/products数据)、dataModelUpdate(登录后写入/user/name、/user/email);
  • beginRendering:uiRoot(设置 UI 根组件);
  • deleteSurface:deleteSurface(删除dashboard-surface-1)。

组件类型覆盖:Heading、Text、Image、TextField、Button、CheckBox、Slider、List、Card、Row、Column、Tabs、Modal、Divider、MultipleChoice、DateTimeInput等标准目录组件几乎全部涉及;travelItinerary、animalKingdomExplorer等场景还包含嵌套列表、深层组件层级等"长尾"考验。

评测难度梯度:从简单的单消息(uiRoot只需输出beginRendering)到超长结构化场景(animalKingdomExplorer要求 3 个 Tab × 多级 Card 嵌套且"不许漏掉任何一项",见 prompts.ts),可以横向评估模型对复杂指令的遵循能力。

新增提示词同样简单:在prompts数组中追加对象并定义 matchers 即可,--prompt前缀过滤自动生效。

底层原理:生成 Flow 与校验体系

生成 Flow:结构化 JSON 输出

核心生成逻辑在 eval/src/flows.ts 的componentGeneratorFlow:

const { output } = await ai.generate({ prompt, model, output: { contentType: "application/json", jsonSchema: schema }, config, });

关键点:通过output.jsonSchema把server_to_client_with_standard_catalog.json直接作为 Genkit 的生成约束注入,模型被强制输出符合 A2UI 协议的结构化 JSON,而非自由文本。main()会为每个提示词读取并JSON.parse该 Schema 文件(index.ts),再并发调度所有 (模型, 提示词, run) 组合。

校验体系:JSON Schema 之上再叠加语义 matcher

A2UI 的校验分两层,两者结果共同决定一次运行是否"失败":

第一层:协议结构校验(eval/src/validator.ts)

validateSchema首先按顶层消息类型分发到四个子校验函数,同时执行通用规则:

  • 顶层必须有且仅有surfaceUpdate/dataModelUpdate/beginRendering/deleteSurface之一;
  • surfaceUpdate必须含components数组,组件id必须唯一;
  • 引用完整性:Card.child、Row/Column/List.children(explicitList或template二选一)、Tabs.tabItems[].child、Modal.entryPointChild/contentChild引用的组件 ID 必须真实存在(checkRefs);
  • 每个组件必须恰好有一个类型键,且按类型检查必填属性:Heading/Text.text、Image/Video/AudioPlayer.url、TextField.label、DateTimeInput/Slider.value、MultipleChoice.selections/options、CheckBox.value/label、Button.child/action.name、Divider无必填项等;
  • 绑定值(bound value)必须是{literalString | literalNumber | literalBoolean | path}四选一且只选一(validateBoundValue);
  • dataModelUpdate的contents每个 item 必须含key且恰好一个 value 属性(valueString/valueNumber/valueBoolean/valueMap),valueMap内部 item 同理;
  • 未知组件类型会报Unknown component type '...'。

第二层:语义 matcher(eval/src/schema_matcher.ts 及三个实现)

SchemaMatcher是一个抽象基类,三个具体实现各有分工:

  1. message_type_matcher.ts:校验顶层消息类型是否恰好为期望值(例如deleteSurface提示词要求顶层键只有一个且为deleteSurface);
  2. basic_schema_matcher.ts:按点号路径(如dataModelUpdate.contents.0.key)在对象树中取值,校验存在性甚至精确值(用JSON.stringify比较);
  3. surface_update_schema_matcher.ts:最复杂的 matcher,在surfaceUpdate.components中查找指定组件类型,并可选校验属性值与期望值匹配。它有两大"智能"处理:
    • Button 标签特判:A2UI 中 Button 的标签通常存在于其child引用的Text组件中,matcher 会顺着properties.child找到子Text组件再比对text值(surface_update_schema_matcher.ts);
    • 值形态兼容:valueMatches同时支持旧式直接值、新式{literalString/literalNumber/literalBoolean}对象、数组(如MultipleChoice.options的{label: {literalString...}, value}结构),并支持caseInsensitive大小写不敏感匹配(如dogBreedGenerator中对 "Dog breed name" 的true参数)。

以loginForm提示词为例,其 matchers 链(prompts.ts)要求:顶层是surfaceUpdate+ 存在text为 "Login" 的Heading+ 存在 label 为 "username"/"password" 的TextField+ 存在 label 为 "Remember Me" 的CheckBox+ 存在 label 为 "Sign In" 的Button——五条全部通过才算该校验通过。

汇总报告生成

所有运行结束后,generateSummary(index.ts)按模型分组生成 Markdown 表格:每个提示词一行的Avg Latency (ms)、Failed Runs(工具错误或校验失败)、Tool Error Runs,模型级合计Total failed runs,最后是总体统计:工具错误运行数、含任意失败(工具错误或校验)的运行数、Mean/Median 延迟、至少失败过一次的模型列表。这份报告默认打印到控制台,--keep时也会落盘为summary.md。

版本演进视角:0.8 与 0.9 评估框架的差异

仓库同时携带了 0.9 版本的评估框架(vendor/a2ui/specification/0.9/eval/README.md),可作为理解 0.8 设计的参照:

  • Schema 注入方式:0.9 把 JSON Schema 直接嵌入提示词,并要求模型在 markdown 代码块中输出 JSON,框架再提取并校验(extractJsonFromMarkdown);0.8 则依赖 Genkit 的output.jsonSchema结构化约束;
  • 模型集:0.9 的 models.ts 扩展了gpt-5.1、gpt-5-nano、gemini-3-pro等更新型号,并为每个模型配置了requestsPerMinute/tokensPerMinute限流参数;
  • 限流机制:0.9 引入两级限流——本地主动限流(按配额控制请求/令牌速率)与响应式熔断(收到RESOURCE_EXHAUSTED429 后暂停该模型请求并按重试时长恢复),见 0.9 的 rateLimiter.ts;
  • 结果输出:0.9 默认打印进度条,日志写入 results 目录的output.log,并提供--log-level、--results、--clean-results等更多参数。

如果你在 0.8 基础上做大规模评测,可以参考 0.9 的限流与结果管理思路自行增强。

在 OpenClaw 项目中的实际落点

A2UI 评估框架虽然位于vendor/目录,但 A2UI 渲染与交互能力已深度集成到 OpenClaw 本体:

  • 框架渲染资产由 canvas-host 静态托管:src/canvas-host/a2ui.ts将 A2UI 前端资源挂在/__openclaw__/a2ui路径下(A2UI_PATH常量,见 src/canvas-host/a2ui.ts),并通过resolveA2uiRoot在源码/发布目录间解析资源位置;
  • Agent 工具层提供a2ui_push与a2ui_reset两个动作(见 src/agents/tools/canvas-tool.ts),分别通过canvas.a2ui.pushJSONL推送 A2UI 消息、canvas.a2ui.reset重置画布,canvas.snapshot则可抓取渲染结果用于视觉验证——这与评估框架"生成 → 校验"的闭环形成了呼应:评估阶段用 matcher 自动判定,运行阶段用快照人工/模型复核。

因此,本指南介绍的评估框架既可以直接在vendor/a2ui/specification/0.8/eval内独立运行以横向对比模型能力,也可以结合 OpenClaw 的 canvas 链路验证"模型生成的 A2UI 消息在真实渲染器中的效果"。

快速上手清单

  1. 在 vendor/a2ui/specification/0.8/eval 下创建.env,填入你有权限的 API Key(GEMINI_API_KEY/OPENAI_API_KEY/ANTHROPIC_API_KEY可任选其一或全部);
  2. pnpm install安装依赖;
  3. 快速验证单点:pnpm run eval -- --model=gemini-2.5-flash-lite --prompt=loginForm;
  4. 全量评测:pnpm run evalAll(注意配额消耗);
  5. 保留产物与报告:pnpm run evalAll -- --keep=output --verbose;
  6. 查看output/summary.md分析各模型在各场景下的延迟与失败率。

限制与前提说明:以上命令依赖pnpm、Node.js 及对应模型的 API Key;模型名单以仓库当前 models.ts 为准(README 示例中的gpt-5-mini (reasoning: minimal)写法在现有代码中应写作gpt-5-mini);全量评测消耗大量配额,建议先跑单点验证配置正确后再扩展规模。

  • 人工智能
  • 大模型
  • LLM 网关
  • AI Agent
  • 即时通讯

【免费下载链接】openclaw-zero-token

OpenClaw: Use All Major AI Models NO API Token! Claude/ChatGPT/Gemini/DeepSeek/Doubao/Grok/Qwen/Manus/Kimi

项目地址:https://gitcode.com/gh_mirrors/op/openclaw-zero-token
点击查看免费下载

相关推荐

上一篇:CrewAI 多智能体故事生成与 Agentic 追踪实践:RagaAI Catalyst scifi_writer 示例深度解析
下一篇:从CAP理论到生产实践:DistributedLock.ZooKeeper分布式锁深度剖析

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询