GitHub Explorer
⏳ 公众号待发布

GitHub 推荐:32 个月 8.4K stars:Boundary 用自研语言 + 自研 VM 把 LLM 集成做出”跨 5 语言 SDK”的不可能三角

GitHub: https://github.com/boundaryml/baml

一句话总结

BAML 是一个为 LLM/Agent 工作流自研的 DSL —— 用 .baml 文件同时表达 prompt、schema、client、retry policy,编译器生成 Python / TypeScript / Go / Ruby / Rust 五种宿主语言的类型化客户端,背后用自研栈虚拟机(BexVM)做跨语言语义一致的运行时,是 Instruct、Outlines、TypeChat 这些「单宿主库」都做不到的”上游路线”。

值得关注的理由

  1. 结构化 LLM 输出赛道唯一的”跨语言”选手:Instructor/Outlines/TypeChat/Guidance 全部是单宿主库,BAML 是唯一把 schema+prompt+runtime 三件事用一套 DSL 表达并生成 5 个语言 SDK 的项目 —— 这是结构化输出从「Python 圈内部工具」变成「跨语言基础设施」的关键拐点。
  2. 「自研语言 + 自研 VM」的工程赌注罕见落地:23+ crate 的 baml_language/ 重写了 lexer/parser/HIR/TIR/MIR/VM,含 BexVM 半空间 GC + TLAB + superinstruction 优化,编译器架构(Salsa 查询 + bidirectional type checking + mu-binder equirecursive subtyping)有教科书深度 —— 是少数把 PL 工程扎到 LLM 基础设施里的项目。
  3. 「schema 嵌 prompt + 解析层宽容」路线让开源小模型也能用:不走 logits masking(被 provider 锁死),用 jsonish 多策略解析 + Flag 评分制(StringToBool / ImpliedKey / ArrayItemParseError),让 Qwen2-VL、Llama 3 等本地模型也能跑出合规结构化输出。

项目展示

BAML logo

README 视觉资产极简(仅 logo + 代码 demo),无 GIF / 无视频;演示靠 docs 站 playground 与博客。Phase 1 已确认 README 无展示性动图。

项目画像

维度数据
GitHubhttps://github.com/boundaryml/baml
Star / Fork8,453 / 439
Watchers / Open Issues / Open PRs30 / 187 / 54
协议Apache License 2.0
创建于 / 最近活动2023-10-06 / 2026-06-30(每日仍在 commit + 多次 nightly release)
默认分支canary(非常规 main,canary 发布模式)
仓库年龄32.8 个月
代码行数1,505,814 行 / 5,092 文件(tokei)
主语言分布Rust 66.3% · TypeScript 12.2% · BAML 8.2% · Python 4.0% · JavaScript 2.7% · MDX 2.3% · Go 1.7% · 其它 < 1%
开发阶段密集开发 + 持续加码(最近 30 天 189 commit,与 2024-05 单月爆量期持平)
贡献模式核心少数 + 社区驱动:105 人贡献,TOP 5 ≈ 77%,TOP 10 ≈ 91%
热度定位大众热门 + 高速增长(pattern = 高速增长)
质量评级代码[优秀] 文档[优秀] 测试[优秀]
公司 / 所在地Boundary · Seattle, WA(无 YC、无 cloud、无 SaaS)

作者视角:为什么存在这个项目

创始人/作者背景

创始团队 6 人,前背景都是大厂底层 / 编译器 / 工具链:

  • Vaibhav Gupta(hellovai)— Co-founder & CEO,前 Google Pixel 4 / HoloLens 工程师;仓库第一大贡献者(666 commits / 15.1%)。
  • Aaron Villalpando(aaronvg)— Co-founder & CTO,前 Amazon EC2 / Prime Video / Twitch;596 commits。
  • Sam Lijin(sxlijin)— 前 Google Identity / Cloud Firestore,前 Trunk 开发者工具,Vanderbilt CS;519 commits。
  • Antonio Sarosi — 独立 Rust 项目背景(数据库 / reverse proxy / 内存分配器),YouTube 教学频道 18 万订阅。
  • Paulo Rossi — 前 YC 创始人,ARR 曾过 $2M,早期 BAML 用户转为员工(dogfooding 的活证据)。
  • Kai Orita — 写过 ere(编译期正则)和百万下载的 VS Code 扩展。

