前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
返回 AI 情报前线
All News · 全部资讯8485
  • 多Agent并行开发的Worktree陷阱
  • 40 行实现类型安全的工具调用
  • RAG 排序不能只靠余弦相似度
  • 生产级 Prompt 的七类隐蔽问题
  • 让 RAG 拒绝使用劣质上下文
  • TypeScript Agent 的四层注入防线
  • 用 LangGraph.js 实现持久化人工审批
  • Node应用如何精确核算LLM成本
  • Token防火墙削减35%上下文成本
  • Qwen3.8 Max性能追近Opus
  • 伪造审查备注绕过AI反诈检测
  • 用 MCP 为纯文本编程智能体补上视觉
  • Cloudflare推出网站智能体就绪度指标
  • Cloudflare构建开放智能体互联网协议
  • Cloudflare推出私有数据AI搜索
  • 一键为现有网站接入WebMCP
  • Kitesurf:运行在Workers上的智能体浏览器
  • 新版MCP转向无状态架构
  • 让过期的 Agent 上下文直接阻断 CI
  • 昇腾适配 Ling-3.0 并推出 PyPTO
  • 让编程 Agent 用你熟悉的语言写脚本
  • 数据库索引提速背后的写入代价
  • Meta低价模型与可恢复编程Agent登场
  • 如何构建 Agent 难以作弊的评测
  • Claude Code 迁移 OpenCode 踩坑实录
  • RAG向量数据库的真实成本陷阱
  • 编码代理缺失的其实是产品定义
  • 用熔断机制约束失控的 AI Agent
  • 别让 AI 任务止步于聊天记录
  • 人类审核仍漏掉三分之一智能体威胁
  • OpenAI智能体曾秘密协同攻击
  • AI 工作流为何会在无改动时失效
  • 开源本地化求职管理平台 FitPilot
  • 在一次性沙箱中测试编程 Agent 越界
  • 别把系统提示词写成规则仓库
  • Agent 审批卡的盲签名陷阱
  • 为真实项目编写AGENTS.md的经验
  • 用固定语料阻止AI审查能力回退
  • 为AI代码变更建立分阶段权限门禁
  • 别让LLM评测工具测到自身拥塞
  • AI自动扫描将放大密钥泄露风险
  • GPT-5.6 Sol能力升级并扩大免费开放
  • 人脸识别的94%匹配为何不可信
  • 如何测试具备工具权限的完整Agent链路
  • 多Agent共享状态为何会静默丢失
  • 一次失控编程Agent如何烧掉138美元
  • 一条命令统一九类触觉传感器数据
  • VS Code 1.132强化智能体开发体验
  • 用对话式设计Agent生成流水线契约
  • 精简智能体规则文件的实用原则
  • LLM 评审为何不能替代确定性校验
  • 已加载 51 / 8485
8.0
热点
AI SCORE
编程提效2026-08-06 20:33

让编程 Agent 用你熟悉的语言写脚本

dev.to · AI#Agent#代码审查#Ruby
Editor brief · 编辑速览

文章建议将一次性脚本统一为开发者最熟悉的语言,以便真正审查 Agent 生成的代码,而不是盲目接受结果。作者还尝试量化 Ruby 相比 Python 的 token 节省效果。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

Lucian Ghinda 发表了一篇文章,主张你应该让 coding agent 使用 Ruby 编写那些用完即弃的脚本。下面是他建议你完整粘贴到 Agent 指令文件里的内容:

## Scripts

Write throwaway and utility scripts (data munging, one-off migrations,
file renames, glue code) in Ruby, even in projects written in another
language. If it needs a pipe, a loop, a conditional, or more than one
line, it is a script: write it in Ruby, not Python, Node, or bash.
Single self-contained commands (`grep`, `git status`) are fine as-is.

Use only the Ruby standard library. If a gem would clearly save
significant effort, stop and ask before using it.

Put temporary scripts in a scratch or temp directory, not the repo
root, and delete them when done unless asked to keep them.

当天晚上,我就把它粘贴进了自己的全局 CLAUDE.md。他的论点围绕代码审查展开:他每天都在读 Ruby,所以当 Agent 编写 Ruby 时,他依然能扮演审查者,而不是看着 diff 频频点头。他给出了三个理由,却没有一个与成本有关。于是,我开始寻找他遗漏的那个数字。

“这条规则能否节省 token”,只有与 Agent 在没有它时会写出的代码相比才有意义。所以,我要做的第一件事,就是从全局配置中移除这段规则。一个已经携带这条规则的 Agent,无法告诉你没有它时自己会怎么做。

在没有个人配置干扰的环境中测量 Agent

下面的每一组实验都通过 Claude Opus 5 的 claude --safe-mode 运行。在这种模式下,它不会加载任何 CLAUDE.md、skills、plugins 或 hooks。其中有两组实验故意没有使用这个参数,我会在它们出现时明确说明:这两组用来衡量我自己的配置会怎样影响结果。值得一提的是,即使移除了这条规则,我的全局配置中仍然有一行要求 Agent 编写能够完成任务的最少代码,还有一行要求优先使用 bun 而不是 node。

四项任务,分别对应规则中提到的四类脚本:整理日志、在一棵配置文件目录树中重命名某个 key、重新编号一堆截图,以及把一个 CSV 转换成另一个 CSV。我直接从他的列表中选择任务,而不是自己发明,这样我就无法悄悄挑选更适合 Ruby 的场景。

在看到任何数字之前,有三点实验设置值得说明。这三点都是我做出的选择,也都存在讨论空间:

没有任何一组实验直接粘贴规则原文。每组实验都直接指定一种语言和“只能使用标准库”的约束,因为这才是规则产生的实际效果,而不是规则本身的文字。

bash 组不能使用 jq,因为规则要求只使用标准库,而 jq 需要单独安装。

只有 Ruby 组被明确告知,可以使用它的一种简洁惯用写法。这确实是在给 Ruby 加码,不过在 Ruby 总计 1660 字节的代码中,它大约只影响了 20 字节。

在证明实现等价之前,我不会统计任何内容。每项任务的每个实现都会与一个参考实现进行对比,必须在 stdout 上输出完全相同的字节,并且对其留下的每一个文件产生完全相同的摘要。比较功能不同的程序长度毫无意义,因此必须先通过下面这道检查:

ruby src/run.rb text
  t1_logs     count requests and errors per path in an access log    53 impls  identical
  t2_config   rename one key across a tree of .env files, decoy key left alone 53 impls  identical
  t3_rename   renumber screenshot-N.png to zero-padded shot-NNNN.png 53 impls  identical
  t4_csv      filter a CSV to rows with stock, compute totals, write a CSV 53 impls  identical

EQUIVALENT: every implementation matches one reference (stdout + output tree)

基线:它会写 Python

十次运行,使用相同的四份任务说明,且任何地方都没有指定语言。其中五次在无配置干扰的环境中运行,另五次则在移除规则后、加载我的真实配置运行。

这份 prompt 并不是盲测,我应该说清楚。它要求 Agent 用一句话解释自己为何选择这门语言,这等于告诉 Agent:有人正在观察它的选择。下一步,我会再做一个盲测版本。

十次运行全部选择了 Python。

没有一次选择 Ruby、bash 或 JavaScript。Agent 给出的理由都与标准库有关:Python 几乎随处都预装了,而且无须依赖就能处理行终止符保留和定点小数格式化。因此,这条规则并不是让 Agent 在 Ruby 与某个抽象的候选集合之间做选择。它每次取代的都是 Python。

其中五次运行加载了我的配置,却依然选择了 Python。只有在能够证明配置确实加载的情况下,这件事才值得报告。事实也确实如此:直接询问处于这种状态的 session,它会向我复述 CLAUDE.md 中的内容;而且如下所示,同一套配置会让代码字节数最多变化 59%。配置已经被读取了。只不过在移除那条规则之后,它对于语言选择没有任何剩余意见。

于是,成本问题变得具体,而答案有着压倒性的差距:

Ruby 是四种语言中代码最短的;在无配置干扰的环境里,为实现相同且经过验证的行为,Agent 生成的 Python 源码长度超过 Ruby 的两倍。

这个数字取决于实验条件,而我自己的环境给出的结果就没这么漂亮了。加载我的真实配置重新运行后,Python 相对 Ruby 的长度优势从多出 120% 降到了多出 18%。这条规则能为你带来多少收益,取决于还有哪些因素正在塑造 Agent 编写代码的方式。

两行数据都是五次运行对一次运行,并使用相同方法测量。无配置干扰的那一行隔离出了规则本身的影响。如果你的 Agent 配置过任何内容,那么底部那一行才更接近你的实际处境,也是我在制定计划时会参考的数字。

计数器会忽略注释和空行,但保留 import,因为必须导入模块确实是这门语言的真实成本。它也保留 Python docstring;这一点对 Python 不利,因为如果 Agent 使用的是 # 注释,就不会被计入。这些 docstring 占无配置干扰环境下 Python 总量的 8%;移除它们之后,Python 不再比 Ruby 大 120%,而是大 101%。

而且,这个差距并不全是 Ruby 带来的。120% 中的大部分并非来自语言本身,而是 Agent 包裹在代码周围的东西:docstring、main()、if __name__ guard,以及行终止符处理。阻止这些习惯之后,Python 相对 Ruby 的差距会降到 18%,接近我手写两种版本时得到的 36%。

这种差异看起来是什么样子

以其中一项任务——配置迁移——为例,下面是中性 prompt 生成的结果。先看 Ruby:

root = ARGV[0]

Dir.glob(File.join(root, "conf", "*.env")).sort.each do |path|
  content = File.read(path)
  renamed = 0

  rewritten = content.lines.map do |line|
    if line.start_with?("CACHE_TTL=")
      renamed += 1
      "TTL_SECONDS=" + line[("CACHE_TTL=".length)..]
    else
      line
    end
  end.join

  File.write(path, rewritten) if renamed > 0
  puts [File.basename(path), renamed].join("\t")
end

这就是完整程序。读一遍,你就知道它是正确的。

Python 对同一项任务的实现有 38 行。下面是它的中间部分,也就是实际执行工作的循环:

        renamed = 0
        lines = text.splitlines(keepends=True)
        for i, line in enumerate(lines):
            body = line.rstrip("\r\n")
            ending = line[len(body):]
            key, sep, value = body.partition("=")
            if sep and key == OLD_KEY:
                lines[i] = NEW_KEY + "=" + value + ending
                renamed += 1

text 是文件内容;OLD_KEY 和 NEW_KEY 是两个 key 的名称,定义在文件顶部。这段循环与 Ruby 版本完成的是同一件事,只是额外加入了手动处理行终止符的逻辑,外面还包着一个带 docstring 的 main()、四个 import 和一个 if __name__ guard。这些都不是糟糕的 Python。只是代码更多,而统计结果也证明了这一点。

Ruby 赢下了两项与阅读成本相关的指标,但在最长行指标上输给了 bash。我是在运行实验之前就选定这四项指标的,并且无论结果如何都会全部报告,因为没有公认的方法可以衡量可读性,而事后才选择指标,衡量的其实是作者自己。

bash 只有在你要求它简短时,看起来才便宜

在没有特别要求的情况下,Agent 会编写谨慎的 bash:使用 shopt -s nullglob、显式排序、为每个输入创建临时文件,还会检查原文件是否以换行符结尾,以便在输出时恢复。这些代码总计 2333 字节,比 Ruby 长 41%。

于是,我第二次运行了中性 prompt,只改变了一件事:关闭 --safe-mode,让系统加载我的真实配置,而不是使用无配置干扰环境。prompt 相同、任务说明相同、fixture 也相同。

每种语言的代码都缩短了,胜者也发生了变化。在无配置干扰的环境中,Ruby 最短;加载我的配置后,bash 比 Ruby 短 31%,得出了那个整洁的“直接用 bash”结论——而这个结果完全是由我自己的环境产生的。

我无法把这种变化归因于某一句配置,也不应该尝试这么做。关闭 --safe-mode 会同时恢复我的 CLAUDE.md、skills、hooks 和 plugins,其中一个 plugin 注入了一种围绕“编写能工作的最短代码”构建的 persona。那一行数据最诚实的标签应该是“我平时运行的所有东西”。

两个数字都是真实的。它们回答的是不同的问题,而其中只有一个是我最初提出的问题。

多短的指令能换来简短代码

如果一行配置就能让数字发生如此大的变化,那么能够有意促成这种变化的最便宜指令是什么?我做了一组阶梯实验:相同的任务说明、相同的无配置干扰环境,每个阶梯上的每种语言分别运行一个 Agent,唯一变化的是指令。

两个单词就能拿到总计 69 个百分点中的 64 个。之后增加的 34 个单词只换来了剩余 5 个百分点,而在每个单元格只运行一次的情况下,这完全落在噪声范围内:相邻阶梯中,每种语言的结果波动最高可达 11%,而两个单词的阶梯已经胜过了三个单词的阶梯。

单词本身远比单词数量重要。"Be terse." 和 "Golf it." 都只有两个单词,但 "Golf it." 生成的代码整体少了 39%,并且在四种语言中都更短。"Golf" 是一个专业术语,它会带入 "code golf" 这个词组蕴含的一切。"Terse" 只是在礼貌地提出要求。

如果你想让 Agent 编写紧凑的代码,整个 prompt 只需要一句 "Golf it."。

简短代码的代价

下面再次展示同一个配置迁移任务,这次是阶梯最底端的版本:

Dir[ARGV[0]+"/conf/*.env"].sort.each{n=0;File.write(it,File.read(it).gsub(/^CACHE_TTL=/){n+=1;"TTL_SECONDS="});puts [File.basename(it),n]*"\t"}

一行,144 字节,而之前是 409 字节;它也通过了同样的逐字节检查。

其中有三处需要解释:

it 是 Ruby 的隐式 block 参数,因此每个 it 都代表当前文件名。它需要 Ruby 3.4 或更高版本。在任何更早的版本中,这一行都会直接报错,而不只是难以阅读。

gsub block 会在统计匹配次数的同时返回替换内容,因此 n 会在构建新文本的过程中作为副作用递增。

[File.basename(it),n]*"\t" 表示使用制表符连接数组,因为对数组使用 * 就是 join。

即便这是我自己的语言,我也不得不看上两遍。

代码行数急剧减少,但每一行本身却变得更糟。Ruby 的最长行从 80 个字符增加到 151 个,JavaScript 从 73 个增加到 199 个;标点符号在非空白字符中的占比也从 24% 上升到 37%。你买到的并不是紧凑的代码,而是高密度代码;你付出的代价,恰恰是当初采用这条规则所看重的东西。

接下来,我让全部 152 个实现处理一个目录名中包含空格的路径,其中包括六个阶梯,以及作为对照组的手写实现。有一个阶梯失败了,而且正是最昂贵的那个:在 36 个单词的指令下编写的四个 bash 脚本全部失败,而更短阶梯中的所有 bash 脚本都正常运行。

awk '{e[$7]+=$9>=400;t[$7]++}END{for(p in t)print p"\t"e[p]"\t"t[p]}' $1/logs/access.log|LC_ALL=C sort -t$'\t' -k2,2nr -k1,1

这里的 $1 没有加引号。其中三个脚本仍然以状态码 0 退出,因为失败的 awk 通过管道传给 sort 后,最终报告的是 sort 的退出状态。这三个脚本中,有两个完全不输出内容,第三个输出 -1。错误确实会到达 stderr,因此盯着终端的人能够看到它。任何只检查退出状态的东西都看不到。

所以,指令中最后增加的 34 个单词换来了 5 个百分点的长度优势,却破坏了它们接触到的每一个 bash 脚本。"Golf it." 本身则没有造成这种问题。

这里的长度单位是字节。我没有对这些代码集运行 tokenizer,因此本文中的每个百分比都是字节百分比;它与 token 账单的接近程度,只是一个尚未经过验证的假设。

每个阶梯上的每种语言都只运行了一个 Agent。四种语言、六个阶梯呈现出的方向是一致的,但具体百分比并不可靠。

四项任务取自原文列出的四种类别,因此我无法挑选有利于自己的场景,但终究也只有四项。

十次运行足以说明这里的默认选择是 Python,却不足以量化它究竟有多大概率选择 Python。

无配置干扰环境移除的是配置,而不是模型本身的先验倾向。"No config" 是我能达到的最诚实下限,却不是一个中立宇宙;换一个模型,完全可能默认选择别的语言。

包含空格的路径故障,只是在一台机器上的一个棘手路径。它展示了这种故障模式,却不能给出可迁移到其他场景的故障率。

我真正会给你的建议

保留这条规则。仅从成本角度看,它也能胜出,尽管这并不是原作者提出它的理由:相较于你什么都不说时 Agent 会选择的 Python,在有配置的环境中,它能让源代码减少约三分之一;在裸环境中,则能减少一半。

不要改用“写得更简短”之类的指令。它们确实比这条规则减少了更多代码,但它们买到的是密度,而不是简洁:在一门并非由你选择的语言中,得到更少、却无人能读懂的代码。沿着这条阶梯推得足够远之后,四个 bash 脚本都因为路径中存在空格而失败了,尽管 "Golf it." 本身并没有导致失败。

有三种情况应该覆盖这条规则。第一,所需的库只存在于其他语言中——这也是 Ghinda 自己提出的例外。第二,脚本必须在没有安装 Ruby 的环境中运行——基线实验中的 Agent 之所以选择 Python,正是因为它几乎随处都预装了。第三,任务确实只需要一条诚实的 shell 命令,而规则本身已经对此做出了豁免。

Ghinda 自己给出的理由依然更好,而且本文中的任何表格都无法对此做出定论。可审查性取决于阅读代码的人。对于一个完全看不懂 Ruby 的人来说,上述数字依然成立,但对他而言,上面的每一行数据都失去了意义。

还有一点不只适用于 Ruby:仅仅取决于是否加载了我自己的配置,本文中的每个数字都会发生变化,其中两个结果甚至出现了逆转。如果你要对 Agent 进行 benchmark,请先移除自己的配置,否则你测量的其实是配置。

如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。

Original source

本文由 AI 翻译整理自 dev.to · AI,原文版权归原作者所有。

阅读英文原文
上一篇
昇腾适配 Ling-3.0 并推出 PyPTO
下一篇
数据库索引提速背后的写入代价