借助智能Rust框架,让预算模型发挥超常表现

Lobsters Hottest 工具

摘要

Dirge是一个基于Rust的代理框架,通过减少内存占用并智能管理错误、上下文和工具调用,帮助较小的人工智能模型发挥超常表现,缩小与前沿模型的性能差距。

<p><a href="https://lobste.rs/s/goo5sh/making_budget_models_punch_above_their">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/06/17 15:52

# 借助智能Rust框架,让预算模型超常发挥 来源:https://yogthos.net/posts/2026-06-08-dirge-code.html Dirge (https://dirge-code.github.io/) 是一个我为自己开发的智能代理框架,如今它已逐渐成熟到可以普遍使用。在这篇文章中,我将探讨其背后的设计理念,以及它相较于同类工具的一些有趣特性。 首先值得关注的是它的性能和内存占用。大多数现有的编码工具(如 OpenCode)相当消耗内存,即使空闲时也常常占用约 300 MB 的 RAM。有些工具(如 Claude Code)甚至在打字时也会出现卡顿。Dirge 采用 Rust 编写,编译后生成一个小巧快速的二进制文件,大小仅约 30 MB。Dirge 启动后空闲时只需约 8 MB 内存,执行任务时也仅上升到约 15 MB。也就是说,运行二十个 Dirge 实例的费用只相当于一个 OpenCode 实例。 然而,轻量并非主要卖点,市面上也有其他基于 Rust 的框架可供选择。Dirge 真正有趣的地方在于它如何支持能力较弱的模型,让它们发挥出最大潜力。传统观点认为,智能存在于模型本身,框架只是最基本的管道。它的唯一任务是给模型一个工具循环和系统提示,然后退居一旁。按照这种观点,获得更好的代理只能靠更大的——通常也更贵的——模型。 在大量使用 DeepSeek 和 Qwen 这类模型进行代理编码后,我改变了看法。事实证明,代理在实践中是否高效,很大程度上取决于框架能否满足模型的期望。模型通常知道自己想要什么,并能找出实现路径和所需动作。真正让一种设置显得前沿、另一种令人沮丧的,是围绕模型的一切。框架需要在模型行动前进行引导,纠正机械性错误,并向模型精确说明错误所在。它还应记住每次尝试中学到的经验,并智能管理上下文。前沿实验室将这些能力大量融入后期训练,并调整自己的框架以适配其特定模型的优缺点。Dirge 虽无法改变模型的训练方式,但可以通过契合模型的实际能力来缩小性能差距。一旦在框架能力上投入一些工作,一个廉价的开源模型就能表现得像成本高得多的模型。 性能差距体现在三个不同的时间尺度上,Dirge 在这些方面都做了投入。每当模型进行一次工具调用,要么成功要么失败。可能是调用格式错误,可能是编辑文件时引入了语法错误,也可能是卡在反复重试同一个失败的命令上。每一步失败都会消耗时间和 token 却无助于任务推进,这些失败迅速累积,用噪声填满上下文窗口,导致模型丢失工作主线。会话运行越久,模型遵循指令的能力就越差,因为窗口接近极限时,早期的指令和修正会被截断或遗忘。于是模型继续重复错误或忽略早期上下文。跨会话的情况更糟,每次新代理启动时对之前发生的事一无所知。模型不记得任何过去的决策、文件结构或你已经解决的问题。每个会话都必须从头重建对代码库的理解。 让我们看看 Dirge 如何处理这些问题的各个环节。这些策略按一定顺序排列,彼此关联,共同构成完整流程。正如常见的情况,整体效果大于各部分之和。 ## Dirge 的工作原理 Dirge 本质上是一个围绕模型构建的状态机。它定义了一系列步骤,每一步包括:运行模型、分类回复、验证并执行任何工具调用,最后在允许模型停止前确认任务确实完成。这个循环本身是核心管道。让它真正成为能力倍增器的是包裹在其外的三层机制,每层对应我们刚才讨论的一个时间尺度。 一个“引导与修复”层确保每一步都落地。一个“长期视野”层确保会话内连续性,尽管上下文窗口大小有限。一个“学习”层将在会话间获得来之不易的知识传递下去,这些知识存储在与项目关联的 SQLite 数据库中。之上是一个插件系统,允许你深入代理循环的任何部分。我们按顺序来看这些功能。 ## 确保每一步落地 你可能听说过开源模型不擅长工具调用,必须为顶级模型付费,这些模型经过 API 合约训练才能获得可靠结果。所有工具调用都要求模型输出特定格式的结构化数据(如 JSON)。前沿模型(如 Claude)直接通过数千个 API 合约训练,使其输出符合函数签名和参数规则。开源模型通常针对通用文本生成训练,而非结构化输出任务,因此难以产生如此精确的输出。但这正是框架可以通过解析、格式化和验证模型输出来缩小差距的关键领域。 首先可以调整的是引导本身。Dirge 包含一组基于现有文献已知有效的指令。这些指令被嵌入系统提示和循环中,促使模型通过对照明确的“完成定义”来自我检查完成的任务,从而培养自律。系统还提示模型在行动前先规划,对于较长任务,会维护简短的进度记录,帮助模型追踪进度。在每个任务开始时,Dirge 会提取几个相关的工具调用示例(通过词匹配找到)并添加到提示之前。上下文中的示例对较弱模型至关重要,因为它们提供了具体模式供模型模仿。在此基础上,模型感知的引导会根据运行的模型调整指导内容。框架特别为 DeepSeek 准备了特殊片段,处理其过度解释或特殊格式要求等怪癖。 精细引导可以减少失败比例,但无法完全防止失败。少量糟糕的工具调用构成了“这个模型不会用工具”抱怨的主要来源。比如某个本应缺失字段的位置出现了 `null`,或者 JSON 数组以字符串形式传入。Dirge 首先尝试原样输入,然后仅纠正模式拒绝的部分,这样有效输入永远不会被重写。这种设计避免了简陋的“先预处理再验证”方法中常见的静默破坏陷阱——重写正确输入会破坏它。Dirge 自动展平模型处理不佳的嵌套工具模式。它还能从模型推理文本中提到但未放入结构化字段的工具调用中“打捞”出来,将其从周围散文中提取出来。 对于编辑操作,Dirge 使用 **tree-sitter** 在 `write`、`edit` 或 `apply_patch` 触及磁盘之前解析并检查语法。该工具将代码解析为抽象语法树,然后对照该语言的形式语法进行检查。语法错误的代码会被拒绝,并附带指向确切行和列的错误信息。丢失的记号会直接从语法中命名,例如“缺少 `;`”。对于大括号和 Lisp 语言,一个能理解注释、字符串和字符字面量的平衡检查器会指出未闭合括号的位置,并尝试自动修复。在能够机械确定具体错误的情况下,没有理由保存有问题的代码,让它三步之后出问题。 有些问题无法通过这类机制解决,因为它们出现在单个查询范围之外。例如,弱模型常常反复尝试相同操作。一个“断路器”会阻止这个过程,强制进入“反思-转向”步骤,让模型重新考虑自己正在做什么,指出导致失败的根本错误信念,并建议尝试其他方法。另一个元认知监控器会追踪一系列不同的失败;达到一定次数后,它会指出最近失败中的共同元素,让模型指出导致失败的单一错误信念。会话内记忆会保存已放弃的方法,防止模型在未来悄悄走入同一条死胡同。当修复失败或写入前语法检查失败时,流程也可以升级到更强的模型,后者再将控制权交还给便宜的模型。 最后,循环不会仅凭模型说“完成”就结束。一个“终前门控”会检查代码是否被修改,以及构建或测试是否运行并通过。如果没有,它会注入一个温和的提示,促使模型实际完成指定任务。当你设置了 `critic_provider`,实质性运行会升级到一个有界的第二意见。这个评判者会问:“这真的完整且正确吗?”如果不是,运行会返回循环继续工作。对于无头运行,你可以给代理一个明确的 `--goal`,比如“所有测试通过且更改已提交”。一个独立的评判者会保持运行直到目标达成或尝试次数耗尽。这与双模型设置(如 DeepSeek Pro 和 DeepSeek Flash)配合得很好,能力强模型做实际工作,便宜快速的模型评判进度状态。 尽管这些功能单独看来可能并不显眼,但它们共同解决了大量机械噪声问题,比如错误引导的调用、中断的编辑和重试循环。这些常见问题否则会消耗上下文,将模型拖入负反馈循环,明显降低其性能。每个功能处理一类特定的失败:格式错误的调用引入垃圾数据、中断的编辑破坏状态、重试循环倍增错误。它们共同防止这些失败不断累积并失控。没有这些轨道,模型会丢失清晰的上下文,开始产生越来越差的输出,导致更多失败,进而陷入恶性螺旋。 ## 在长任务中保持主线 引导和纠正每一步有助于维持单个任务的存活。但实际工作跨越多个步骤,这意味着上下文窗口最终会被填满。处理这个问题最明显的方法——在会话过长时进行总结——在实践中效果并不好。在容量边界附近的单一总结往往会丢失重要信息。更糟的是,模型恰好在压缩能力最差的时候进行总结。 Dirge 的长期架构灵感来源于 MiMo-Code (https://github.com/XiaomiMiMo/MiMo-Code),当对话过长时,它会把旧历史折叠成结构化摘要。然后这个摘要被视为一个永久会话检查点。每个对话被分配一个稳定的 ID,即使在内部旋转折叠期间也保持不变。检查点将最新摘要与原始请求配对,创建一个一次写入的锚点,防止模型反复重新总结主体时发生目标漂移。 两个机制确保这个系统在长会话中平稳运行。首先,检查点在后台以固定间隔逐步更新自身,始终保持在上下文窗口内。这个过程确保折叠发生在模型仍能有效总结的时刻,避免紧急压缩。其次,恢复功能实际上精确地从用户离开处恢复,因为 Dirge 会映射任何 ID 到其链条的活末端。 最终结果是,长时间运行的任务保持在轨道上。模型始终针对最新、锚定意图的状态图进行工作,而不是一个退化的转录。 ## 一个学习你项目的代理 第三个时间维度是现代代理最令人烦恼的地方。由于没有记忆,每个会话都从零开始。全新的代理不会记得你的项目使用 `eslint-config-custom`,或者集成测试 mock 服务器需要用 `--feature=test-utils` 启动。它也不知道你上周花了 45 分钟修复认证中间件中的竞态条件。这种失忆行为意味着每次会话开始时都必须重建上下文和指令。 Dirge 通过为每个项目构建一个主动学习系统来解决这个问题,借鉴了 Hermes Agent (https://hermes-agent.nousresearch.com/) 的记忆架构并适配到编码场景。一个记忆存储收集关于项目的事实:包括构建命令、编码约定、库的怪癖等。存储还记录编码会话中出现的错误日志,跟踪哪些方法尝试过但无效。这是一个技能系统,为这个代码库中的特定任务类型获取专门知识。当会话结束时,一个后台进程派生代理,只保留其记忆和技能工具。然后该进程查询代理学到了什么。这些发现随后被保存到存储中,不会干扰你的会话。一个策展代理负责保持知识库健康:合并重叠条目,归档陈旧条目。此外,还有一个跨项目的全局层。比如你总是想要 TDD,或者提交信息要简洁;这些指令会进入该层,与项目特定事实分开。 大多数代理严重依赖 `MEMORY.md` 这样的 Markdown 文件,代理将其读入上下文并在会话运行期间编辑。这是一个脆弱的过程,因为这些文件会迅速膨胀到失控;每个字节都随提示一起加载,无论是否相关,而且代理无法有效搜索它们。此外,这些文件很容易与项目的实际状态不同步,最终包含误导性信息,轻易将代理引向错误方向。Dirge 采用每个项目一个 SQLite 数据库的方法,存储记忆、技能元数据、完整会话历史以及长期检查点。 记忆形成由两层注入系统处理。首先,高相关性的热点条目直接放入系统提示。一旦内联空间用完,剩余条目降级为一行面包屑索引,代理需要时可查找。这种方法使提示保持小巧且稳定在缓存中,无论项目增长多大。由于有数据库支持,SQLite FTS5 引擎支持全文搜索,取代了 Markdown 文件的处理。代理现在可以询问自己的历史,而不是通读一墙 Markdown 文本。每个条目还有一个显著性分数:使用条目会提升其显著性,不使用时下降。当空间不足时,最不用的条目最终会从数据库中修剪。删除条目会创建一个“墓碑”,因此如果有需要,任何归档材料都可以复活。于是,你

相似文章

@AlphaSignalAI: https://x.com/AlphaSignalAI/status/2074130508833845396

X AI KOLs Timeline

自我改进的机制使AI代理能够通过分析执行轨迹自主重写其运行规则,从而实现60%的性能提升。来自上海AI实验室的研究引入了Self-Harness框架,使得轻量级模型能够在无需人工工程的情况下超越更大规模的模型。

用Rust重写Bun

Simon Willison's Blog

Jarred Sumner详细介绍了使用AI将Bun从Zig重写为Rust的过程,花费了16.5万美元的token,并使启动速度提高了10%。

从模型扩展到系统扩展:在自主AI中扩展架构框架

Hugging Face Daily Papers

本文认为,推进自主AI需要扩展围绕基础模型的系统架构,重点关注可审计、模块化和可验证的组件。作者介绍了参考架构框架CheetahClaws,并概述了上下文管理、可信内存和动态技能路由方面的瓶颈。