领域背景总结:大厂底层 + 编译器 / 工具链经验密集(Google 设备 / Amazon 分布式 / Rust 独立项目 / Rust 教学),无 web-app / 前端出身 —— 典型 systems + PL 工程文化。

问题判断

LLM 集成在产品工程里是「黑盒字符串拼接」:开发者用 f-string 拼 prompt、用 regex 抽 JSON、用 Pydantic 在 Python 边界救火 —— 没有一个把”提示工程”当成”工程”来对待的中间层。当 prompt 里有控制流(if / for / match)、需要 retry / fallback / 跨 provider 路由、需要 schema 校验、需要 streaming 解析时,工具链的断裂让 LLM 集成永远处在「能跑但脆」的状态。

时机判断:作者们认为 “AI agents are a new paradigm that requires a new programming language, just like in the past: Hardware → Assembly, Operating Systems → Java, Web → JavaScript, Agentic Coding → ???” —— 现在是新范式的语言空窗期,自研语言 + 自研 VM 的工程赌注值得下。

解法哲学

README 把设计哲学明示为 7 条,每条都对应到具体代码:

哲学代码落地点
Look like TypeScriptBAML 语法故意用 TS 风格(class Foo { field int }、Jinja {{ x }}),但底层类型系统是 Rust 风格(invariant generics、structural typing、narrowing)
Make undesired state unrepresentable用 mu-binder 表达递归类型(type JSON = string | int | JSON[]),用 equirecursive subtyping 让 alias 透明
No viral editsLLM 函数被 desugar 成 func$render_prompt / func$build_request / func$parse 三个 companion(COMPANIONS: [fn(&FunctionDef) -> Option<FunctionDef>; 3]),下游 HIR/TIR/MIR/Emit 全程零特殊处理
One obvious wayIR 层(IntermediateRepr)是唯一的 schema 表示,5 个生成器都从 IR 取,不允许”每个语言有自己的方言”
Tools for agents, not IDEssnapshot test 输出”designed to be readable by both humans and LLMs”;baml_test! 宏循环明确写给 coding agent
Make nondeterminism observablejsonish 解析给每个 fixable error 打 Flag(Flag::ArrayItemParseError / Flag::StringToBool / Flag::ImpliedKey)存档

战略意图

当前 = 0 商业化:README 仅招 Rust 工程师,无 cloud / SaaS / pricing 页。但产品形态已经埋下 SaaS 化伏笔:

  1. Tracing / Observability —— engine/baml-runtime/src/tracingv2/ 已做了 v1 + v2 两套,每次 LLM call 都有 prompt、request、response、latency、token 用量 —— 正是 Helicone / LangSmith / TensorZero 卖的东西。
  2. Prompt registry / versioning —— BAML 已有 lockfile (engine/baml-lib/baml-core/src/lockfile.rs),是 BAML Cloud 的天然入口。
  3. Eval / optimize —— baml-cli optimize、engine/baml-runtime/src/optimize/ 已存在。
  4. OpenAPI 协议层 —— Issue #892 暗示团队想把 BAML 当”agent 之间交换 schema 的协议”,与 AsyncAPI / OpenAPI 当年的”想当协议”姿态一致。

核心价值提炼

创新之处

按新颖度 × 实用性排序:

  1. Companion Function 自动展开(AST-level desugaring):每一个 LLM function 在 AST 阶段被 desugar 成 3 个 companion,实现是 COMPANIONS: [fn(&X) -> Option<X>; N];下游全程零特殊处理。新颖度 4 / 实用性 5 / 可迁移性 4。
  2. 宽容 JSON 解析 + Flag 评分制(jsonish + WithScore):3 套 parser(fixing / markdown / multi-json)并行跑,每个 fixable error 打 Flag,最后用加权和(数字字段比 string 字段重 10×)取最低分路径 —— 这是 BAML 兼容任何 LLM(含开源小模型)的工程根基。新颖度 4 / 实用性 5 / 可迁移性 4。
  3. Salsa 查询作为 IR 层(“After AST, everything is a query”):传统编译器每层拷贝 + 增量难做对;compiler2 反过来 —— HIR/TIR 是 query 不是 transformation,只有 AST/MIR/bytecode 是 transformation。加注释编辑只重跑 lexer + HIR,type 推断不会失效。新颖度 3(rust-analyzer 用过)/ 实用性 5 / 可迁移性 5。
  4. Stream 类型在 PPIR 层注入回 HIR(self-feeding IR):@stream.done / @stream.not_null / @stream.with_state 这些流式属性需要在生成 *$stream 合成类型时,把合成出的 AST 节点重新喂回 HIR —— Salsa query 架构下”两个层之间循环”的优雅解法。新颖度 5 / 实用性 4 / 可迁移性 3。
  5. Snapshot 测试面向 LLM 优化(“designed to be readable by LLMs”):每个 pipeline 阶段(lexer / parser / HIR / TIR / MIR / diagnostics / codegen)都有独立 snapshot 格式;baml_test! 宏 + cargo insta accept 是明确给 coding agent 用的循环。新颖度 4 / 实用性 5 / 可迁移性 5。
  6. baml-bench dogfooding 闭环(agent 跑 BAML 找 BAML bug):用 Convex claimable queue + Next.js dashboard + claude-proxy + notion-fixer + cursor fix dispatch,把”agent 跑基准 → 写 trophy → 去重 → 派发 Cursor 修 → 重跑”做成全自动流水线。新颖度 5 / 实用性 4 / 可迁移性 4。
  7. Co-inductive equirecursive subtyping + mu-binder:type JSON = string \| int \| JSON[] 在 type-check 时不爆栈;用 mu-binder 表达递归,subtype 检查用 assumption set 防止无限递归。ACI unification 是 NP-hard,BAML 显式承认并 fail closed —— 工程上”我宁可让你多写一个 implements 也不愿意编译期允许一个运行时 panic”。新颖度 3 / 实用性 4 / 可迁移性 3。
  8. BexVM 半空间 GC + TLAB 无锁分配:runtime_spaces: [ChunkedVec<Object>; 2] 互为 GC 切换;tlab.alloc_ptr 单调 bump,满了 fetch_add 抢下一块。配合 CPython 风格 superinstruction(LoadVar2(a, b) 一次读两个 u32,省一次 PC++)。新颖度 3 / 实用性 4 / 可迁移性 3。

可复用的模式与技巧

  1. “Before AST produce the AST, after AST answer questions about the AST”:编译器层数选择的不对称原则 —— 前 3 层是 transformation(Parser/CST→AST/低层 IR),后面全是 query。适用场景:所有做 IDE-grade 编译器的项目。
  2. Companion function 数组(COMPANIONS: [fn(&X) -> Option<X>; N]):把”同一 source 节点展开成多个 IR 节点”做成纯函数数组,加新 desugar 只需要加一个函数。适用场景:DSL 设计。
  3. build.rs 同时跑 .baml → AST → 生成 Rust trait impl:编译期让”自研语言的 stdlib”在宿主语言里有对应实现,免去手写镜像。适用场景:自研语言 + Rust runtime。
  4. Snapshot format per pipeline phase + 显式 “designed for LLM” 注释:把工具链的”中间产物”做成”人类和 LLM 都能读”。适用场景:所有”用 AI 写工具、工具改 AI”的循环。
  5. “声明式 schema 嵌 prompt + 解析层宽容恢复”代替 logits masking:避开 provider 锁定,让开源小模型也能用。适用场景:LLM structured output 的工程妥协。
  6. TypeBuilder fluently typed 客户端 + IsLiteral / CheckNever 类型保护:把”运行时数据”用”编译期类型”约束住 —— TS 的 string extends T ? false : true 风格判别联合。适用场景:任何”动态 schema”工具。
  7. /^[ \t]*```([a-zA-Z0-9 ]+)(?:\n|$)/m 锚定首列才识别代码块的 markdown parser:避免误吃字符串里的 ```json。适用场景:所有 markdown → 结构化解析的代码。
  8. read_u32_unchecked + 手动解释字节序的 superinstruction:性能优化的最朴素做法 —— LoadVar2(a, b) 一次读两个 u32,省一次 PC++。适用场景:解释器性能调优。

关键设计决策

  1. 决策:做自研语言(DSL + 编译器 + VM),而不是 Python 库 / TS 库

    • 问题:跨 5+ 个宿主语言做”统一的 schema + 统一的 prompt 渲染 + 统一的 retry/fallback + 统一的 stream 解析”,单宿主库做不到。
    • 方案:把 schema、prompt、client、retry policy 全部用 .baml 单一 DSL 表达;baml-cli generate 吐出 5 种宿主语言的 typed client;运行时用 BexVM 字节码统一执行(BexVM 是 BAML → 字节码 → Rust 解释器,不依赖任何宿主 VM)。
    • Trade-off:自研语言意味着语言入门成本 + 编译器维护成本 + 用户调试成本三高;换取跨语言语义一致性 + 长期可演进性。
    • 可迁移性:低 —— 只有当你有”必须跨 N 个语言且不能分裂”的强需求时才划算。这是 BAML 最大的护城河决策。
  2. 决策:HIR / TIR / MIR / Emit 四层中间表示 + PPIR 旁路

    • 问题:单纯 AST → 字节码的两层结构会让类型信息丢失、要不停回头查表。
    • 方案(ARCHITECTURE.md 关键引述):“before the AST, produce the AST. After the AST, answer questions about the AST.” —— 只有 3 个”生产型”层(Parser → AST,AST → MIR,MIR → bytecode),中间全是 Salsa 查询。
    • Trade-off:层数越多越难上手;编译器新人必须先吃透 5 层职责边界(“Cardinal Rule: Upstream Over Downstream”)。
    • 可迁移性:中 —— 任何做 IDE-grade 编译器的项目(语言服务器、增量编译、refactor 工具)都受益。
  3. 决策:编译期 schema 校验 + 运行时类型校验(双层)

    • 问题:纯编译期类型检查在 LLM 输出场景不够 —— LLM 可能输出不合法 JSON。纯运行时校验又拿不到 IDE 提示。
    • 方案:编译期用 TIR 校验所有 prompt 模板里的 {{ ctx.output_format }} 调用、类型引用、union 分支;运行时用 jsonish 解析器对 LLM 原始输出做”宽容解析 + flag 评分”。
    • Trade-off:运行时解析器 ~1.5k 行 Rust,是 BAML 复杂度的主要来源之一;换取”LLM 输出永远能 recover 出 BamlValue”的强保证。
    • 可迁移性:高 —— 任何”需要从非结构化文本中恢复结构”的场景都能用。
  4. 决策:约束解码走”prompt 嵌入 schema + 运行时宽容解析”路线,不强求 logits masking

    • 问题:logits masking / grammar-constrained decoding 需要 provider 支持(OpenAI 的 response_format: json_schema、Anthropic 的 tool use、Google 的 response schema 等各家不同),强求 mask 会被 provider 锁死。
    • 方案:BAML 不强制走 provider 的 grammar API,而是把 schema 当作提示的一部分用 {{ ctx.output_format }} 嵌进 prompt(output_format: "Answer ONLY with a JSON object that has these fields..."),再让运行时 jsonish 做”宽容解析”。
    • Trade-off:少一个”用 OpenAI 的 json_schema 时 100% 合法”的金标准保证;换取”任何 LLM(开源 / 小模型)都能用”的最大兼容。
    • 可迁移性:高 —— 这套”schema 嵌 prompt + 解析层兜底”思想任何 structured-output 项目都能用。
  5. 决策:把 stdlib 写在 BAML 自己里(baml_builtins2/baml_std/baml/)

    • 问题:传统”编译器内置 stdlib”会让 stdlib 类型变化需要改编译器。
    • 方案:核心类型(Client / PrimitiveClient / Array<T> / Map<K,V> / baml.llm.PromptAst / baml.http.Request)都是 .baml 文件;编译器通过 include_str! 嵌入 + build.rs 在 Rust 编译时也跑一遍 codegen 生成 Rust 侧 trait 实现。
    • 关键:编译器路径和运行时路径共享同一份 .baml 文件但独立 codegen —— 这是 BAML “hosted language” 的基础。
    • Trade-off:改一个 stdlib 类型需要同时检查编译器侧和运行时侧。
    • 可迁移性:高 —— 任何”自研语言 + 自带 stdlib”项目都该这么干。

竞品格局与定位

竞品对比矩阵

维度BAMLInstructor (13.3k★)Outlines (14.3k★)TypeChat (8.7k★)TensorZero (11.7k★)
形态DSL + 编译器 + 5 SDK + 自研 VMPython 库Python 框架TS 库Rust gateway + LLMOps 平台
跨语言✅ 5 语言(Py/TS/Go/Ruby/Rust)❌ Python only❌ Python only❌ TS only❌ 服务端,多语言客户端
跨 provider✅ 7+ provider(OpenAI/Anthropic/Vertex/Bedrock/Ollama/…)主要 OpenAI + tools✅ 通过 logits processor主要 OpenAI✅ gateway 路由
开源模型兼容✅(prompt-embed + jsonish 宽容)弱(依赖 OpenAI format)中(logits masking 要求兼容)弱中
类型系统自研(mu-binder + invariant generics + narrowing)PydanticPydanticTS 类型系统无(gateway 视角)
Streaming 类型化✅ @stream.done / @stream.with_state❌❌❌✅(gateway 视角)
IDE/LSP✅ VS Code / JetBrains / Zed仅 Python LSP无仅 TS无
动态 schema✅ TypeBuilder❌❌❌❌
商业化0(仅招人)已成立公司已成立公司微软实验性已成立公司 + 客户
学习曲线高(自研语言)低(Python 库)低低(TS 库)中(LLMOps 平台)

差异化护城河

  1. 跨语言语义一致性 —— 这是 5 个语言 SDK 真正的卖点,竞品都是单宿主。
  2. 自研 VM(BexVM) —— 让 BAML 能”独立跑”(不依赖任何宿主 VM),同时让 tracing / profiling / optimization 成为 first class。
  3. Streaming 类型化 —— @stream.done / @stream.not_null / @stream.with_state 是 BAML 在 streaming 场景的杀手锏。
  4. 动态 schema(TypeBuilder) —— 同类产品没做或做得肤浅。
  5. dogfooding 闭环(baml-bench) —— 这是组织能力,不是技术。

竞争风险

  1. OpenAI / Anthropic 自家 structured output 越来越强 —— json_schema mode / tool use / structured outputs 把”结构化输出”逐渐变成 commodity,BAML 在”OpenAI + Anthropic”上的差异化会被持续压缩。
  2. Python 生态 —— Instructor + Pydantic + LangChain 在 Python 圈根深蒂固,BAML 改写用户习惯成本高。
  3. 学习曲线 —— 自研语言注定比 Pydantic 类库难上手;BAML 的目标用户群比 Instructor / TypeChat 窄。
  4. 0 商业化 —— 30+ 核心贡献者、5 个 SDK、weekly release 节奏,烧钱速度需要 cloud 化来撑。

生态定位

BAML 不是 “Pydantic for LLM” —— 它是”自研 agent 编程语言 + 跨语言 SDK + 跨 provider 运行时”。真正的同位竞品是 LangChain / LlamaIndex(“agent 框架”),但 BAML 选择做语言而不是做框架 —— 这是更上游、更长期、风险也更高的赌注。

短中期定位:“用一套 BAML schema 替代你们跨 5 个语言各自拼 prompt 的胶水代码”。

