怎么读这份源码

AGENTS.md 分层、设计文档与生成清单、无注释区、导入边界、实验开关、TS 设定与几条阅读捷径。

作者 David更新于 第 3 篇(共 33 篇)

先读 AGENTS.md,不是 README

这个仓库把架构说明写在 AGENTS.md 里——给 AI 编码助手看的指令文件,因为天天被使用,往往是最新的架构文档。根目录的 CLAUDE.md 只有一行 AGENTS.md,指回同一份文件。

分层放置:

AGENTS.md                              仓库级:项目地图、硬约束、工作流
apps/kimi-code/AGENTS.md               CLI/TUI 的入口链与模块职责
apps/kimi-inspect/AGENTS.md
packages/klient/AGENTS.md              门面 / 契约 / 传输三层规则
packages/minidb/AGENTS.md
packages/pi-tui/AGENTS.md              与上游 pi-mono 的本地差异清单
packages/agent-core-v2/src/human/llm/AGENTS.md   目录级
docs/AGENTS.md

规则明确写着往哪写:

Hard rules that affect almost every task: update the root AGENTS.md. Rules that only affect a specific directory: update the nearest sub-directory AGENTS.md.

但仓库同时声明代码才是唯一真相:

Treat code, not documentation, as the source of truth.

这句话要当真。v0.43.0 的根 AGENTS.md 说 agent-core-v2 有四级 LifecycleScope,调用方经 IWorkspaceLifecycleService.handlerFor 组合会话生命周期;代码里的枚举只有三级,这个服务在引擎里也找不到,只剩 SDK 的注释还提到它。文档可以当索引,结论要回到代码。

第二读:设计文档与生成的清单

v2 引擎没有模块 README,取而代之的是 packages/agent-core-v2/docs/:

  • zh/llm.md(及英文版)——human/llm 请求库的设计指南,九条设计原则写得很透;src/human/llm/AGENTS.md 要求改这个目录前先读它。
  • wire-manifest.d.ts、state-manifest.d.ts、config-manifest.toml——由包内 scripts/gen-*-manifest.mts 生成,分别列出 wire 记录、App / Workspace / Session / Agent 各层状态与全部配置段。想一眼看全引擎的「数据面」,先翻这三份。

无注释区

agent-core-v2、kap-server、transcript 是 comment-free zones:不许有任何注释,连导出符号的 JSDoc 也不行,只保留必要的 lint 抑制指令。scripts/check-no-comments.mjs 扫这三个包的 src/、test/、scripts/,作为 pnpm lint 的一部分执行。

所以读引擎没有注释可依靠,只能靠类型、命名与测试;命名也因此普遍很长、很具体,比如 llmRequesterMediaStrippedTurnsKey。反倒是 node-sdk 的 sdk-rpc-client-v2.ts 注释极多,逐方法写明与 v1 行为的对齐和差异,是理解换代的好材料。

目录约定

apps/            可运行的应用(CLI/TUI、VS Code 插件、可视化调试器、检查器)
packages/        库
plugins/official 官方插件(kimi-datasource、kimi-webbridge)
docs/            用户文档(中英双语)
scripts/         构建与检查脚本
.agents/skills/  仓库自带的 agent skills(write-tui、tdd、gen-changesets…)
.changeset/      变更集(发版用)

packages/agent-core-v2/src/ 内部:

_base/        DI 容器、事件、生命周期、贡献点等底座
human/        纯内核:agent / turn / tool 状态机、单次 LLM 请求库
llm-adapter/  引擎侧的 LLM 兼容边界(模型、provider、协议路由)
app/          App 级服务:配置、认证、插件、会话索引、flag……
workspace/    工作区:目录、git、信任、MCP 配置……
session/      Session 级:元数据、子代理、会话级工具策略……
agent/        Agent 级:loop、上下文、压缩、权限、工具执行、内置工具
features/     以 Feature 接入的功能:goal、plan、skill、swarm、cron……
tool/         工具契约与资源访问模型
wire/         wire 记录、日志与版本迁移
persistence/  存储接口与后端(node-fs / minidb / memory)
os/           宿主文件系统与进程

导入边界

