喜欢对技术刨根问底,却总是被打退,晕,再上,屡败屡战

注定要与程序打交道,毫无疑问我喜欢编程,而且适合

导航

kimi-code 深度掌握系列文章-Agent 类编排者(四)

Posted on 2026-08-06 13:08  Carmack  阅读(2)  评论(0)    收藏  举报

在 kimi-code 的架构中,没有比 Agent 类更中心的模块了。它就是乐团的指挥,不亲自演奏任何乐器,却协调着所有的乐手——15 个以上的子系统——在正确的时机发出正确的声音。本章深入 Agent 类的内部构造,拆解它如何将一组互相依赖的服务编织成一个能完成完整对话循环的有机整体。

1. Agent 的定位

Agent 不是一个"类"

如果只看一行导入,你会觉得 Agent 不过是一个普普通通的 TypeScript class:

export class Agent {
  constructor(options: AgentOptions) { /* ... */ }
}

但这个 class 的体内却容纳了 15 种以上的子系统协同工作。Agent 的真正定位是​编排者 (Orchestrator)​——它自己不负责执行具体任务,而是创建者、持有者、调度者。它把自己的各个子系统串起来,让它们在合适的时刻互相通信,形成一条完整的响应流水线。

​核心设计原则:组合优于继承。​Agent 不是通过多层次的继承链来逐步增加能力,而是通过构造函数注入所有依赖,在内部将它们组合成一个有向协调图。这种设计使得每个子系统都可以独立测试、独立替换、独立演进。

从代码结构来看,Agent 类中 80% 以上的字段都是 readonly 的子系统引用。这些子系统大多持有一个对 Agent 的反向引用(通过 protected readonly agent: Agent),从而形成双向引用图,实现子系统之间通过 Agent 作为中介进行通信。

2. Agent 的组成结构

以下是 Agent 内部的所有子系统及其职责,按它们在构造函数中初始化的顺序排列:

子系统 类型 职责
llmRequestLogger LlmRequestLogger LLM 请求日志记录,每次 LLM 调用前输出结构化的请求信息
llmRequestRecorder LlmRequestRecorder LLM 请求持久化记录,用于调试和回放
records AgentRecords 持久化事件日志 (wire.jsonl),记录 Agent 的每一个状态变更事件,支持会话恢复 (resume)
fullCompaction FullCompaction 完整上下文压缩——当上下文接近窗口上限时,用 LLM 做一轮总结压缩
microCompaction MicroCompaction 微压缩——对旧媒体进行降级、对用户消息进行裁剪,不涉及 LLM 调用
context ContextMemory 对话历史管理,包括消息追加、token 计数、上下文导入导出、undo 操作
config ConfigState 运行时配置状态:当前模型、系统提示词、thinking effort、max output tokens
turn TurnFlow 主响应循环——接收 prompt,进入 Step 循环(prompt → generate → 工具调用 → 结果)
injection InjectionManager 上下文注入边界,在每个 Step 前向对话注入提醒(计划模式、权限模式、技能提示等)
permission PermissionManager 工具执行前的权限检查——策略链评估(deny → approve → ask),支持 yolo/auto/manual 模式
planMode PlanMode 结构化代码审查 / 规划模式——Agent 进入只读计划状态,输出审查报告或执行计划
swarmMode SwarmMode 并行多 Agent 协调模式——支持 manual 切换、task 单次触发、tool 入口三种触发方式
usage UsageRecorder Token 使用追踪——按 model 聚合 session 级别和 turn 级别的 token 消耗
skills SkillManager | null 技 能 注册表——管理用户可激活的技能 (skill),激活时将技能提示词注入上下文
tools ToolManager 工具注册、发现、执行—管理 builtin tools、MCP tools、user tools 三种工具源
background BackgroundManager 后台进程 / 子 Agent 管理——跟踪后台 bash 任务和子 Agent 任务的生命周期
cron CronManager | null 定时 / 调度任务 —基于 cron 表达式的定时触发,主 Agent 特有,子 Agent 为 null
goal GoalMode 自主多轮目标驱动执行——维护一个活跃目标,自动在每轮完成后继续推进

子系统间的通信模式

这些子系统之间的通信遵循一个核心模式:​通过 Agent 进行中介通信​。每个子系统在构造函数中接收 agent: Agent 引用,通过它调用其他子系统的方法或读取状态。例如:

  • TurnFlow 通过 agent.context 读取对话历史,通过 agent.config 获取当前 provider,通过 agent.tools 解析工具列表
  • FullCompaction 调用 agent.llm 创建一个专门的 LLM 实例来执行压缩,调用 agent.context 读取需要压缩的消息
  • InjectionManager 通过 agent.context 追加系统提醒,通过 agent.planMode 检查计划模式状态
  • PermissionManager 通过 agent.records 记录审批结果,通过 agent.rpc 向前端发起 ask 请求