套利机会分析

  • 信息差:HN 总声量偏弱(仅 1 条 Show HN by aaronvg),增长主要靠 GitHub Trending + dev.to / 个人博客扩散 —— 在国内技术圈几乎未被充分讨论,公众号端是优质信息差。
  • 技术借鉴:可立即迁移的模式 —— ① jsonish 宽容解析 + Flag 评分(任何 LLM 输出抽取场景可用)② schema 嵌 prompt + 解析层兜底(任何想兼容开源小模型的项目可用)③ snapshot per pipeline phase + “designed for LLM”(任何 AI agent 写代码的工具链该学)④ Companion function 数组 desugaring(DSL 设计的通用模式)。
  • 生态位:填补”跨语言栈团队没有统一 prompt 表达层”的空白。对国内多语言栈公司(字节 / 阿里 / 美团 / 拼多多都有 Python + Go + TS 的混合栈)特别有价值 —— 这类公司目前要写 5 套 prompt 胶水代码。
  • 趋势判断:① 2026-06 单月 189 star 创 2025 以来新高(agent 浪潮红利)② default branch = canary、daily nightly release,节奏不降反升 ③ 团队已宣布招 Rust 工程师 → 处在产品化加速 + 商业化前夜。

风险与不足

  1. 0 商业化 + 持续高投入:30+ 核心贡献者 + 5 个 SDK + weekly release 节奏,烧钱速度需要 cloud 化来撑;如果 18 个月内没有 cloud/enterprise 收入,团队稳定性有风险。
  2. 双代架构迁移成本:engine/(5,574 变更)和 baml_language/(23,415 变更)并存,HIR/PPIR 循环是新代独门但旧代还在维护,新人上手成本高。
  3. TypeScript 注释里 “ask vaibhav” 之类的 TODO 痕迹:说明作者在快速迭代中,部分模块文档化滞后。
  4. 部分新代 crate(如 compiler2_ppir)snapshot 还在 evolve,稳定性未达 v1 水平。
  5. schema 编译时版本 vs 运行时版本漂移(Issue #2241):客户端生成器与运行时版本对齐是 0.2xx 阶段的明显痛点,可能在升级到 1.0 前是 friction。
  6. 依赖 Rust 工具链:用户调试 / IDE 体验比 Python 库重一档 —— TypeChat 用 TS 自带 IDE 提示是 BAML 短期追不上的体验优势。

行动建议

  • 如果你要用它:
    • 选 BAML 的场景:跨语言栈团队(Py + TS + Go / Ruby)需要统一 prompt + schema;想用本地开源模型跑结构化输出;想要 streaming 类型化(@stream.done 不会重复发”已确认字段”)。
    • 不选 BAML 的场景:只用 Python + OpenAI —— Instructor + Pydantic 五分钟上手,BAML 学习曲线不值;只跑简单 f-string prompt —— BAML 的 DSL 抽象是过度工程。
  • 如果你要学它:
    • 必读:baml_language/architecture/ARCHITECTURE.md、TYPE_SYSTEM.md、baml_language/crates/bex_vm/README.md —— 三个 1000+ 行设计 doc 解释了为什么这样做而不是那样做。
    • 重点关注:baml_language/crates/baml_compiler2_hir/ 的 Salsa 查询实现、engine/baml-lib/jsonish/ 的宽容解析 + Flag 评分、engine/generators/ 的多语言代码生成 dispatch。
    • 可复用技巧:jsonish 解析 + snapshot per pipeline phase + “designed for LLM” 这三个模式任何 AI 工具都能学。
  • 如果你要 fork 它:
    • 改进方向 1:加 litellm 风格的统一 provider adapter,把 7 个 provider 的差异收敛到 trait 后面(当前是各 provider 一个文件)。
    • 改进方向 2:TypeBuilder 加 IDE-time 提示 —— 当前 TS 端的 IsLiteral<T> 是手写,缺泛化的”动态 schema 编译期类型保护”生成器。
    • 改进方向 3:tracingv2 上做 OpenTelemetry 兼容 export,让用户能直接对接 Langfuse / Helicone / 自家 observability 后端。

知识入口

资源链接
DeepWiki未收录
Zread.ai未收录
公开 RFC 流程(BEPs)https://beps.boundaryml.com
官方文档站https://docs.boundaryml.com
公司站 / 团队介绍https://www.boundaryml.com/who-are-we
官方 Playgroundhttps://www.boundaryml.com/explore
关联论文无(BAML 是工程产品,非学术研究)
在线 Demohttps://docs.boundaryml.com(内嵌 playground + editor preview)

相关报告