ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

BAML Gradle 插件(com.boundaryml.baml):在构建期从 baml_src 生成类型安全 Java SDK 的完整指南

BAML Gradle 插件(com.boundaryml.baml):在构建期从 baml_src 生成类型安全 Java SDK 的完整指南 编程语言AI Agent编译器CLI人工智能【免费下载链接】bamlThe programming language for agents项目地址https://gitcode.com/gh_mirrors/ba/baml点击查看免费下载导读BAML 是面向 Agent 的编程语言而com.boundaryml.bamlGradle 插件让 Java/Kotlin 项目可以在构建期build time直接从baml_src/目录生成类型安全的 BAML Java SDK无需把任何生成代码提交进仓库。本文以 gradle-plugin/README.md 为主体结合仓库内的插件源码、功能测试与 quickstart 示例完整讲解插件的接入方式、baml { … }全部配置项、generateBaml任务的增量与缓存机制、依赖自动注入原理以及插件的发布流程。读完本文你将能在一行插件声明内完成 BAML Java 工程的搭建并理解其底层protobuf-gradle-plugin 模式的工程决策。1. 插件定位构建期生成protobuf-gradle-plugin 模式com.boundaryml.baml是 Java 打包方案中pattern C构建期生成的具体实现模型参照 protobuf-gradle-plugin一个可缓存的generateBaml任务运行已安装的bamlCLI把 SDK 写入build/generated/sources/baml/java/main并把这个目录接入主 source set。这一设计带来三个直接收益零提交生成代码永远不会进入仓库.gitignore无需额外维护增量当baml_src/下的文件、baml.toml或 CLI 版本都没有变化时Gradle 将任务标记为UP-TO-DATE并跳过单一事实来源BAML 源码.baml文件是唯一需要维护的类型定义。在 BamlPlugin.java 的类注释中可以读到插件职责的完整清单应用java插件、注册baml { … }扩展、注册可缓存的GenerateBamlTask、把任务输出注册为 Java 源码根与资源、并自动管理 BAML 运行时依赖。2. 接入一行插件声明即完成全部配置插件本身就是全部配置。在build.gradle.kts中加入plugins { id(com.boundaryml.baml) version 0.15.0-nightly.1 } repositories { mavenCentral() }应用该插件后插件会替你完成三件事BamlPlugin.java#L88-L163自动应用java插件——因此一个只有baml.toml和baml_src/目录的项目无需再声明任何插件java/java-library/application已存在时幂等注入implementation(com.boundaryml:baml-bridge:pluginVersion)——生成 SDK 编译所依赖的 BAML 运行时版本锁定为插件自身版本。插件与baml-bridge由同一条发布流水线以同一版本发布因此两者永远匹配注入runtimeOnly(com.boundaryml:baml-bridge:pluginVersion:natives-platform)——为构建机器平台自动注入对应平台的原生 jar平台由os.name/os.arch自动探测这正是运行时原生库加载器会查找的 classifier。之后正常构建即可gradle build # 先运行 generateBaml再执行 compileJava仓库内的 examples/quickstart 演示了最简形态——plugins块一行 repositories { mavenCentral() }然后gradle run即可运行示例输出add(2, 3) 5。该示例要求 JDK 17且bamlCLI 的版本与插件版本一致。2.1 从 Maven Central 解析插件nightly 版本夜间版nightly只发布到 Maven Central而不发布到 Gradle Plugin Portal。如果你从 Central 而非 Plugin Portal 解析插件需要在settings.gradle.kts中同时声明两个仓库pluginManagement { repositories { gradlePluginPortal() mavenCentral() } }这与 examples/quickstart/settings.gradle.kts 的写法一致——示例注释指出实际使用中 Portal 端点也会代理 Central但示例不应依赖基础设施行为因此显式声明了两个仓库。3. 配置项baml { … }扩展块插件的全部可调项集中在可选的baml { … }块中完整定义见 BamlExtension.java选项类型默认值含义srcDirDirectoryProperty项目目录包含baml.toml与baml_src/的目录作为--from传给 CLIbamlExecutablePropertyStringbaml要运行的 CLI——可以是PATH上的裸命令名也可以是特定二进制文件的绝对路径outputTypePropertyStringjava仅作信息展示。真正的生成器配置位于baml.toml的[generator.name]中nativePlatformsListPropertyString(空 → 探测宿主机)要依赖的原生 jar classifier 列表。空则自动探测构建机器显式列表替换探测[all]则添加全部已知平台manageDependenciesPropertyBooleantrue是否由插件自动注入baml-bridge运行时 原生 jar。设为false表示这些依赖由你自己管理一个典型的配置块baml { srcDir.set(layout.projectDirectory) bamlExecutable.set(baml) // 跨平台产物依赖每个平台的原生 jar。安全——运行时加载器会按 // os/arch 挑选正确的一个其余是惰性的inert。 nativePlatforms.set(listOf(all)) // 或者显式点名listOf(linux-x86_64, macos-aarch64)。 }已知的nativePlatformsclassifierlinux-x86_64、linux-aarch64、macos-x86_64、macos-aarch64、windows-x86_64、windows-aarch64。实验性的 musl classifier 永远不会被自动探测也不属于all——在 Alpine 上需要显式请求linux-arch-musl。3.1 平台探测与all展开的源码细节从 BamlPlugin.java#L233-L252 的resolveNativePlatforms可以看到三态逻辑空列表 →detectPlatform()只取宿主机一个平台列表含all→ 展开为ALL_PLATFORMS六个平台linux-x86_64、linux-aarch64、macos-x86_64、macos-aarch64、windows-x86_64、windows-aarch64其他显式列表 → 按原样去重、保序。detectPlatform()的映射逻辑mapOsmapArch在 BamlPlugin.java#L322-L363 中它与运行时baml_bridge的 NativeLibraryLoader.java 完全一致macOS 判断必须排在 Windows 之前因为darwin包含子串winamd64/x64映射为x86_64arm64/aarch64映射为aarch64。这样插件依赖的 jar 恰好就是运行时加载器要查找的那个。all之所以安全是因为运行时加载器按 JVM 自身的os.name/os.arch在/native/os-arch/classpath 资源上做 first-hit-wins 选择见 NativeLibraryLoader.java#L43-L81多余平台的原生 jar 只是闲置在运行时 classpath 上。代价仅仅是下载体积每个平台一份引擎 cdylib而非正确性。3.2 退出依赖管理opt-out如果你已经在依赖中声明了com.boundaryml:baml-bridge插件会检测到并什么都不注入以info级别日志记录让位于你的声明。如果需要完全手动控制——自定义运行时的坐标、自带的 jar、或非常规平台——则设置manageDependencies.set(false)并自行添加依赖baml { manageDependencies.set(false) } dependencies { implementation(com.boundaryml:baml-bridge:0.15.0-nightly.1) runtimeOnly(com.boundaryml:baml-bridge:0.15.0-nightly.1:natives-linux-x86_64) }插件注入逻辑的完整规则含defer to explicit检测与 Kotlin 消费者额外注入baml-bridge-kotlin的分支见 BamlPlugin.java#L176-L277。其中值得注意的细节Kotlin JVM 插件org.jetbrains.kotlin.jvm被应用时插件会额外注入同版本的com.boundaryml:baml-bridge-kotlinKotlin 人体工学层其 POM 以api依赖传递引入baml-bridge纯 Java 消费者永远不会拉到 Kotlin 运行时。4.generateBaml任务做了什么generateBamlgroup 为bamlCacheableTask的定义在 GenerateBamlTask.java 中。它声明了三类输入和一个输出Inputs——baml.tomlInputFile路径敏感RELATIVE、srcDir/baml_src/下每个文件InputFiles路径敏感因此重命名/删除也会被追踪、以及解析出的 CLI 版本baml --version作为Input工具链升级会触发重新生成Output——build/generated/sources/baml/java/main执行体——先删除输出目录再以baml generate --from srcDir -o outputDir/baml_sdk的形式运行 CLI。4.1 输出布局与baml_sdk子目录生成的.java声明package baml_sdk.*因此 emitter 的输出根必须是一个baml_sdk/子目录baml generate --from srcDir -o outputDir/baml_sdk而outputDir本身注册为 Java 源码根GenerateBamlTask.java#L107-L124。任务执行前总是清理输出目录——因为 BAML 自身的generate不会移除陈旧文件一个被重命名或删除的 BAML 类若不清理就会留下一个仍然能编译通过的过期.java。4.2 布线Wiring三件事插件把生成结果接入构建图的方式BamlPlugin.java#L123-L151源码生成的.java加入sourceSets.main.java。注意这里是注册任务 Provider而非裸目录——srcDir(generateBaml)会让 Gradle 从 source set 本身推断出generateBaml → compile的依赖这正是 IntelliJ 在 Gradlesync时就能生成源码的原因IDE 读取 source-set 模型而模型此时指向一个任务输出资源baml_sdk/**/*.b64字节码被打包为资源——它必须位于运行时 classpath 的/baml_sdk/inlinedbaml.b64。include 范围限定在该fromspec 内以免触碰消费者自己的资源依赖compileJava与processResources都dependsOn(generateBaml)前者作为保险丝即使 source set 推断已覆盖也保留。4.3 增量与 UP-TO-DATE因为输入与输出都已声明Gradle 只在.baml源文件、baml.toml或 CLI 版本变化时才真正执行generateBaml否则任务为UP-TO-DATE任务体——包括 CLI 调用——被整体跳过。运行已构建的程序永远不会触发生成。这条行为由功能测试直接验证在 BamlPluginFunctionalTest.java 中第一次构建generateBaml结果为SUCCESS同时断言baml_sdk/Baml.java生成、baml_sdk/Baml.class编译、resources/main/baml_sdk/inlinedbaml.b64打包第二次无变化的构建结果为UP_TO_DATE。4.4 CLI 缺失配置期永远成功执行期给出安装提示如果baml可执行文件找不到或无法运行任务会在执行期失败配置期总是成功并附带安装提示curl -fsSL https://pkg.boundaryml.com/install.sh | sh安装脚本见仓库根目录 scripts/install.sh。修复方式是baml { bamlExecutable.set(/path/to/baml) }或将baml加入PATH。这个延迟失败的机制很精巧插件通过一个 provider 在输入快照时刻执行期解析 CLI 版本缺失时返回空字符串哨兵BamlPlugin.java#L371-L392GenerateBamlTask.generate()在版本为空时抛出带安装提示的GradleExceptionGenerateBamlTask.java#L82-L85。功能测试 missingExecutableFailsTaskWithInstallHint 断言了FAILED结果与错误输出包含安装命令。5. 从 CLI 到 classpath一条完整链路把以上机制串起来一次gradle build的实际链路是Gradle 对generateBaml做输入快照baml.tomlbaml_src/** CLI 版本快照未变 →UP-TO-DATE跳过变了 → 清理输出目录调用baml generate --from srcDir -o outputDir/baml_sdk生成的baml_sdk/**/*.java进入编译compileJava直接编译它们它们编译期依赖注入的com.boundaryml:baml-bridgebaml_sdk/**/*.b64经processResources进入resources/main运行时随 classpath 加载运行时NativeLibraryLoader按宿主os.name/os.arch从natives-platformjar 中提取并System.load对应的bridge_javacdylibNativeLibraryLoader.java#L43-L81BAML 引擎由此生效。5.1 quickstart 的完整工程形态仓库中的 examples/quickstart 给出了可直接运行的最小工程三份关键文件相互印证baml.toml——真正的生成器配置在这里[generator.java_client]声明output_type java、output_dir .、naming_convention preserve-case。这正是上文outputType选项仅作信息展示的原因真正的生成器配置由baml.toml拥有main.baml——两个极简函数add(a: int, b: int) - int与greet(name: string) - string生成 SDK 后即可在 Java 中类型安全地调用settings.gradle.kts——标准pluginManagement双仓库声明。6. 插件自身的发布双渠道与本地排练插件从发布流水线发布到两个地方README 的 Publishing 一节对此有完整说明Gradle Plugin Portalcom.gradle.plugin-publish→publishPlugins——plugins { id(com.boundaryml.baml) version X }的规范家园仅发布稳定渠道canary/stablepublishPlugins任务原生地从GRADLE_PUBLISH_KEY/GRADLE_PUBLISH_SECRET环境变量读取 Portal API 密钥Maven Central——Portal 要求的元数据displayName、description、website/vcsUrl、tags加上 marker POMcom.boundaryml.baml:com.boundaryml.baml.gradle.plugin与baml-bridge一同搭载在同一份签名 Central bundle 上因此nightlyPortal 不接受能经由mavenCentral()到达 Gradle 消费者。产物坐标为com.boundaryml:baml-gradle-pluginmarker 发布由java-gradle-plugin自动生成见 gradle-plugin/settings.gradle.kts。本地排练命令# 发布到 ~/.m2无需任何凭据 gradle publishToMavenLocal -PbamlVersion0.15.0-nightly.1 # 仅校验 Portal 元数据而不发布校验阶段需要 Portal 凭据不发布任何东西 gradle publishPlugins --validate-only -PbamlVersion0.15.0-nightly.1 # 暂存签名后的 Central 布局写入 build/staging-deploy或用 -PbamlStagingDir # 指向共享目录树让插件 marker 与 baml-bridge 加入同一 bundle gradle publishAllPublicationsToStagingRepository -PbamlVersion0.15.0-nightly.1相关属性属性默认值含义bamlVersion0.0.0-dev发布版本canary 为纯版本号nightly 带后缀bamlStagingDirbuild/staging-deploy暂存发布的 file-repo 目的地可指向共享的 Central 树bamlSign(未设置)存在时通过本地 gpg agent 对每个发布签名Maven Central签名有两条路径与baml_bridge对称详见 baml_bridge/PUBLISHING.mdCI 内存密钥GPG_PRIVATE_KEY/GPG_PASSPHRASE环境变量优先否则-PbamlSign使用本地 gpg agent——此时务必传-Psigning.gnupg.keyNameKEYID。未配置密钥时自动创建的sign*任务会跳过因此publishToMavenLocal、publishPlugins与 TestKit 都不受阻碍。首次提交 Portal 需要 Gradle 团队对插件 id 的一次性人工审批通过publish-gradle-plugin-manual.yml工作流workflow_dispatch 版本输入触发。7. 测试保障功能测试覆盖的行为矩阵gradle-plugin/src/test 使用 Gradle TestKitGradleRunner覆盖了五类行为测试验证点pluginAppliesAndRegistersGenerateTask插件应用并注册generateBaml无 CLI 也须成功配置generatesCompilesAndIsUpToDateOnRerun端到端生成 编译 资源打包 二次构建UP-TO-DATEmissingExecutableFailsTaskWithInstallHint缺失可执行文件在执行期失败并带安装提示配置期不失败generatedSourceRootIsBackedByGenerateBamlTask生成源码根由任务 Provider 支撑IntelliJ sync 生成的依据依赖管理系列5 个用例默认注入baml-bridge 宿主原生 jarKotlin 消费者额外获得baml-bridge-kotlin显式依赖压制注入nativePlatforms显式列表替换探测all展开全部平台manageDependenciesfalse零注入测试中还使用了一个 fakebaml脚本模拟真实 CLI应答--version并写出自包含的baml_sdk树使端到端编译测试保持封闭BamlPluginFunctionalTest.java#L518-L561。这组测试本身就是插件契约的可执行文档。8. 常见问题速查baml命令找不到任务失败并输出安装提示。先执行curl -fsSL https://pkg.boundaryml.com/install.sh | sh安装 CLI或bamlExecutable.set(/absolute/path/to/baml)或把baml加入PATH。版本不匹配插件、baml-bridge、CLI 在同一流水线以同一版本发布。plugins块中的版本应与安装的 CLI 版本一致见 quickstart README 的版本说明。需要在 Alpine/musl 上运行显式请求linux-arch-muslclassifier——它不在自动探测与all之列。需要跨平台发布产物nativePlatforms.set(listOf(all))运行时加载器会按宿主平台挑选正确的原生 jar多余平台 jar 是惰性的。想自己管理运行时依赖声明自己的com.boundaryml:baml-bridge插件自动让位或manageDependencies.set(false)完全接管。IDE 不识别生成的 SDK生成源码根注册的是任务 ProvidersrcDir(generateBaml)因此 Gradle sync 时 IntelliJ 就会生成源码若仍异常先执行一次gradle build或gradle generateBaml。进一步阅读仓库内插件实现BamlPlugin.java、GenerateBamlTask.java、BamlExtension.java功能测试BamlPluginFunctionalTest.java可运行示例examples/quickstart含 baml.toml 与 main.baml运行时原生库加载器NativeLibraryLoader.java发布说明baml_bridge/PUBLISHING.mdCLI 安装脚本scripts/install.sh赞分享编程语言AI Agent编译器CLI人工智能【免费下载链接】bamlThe programming language for agents项目地址https://gitcode.com/gh_mirrors/ba/baml点击查看免费下载相关推荐public-image-mirror容器镜像加速 Mirror 的完整使用指南——前缀映射、白名单机制与 K8s/Docker 加速实战public image mirror容器镜像加速 Mirror 的完整使用指南——前缀映射、白名单机制与 K8s/Docker 加速实战 很多镜像源仓库如编程语言AI Agent编译器CLI人工智能gRPC-Java 编译构建完全指南Gradle、代码生成插件与 Bazel 双构建体系详解gRPC Java 编译构建完全指南Gradle、代码生成插件与 Bazel 双构建体系详解 导读 本文以 grpc java 仓库根目录下的 COMPILI后端RPC框架大麦自动抢票工具3 个脚本完成移动端自动购票的方法大麦自动抢票工具3 个脚本完成移动端自动购票的方法 这是一个开源的大麦自动抢票项目用 Python 实现。它把自动化拆成两条路线Web 端用 SeleniGUI 自动化RPA上一篇toBeBetterJavaer缓存预热Redis数据加载策略下一篇TiXL FractalNoise 算子完全指南用 Simplex 分形噪声实时生成云、烟、尘埃与胶片颗粒创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表