packages/agent-core-v2/scripts/check-import-boundaries.mjs(pnpm --filter @moonshot-ai/agent-core-v2 lint:imports)把分层写成了可执行的规则:

  • human/ 不许 import 内核以外的任何东西——它是纯 LLM / agent 内核,不认识 llm-adapter 与 v2 的各个领域;
  • v2 代码里只有 llm-adapter/、agent/loop/machine/、session/agentLifecycle/ 三处能 import human 的实现,其余只能用一小组「词汇」模块(消息、用量、能力等类型);
  • 协议基座内部的 format / lower / patterns 只许基座自己和测试 import;
  • 不许再 import kosong。

知道这三个适配层,就知道内核与外壳在哪里接缝。

实验开关

未公开的功能一律挂在开关后面,env 驱动、默认关闭:

环境变量作用
KIMI_CODE_EXPERIMENTAL_<NAME>打开单个开关
KIMI_CODE_EXPERIMENTAL_FLAG打开全部

优先级是:单个 env > 配置里的 [experimental] > 总开关 env > 条目的 default;发布某功能就是把 default 翻成 true。v2 没有中央注册表,各领域在 import 时自己调 registerFlagDefinition(app/flag/flagRegistry.ts),用 IFlagService.enabled(id) 判断。例如 features/tower/flag.ts(有删减):

export const towerFlag: FlagDefinitionInput = {
  id: TOWER_FLAG_ID,
  title: 'Tower mode',
  env: TOWER_FLAG_ENV,
  default: false,
  surface: 'both',
  isExposed: (flags) => isTowerFeatureAssembled(flags),
};

想知道默认配置下哪些路径根本不会执行,rg registerFlagDefinition 扫一遍即可。

TypeScript 设定

  • 根 tsconfig.json 开了 strict、noUncheckedIndexedAccess、noImplicitOverride、noPropertyAccessFromIndexSignature、verbatimModuleSyntax 与 experimentalDecorators。最后一个给 DI 用:服务在构造函数参数上用 @IAgentLoopService private readonly loop 这样的装饰器声明依赖。
  • 没有开 exactOptionalPropertyTypes。AGENTS.md 明确可选属性不必再写 | undefined(写 user?: User 即可);传值直接给 { user },不用条件展开。
  • 路径别名:agent-core-v2 的 package.json 里 #/* 指 ./src/*.ts、#human/* 指 ./src/human/*.ts;src/human/ 还有自己的 package.json,其中的 #/* 只指向 human 内部——内核在包里又划了一道包界。
  • exports 用 ./* 暴露深路径,所以常见 @moonshot-ai/agent-core-v2/agent/loop/turnOps 这样的子路径导入。
  • 除包的 index.ts 外,其余 index.ts 一律 export * from './module'。

几条阅读捷径

想弄清一个功能怎么实现,按这个顺序找:

  1. docs/zh/ 或 docs/en/ 找该功能的用户文档,拿到准确名词。
  2. rg 搜那个名词(仓库工作流明确要求用 rg)。
  3. 落到 packages/agent-core-v2/src/<层>/<领域>/:先看接口文件(如 agent/loop/loop.ts 定义 IAgentLoopService),再看 *Service.ts 实现,最后看文件末尾的 registerScopedService(...)——它告诉你服务挂在哪一级 Scope、何时激活。

想弄清一次调用的完整链路,从 klient 契约切入:packages/klient/src/contract/ 按 global / session / agent 列出每个线上方法的 zod 输入输出,src/core/facade/ 把它们映射到引擎的服务名与方法(如 agentPromptService.submit)——这就是「前端能让引擎做什么」的清单。反方向(审批、提问)看 SDK 的 src/v2/session-wiring.ts。

想知道某处行为的边界,看测试。v2 的 test/ 与 src/ 同构,比如 test/agent/loop/ 下的 loop.test.ts、turnOps.test.ts、machineTools.test.ts;klient 另有一套对每种传输原样重跑的一致性测试(test/helpers/conformance.ts)。

本专栏的引用约定

  • 路径一律相对仓库根:packages/agent-core-v2/src/agent/loop/loopService.ts。
  • 引用行号时以基准 tag @moonshot-ai/[email protected](commit ffa94fa)为准。这个仓库变化很快——从 v0.29.1 到 v0.43.0 只隔七周,引擎就换了代——行号与结构都可能漂移,读时请以当前 HEAD 为准。
  • 代码片段会做删减(省略无关分支、错误处理),保留结构;需要精确细节请回原文件。

下一篇:一条消息的生命周期——把所有层串起来走一遍。

本页目录