A2UI Express 推理格式优化实践:ExpressCompiler 的大小写不敏感枚举强转(run_016 / Pass 11)
【免费下载链接】a2ui项目地址: https://gitcode.com/GitHub_Trending/a2/a2ui
本文以 A2UI 推理格式迭代优化框架(iterative format optimizer)中一次真实保留(Kept)的优化运行run_016为主体,完整拆解“假设 → 编译器改动 → 单测 → 评测 → 决策 → 归档”的全流程:你可以通过本文理解 Express 格式中大小写不敏感的枚举值强转(case-insensitive enum coercion)是如何在ExpressCompiler._compile_value中实现的、为何它没有违反效率上限被保留,以及如何用仓库自带的脚本复现与验证同类优化。
1. 这份运行报告是什么:四个自包含归档文件
eval/iterative_format_optimizer/history/express/目录下按格式归档了历次优化运行,本次分析的主体是其中一次运行目录:
- report.md:优化报告,含指标汇总表、Active Git Diff 段与失败明细(Failure Details);
- patch.diff:本次运行对编译器与测试的完整 Git diff,可独立查看或重放(
git apply patch.diff); - run_meta.json:机器可读元数据,记录假设(hypothesis)、状态(Kept)与关键指标;
- results.json:Inspect AI 完整执行日志,含每个样本的系统提示词、模型输出、编译产物与评分过程。
这套“四文件自包含归档”是优化框架的设计约定:每个归档目录可脱离分支保留独立存在,详见 inference_format_iteration.md 第 4.2 节。
报告正文的核心指标(report.md 原文继承)
report.md 给出的摘要表如下:
| Metric | Baseline | Current | Diff |
|---|---|---|---|
| Pytest Conformance | - | PASS | - |
| Overall Pass Rate | - | 100.0% | |
| Algorithmic Schema Pass Rate | - | 100.0% | |
| Inference Duration (sec) | - | 14.52s | |
| Avg Input Tokens | - | 5951 | |
| Avg Output Tokens | - | 338 |
- 评测策略(格式):
express; - 评测模型:
google/gemini-3.5-flash; - 失败明细:
Failure Details (Count: 0 / 6),即验证子集的 6 个提示词全部通过,报告中明确写着 “All tests passed successfully”。
Active Git Diff一节记录的是归档时刻主工作树的状态(No files modified under agent_sdks),本次运行的实际改动则完整保存在同目录的patch.diff中——从归档结构看,这符合框架“改动在隔离 Git worktree 中进行、主仓只留补丁”的隔离设计(同一参考文档 4.1 节)。
run_meta.json补充了更细的元信息:
{ "format": "express", "hypothesis": "Pass 11: Case-insensitive enum choice coercion in compiler.py", "status": "Kept", "notes": "Case-insensitive enum choice coercion added to ExpressCompiler._compile_value. Pytest passed (61/61), Quality Score 100.0%, Output Tokens expansion +4.64%.", "metrics": { "schema_acc": 1.0, "quality_acc": 1.0, "code_tokens_median": 272.5, "reasoning_tokens_median": 2325.0, "input_tokens_median": 5936.5, "latency_seconds_median": 14.472916997037828, "total_samples": 6 } }可以看到 report.md 中的均值(14.52s / 5951 / 338)与 run_meta.json 中的中位数(14.47s / 5936.5 / 272.5)来自同一份results.json的两种聚合口径。
2. 背景:Express 格式优化循环与决策规则
Express 是 A2UI 的一种实验性推理格式(inference format),位于 agent_sdks/python/a2ui_agent/src/a2ui/inference_formats/experimental/express/:模型先输出紧凑的 Express DSL(每行一条变量 = 组件(位置参数)语句),再由宿主侧编译器把它编译成标准 A2UI v1.0 JSON 消息。模块文档 compiler.py 开头即说明其职责:“Tokenizes, lexes, and parses A2UI Express plain-text statements into a clean AST, compiling it directly into standard A2UI v1.0 JSON messages”。
优化框架的工作流(SKILL.md 中的 6-Step Workflow)是:
- 分析历史:读
history/<format>/与 history_summary.md,避免重复已被回退的假设; - 实现假设:修改
compiler.py/prompt_generator.py/parser.py; - 跑 pytest 单测:验证不破坏既有编译器契约;
- 跑基准评测:
python scripts/optimize_format.py --format express(默认跑 6 条提示词的验证子集:dogBreedGenerator、loginForm、settingsPage、productGallery、productGalleryData、updateDataModel,约 15 秒一次迭代); - 按决策规则评估:必须通过 pytest、精度不低于基线;代码输出 token 膨胀不得超过 +5%;保留时综合分 $S_{opt}$ 提升,否则
git reset --hard HEAD回退; - 归档与同步:
--archive归档运行产物,sync_history.py重建历史索引。
决策模型(inference_format_iteration.md 第 3 节)分三层:
- 正确性护栏:pytest 必须 PASS;
SchemaAcc(a2ui_scorer,算法侧编译+schema 校验通过率)与QualityScore(measured_model_graded_qa,LLM 语义评分)均不得低于基线,否则立即回退; - 效率回归上限(任一触发即回退):代码输出 token 增长 > +5%、流式(非推理)输出时间增长 > +10%、推理 token 中位数增长 > +15%;
- 综合分:$S_{opt} = 0.50 \times SchemaAcc + 0.30 \times QualityScore - 0.15 \times (CodeTok/BaseCodeTok) - 0.05 \times (ReasonTok/BaseReasonTok) - 0.03 \times (InputTok/BaseInputTok)$,当前 > 基线则 KEEP,否则 REVERT。
在 history_summary.md 的总表中,本次运行记录为:express/016/ Hypothesis “Pass 11: Case-insensitive enum choice coercion in compiler.py” / Pytest PASS / Overall 100.0% / Algo 100.0% / Latency 14.47s / Input 5936 / Output 272 /Kept,Notes 与 run_meta 一致。
3. 问题根源:严格枚举校验与 LLM 输出大小写的矛盾
改动前,编译器对带枚举约束的属性做严格匹配校验。当前仓库 compiler.py 中可以看到这段逻辑(它是改动前后都存在的校验点):
enum_vals = self.helper.get_property_enum(comp_name, prop_name) if enum_vals and isinstance(mapped_val, str): if mapped_val not in enum_vals: raise ValueError( f"Value '{mapped_val}' is not a valid enum choice for" f" property '{prop_name}' of component '{comp_name}'." f" Allowed values are: {enum_vals}" )枚举候选值来源于目录(catalog)的 JSON Schema,由CatalogSchemaHelper在初始化时抽取为(组件名, 属性名) -> 枚举值的映射,见 schema_helper.py(self.component_property_enums = {}与 L106 的填充、L230-L242 的get_property_enum)。
与此同时,提示词侧已经把枚举候选写进了组件签名。prompt_generator.py 会读取 schema 中的枚举并渲染成“Must be one of: 'default', 'primary', 'borderless'”这样的行注入系统提示词(run_016 的results.json中 sample 1 的系统提示词即可看到Button的variant签名带着这段枚举约束)。即便如此,模型仍可能输出"PRIMARY"、"MultipleSelection"这类大小写偏离规范值的形式——严格校验下这会直接抛ValueError,导致该样本在a2ui_scorer的编译/校验环节失败。本次优化的假设正是:在编译器值编译阶段做大小写不敏感的枚举强转,把非规范大小写自动纠正回目录定义的规范值。
注意一个事实边界:当前仓库 HEAD 的
compiler.py中并不包含本次运行引入的强转代码(_enum_map逻辑仅存在于归档的patch.diff中),也就是说这份记录以“优化历史归档”的形式保存在仓库里;下文的代码均以patch.diff为准。
4. 改动详解:patch.diff 的四处变更
patch.diff共修改两个文件:编译器 compiler.py 与单测 tests/express/test_compiler.py。
4.1 构造函数:预构建全局小写枚举映射
self.helper = CatalogSchemaHelper(catalog) + self._enum_map = {} + for enums in self.helper.component_property_enums.values(): + for enum_val in enums: + if isinstance(enum_val, str): + self._enum_map[enum_val.lower()] = enum_val初始化时遍历目录中所有组件属性的枚举值,建立小写形式 -> 规范形式的全局映射(例如"primary" -> "primary"、"PRIMARY" -> "primary")。一次性构建避免了在每次值编译时重复计算。
4.2 组件属性编译:把该属性的枚举候选透传给_compile_value
+ enum_vals = self.helper.get_property_enum(comp_name, prop_name) mapped_val = self._compile_value( arg, raw_symbols, ctx, is_action=(prop_name in ["action", "submitAction"]), + enum_vals=enum_vals, )只有当属性确实声明了枚举约束时,enum_vals才非空;没有枚举约束的普通字符串属性不会进入强转分支,影响面被严格限制。
4.3 值编译:字符串强转 + 列表元素递归
_compile_value新增enum_vals: Optional[list[str]] = None形参。对列表,逐项递归时把enum_vals继续传递下去(覆盖“枚举值出现在数组元素”的情况);对字符串,新增如下兜底分支:
+ if isinstance(val, str): + if enum_vals: + enum_map = {e.lower(): e for e in enum_vals if isinstance(e, str)} + if val.lower() in enum_map: + return enum_map[val.lower()] + return val语义非常克制:只在小写形式命中枚举候选时才替换为规范值;未命中则原样返回,随后由 3 节的严格校验决定是否抛错。也就是说强转是“尽力纠正”,不改变既有错误路径——写错成完全无关的词(例如"PRIMARYX")依然会像改动前一样报错,而不是被静默放行。
4.4 新增单测:锁定“大小写纠正”行为
+ def test_case_insensitive_enum_coercion(self): + """Verifies that enum values with non-canonical casing are coerced to canonical enum choice.""" + compiler = ExpressCompiler(self.catalog) + dsl = 'root = Button("Click", "PRIMARY")' + res = compiler.compile(dsl) + self.assertEqual(res["createSurface"]["components"][0]["variant"], "primary")这条用例(插入在既有的“非法枚举值应报错”用例之后,见 diff 上下文)断言:输入 DSL 中写了大写"PRIMARY",编译产物的variant必须被纠正为规范值"primary"。它同时隐含了反面契约——紧邻的旧用例仍验证“非枚举字符串会抛is not a valid enum choice异常”,两者合起来界定了强转的边界。
5. 评测结果:为什么这次改动被保留
5.1 双评分器都拿到满分
results.json显示 6 个样本全部完成(completed_samples: 6),两个评分器的accuracy均为1.0:
a2ui_scorer(version 1.0):对编译产物做算法校验,sample 1 的解释为 “Valid A2UI payload”;measured_model_graded_qa(模型为google/gemini-3.5-flash):LLM 按 C/P/I 三级给语义正确性评分,sample 1 得到GRADE: C,且评分指令中明确允许“大小写、标点等变体在语义完整时视为可接受”,与编译器侧的大小写容忍形成呼应。
5.2 端到端样本走读(sample 1:dogBreedGenerator)
results.json中 sample 1 完整呈现了“模型输出 DSL → 编译 → 评分”的链路:
系统提示词(
a2ui_eval/format_system_promptsolver 注入):要求模型用<a2ui>/</a2ui>包裹 Express DSL 输出,并给出 14 条文法规则与全部组件/函数的位置签名(Button(child, variant?, action, ...)等);用户提示:在
surfaceId 'main'上生成一个包含“犬种信息卡片 + 虚构犬种生成器表单”的createSurfaceUI;模型输出(节选,原样例中的图片 URL 已省略):
<a2ui> $/breeds = [{url: "..."}, {url: "..."}] $/generator/name = "" root = Column([breedCard, genCard]) breedCard = Card(breedContent) breedContent = Column([breedTitle, breedHeaderImage, breedList]) breedList = List(_template($/breeds, breedItemTemplate), "horizontal") genButton = Button(btnLabel, "primary", genEvent) genEvent = Event("generate_dog", {name: $/generator/name, ...}) ... </a2ui>注意模型在这里恰好按规范写出了小写
"primary"——大小写强转的价值在于为下一次模型输出"PRIMARY"这类偏离时兜底;编译(
a2ui_eval/compile_format_payloadsolver):DSL 被编译为 v1.0 JSON,genButton最终形如:{ "id": "genButton", "component": "Button", "child": "btnLabel", "variant": "primary", "action": { "event": { "name": "generate_dog", "context": { "name": { "path": "/generator/name" }, "legs": { "path": "/generator/legs" } } } } }同时
dataModel由$/breeds = ...、$/generator/... = ...这类路径赋值自动汇集而成(breeds数组与generator对象);评分:
a2ui_scorer判 1.0,LLM 评分给出 GRADE: C。
5.3 决策核算:Kept 的依据
对照第 2 节的决策规则,本次运行的账本非常清晰:
| 检查项 | 本次运行 | 判定 |
|---|---|---|
| Pytest 单测 | PASS(notes 记录 61/61) | 满足护栏 |
| SchemaAcc / QualityScore | 100.0% / 100.0% | 不低于基线 |
| 代码输出 token 膨胀 | +4.64%(notes 记录) | 低于 +5% 上限 |
| 推理 token 中位数 | 2325 | 未触发 +15% 上限(notes 未报告回归) |
输出 token 的 +4.64% 膨胀贴线但仍在 5% 效率上限之内——这个“贴线通过”的判例在 express 历史中很有代表性:对照总表中 express 的 run_007/009(+30.6%)、run_011(+30.0%)、run_015(+17.4%)等因超出上限被 Backtracked 的运行,可见上限规则被严格执行。综合以上,run_meta 将状态记为Kept,总表同步记录。
6. 如何复现与验证这次运行
以下操作仅涉及查看、安装与运行,均为框架自带的只读/本地执行方式:
- 查看与重放补丁:补丁是自包含的,可在任意检出中查看,或在一个独立的工作副本里执行
git apply eval/iterative_format_optimizer/history/express/run_016_843ac936_pass_11_case_insensitive_enum_choice_coe/patch.diff重放改动; - 跑单测:在
agent_sdks/python/a2ui_agent下运行 pytest 验证(本次运行记录为 61/61 通过,重点用例即 4.4 节的test_case_insensitive_enum_coercion); - 跑格式验证评测:使用技能脚本(路径见 SKILL.md 的 CLI 表):
- 快速验证子集:
python scripts/optimize_format.py --format express; - 全量套件:
python scripts/optimize_format.py --format express --full; - 单条 DSL 编译调试:
python scripts/optimize_format.py --format express --compile "(Card (Text \"Hi\"))";
- 快速验证子集:
- 与基线对比:
python scripts/compare_results.py --baseline eval/iterative_format_optimizer/baselines/<format>/unbounded_run_meta.json <日志目录>,脚本会计算各指标 delta 与 $S_{opt}$; - 归档:验证通过后用
--archive --hypothesis "..." --status KEEP产出与本文一致的report.md/patch.diff/run_meta.json/results.json四件套。
运行环境前提:评测依赖 Inspect AI(results.json记录版本 0.3.242)与 Gemini API 访问(评测/评分模型均为google/gemini-3.5-flash),指标数值与所跑样本数(验证子集 6 条)相关,重跑时请留意与基线的样本对齐(比较器会自动做 1:1 样本过滤)。
7. 小结
- 这次
run_016(Pass 11)在ExpressCompiler中加入了大小写不敏感的枚举强转:构造函数预建小写映射(_enum_map)、组件属性编译时透传enum_vals、_compile_value对字符串(含列表元素)做“小写命中则纠正为规范值”的兜底,未命中的值仍走既有的严格校验报错路径; - 评测结果:pytest 61/61 通过、6 条验证样本 Overall 与 Algorithmic Schema 通过率均为 100%,输出 token 膨胀 +4.64% 低于 5% 效率上限,因此按决策模型记为Kept;
- 该运行是 Express 格式迭代历史(history_summary.md 中 express 001–027)里“编译器侧容错”类改动被成功保留的案例之一,其完整证据链(报告、补丁、元数据、原始日志)均可在上述四个归档文件中追溯。
【免费下载链接】a2ui项目地址: https://gitcode.com/GitHub_Trending/a2/a2ui
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考