返回资讯中心
外部精选
软件工程
#开发者实时流

BAML团队重写Agent技能并加入代码质量指标,提升Agent生成的BAML代码质量

来源标题:Teaching Agents to Write Maintanable Code

BAML团队重写了Agent技能,并在工具链中内置代码质量指标,以改善Agent生成的BAML代码质量。团队发现,Agent当前编写的BAML代码虽能通过测试,但质量明显低于同一批Agent生成的TypeScript或Rust代码。这些问题出在Agent产出的代码本身,而非BAML语言设计。

Hacker News 最新aaronvg2026/11/7 · 今天30 分钟阅读

以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。

我们重写了 agent skill,并在工具链中内置了代码质量指标,帮助 agent 写出更好的 BAML 代码。

过去几个月,我们一直在对 BAML 语言做最后的打磨,为 1.0 版本发布做准备。我们花了一年多时间设计这门核心语言,在这方面我们认为 BAML 已接近完成。但仍有工作要做:确保 BAML 能与编码 agent 良好配合,因为 agent 如今已是工程工作流的重要组成部分。

目前,agent 已经能写出解决实际问题并通过测试的 BAML 代码。BAML 是一门真正图灵完备的语言,配有编译器、字节码 VM、格式化工具等。BAML 剩下的问题不在语言本身,而在 agent 生成的 BAML 代码上。我们和许多测试者都注意到,agent 所写 BAML 代码的质量明显不如同一批 agent 写出的 TypeScript 或 Rust 代码。例如,下面是 agent(GPT-6.1-Sol 配合 Codex)在我们当前 skill 下写出的国际象棋走法生成器的一部分:

function chess_candidates(position: ChessPosition) -> ChessCandidate[] { let board = position.board; let candidates: ChessCandidate[] = []; let from = 0; while (from < 64) { let piece = board[from]; if (chess_color(piece, position.white)) { let kind = piece.to_lower_case(); if (kind == "p") { chess_pawn_candidates(position, from, candidates); } else { let directions = if (kind == "n") { CHESS_KNIGHTS } else { CHESS_RAYS }; for (let direction in directions) { let dx = direction[0]; let dy = direction[1]; let diagonal = dx != 0 && dy != 0; if ((kind != "b" || diagonal) && (kind != "r" || !diagonal)) { let x = from % 8 + dx; let y = from / 8 + dy; while (chess_inside(x, y)) { let to = y * 8 + x; if (chess_color(board[to], position.white)) { break; candidates.push(chess_candidate(from, to)); if (board[to] != "" || kind == "n" || kind == "k") { break; x += dx; y += dy; if (kind == "k") { chess_castling_candidates(position, from, candidates); from += 1; candidates

这是一个单独的函数,嵌套了七层。棋子用字符串表示,所以马是 kind == "n",打错字也照样能编译。它能跑,但没有充分利用 BAML 丰富的特性,也没人愿意维护这样的代码。我们必须想办法改进,否则在大多数人用 agent 写代码的今天,很难为使用 BAML 找到充分理由。

按理说,现有语言不会这么严重地受这个问题困扰,因为训练语料里有大量人类写的高质量代码。更不用说,大型 AI 实验室很可能针对这些语言在代码质量指标上做了优化。因此,在没有 BAML 代码进入训练数据、也没有大实验室支持的情况下,我们唯一能用来提升代码质量的手段,就是改进随 BAML 工具链一起发布的 skill。

我们当前的 skill 主要只是罗列 BAML 的特性:我们有 match,有类型联合,有反射,等等。它确实有一小节“最佳实践”,但大多数条目只是解释某个特性是做什么的,完全没讲什么时候该用、该怎么用;agent 知道了 enum 的存在,却从没被告知应该在什么场景下使用它。

这种做法显然不管用:在这个 BAML 国际象棋走法生成器任务上,十次 Codex 运行中没有一个 agent 选择使用 enum。于是,我们决定重写 skill 的大部分内容,把重点放在最佳实践和反模式上,这些是从人工审查 agent 生成的 BAML 代码中总结出来的。

新 skill 描述的是如何(以及如何不要!)写 BAML,而不只是它有哪些特性。它新增了 27 条要求 agent 始终遵循的准则,每条都配有一个坏例子和一个好例子。这些准则在格式上多少参考了 C++ Core Guidelines。下面是几条与国际象棋走法生成器例子相关的准则:

对于固定的取值集合,使用封闭类型。string 允许拼写错误。应使用 enum 或字面量联合类型。

// Bad class Ticket { status: string,

// Good enum Status { Open, Closed,

class Ticket { status: Status,

用 match 代替 if 链。match 是穷尽的,因此新增一个变体时会产生编译错误,而不是悄悄落到默认分支。

// Bad function hex(c: Color) -> string { if (c == Color.Red) { "#f00" } else { "#0f0"

// Good function hex(c: Color) -> string { match (c) { Color.Red => "#f00", Color.Green => "#0f0",

有了这些新准则,在使用新 skill 的十次 Codex 运行中,有九次在国际象棋走法生成器里至少声明了一个 enum。

新 skill 确实让我们感觉好了一些,但我们还想看看能否找到某种量化手段来衡量它的效果。于是,我们引入了文献中几个相对简单的指标:

// Cognitive 9 function cost_bad(o: Order) -> int { if (o.paid) { if (o.in_stock) { if (o.express) { 20 } else { 5 } else { 0 } else { 0

// Cognitive 4 function cost_good(o: Order) -> int { if (!o.paid || !o.in_stock) { return 0; if (o.express) { 20 } else { 5

圈复杂度

// Cyclomatic 5 function days_bad(month: string) -> int { if (month == "jan") { 31 } else if (month == "feb") { 28 } else if (month == "mar") { 31 } else if (month == "apr") { 30 } else { 0

// Cyclomatic 2 const DAYS = { "jan": 31, "feb": 28, "mar": 31, "apr": 30 };

function days_good(month: string) -> int { DAYS.get(month) ?? 0

NPath

// NPath 8 function badges_bad(o: Order) -> string[] { let badges: string[] = []; if (o.paid) { badges.push("paid"); if (o.in_stock) { badges.push("in stock"); if (o.express) { badges.push("express"); badges

// NPath 1 function badges_good(o: Order) -> string[] { Badge { name: "paid", on: o.paid }, Badge { name: "in stock", on: o.in_stock }, Badge { name: "express", on: o.express }, .filter((b) -> { b.on }) .map((b) -> { b.name })

嵌套深度

// Nesting 3 function fragile_bad(carts: Cart[]) -> string[] { let names: string[] = []; for (let cart in carts) { for (let item in cart.items) {

(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →