kimi-code — 本课题摘录
读了哪几篇: 01-loop(无状态回合循环)、02-agent(主机层)。
其余四篇(工具套件、抹平两层差异、再工程化、交付面)本轮没读。
这一家把"循环该管什么、不该管什么"这条线画得最清楚,而且它把这条线写进了自己的说明文件第一句。
它对本课题回答了什么
决定一(架构):循环刻意不拥有世界
它的说明文件第一句就划线:"这是无状态的 agent 循环。它不拥有会话、传输、压缩执行、权限界面、持久化协议桥接。"
清单很具体:
| 上层拥有 | 循环怎么"借"到它 | 为什么不放进循环 |
|---|---|---|
| 会话状态、历史、持久化 | 循环无状态,跑完即返回 | 无状态才能被反复、并发、可测地调用 |
| 拼提示 / 投影历史 | 由一个"拼消息"的回调注入 | 循环不认识"消息该怎么拼"这件事 |
| 上下文压缩的执行 | 只在"这一步之前"的钩子里由上层触发 | 循环只提供"安全点",不决定压什么 |
| 权限界面 / 批准 | 由一个"授权这次工具执行"的回调 | 弹窗、等用户点是界面职责 |
| 传输、落盘 | 由"发事件"的回调注入 | 循环只产事件,不管字节去哪 |
| 系统提示、模型选择 | 由一个模型对象携带 | 单一来源,循环不自己拼提示 |
(依据:Agent 库 · Kimi Code CLI · 无状态回合循环:一次工具调用的一生 —— README 第一句划线「loop 是无状态的 agent 循环,不拥有 sessions、wire transport、compaction execution、permissions UI 或 durable protocol bridging」,这些全由 host 通过 buildMessages / authorizeToolExecution / dispatchEvent 等回调注入)
它的比喻:把循环想成一台只会转圈的马达——它只管"进一格、出一格"的机械节奏和刹车安全,至于油箱怎么加、方向盘怎么打、仪表盘怎么显示,全接在马达外面。马达自己不存油、不认路。
这是本课题"循环要薄"这条主张最彻底的一份实现。 whale 说"循环只管控制流"、webwright 说"循环体只有一 行"、pi 把状态分到上一层—— kimi-code 把"不拥有什么"列成了一张带理由的表。这张表可以直接当我们的设计约束。
"循环只提供安全点,不决定压什么"这一条特别值得记: 压缩不是循环的事,但压缩需要循环给一个"现在可以安全地改历史"的时机。
决定四:三层嵌套,而且每层的边界都对应一个函数
| 词 | 白话 | 边界在哪 |
|---|---|---|
| 回合 | 用户说一句话后,agent 忙活到再次把话筒交还给用户的整段过程 | 一次"跑回合"调用 |
| 步 | 回合里的一次模型调用(可能带一批工具调用) | 一次"跑一步"调用 |
| 批次 | 一个步里模型一口气点名的那一组工具 | 一次"跑工具批次"调用 |
(依据:Agent 库 · Kimi Code CLI · 无状态回合循环:一次工具调用的一生 —— 三层嵌套是 turn(用户说一句到再次交还话筒的整段)、step(回合里的一次模型调用)、batch(一个 step 里模型一口气点名的那组工具),各对应 runTurn / executeLoopStep / runToolCallBatch)
前面 codex 是"回合/采样"两级、deepseek-harness 是"轮/步"两级、pi 是"外层/内层"—— kimi-code 是三级,多出来的"批次"这一层正是"一次模型调用点了好几个工具"的那一层。 这一层不显式命名,并发和顺序的讨论就没有落点。
决定三:并发按"资源访问冲突"调度 —— 而且发和收都按厂商给的顺序
"一批工具里,互不干扰的并发跑,会互相踩的串行跑。"
判定"冲突"的是一个专门的资源访问模型:什么样的两把访问算冲突。 (依据:Agent 库 · Kimi Code CLI · 无状态回合循环:一次工具调用的一生 —— 一批工具里互不干扰的并发跑、会互相踩的串行跑,由 tool-access.ts 的资源访问模型判定什么样的两把访问算冲突,ToolScheduler 做有状态调度)
而且有一条不变量:按厂商给的顺序发出调用、按厂商给的顺序收回结果。
这条是并发的第五种答案,而且是最完整的一种:
- openai-agents-js:按动作类型硬分;
- haystack:按读写集合自动推;
- nanobot / pydantic-ai:工具自己声明;
- dexter:连续只读凑一批;
- kimi-code:一个专门的资源访问模型 + "