
编程语言AI Agent编译器CLI人工智能【免费下载链接】bamlThe programming language for agents项目地址https://gitcode.com/gh_mirrors/ba/baml点击查看免费下载本篇技术指南围绕 BAML 项目 tools/speedtest 基准体系中的compute::nested field access 500k工作负载展开剖析它在 BAML、Python、TypeScript 三套语言下的等价位实现说明它究竟在测什么、如何被 speedtest 框架自动解析与执行以及如何借助该工作负载定位 BAML 解释器在嵌套对象构造 深层字段访问路径上的性能特征。读完本文你将掌握该类 workload 文件的完整语法结构、运行方式以及如何用--filter单独跑它并解读对比结果。工作负载定位它测的是构造 深层读取的组合开销nested-field-access-500k.md是 speedtest 基准集中 compute 类别 下的一个微基准micro-benchmark。它属于 baml_language/tools/speedtest 工作负载目录该目录按语义划分了classes、compute、concurrency、interfaces、string等类别每个.md文件就是一个可独立运行的 workload。与同目录下仅测单层结构的 class-instances-100k.md单个Point { x, y }的创建与读取相比本工作负载刻意叠加了两层负担嵌套对象创建每轮迭代都要构造三层嵌套的Outer { middle: Middle { inner: Inner { value } } }深层字段访问随后通过o.middle.inner.value连续穿透两层中间对象才能读到最终整数值。循环次数固定为500,000 次这正是文件名后缀500k的由来。这样的设计意图非常明确把对象分配/构造与多级引用解引用两类高频操作叠加放大用于放大解释器在嵌套结构上的真实成本避免单层访问的缓存友好性掩盖实现差异。BAML 侧实现三段式嵌套类 累加循环工作负载的 BAML 源码是文章的核心原文完整给出如下class Inner { value: int } class Middle { inner: Inner } class Outer { middle: Middle } function main() - int { let s 0; for (let i 0; i 500000; i 1) { let o Outer { middle: Middle { inner: Inner { value: i } } }; s o.middle.inner.value; }; return s; }逐部分解读三个嵌套类定义Inner叶子持有一个int、Middle持有一个Inner、Outer持有一个Middle。三层结构保证了最终读取必须穿透两级指针跳转而不是编译器可以轻易折叠成单次 load 的浅层访问。构造表达式Outer { middle: Middle { inner: Inner { value: i } } }使用 BAML 的结构化字面量语法一次性构建完整对象树每轮迭代都新建三个对象测的是对象分配与字段初始化的开销。累加循环s o.middle.inner.value把深层字段值累加到局部变量return s把最终结果作为程序退出码输出。这个返回值极其关键——speedtest 框架正是拿它来做跨语言一致性校验见下文输出一致性校验一节。值得对照的是同目录下的 wide-nested-class-create-50k.md它把嵌套对象造得又宽又深BigRecord内嵌两个Node与多个Leaf并在读取阶段一次访问 7 个不同深度的字段。两者组合起来可以从窄而深与宽而深两个维度评估 BAML 对象系统的性能。Python 对照实现__slots__压榨下的等价位为了保证三种语言执行的是语义等价的同一基准Python 版本刻意做了两件事class Inner: __slots__ (value,) def __init__(self, v): self.value v class Middle: __slots__ (inner,) def __init__(self, i): self.inner i class Outer: __slots__ (middle,) def __init__(self, m): self.middle m s 0 for i in range(500000): o Outer(Middle(Inner(i))) s o.middle.inner.value print(s)__slots__声明为每个类显式限定字段名消除__dict__字典带来的额外内存与查找开销把 Python 侧的属性访问成本压到最低确保对比时Python 慢是解释执行本身的成本而非实现上的浪费嵌套构造Outer(Middle(Inner(i)))与 BAML 的结构化字面量一一对应o.middle.inner.value的读取链也与 BAML 完全同构输出约定Python 用print(s)输出结果而 BAML 用return srunner 会取进程 stdout 的最后一行与 BAML 打包产物的输出比对。TypeScript 对照实现一行式紧凑写法TS 版本把类定义、循环、累加全部压缩到一行逻辑与前两者完全一致class Inner{constructor(v){this.valuev}} class Middle{constructor(i){this.inneri}} class Outer{constructor(m){this.middlem}} let s0;for(let i0;i500000;i){const onew Outer(new Middle(new Inner(i)));so.middle.inner.value}console.log(s)这里用console.log(s)输出同样满足 runner 的取末行 stdout校验约定。由于该代码对 Node 与 Bun 都适用同一份 JS 文件会被 runner.py 分别交给node和bun执行也就是说这一个 workload 最多会产出BAML / Python3 / Node / Bun 四组计时数据。workload 文件格式speedtest 如何解析这份文档要理解这份.md为什么能直接当基准跑需要看 loader.py 的解析逻辑。parse_workload_md()用正则 ^##\s([\w-])\s*\n\w*\n(.*?) 扫描文档把#开头的一行作为 workload 全名即compute::nested field access 500k把每个## 小节名下的代码块按小写键存入 sections分别取baml、python、typescript三个键三个语言代码缺一不可任何一个缺失都会导致parse_workload_md返回None而被跳过load_workloads()会打印WARN: skipping ... (parse failed)目录名compute由path.parent.name自动成为 workload 的category字段。这就是为什么本文档只有## BAML/## Python/## Typescript三个小节它们是 speedtest 解析器的硬性约定。此外 loader 还支持可选的## eval-setup小节配合$$var模板替换本 workload 未使用。执行管线从打包、校验到计时当运行speedtest run时runner.py 对每个 workload 执行如下流程写临时文件把三份源码分别写入{slug}.baml、.py、.jsslug 由名字做小写化与去非字母数字得到打包调用baml-cli pack main --file baml -o packed把 BAML 源码编译打包为独立可执行产物pack 失败则跳过该 workload期望值校验先运行打包产物取末行 stdout 作为期望输出输出一致性检查依次跑python3 -S py、node js、bun js前提是环境里有对应运行时一旦某语言输出与 BAML 不一致就在结果行标记(!)。这一步是本工作负载return s / print(s) / console.log(s)三者必须结果一致的根本原因——500000 次累加的结果是跨语言对账的黄金标准计时默认按time_command_adaptive()自适应采样先 3 次预热丢弃再按预估耗时凑够--measurement-time秒采样数夹在 5~100 之间默认 5 秒也可用--runs N切换为固定 N 次采样统计与落盘对每语言取中位数med与标准差sd保存到~/.speedtest/可用--results-dir覆盖下的 baseline 目录并支持--tag打标签。单独运行与结果对比的实操命令在该 workload 所在仓库根目录执行speedtest包位于 baml_language/tools/speedtest可用uv按 pyproject.toml 安装后运行# 只跑本 workload名字子串过滤可重复传多个 --filter speedtest run --filter nested field access --build # 固定跑 20 次减少抖动 speedtest run --filter nested field access --runs 20 # 只看 BAML跳过 python/node/bun speedtest run --filter nested field access --only-baml # 用 samply 采集 BAML 侧 CPU profile需 profiling 构建产物与 samply speedtest run --filter nested field access --profile结果默认保存为baselines/分支/latest随后可以speedtest list # 列出所有 workload 名称 speedtest compare base new # 终端 diff 两个 baselinecritcmp 风格 speedtest compare base new --filter nested --threshold 2 speedtest open # 打开浏览器 UI 查看结果compare子命令compare.py会按类别分组输出每个 workload 的 before/after 耗时、变化百分比与显著性标记*表示统计显著~表示变化超过 5%当 BAML 源码在两次运行间被修改时还会标注(src changed)提醒你结果差异可能来自基准本身而非引擎改进。这意味着你可以在改完 BAML 解释器的对象访问实现后用--filter nested field access精确复测这一条路径的回归情况。更深一层该工作负载还能进入 Rust 基准套件值得注意的桥梁是 export_baml.py它把所有 workload 的展开后BAML 源码导出为 JSON{name, category, baml}数组让 Rust 侧基准套件crates/baml_tests直接复用tools/speedtest/workloads/下的这些.md作为 CodSpeed 基准而无需重复 loader 的解析与$$模板逻辑。也就是说nested-field-access-500k同一份定义既驱动 Python 侧的 speedtest CLI也驱动 Rust 侧的 CodSpeed 回归测试——修改它会影响两套基准的结果可比性。小结nested-field-access-500k是一个精心设计的窄而深嵌套访问微基准50 万次迭代 ×3 个嵌套对象构造 2 级字段解引用并用三语言等价实现 输出一致性校验保证对比公平。它的价值在于当 BAML 引擎在对象分配、字段初始化或引用链 load 上有任何实现变动例如 field-access-100k.md 中提到的virtual_load_field类改动这个 workload 都能以最小噪声把性能变化暴露出来。配合--filter单独运行与compare统计对比它既是基准定义也是一份可执行的性能回归哨兵。赞分享编程语言AI Agent编译器CLI人工智能【免费下载链接】bamlThe programming language for agents项目地址https://gitcode.com/gh_mirrors/ba/baml点击查看免费下载相关推荐ChatGPT Google Extension容器化部署终极指南Docker与CI/CD完全集成方案ChatGPT Google Extension容器化部署终极指南Docker与CI/CD完全集成方案 在当今快速发展的AI工具生态中ChatGPT Goo编程语言AI Agent编译器CLI人工智能如何让电视盒子播放几乎所有格式TVBoxOSC 完整上手指南如何让电视盒子播放几乎所有格式TVBoxOSC 完整上手指南 电视盒子自带的播放器总会在某些文件上翻车MKV 封装播不了、H.265一种压缩率高但解码负担编程语言AI Agent编译器CLI人工智能Rakam-API高级功能Webhook集成与实时事件处理Rakam API高级功能Webhook集成与实时事件处理 在当今数据驱动的世界中 实时事件处理 和 Webhook集成 已成为现代应用分析的核心需求编程语言AI Agent编译器CLI人工智能上一篇Valibot与Nuxt.js集成打造全栈验证的终极解决方案下一篇c-ares 1.34.6 编译安装完全指南从 AutoTools 到 CMake 的多平台构建实践创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考