AREX Feed Article
MiniMax Code 开源次日,研发负责人长文拆解 agent harness:能力租用、上下文预算公式与多代理确认语义
北京时间 9 月 19 日 20 时 52 分,MiniMax Code 研发负责人 Ronny He(@Ronny_MiniMax)在 X 发布长文《》,逐层披露了 9 月 18 日以 MIT 许可开源的 MiniMax Code 命令行工具(CLI)v0.4.12 背后 agent harness(承载模型循环与工具执行的宿主框架)的实现细节:能力按插件修订版本在同步临界区内租用快照,MCP(Model Context Protocol,模型上下文协议)工具按窗口 15% 的阈值延迟披露,上下文输入预算与压缩阈值由具体公式算出,工具结果按固定顺序提交进规范历史,多代理后台任务的结果要等父 Turn 提交完成后才确认消费()。
此前一天(9 月 18 日)的发布公告给出的是发布细节与公司自报的评测数字;这篇长文转到实现层面。开源代码位于 GitHub 仓库 。
三个入口共用一条进程内运行时
文章从两个问题开始:如果一个工具改完文件、进程却在结果写入历史之前退出,恢复的会话会知道什么?如果模型已经读过某个工具的描述、插件偏在此时更新,该执行哪一个版本?He 把这两个问题还原为运行时状态与操作顺序的问题,再从任务入口讲起。
MiniMax Code 有三个入口:交互式 mcode、面向脚本的 mcode exec、对接兼容客户端的 mcode acp(GitHub 仓库的说明与此一致)。三者共用同一条经 CliService 与本地应用的进程内运行时:启动时 createEmbeddedRuntimeHost() 创建本地主机、等待就绪并取得 CliService,这条路径不依赖桌面端 HTTP 服务,模型请求与部分工具仍可访问远程服务。
Session 保存需要跨回合存活的状态——对话历史、会话配置、任务关系;执行被接纳时,运行时创建一个带独立标识、取消信号与终态的 Turn,模型请求和工具步骤都在这个 Turn 里进行。LocalAgentHost 负责协调:准备环境、经 agent-runtime 组装能力,再把模型与工具循环交给使用内置 Pi 组件的 PiTurnRunner;历史存储与恢复由 Session 系统负责。循环的每次迭代里,运行时准备模型请求;模型提出调用工具,运行时检查并执行调用,再把结果提交进历史供后续请求使用——搜索结果、文件内容、测试输出就这样逐步进入上下文。一个 Turn 可以包含多次模型请求,一个 Session 可以跨越多个 Turn;runTurn() 每次都新建 Agent、事件桥、事件队列和历史游标,可变的执行对象属于当前 Turn,后续回合要用的信息放进会话层。
能力按修订版本租用,插件更新换不掉已读的工具描述
第一道约束在能力组装阶段。扩展 Registry 的正常流转是 new → initializing → ready,初始化出错则进入 failed;扩展只能在各自的初始化窗口内注册能力,部分初始化的 Registry 不能当作 ready 使用。进入 assembleTurn() 时,Registry 会在第一个 await 之前同步快照哪些扩展处于启用状态;组装期间调用 setEnabled() 只影响下一次组装;钩子以独立闭包的形式绑定当前 Turn 的 ctx,避免并发组装互相串用上下文。
在此之上,插件能力按修订版本「租用」:每接纳一次执行,Turn 的能力生命周期就取得一份包含插件、技能、运行时工具和钩子的视图,而且取得视图与登记在途执行两步之间不允许插入 await,处在同一个同步 JavaScript 临界区内;执行结束时释放引用。文中给出的效果是:模型读过某工具的描述之后,插件更新无法悄悄换掉这一版能力,新接纳的 Turn 则可以使用新版本;边界同样明确——这些工具访问的文件与远程服务本身仍可能变化。
MCP 工具的披露策略处理另一条约束:工具描述本身也占上下文。策略先检查功能开关、模型允许列表和生效窗口,再估算已配置 MCP 工具的描述体积;到达阈值时,符合条件的工具被移到搜索索引和延迟调用注册表之后,其余工具保持直接暴露,默认阈值是窗口的 15%,模型资格与配置覆盖仍然生效。作者写明了代价:延迟披露省下完整工具目录的空间,但多出一层发现环节,能否找对工具取决于检索质量。
上下文预算公式:131,072 窗口下输入上限 112,640,压缩从 98,304 开始
能力就位后,运行时把历史转成模型输入。MiniMax Code 的本地体积测量器对消息、系统提示和工具定义估算 token(词元),并计算请求表示的 UTF-8 序列化字节数;文中说明,本地测量与服务商对最终线上载荷的精确记账可能存在出入。
预算要为输出和继续执行留出空间。设 C 为上下文窗口、O 为输出上限、R 为预留、S 为安全余量,共享默认值为 R = 16,384、S = 2,048;当 C − O − S ≥ R 时按完整输出上限 O 计算,否则取 min(O, R),记作 O_eff。输入上限为:
L = max(1, min(floor(0.95 × C), C − R, C − O_eff − S))
自动压缩从更早的阈值启动:
T = min(L, max(1, C − min(2 × R, floor(C / 4))))
以 131,072 窗口、16,384 输出上限代入共享默认值,得到 L = 112,640、T = 98,304;上下文管理在输入触及硬上限之前就开始工作,换模型或改设置后需要重新计算。
具体压缩由 ToolResultArchiver 执行:它按输出水位、候选体积、对近期回合的保护和预期节省量挑选归档候选,先在不改动状态的前提下制定计划,再落地归档;当读工具可用时,较早的大体积输出可替换为归档引用,原件仍留在本地。候选必须通过校验:token 数与字节数至少一项下降、token 数落入输入预算、字节数满足相应限额;没有显式字节上限时,候选的序列化体积不得超过原输出。归档候选无法直接满足准入时,执行转入 LLM(大语言模型)检查点路径:生成检查点、校验、替换历史、重新测量;仍然超限就返回 POST_ADMISSION_FAILED,压缩要等下一个请求——连同提示与工具定义——满足准入才算完成。
判断压缩时机还靠一个进程内使用锚点:取一条符合条件的助手用量报告作锚,加上对后续增长的估计,与当前本地估计取较大者。锚点绑定会话范围、服务商、API、模型、系统提示与工具指纹、历史纪元和锚定消息身份,换模型、换工具或改历史都要重新检查它是否仍然适用;压缩前后的候选比较各自使用新鲜估计,锚点只影响触发判断,不能替代候选校验。作者同时提醒:即使结果装得下,压缩也可能丢失任务信息,评测除了看体积缩减,还应检查是否漏掉约束、是否重复调查。
规范历史的提交顺序:语义快照、落盘、重读、投影、确认
工具调用真正执行之前还有一道复查链:先查 Turn 内有无重复的工具调用 ID;带主机 tool_ref 的委托调用要解析出实际执行目标;随后经过安全与插件预处理、工具策略和扩展钩子,才进入权限评估——下游检查拿到的是实际目标,授权不能只查包装工具。文中举了一个竞态:工具正在等待用户批准时用户取消了任务,批准到达时原 Turn 可能已经结束;因此权限批准后链条会尝试 openToolResultTail(),只有匹配的活跃 Turn 仍在运行才能成功。Turn 控制器核对 sessionId、turnId、leaseId、接纳序号、执行原因和信号身份,租约在本运行时内拒绝过期执行。实际的文件系统与网络访问还受沙箱后端约束:当前 V2 默认注册 macOS 的 srt-macos 后端,其他平台的隔离取决于对应后端的支持。
MiniMax Code 把执行事件与规范历史分开:事件描述正在运行的进程,规范历史才是继续执行所依据的权威历史,由 Session 系统存储和恢复;一个共享的已提交历史写入器负责普通追加、替换、压缩与对账。按文中描述,一次提交按固定顺序走完五步:
- 捕获语义快照,并校验会话、Turn 与操作身份;
- 执行持久化变更,然后在同一条每会话操作通道内重读规范历史;
- 校验重读结果,取得已提交的修订版本;
- 等待必需的 HistoryCommitted 投影,以及(如适用)压缩生命周期完成;
- 向调用方返回确认。
快照防止调用方在异步提交期间改动已提交的对象;重读让下游拿到存储确认过的版本,而不是调用方想写入的数组。重试时,写入器以 sessionId + operationId 识别操作并比较语义指纹,身份与内容都匹配才复用执行,身份相同而内容不同会触发冲突处理;这个重放注册表有界且只存在于进程内,跨进程、跨外部服务不保证恰好一次执行。
工具结果之外携带的输入遵循同样的「先认领、后确认」:输入先被认领,历史提交后才确认;消费仍在途时推迟关闭 Turn;未被消费的用户转向消息有重新排队路径,已投递的机器输入不得在收尾时被丢弃。必需的状态投影完成后才确认历史;用量记账与诊断属尽力而为,失败只记录、不阻塞确认。外部副作用需要另行处理:远端写入成功但响应丢失时,目标服务仍需要幂等键,或应用需要补偿机制——本地历史不能自动撤销那次写入。
多代理任务:结果读过不等于消费完成
同一类修复任务可以拆分:主代理改函数,子代理查调用方或调查相关代码;子代理有自己的会话与执行,主代理要在合适的时点拿到结论。MiniMax Code 为每个后台任务记录独立任务 ID、所属会话、父任务、状态与输出引用,状态包括 queued、running、stopping、succeeded、failed、canceled、lost 七种;终端界面(TUI)通过父子会话关系展示被委托的代理。
委托带来的问题是:父代理什么时候算真正「消费」了一个已完成的结果?任务完成、通知投递、结果读取可能发生在不同时间,父代理也可能在读完输出后才失败。deliveredAt 记录的是投递状态,自动完成通知并不把结果标记为已消费;按文中描述的当前 Host 路径,只有成功读取终态任务输出(经 task_output)后才记录消费候选,读取运行中任务的进度不会抑制稍后的完成通知,Host 要等父 Turn 以完成态结束、终态提交之后才确认这些候选。理由写在例子里:子代理查完调用方,主代理经 task_output 读到结论,随后主代理失败——如果读取返回时就永久标记已消费,父代理恢复时就少了一次提醒机会。
这个顺序也留下失败窗口:确认消费或后续结算失败时,Turn 可能已经提交,这类失败只产生诊断信息,不会把已提交的 Turn 追改成失败——各步骤并非横跨所有组件的单一原子事务。运行时重启后的恢复逻辑检查任务执行所有权:没有有效执行者的任务被结算为 lost,而不是无限期停在 running;父代理可以从恢复的会话历史继续,但消失的子代理执行进程需要单独处理。
重申的自报评测,与可以动手核验的代码
长文重申了发布公告中的 FrontierHarness 评测:30 项任务通过 23 项、成功率 76.7%、成功任务中位用时 4 分 33 秒,并称评测报告记录了结果与比较条件。这组数字出自 MiniMax 自己的评测运行,属于公司自报;实现细节不同,可以对照开源代码核对。
可以独立核对的是代码侧的事实:GitHub 仓库当前以 MIT 许可公开,npm 上的 最新版本 0.4.12 于 9 月 18 日发布;截至 9 月 20 日,仓库显示 1,238 颗 star,长文帖经第三方 API 查询显示 77 个赞、15 条回复与 3,630 次浏览。He 在文末邀请更多开发者检视这些取舍,在自己的环境里使用、测试并改进,问题与反馈可以提 issue。
参考链接
- Ronny He(@Ronny_MiniMax)的 X 帖文:
- 长文《MiniMax Code Is Now Open Source: Inside the Harness Behind a Coding Agent》:
- GitHub 仓库 MiniMax-AI/minimax-code:
- npm 包 @minimax-ai/code: