[控场AI]
· 8 分钟阅读· 4,244 字

元能力:让代码替大模型思考——CodeSmith的RLM设计解析

元能力:让代码替大模型思考——CodeSmith的RLM设计解析

CodeSmith RLM通过让LLM写代码、交解释器执行,从架构上弥补大模型概率推理无法精确计算的天生缺陷。

大语言模型因概率性推理机制在精确计算和严格逻辑上天生孱弱,开源项目 CodeSmith 的 RLM(递归语言模型)以"LLM 作翻译、解释器作计算器"为核心原则,将这一分工写进系统 Prompt 合约:模型只接收文档的元数据句柄而非原文,所有精确操作(切片、搜索、计数)一律通过 Python REPL 执行,语义判断才由模型或子 LLM 处理。"每轮只输出一个 repl 代码块"的强制约定,把"用代码思考"从建议变成了硬协议。与此同时,系统通过超时、输出截断、子调用模型锁定和递归深度封顶等枷锁约束元能力的潜在破坏力——这是 CodeSmith 一贯"不信任"设计哲学在推理层的落地。

大语言模型能写诗、能对话,却常常在一道简单的算术题上翻车。这不是模型"笨",而是它工作方式的天性使然。开源项目 CodeSmith(v0.5.0)的 RLM(Recursive Language Model,递归语言模型)设计给出的答案是:别让模型自己算,让它写代码,交给解释器去算。这篇文章基于 CodeSmith 作者的技术拆解,剖析"让代码替模型思考"背后的工程逻辑。

什么是"元能力"

普通能力是 Agent 能做某件具体的事:回答问题、调用某个 API、生成一段文本。而元能力(Meta-Ability)是"能创造其他能力的能力"——有了它,Agent 可以当场写出新工具、新约束、新表达形式来完成任务,而不必把每种能力都预先封装好。

代码生成恰恰是这样一种元能力:精确、可执行、可组合。它可以产出新工具(脚本、探针、API 调用序列)、新约束(断言、校验规则)和新的表达形式。按作者的梳理,这种能力从内到外至少能作用于六个方向:思维本身、业务规则、内容呈现、系统接口、用户界面,以及 Agent 自身。

CodeSmith Meta-Ability: Let Code Think for the Model

本文聚焦最内层的"思维"方向:为什么"让模型写代码"不是画蛇添足,而是对模型思考方式根本缺陷的一次打补丁。

概率大脑算不好确定性的数

LLM 在自然语言理解与生成上表现惊艳,但在精确算术、符号运算和严格逻辑推导上却天生孱弱。原因一句话就能说清:模型是概率性、近似性地思考,而数学和逻辑要求确定、精确的答案。

作者给了一个直观对比。题目是:一个班 40 人,60% 学数学,45% 学物理,25% 两门都学,问只学物理不学数学的有多少人?

自然语言推理很容易这样走:60% 数学 = 24 人,45% 物理 = 18 人,25% 都学 = 10 人,于是"物理 only = 24 - 10 = 14"——它从数学人数里减,答错了。而代码推理则严丝合缝:phys = int(40*0.45) 得 18,both = int(40*0.25) 得 10,only_phys = phys - both 得 8,正确。

左边不是模型"犯傻",而是它的原生工作模式:每一步推理都是从概率分布中采样,多步串联后误差会滚雪球式放大。右边则没有这个问题——代码要么跑对要么报错,不存在"大致正确"。

这个思路并非 Agent 时代才有。Mathematica 创始人 Stephen Wolfram 早就指出:符号计算系统精确,却听不懂人话,Wolfram Alpha 依赖内置语法解析器,题目措辞稍变就解析失败。LLM 恰好补上这个洞,又把自己在计算上的短板暴露出来。于是协作范式定型为:LLM 当翻译官,解释器当计算器——永远别让翻译官去做算术。

User's natural language ──LLM──▶ formal expression (code) ──interpreter──▶ exact result
(模糊、开放)                   (结构清晰、无歧义)              (确定)

Stephen Wolfram 提到的这套协作范式,在学术界有一个更正式的名字:工具增强型语言模型(Tool-Augmented LLM)。早期代表工作包括 Google 的 Toolformer(2023)和 Meta 的 PAL(Program-Aided Language Models),后者与 RLM 思路高度相似:让模型生成 Python 程序,再由解释器执行得出答案,而非让模型直接输出数字。PAL 在 GSM8K(小学数学题基准)上的准确率比纯文字链式推理(Chain-of-Thought)高出约 10-15 个百分点,印证了"翻译官不做算术"的有效性。这类方法的核心假设是:LLM 的优势在于将自然语言意图映射为结构化操作序列,而非执行操作本身——这与人类使用计算器的直觉完全一致。

回到代码:RLM 的 Prompt 把这句话写成合约

带着这个视角重读 crates/agent-runtime/src/rlm/prompt.rs 里的 RLM 系统提示,会发现它正是上述分工原则的工程化落地。开篇就定了规矩(prompt.rs:14):模型是递归语言模型的根节点,输入被加载进一个长期运行的 Python REPL,模型拿到的是"实时上下文句柄,而非原始内容"——只能通过受限的辅助函数读取,用 Python 做计算,把语义判断委派给子调用。

翻译过来就是三句话:模型不能直接看原始素材,只拿到一个 live handle;切片、搜索、计数这类精确活一律写 Python 来做;而"这段代码意味着什么、该不该改"这类语义判断,才交给模型和子 LLM。

模块头部注释(rlm/mod.rs:15-18)把不变量定得更严:输入 P 永远只作为 REPL 变量(context/ctx)存在,绝不出现在根 LLM 的窗口里;根 LLM 只收到小体量的元数据消息——长度、预览、辅助函数列表、上一轮摘要。这正是 VarHandle"虚拟内存"思路(CodeSmith 系列第 8 篇)在推理场景的复刻。

Prompt 下挂的几个 REPL 辅助函数把"翻译/计算"分工落到了实处:context_meta() 返回受限元数据;peek(start, end) 按偏移取有界切片;search(pattern, max_hits=100) 是带命中上限的正则搜索;sub_query(prompt, slice) 把语义判断委派给子 LLM,还能把范围限定在单个切片。

最关键的是那条合约条款(原文照录):

Contract: every turn, output exactly one repl block of Python and nothing else. No prose-only turns.

每一轮只输出一个 repl 代码块,不许光说不做。"接下来我要数一下……"这种话被明文禁止——想说,就把数的代码写出来。这就把"让代码替模型思考"从口号变成了协议。

REPL(Read-Eval-Print Loop,读取-求值-输出循环)是一种交互式编程环境,代码被逐块提交、立即执行并返回结果,变量状态在多轮交互中持续保留。Python 的 REPL 环境(如 IPython、Jupyter Kernel)因此天然适合作为 Agent 的"工作内存":上一轮计算出的中间变量可以在下一轮直接引用,无需重新传递。RLM 把输入文档以 context 变量的形式注入 REPL,而非拼入对话文本,正是利用了这一特性——文档内容作为 Python 对象活在解释器的堆里,模型只拿到元数据句柄,实际的字节搬运和模式匹配全部通过执行代码完成。这一设计同时解决了长文本塞满上下文窗口的问题:模型看到的永远是轻量的元数据,重量级内容按需通过 peek() 或 search() 取回。

枷锁要先于能力到位

有个细节必须老实交代:RLM 的 Python 子进程是个普通子进程,并不经过操作系统级沙箱。Seatbelt/bwrap 那套机制只覆盖 shell 命令,repl/runtime.rs 直接拉起 PATH 上找到的 python。它的笼子是另一种:有界退出(stdout 超过 1000 字符就转为句柄)、子调用被钉死在 Flash 模型(模型参数被没收)、嵌套深度封顶。

预算也由实打实的数字看守:rlm/bridge.rs 里每个子调用有 120 秒超时(CHILD_TIMEOUT_SECS)、默认 max_tokens 4096、单次 RPC 批次最多 16 个 prompt(MAX_BATCH);递归深度由 depth_remaining 计数,耗尽后降级为普通 LLM 补全。翻译官可以层层委派给翻译官,但每一层都有一个时钟和一个钱包。

元能力放大的不只是能力,还有破坏力,所以枷锁必须先于能力到位——哪怕这个枷锁不是沙箱,而是一纸关于退出口和子调用的合约。这正是 CodeSmith 系列贯穿始终的"不信任"主线:我们敢给模型写代码的权力,恰恰是因为每一层的出口都被围了起来。

文中提到的 Seatbelt 和 bwrap 是两种操作系统级进程隔离机制:Seatbelt 是 macOS 的沙箱框架,通过内核策略限制进程的文件系统访问、网络调用和系统调用;bwrap(Bubblewrap)则是 Linux 上基于用户命名空间(user namespace)的轻量级容器工具,Flatpak 等应用沙箱底层均依赖它。CodeSmith 选择不对 Python 子进程应用这套机制,意味着它有能力访问宿主文件系统和网络——这是一个有意识的权衡:完整沙箱会带来显著的启动延迟和 I/O 限制,而 RLM 的使用场景(本地开发辅助工具)对性能更敏感。作者用合约式约束(超时、输出截断、模型锁定)替代了硬隔离,这体现了安全设计中"纵深防御"思想的一种轻量化变体——承认边界是软的,但在每一层出口都部署了熔断器。

一个绕不开的权衡

写代码再执行,每一轮的延迟和 token 开销都远高于"想一想"。对简单问题而言,这是杀鸡用牛刀。因此 RLM 被设计成按需开启——只在模型判断确实需要时才启动,而非默认常开。

归纳全文的核心逻辑:模型推理是概率性的,精确计算和严格逻辑是它的软肋;LLM 作翻译、解释器作计算器,神经系统与符号系统天然互补;RLM 把这套分工写进合约,模型只见元数据、所有精确操作都走 Python;"每轮一个 repl 块"的约定把"用代码思考"从建议变成协议;而递归有预算、能力有牢笼。

代码不仅是解题工具,也是约束行为的守门员——这是元能力的另一张面孔。

#元能力#RLM递归语言模型#CodeSmith#LLM代码推理#大模型Agent#AI工具调用#符号计算
分享:

相关推荐