A2UI Express 格式优化实录:run_020 数据路径斜杠预处理如何让评测通过率稳定在 100%
【免费下载链接】a2ui项目地址: https://gitcode.com/GitHub_Trending/a2/a2ui
本篇以 A2UI 仓库中一次完整的迭代优化报告eval/iterative_format_optimizer/history/express/run_020_5a1f2426_pass_23_data_path_slash_preprocessing_fo/report.md为主体,拆解"Express 推理格式"第 23 轮优化(数据路径斜杠预处理)的评测结果、指标口径、底层补丁实现与配套单元测试,帮助读者理解 A2UI Agent SDK 是如何通过"假设—评测—护栏—归档"的闭环流程,持续压降 LLM 生成 UI 的格式错误率的。
这份报告在优化流水线中的位置
A2UI 的 Python Agent SDK 内置了多个实验性推理格式(inference format),如express、atom、elemental。这些格式让 LLM 用更紧凑的 DSL 而非完整 JSON 来描述界面,再由宿主侧编译器编译为标准 A2UI 协议消息。仓库中的 inference-format-optimizer 技能 定义了一套迭代优化流程,其六步工作流为:
- 分析历史:检查
eval/iterative_format_optimizer/history/<format>/与 历史总表,避免重复已被回退的假设; - 实现假设:修改
compiler.py、prompt_generator.py或parser.py; - 跑单元测试:pytest 单元一致性测试必须全绿;
- 执行基准评测:
python scripts/optimize_format.py --format <format>; - 按决策规则取舍:必须通过 pytest 且不劣化准确率,代码输出 token 增幅不得超过 +5%,综合分
S_opt提升才保留(KEEP),否则回退(REVERT); - 归档与同步:将本次运行的产物(
report.md、results.json、patch.diff、run_meta.json)归档到history/<format>/run_NNN_<commit>_<假设摘要>/目录,并用sync_history.py更新历史索引。
本文的 run_020 报告正是该流程第 5、6 步的产物:一次针对express格式、以google/gemini-3.5-flash为评测模型的完整评测运行记录。
运行元数据:一次被判定为 KEEP 的优化
本次运行归档目录下共有四个文件,各自承担不同角色:
| 文件 | 作用 |
|---|---|
| report.md | 人类可读的评测摘要(本文主体) |
| results.json | inspect_ai 导出的完整评测记录(含每条样本的消息、评分、token 用量) |
| patch.diff | 本次优化实际引入的代码变更 |
| run_meta.json | 结构化指标快照与状态 |
run_meta.json 记录了本次运行的核心元信息:
- 格式:
express - 假设(hypothesis):
Pass 23: Data path slash preprocessing for relative references in compiler.py - 状态:
Kept(保留并更新基线) - 指标:schema 准确率
1.0、质量分1.0、代码输出 token 中位数271.0、推理 token 中位数2412.5、输入 token 中位数5936.5、延迟中位数14.62s、样本总数6
report.md 的摘要表(原文照录)如下:
| 指标 | 基线 | 当前 | 差值 |
|---|---|---|---|
| Pytest Conformance | - | PASS | - |
| Overall Pass Rate | - | 100.0% | |
| Algorithmic Schema Pass Rate | - | 100.0% | |
| Inference Duration (sec) | - | 15.00s | |
| Avg Input Tokens | - | 5951 | |
| Avg Output Tokens | - | 304 |
可以看到报告表使用的是 6 个样本的均值口径(15.00s / 5951 / 304),而run_meta.json记录的是中位数口径(14.62s / 5936.5 / 271),两者数值略有差异属于统计口径不同,并非矛盾。报告结论部分写道:Active Git Diff — No files modified under agent_sdks,且失败明细为0 / 6("All tests passed successfully")。从仓库结构看,这表示评测完成时补丁已随归档流程固化,而本次 pass 的实际代码变更完整保留在同目录的patch.diff中——这正是下一节要拆解的核心内容。
核心变更:_compile_value中的数据路径斜杠预处理
patch.diff显示,本次优化只改了两处文件:compiler.py(新增约 11 行逻辑)和test_compiler.py(新增 1 个单元测试)。变更位置在 ExpressCompiler 的_compile_value方法中,即在处理字符串值时、进入枚举值(enum)大小写折叠逻辑之前,插入了一段"数据路径预识别"代码:
if isinstance(val, str): if val == "$" or ( val.startswith("$") and len(val) > 1 and (val[1].isalpha() or val[1] in ("/", "_")) ): path_val = val.replace(".", "/") if path_val.startswith("$/"): path_val = path_val[1:] elif path_val.startswith("$"): path_val = path_val[1:] return {"path": path_val} if enum_vals: ...逐条拆解其语义:
- 识别边界:只有形如单独
$,或以$开头且第二个字符是字母、/或_的字符串才被当作数据绑定路径。这个"第二字符守卫"非常关键——像$100、$5.99这类以$开头但随后跟数字的字符串(常见于价格文案)不会被误判为数据路径,从而原样保留为字面量文本。 - 点号归一:
val.replace(".", "/")将$a.b这种点分写法统一转为 JSON Pointer 风格的分隔符$a/b,容忍 LLM 输出路径时偶尔使用.而非/。 - 剥离
$前缀:$/form/val→/form/val(绝对路径);$user→user(相对路径,用于列表模板作用域内的引用);单独$→ 空相对路径(对应 DSL 契约中"模板内表示整个 item 自身"的语义)。 - 返回绑定对象:最终统一产出 A2UI v1.0 的数据绑定对象
{"path": <path>},而不是一个裸字符串。
这一步为什么重要?对照评测记录中实际注入的 Express 系统提示契约(见results.json的 system 消息)中的语法规则 6:
Data bindings: prefix absolute paths in the data model with
$, e.g.,$\/user/firstName. Prefix relative list scopes with$, e.g.,$firstName. A lone$represents an empty relative path which resolves to the root of the current context.
即提示词明确要求模型用$前缀书写绑定路径,但模型有时会把路径放进带引号的字符串字面量(如TextField("Name", "$name"))。在补丁之前,这类引号包裹的$字符串不会被_compile_value识别为绑定,可能落到后续的字面量分支,导致编译出的组件属性是一个普通字符串而非{"path": ...}对象,从而在 schema 校验(a2ui_scorer)环节失分。补丁把"识别 + 归一化"前置到编译器侧,等于把格式容错从"依赖模型每次都写对"变成"编译器兜底修正",这正是该 pass 能在不改动任何提示词的前提下把 Algorithmic Schema Pass Rate 维持在 100% 的原因。
配套单元测试:三种路径形态一次覆盖
patch.diff同时向 tests/express/test_compiler.py 新增了test_quoted_data_path_string_literal_normalization测试,输入如下 DSL:
compiler = ExpressCompiler(self.catalog) dsl = """root = Column([field1, field2, field3]) field1 = TextField("Rep", "$user") field2 = TextField("Name", "$name") field3 = TextField("Val", "$/form/val")""" envelope = compiler.compile(dsl) comps = envelope["createSurface"]["components"] f1 = next(c for c in comps if c["id"] == "field1") f2 = next(c for c in comps if c["id"] == "field2") f3 = next(c for c in comps if c["id"] == "field3") self.assertEqual(f1["value"], {"path": "user"}) self.assertEqual(f2["value"], {"path": "name"}) self.assertEqual(f3["value"], {"path": "/form/val"})三条断言分别锁定了预处理逻辑的三种形态:相对路径$user→{"path": "user"}、$name→{"path": "name"}、绝对路径$/form/val→{"path": "/form/val"}。这也解释了报告摘要表中 "Pytest Conformance: PASS" 的含义——它不只是既有 60 个左右的历史测试不回归,还包含本 pass 新写的回归测试,确保"引号字符串字面量形式的绑定"这一行为被契约化。
评测方法与证据:6 个样本、双评分器
从results.json可以还原本次评测的完整执行链(inspect_ai 0.3.242,任务a2ui_v1_0_eval):
Solver 管线(plan.steps):
a2ui_eval/format_system_prompt:按express格式、版本1.0动态拼装系统提示(语法规则、组件位置签名、目录说明与示例);a2ui_eval/measured_generate:调用google/gemini-3.5-flash生成带<a2ui>...</a2ui>哨兵标签的 Express DSL,并计量 token 与耗时;a2ui_eval/compile_format_payload:宿主侧调用 ExpressCompiler 把 DSL 编译成 A2UI v1.0 JSON 信封(createSurface消息)。
双评分器:
a2ui_scorer(版本 1.0):算法式 schema 校验,检查编译产物是否为合法 A2UI 负载;measured_model_graded_qa:模型评分器,让google/gemini-3.5-flash依据评分细则输出GRADE: C/P/I(正确/部分正确/不正确)。其评分细则中专门有一条与本文主题相关的规则:"If data binding paths are not explicitly specified in the prompt, accept any logically sound path structure(例如接受/user/email或/email)"——可见评测端对数据路径的判定口径是语义化而非字面匹配的。
两个评分器在 6 个样本上的 accuracy 均为1.0,对应报告表中的 Overall Pass Rate 与 Algorithmic Schema Pass Rate 双 100%。results.json中还保留了完整的样本证据:例如样本 1("dogBreedGenerator",要求构建犬种信息卡 + 犬种生成器表单)中,模型输出的 DSL 使用了_template($/breeds, breedTemplate)动态列表、TextField("Breed Name", $/generator/name, ...)绑定与Event("generate_dog", {name: $/generator/name, ...})事件上下文,编译后得到children: {"path": "/breeds", "componentId": "breedTemplate"}、value: {"path": "/generator/name"}等标准绑定对象,最终 schema 分 1.0、质量评分 "C"。整个评测的 token 消耗(含评分阶段)记录在stats.model_usage中:输入 33,214、输出 3,804、推理 21,502。
决策规则与后续演进
按照 SKILL.md 中的护栏(决策规则详见同目录 references/scoring_model.md):pytest 必须通过、准确率不得低于基线、代码输出 token 增幅不得超过 +5%。run_020 以Kept状态归档并在 历史总表 中登记为第 20 次 express 运行(表中记录:PASS / 100.0% / 100.0% / 14.62s / 5936 输入 / 271 输出,备注 "Pytest PASS")。值得注意的是,总表中紧挨其后的 run_021 归档了同一假设(同 commit5a1f2426),说明该 pass 在历史同步流程中产生了重复归档条目,两条记录的指标完全一致。
从历史总表还能看到这次优化并非孤例:express 系列的 run_010 到 run_019 分别实现了字符串数值自动强制转换(Pass 6)、单值/列表槽位自动包装(Pass 7)、枚举大小写折叠(Pass 11)、选项对象归一化(Pass 16)、事件处理器字符串自动包装(Pass 19)等一系列编译器侧容错,而 run_020 的数据路径斜杠预处理是其中针对"绑定路径书写变体"的专项补强;其后 run_022 起继续推进组件构造器大小写不敏感匹配(Pass 25)、布尔字符串强制转换(Pass 26)等。这一连串 KEEP/REVERT 记录共同构成了 A2UI Express 格式从"能用"走向"稳定 100% schema 通过率"的实证轨迹。
复现与延伸阅读路径
如需在自己的环境中验证本文描述的行为(仓库为只读,以下为查看/运行方式):
- 查看补丁全文:patch.diff;
- 查看预处理逻辑所在文件:compiler.py 的
_compile_value方法(约 L640 起); - 查看回归测试:test_compiler.py 中的
test_quoted_data_path_string_literal_normalization; - 复跑快速评测:
python scripts/optimize_format.py --format express(脚本位于 skills/inference-format-optimizer/scripts/ 下); - 追溯完整优化历史:history_summary.md 与 history/express/ 各 run 目录。
总体而言,这份 run_020 报告的价值不在于它报告了一个新特性,而在于它完整展示了 A2UI 格式优化的工程范式:把 LLM 输出中的高频书写变体(点分路径、$/$/前缀、引号包裹的绑定字面量)识别为编译器问题而非提示词问题,用 11 行防御性代码 + 1 个单元测试固化契约,再交给双评分器评测与 token 效率护栏裁决是否保留。
【免费下载链接】a2ui项目地址: https://gitcode.com/GitHub_Trending/a2/a2ui
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考