​为什么不使用事件总线?​Agent 子系统之间的通信是上下文敏感且有严格顺序的——InjectionManager 必须在 TurnFlow 的 beforeStep 阶段调用,Compaction 必须在 token 超过阈值时触发。事件总线难以保证这种时序约束,而显式的双向引用让我们可以在 TypeScript 的帮助下通过 method call 精确控制执行顺序。

3. Agent 与 Session 的关系

Session 和 Agent 是 kimi-code 中两个最核心的概念,关系如下:

Session 拥有 Agent

Session 是 Agent 的容器和生命周期管理者。一个 Session 代表一次完整的用户会话——它包含了工作目录、配置快照、模型选择、插件状态等所有会话级别的上下文。Session 负责:

  • 创建 Agent​ :通过 DI 容器 (IInstantiationService) 实例化 Agent,注入所有会话级依赖(kaos、config、homedir、modelProvider、subagentHost 等)
  • 初始化 Agent​:调用 agent.useProfile() 设置行为配置,调用agent.config.update() 设置初始状态
  • 恢复 Agent​:在重新连接时调用 agent.resume(),通过 replay wire.jsonl 记录重建 Agent 的内部状态
  • 销毁 Agent​:Session 结束时清理 Agent 持有的资源
// Session 中 Agent 创建和初始化的简化流程
class Session {
  async createAgent(): Promise<Agent> {
    const agent = this.instantiationService.createInstance(Agent, {
      kaos: this.kaos,
      config: this.config,
      homedir: this.sessionDir,
      modelProvider: this.modelProvider,
      subagentHost: this,
      skills: this.skillRegistry,
      mcp: this.mcpManager,
      hookEngine: this.hookEngine,
      // ...
    });

    // 恢复或初始化 agent 状态
    if (this.isResume) {
      await agent.resume();
    } else {
      agent.useProfile(this.profile);
      this.runSessionStartHooks(agent);
    }

    return agent;
  }
}

多 Agent 场景(Swarm Mode)

在 Swarm Mode 下,一个 Session 可以同时存在多个 Agent:

  • 主 Agent (Main Agent)​:用户直接对话的 Agent,拥有完整的子系统集合(包括 cron)
  • 子 Agent (Sub Agent)​:由主 Agent 通过工具调用创建的 worker Agent,type === 'sub',cron 为 null,拥有独立的 ContextMemory 和 TurnFlow
  • 独立 Agent (Independent Agent)​:type === 'independent',不依附于任何 Session,具有最高的隔离性

子 Agent 的创建通过 SessionSubagentHost 接口进行,Session 自身实现了这个接口:

// packages/session/subagent-host.ts(概念示意)
interface SessionSubagentHost {
  createSubagent(options: SubagentOptions): Promise<Agent>;
  startBtw(): void;  // 后台任务等待模式
}

每个子 Agent 拥有自己的 homedir(独立的 wire.jsonl)、自己的 ContextMemory、独立的 TurnFlow 循环。它们通过 rpc 接口向前端推送事件,形成并行的、隔离的对话流。

4. 生命周期:创建 → 运行 → 销毁

4.1 创建:构造函数中的世界构建

Agent 的构造函数是其生命周期的起点,也是最关键的一段代码。它按照严格的顺序创建所有子系统,确保依赖关系正确:

constructor(options: AgentOptions) {
  // 第一阶段:基础属性赋值
  this.type = options.type ?? 'main';
  this._kaos = options.kaos;
  this.kimiConfig = options.config;
  this.homedir = options.homedir;
  this.mediaOriginalsDir = options.mediaOriginalsDir;
  this.rpc = options.rpc;
  this.toolServices = options.toolServices;
  this.rawGenerate = options.generate ?? generate;
  this.modelProvider = options.modelProvider;
  this.subagentHost = options.subagentHost;
  this.mcp = options.mcp;
  this.hooks = options.hookEngine;
  this.log = options.log ?? log;
  this.telemetry = options.telemetry ?? noopTelemetryClient;

  // 第二阶段:日志和记录子系统
  this.llmRequestLogger = new LlmRequestLogger(this.log);
  this.llmRequestRecorder = new LlmRequestRecorder(this);
  this.blobStore = options.homedir
    ? new BlobStore({ blobsDir: join(options.homedir, 'blobs') })
    : undefined;
  this.records = new AgentRecords(this, /* ... */);

  // 第三阶段:核心引擎子系统
  this.fullCompaction = new FullCompaction(this, options.compactionStrategy);
  this.microCompaction = new MicroCompaction(this, options.microCompaction);
  this.context = new ContextMemory(this);
  this.config = new ConfigState(this);
  this.turn = new TurnFlow(this);
  this.injection = new InjectionManager(this);
  this.permission = new PermissionManager(this, options.permission);
  this.planMode = new PlanMode(this);
  this.swarmMode = new SwarmMode(this);

  // 第四阶段:功能扩展子系统
  this.usage = new UsageRecorder(this);
  this.skills = options.skills ? new SkillManager(this, options.skills) : null;
  this.tools = new ToolManager(this);
  this.background = new BackgroundManager(this, /* ... */);
  this.cron = this.type === 'sub' ? null : new CronManager(this);
  this.goal = new GoalMode(this);
  this.replayBuilder = new ReplayBuilder(this, options.replay);
}

注意创建顺序中的几个关键约束:

  • records 必须在 context 之前创建​——因为 ContextMemory 在添加消息时需要写入持久化记录
  • Compaction 子系统在 context 之前创建—因为 context 在计算 token 时需要参考 compaction 策略
  • cron 对子 Agent 为 null​——避免子 Agent 独立调度定时任务

4.2 运行:进入 TurnFlow

Agent 运行的核心入口是 rpcMethods.prompt(),它将用户的输入转发给 TurnFlow:

get rpcMethods(): PromisableMethods<AgentAPI> {
  return {
    prompt: (payload) => {
      this.turn.prompt(payload.input);
    },
    // ... 其他 RPC 方法
  };
}

从这里开始,TurnFlow 接管执行——它进入一个 while(true) 循环,反复执行以下步骤:

  1. beforeStep​:InjectionManager 注入上下文提醒,Compaction 在必要时压缩上下文
  2. buildMessages​:从 ContextMemory 构造发送给 LLM 的完整消息列表
  3. LLM Generate​:通过 agent.generate 调用大模型,流式接收 tokens
  4. Tool Execution​:如果模型返回 tool_use,PermissionManager 检查权限,通过后执行工具
  5. 收敛检查​:检查是否达到 maxSteps、是否被 abort、是否需要 continuation

4.3 销毁

kimi-code 中 Agent 的销毁并非通过一个显式的 dispose() 方法,而是采用分散式的资源管理:

  • Session 级别​:当 Session 结束时,Session 自身的 DisposableStore 负责清理所有持有的 Agent 引用
  • TurnFlow 级别​:每个 Turn 都关联一个 AbortSignal,取消时通过信号传播终止正在进行的 LLM 请求和工具执行
  • BackgroundManager 级别​:持久化的后台任务状态在 Agent resume 时进行 reconciliation——检查磁盘记录与实际进程状态的匹配,清理孤儿任务

这种设计避免了单一的大 dispose() 方法,而是在每个子系统的生命周期钩子中处理各自的清理逻辑。

5. DI 在 Agent 中的应用

Agent 的创建本身就是一个 DI (Dependency Injection) 的经典应用场景。kimi-code 的自研 DI 容器(借鉴 VS Code 风格)提供了两个关键特性,直接影响 Agent 的设计:

Scoped 服务 vs Singleton 服务

服务类型 作用域 示例
Singleton 应用生命周期——整个进程共享一个实例 FlagResolverMcpConnectionManagerSkillRegistry
Scoped (Session) 会话生命周期——每个 Session 一个实例 ModelProviderHookEngineTelemetryClient
Agent-owned Agent 生命周期——Agent 构造时直接 new ContextMemoryTurnFlowPermissionManager 等 15+ 子系统

​关键决策:为什么 Agent 的子系统不通过 DI 容器创建?​Agent 的子系统和 Agent 本身是紧密耦合的——它们需要 Agent 的引用才能工作。将它们放入 DI 容器会造成循环依赖问题。Agent 选择在构造函数中直接 new 所有子系统,将它们的生命周期和 Agent 本身绑定在一起。

Agent 创建的依赖注入

Session 通过 DI 容器创建 Agent 时,注入的是会话级别和全局级别的服务:

// Agent 的构造函数参数 (AgentOptions) 全部来自外部注入
const agent = instantiationService.createInstance(Agent, {
  kaos: kaos,                          // DI 提供的执行环境
  config: sessionConfig,               // Session 级配置
  homedir: sessionDir,                 // Session 级目录
  modelProvider: providerManager,      // DI 提供的 ModelProvider
  subagentHost: session,               // Session 自身作为 SubagentHost
  skills: skillRegistry,               // 全局 SkillRegistry
  mcp: mcpManager,                     // 全局 MCP 管理器
  hookEngine: hookEngine,              // Session 级 Hook 引擎
  experimentalFlags: flagResolver,     // 全局 Feature Flag
  // ...
});

这种设计让 Agent 本身不依赖 DI 容器——它只是一个普通的 TypeScript class,接收所有依赖作为构造函数参数。这使得 Agent 可以在任何上下文中被创建,只要提供正确的依赖即可,无论是真实的生产环境还是单元测试。

服务延迟解析

Agent 中有几个通过 getter 实现的延迟解析:

  • get llm():每次访问都创建一个新的 KosongLLM 实例,封装当前的 provider、systemPrompt、token 计数等运行时状态
  • get generate():包装原始的 generate 函数,自动注入 LLM 请求日志、请求录制、认证解析等横切关注点
  • get toolSelectEnabled():运行时评估 model capability + feature flag,决定是否启用动态工具加载 (progressive disclosure)

6. 扩展点

6.1 通过 Profile 配置 Agent

Profile 是 Agent 行为的主要配置手段。agent.useProfile() 接收一个 ResolvedAgentProfile,其中包含:

  • 系统提示词模板函数​:接收 cwd、skills、additionalDirs 等上下文,生成最终的系统提示词
  • 工具白名单​:通过 tools.setActiveTools() 启用指定的工具集合
  • Profile 名称​:用于事件追踪和遥测

6.2 通过 Plugin 系统扩展

Plugin 系统通过以下几个入口影响 Agent 的行为:

  • Plugin Commands​:通过 activatePluginCommand() RPC 方法激活,将扩展的命令文本注入为 prompt
  • Plugin Session Start​:在 Session 启动时,通过 PluginSessionStartInjector 将插件提醒注入上下文
  • Hook Engine​:支持 UserPromptSubmit、PreToolUse、PostToolUse 等钩子,允许插件在关键决策点插入自定义逻辑

6.3 添加自定义子系统

虽然 Agent 的子系统是硬编码的,但可以通过以下方式扩展能力:

  • 通过 ToolManager 注册自定义工具​:使用 rpcMethods.registerTool() 动态注册 UserToolRegistration
  • 通过 MCP 集成外部工具​:MCP 工具自动注册到 ToolManager,通过 mcpResultToExecutableOutput 执行
  • 通过 Hook Engine 注入自定义行为​:Hook 是 Agent 与外部逻辑交互的最灵活接口
  • 通过 AgentOptions 注入系统提示词上下文提供者​:systemPromptContextProvider 允许调用方自定义系统提示词中的运行时上下文

7. 核心结构伪代码

以下是 Agent 类的核心结构伪代码,省略了实现细节,只展示架构骨架:

// ============================================================
// Agent 类核心结构(伪代码)
// 文件: packages/agent-core/src/agent/index.ts
// ============================================================

export interface AgentOptions {
  // 执行环境
  readonly kaos: Kaos;

  // 配置与路径
  readonly config?: KimiConfig;
  readonly homedir?: string;
  readonly mediaOriginalsDir?: string;

  // 通信接口
  readonly rpc?: Partial<SDKAgentRPC>;

  // LLM 提供者
  readonly modelProvider?: ModelProvider;
  readonly generate?: typeof generate;

  // 会话协作
  readonly subagentHost?: SessionSubagentHost;

  // 外部集成
  readonly mcp?: McpConnectionManager;
  readonly hooks?: HookEngine;
  readonly skills?: SkillRegistry;

  // 扩展点
  readonly toolServices?: ToolServices;
  readonly compactionStrategy?: CompactionStrategy;
  readonly permission?: PermissionManagerOptions;
  readonly pluginSessionStarts?: readonly EnabledPluginSessionStart[];
  readonly pluginCommands?: readonly PluginCommandDef[];
  readonly experimentalFlags?: ExperimentalFlagResolver;
  readonly systemPromptContextProvider?: () => Promise<PreparedSystemPromptContext>;

  // 持久化
  readonly persistence?: AgentRecordPersistence;

  // Agent 类型
  readonly type?: AgentType; // 'main' | 'sub' | 'independent'
}

export class Agent {
  // ── 基础属性 ──
  readonly type: AgentType;
  readonly kimiConfig?: KimiConfig;
  readonly homedir?: string;
  readonly rpc?: Partial<SDKAgentRPC>;

  // ── 外部服务引用(来自 Session/DI) ──
  readonly rawGenerate: typeof generate;
  readonly modelProvider?: ModelProvider;
  readonly subagentHost?: SessionSubagentHost;
  readonly mcp?: McpConnectionManager;
  readonly hooks?: HookEngine;
  readonly log: Logger;
  readonly telemetry: TelemetryClient;
  readonly experimentalFlags: ExperimentalFlagResolver;

  // ── 横切关注点 ──
  readonly llmRequestLogger: LlmRequestLogger;
  readonly llmRequestRecorder: LlmRequestRecorder;

  // ── 持久化与记录 ──
  readonly blobStore: BlobStore | undefined;
  readonly records: AgentRecords;

  // ── 上下文管理 ──
  readonly fullCompaction: FullCompaction;
  readonly microCompaction: MicroCompaction;
  readonly context: ContextMemory;

  // ── 运行时状态 ──
  readonly config: ConfigState;

  // ── 核心引擎 ──
  readonly turn: TurnFlow;

  // ── 上下文注入 ──
  readonly injection: InjectionManager;

  // ── 安全与模式 ──
  readonly permission: PermissionManager;
  readonly planMode: PlanMode;
  readonly swarmMode: SwarmMode;

  // ── 功能扩展 ──
  readonly usage: UsageRecorder;
  readonly skills: SkillManager | null;
  readonly tools: ToolManager;
  readonly background: BackgroundManager;
  readonly cron: CronManager | null;      // 子 Agent 为 null
  readonly goal: GoalMode;
  readonly replayBuilder: ReplayBuilder;

  // ── 延迟计算属性 ──
  get llm(): KosongLLM { /* 动态构建 LLM 封装 */ }
  get generate(): typeof generate { /* 注入日志、录制、认证 */ }
  get toolSelectEnabled(): boolean { /* 评估 model capability */ }

  // ── RPC 接口 ──
  get rpcMethods(): PromisableMethods<AgentAPI> {
    return {
      prompt, runShellCommand, cancelShellCommand,
      steer, cancel, undoHistory,
      setThinking, setPermission, setModel,
      enterPlan, cancelPlan, clearPlan,
      enterSwarm, exitSwarm, getSwarmMode,
      beginCompaction, cancelCompaction,
      registerTool, unregisterTool, setActiveTools,
      stopBackground, detachBackground,
      clearContext, importContext,
      activateSkill, activatePluginCommand,
      createGoal, getGoal, pauseGoal, resumeGoal, cancelGoal,
      getCronTasks, getBackgroundOutput,
      getContext, getConfig, getPermission, getPlan, getUsage, getTools,
      // ...
    };
  }

  // ── 生命周期方法 ──
  useProfile(profile, context?, brandHome?): void;
  resume(options?): Promise<{ warning?: string }>;
  refreshSystemPrompt(): Promise<void>;

  // ── 事件发射 ──
  emitEvent(event: AgentEvent): void;
  emitStatusUpdated(): void;
}

从这个结构可以清晰地看到:Agent 类的核心特征是 ​组合​——大量的 readonly 子模块持有,构成一个高内聚但低耦合的子系统集合。

8. 总结

Agent 类是 kimi-code 架构中承上启下的枢纽:

  • 向上​,它通过 SDKAgentRPC 接口接收前端/SDK 的命令(prompt、cancel、setModel 等)
  • 向下​,它协调 15+ 个子系统完成对话的完整生命周期——从上下文管理到 LLM 调用到工具执行到记录持久化
  • 横向​,它通过 Session 创建的多个 Agent 实例实现多租户、多 Agent 协作和隔离

设计 Agent 的核心理念可以概括为三点:

1. 组合优于继承​——15+ 个子系统通过字段持有而非继承链组织
2. 中介者模式​—子系统通过 Agent 引用相互通信,避免点对点耦合
3. 构造时注入​——所有依赖在构造函数中显式传入,无需 DI 容器感知

理解 Agent 类,就理解了 kimi-code 作为一个 AI Agent 平台是如何将 LLM 调用、工具系统、权限控制、上下文管理、状态持久化等能力编织成一个协调的整体。下一篇将深入 TurnFlow——Agent 内部最核心的执行引擎,揭示它如何在循环中驱动整个对话的进展。