kimi-code 深度掌握系列文章-V2 引擎的 HTTP 服务层:kap-server(十六)

1. kap-server 的定位

1.1 在 kimi-code 架构中的位置

packages/kap-server 是 agent-core-v2 的 HTTP 外围服务层。它不是一个独立的应用------它是引擎的"外壳",将 DI x Scope 容器内的所有能力暴露为标准化的 REST + WebSocket 接口。在 kimi-code 系统的分层结构中,它位于以下位置:

scss 复制代码
┌───────────────────────────────────────────────────────────────────┐
│                           消费者层                                  │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌───────────────────┐  │
│  │ kimi-web  │  │kimi-inspect│ │  pi-tui │  │  kimi-code CLI   │  │
│  │ (Web UI)  │  │ (调试面板)│  │ (TUI)   │  │  (web/daemon)   │  │
│  └─────┬─────┘  └─────┬─────┘  └────┬────┘  └─────────┬─────────┘  │
│        │              │              │                  │           │
│        │         HTTP + WebSocket    │         process.fork()      │
│        └──────────────┴──────────────┘                  │           │
│                       │                                │           │
│                       ▼                                ▼           │
│  ┌─────────────────────────────────┐  ┌──────────────────────────┐ │
│  │          kap-server             │  │      kimi-code CLI       │ │
│  │   Fastify  HTTP  Server  +  WS  │  │  (Embedding Host via SDK)│ │
│  │                                  │  │  startServer({hostIdentity,...})│
│  │   ┌──────────────────────────┐  │  └──────────────────────────┘ │
│  │   │   agent-core-v2 (Core)   │  │                                │
│  │   │   DI × Scope 容器        │  │                                │
│  │   └──────────────────────────┘  │                                │
│  └─────────────────────────────────┘                                │
└───────────────────────────────────────────────────────────────────┘

kap-server 是 ​kimi-web ​(Web 前端)和 ​kimi-inspect ​(调试面板)的后端。CLI 的 kimi web 命令本质上就是启动一个 kap-server 实例并将 web 静态资源挂载上去。每当用户在浏览器中打开 Web UI、提交 Prompt、查看会话记录、或者调试面板通过 RPC 调用引擎内部服务时,请求都先到达 kap-server。

1.2 核心职责

  • 会话管理:创建、列表、更新、归档、fork、compact、undo、abort 会话
  • Prompt 提交:接收用户输入、图片附件、文件引用,转发给引擎调度
  • 事件广播:通过 WebSocket 实时推送会话事件(每个 token、工具调用、审批请求)
  • 文件操作:上传/下载、工作空间文件系统浏览
  • 审批与问题:工具审批流、Agent 问题交互
  • 配置与模型:暴露 provider 和 model 目录、用户配置读写
  • 认证与安全:Bearer Token 认证、Host/Origin 校验、速率限制

2. 技术栈全景

2.1 核心依赖

技术 角色 说明
Fastify HTTP 框架 高性能 Node.js Web 框架,内置日志(Pino)、Schema 验证、插件系统
agent-core-v2 引擎核心 DI x Scope 容器,提供 ISessionLifecycleService、IAgentPromptService 等全部引擎服务
transcript 会话数据层 TranscriptStore 分级存储、WireRecord 持久化、实时增量投影
@fastify/swagger API 文档 从 Zod Schema 自动生成 OpenAPI 3.0 文档,暴露 /openapi.json
WebSocket (ws) 实时通道 基于 ws 库的 WebSocket 服务器,noServer 模式与 Fastify 共享 HTTP Server
ulid ID 生成 连接 ID、Server ID 的唯一标识
Zod 验证层 类型安全的请求/响应 Schema 验证,同时驱动 Swagger 文档生成

2.2 defineRoute:声明式路由定义

kap-server 没有使用 Fastify 原生的 AJV 验证。它通过自研的 defineRoute 中间件实现了一套声明式路由系统:一个对象同时声明 Zod Schema(运行时验证)和 OpenAPI Schema(Swagger 文档)。

Typescript 复制代码
// packages/kap-server/src/routes/prompts.ts
const submitRoute = defineRoute(
  {
    method: 'POST',
    path: '/sessions/{session_id}/prompts',
    body: promptSubmissionSchema,      // Zod --- 运行时验证
    params: sessionIdParamSchema,
    success: { data: promptSubmitResultSchema },  // 成功响应
    errors: {
      40001: { detailsSchema: z.array(/* ... */) },  // 校验失败
      40401: {},  // 会话不存在
    },
    description: 'Submit a prompt to a session',
    tags: ['prompts'],
  },
  async (req, reply) => {
    // req.body  →  PromptSubmission (自动推断)
    // req.params → { session_id: string }
    // ...
  },
);
app.post(submitRoute.path, submitRoute.options, submitRoute.handler);

这套系统带来的好处:

  • 类型安全 :Handler 中的 req.bodyreq.params 自动推断为正确的 Zod 类型
  • 统一错误格式 :200 响应中通过 oneOf 包含成功信封和所有可能的错误信封
  • 文档即代码:定义 route 的同时就完成了 OpenAPI 文档的声明
  • 零运行时开销:验证只在 preHandler 层执行一次

2.3 统一信封格式

所有 REST 响应都包裹在统一的信封中:

Typescript 复制代码
// packages/kap-server/src/protocol/envelope.ts
interface Envelope<T> {
  code: number;      // 0 = 成功,4xxxx/5xxxx = 业务错误
  msg: string;       // 'success' 或错误描述
  data: T | null;    // 业务数据
  request_id: string; // 请求追踪 ID
  details?: unknown;  // 结构化错误详情
  stack?: string;     // 堆栈信息(仅错误时)
}

code=0 表示成功,非零值为业务错误码。这与 HTTP 状态码分离------​所有 kap-server 响应都是 HTTP 200 ​,真正的结果通过信封中的 code 字段传达。Fastify 的 access log 因此被禁用,由 kap-server 自有的请求日志替代。

3. REST API 路由体系

3.1 路由注册总览

所有路由通过 registerApiV1Routes 统一注册,挂载在 /api/v1 前缀下。

Typescript 复制代码
// packages/kap-server/src/routes/registerApiV1Routes.ts
export async function registerApiV1Routes(app, core, opts) {
  await app.register(async (apiV1) => {
    registerHealthRoute(apiV1);           // /healthz
    registerMetaRoute(apiV1);             // /meta
    registerAuthRoute(apiV1, core);       // /auth/*
    registerOAuthRoutes(apiV1, core);     // /oauth/*
    registerConfigRoutes(apiV1, core);    // /config/*
    registerModelCatalogRoutes(apiV1);    // /models, /providers
    registerSessionsRoutes(apiV1, core);  // /sessions
    registerPromptRoutes(apiV1, core);    // /sessions/:id/prompts
    registerMessagesRoutes(apiV1, core);  // /sessions/:id/messages
    registerApprovalsRoutes(apiV1, core); // /sessions/:id/approvals
    registerQuestionsRoutes(apiV1, core); // /sessions/:id/questions
    registerWorkspacesRoutes(apiV1);      // /workspaces
    registerFilesRoutes(apiV1, core);     // /files
    registerFsRoutes(apiV1, core);        // /fs
    registerToolsRoutes(apiV1, core);     // /tools
    registerTasksRoutes(apiV1, core);     // /sessions/:id/tasks
    registerTerminalsRoutes(apiV1, core); // /terminals
    registerSkillsRoutes(apiV1, core);    // /skills
    registerTranscriptRoutes(apiV1);      // /sessions/:id/transcript
    registerSearchRoutes(apiV1, core);    // /search
    // ... 调试、快照、shutdown 等
  }, { prefix: '/api/v1' });
}

3.2 核心路由详解

会话管理 --- /api/v1/sessions

会话路由是 kap-server 最复杂的路由模块,实现了 v1 的完整 wire contract:

方法 路径 功能
POST /sessions 创建新会话(需 workspace_id 或 metadata.cwd)
GET /sessions 列表会话(支持 before_id/after_id 游标分页、workspace_id/status 过滤)
GET /sessions/:id 获取单个会话
POST /sessions/:id/profile 更新标题、metadata、agent_config
GET /sessions/:id/children 列出子会话
POST /sessions/:id/children 创建子会话(fork + tag)
POST /sessions/:id/fork Fork 会话(复制上下文到新会话)
POST /sessions/:id/compact 触发上下文压缩
POST /sessions/:id/undo 撤销最后 N 轮对话
POST /sessions/:id/abort 取消当前正在运行的 turn
POST /sessions/:id/archive 归档会话
POST /sessions/:id/restore 恢复已归档会话
POST /sessions/:id/btw 启动后台 Agent(side-channel)

这些 action 路由通过统一的 /sessions/{tail} 模式处理------parseActionSuffix 从 tail 中解析出 { session_id, action },然后 dispatch 到对应的引擎服务。

Prompt 提交 --- /api/v1/sessions/:id/prompts

Prompt 路由处理用户输入的全流程:

  1. 会话恢复 :通过 resumeSessionById 获取或冷加载会话 Scope
  2. 图片处理 :提取 ContentPart 中的 base64 图片、解析 kimi-file:// URL、压缩为模型可接受的尺寸
  3. 权限与策略 :应用 IAgentPermissionModeServiceIAgentToolPolicyService
  4. Profile 绑定 :通过 IAgentProfileService 解析系统提示、工具集、Skills
  5. 调度执行 :调用 IAgentPromptService.prompt() 启动一次 turn
  6. 事件广播:引擎产生的 token 流、工具调用、结果等事件通过 WebSocket 实时推送给前端

工作空间管理 --- /api/v1/workspaces

工作空间路由负责目录注册和文件浏览:

  • GET /workspaces --- 列表所有已注册的工作空间(从 IWorkspaceService 读取)
  • POST /workspaces/register --- 注册新目录为工作空间
  • GET /workspaces/:id/files --- 浏览工作空间目录树(folder picker)

4. WebSocket 实时通信

4.1 WebSocket 端点与升级流程

kap-server 在 /api/v1/ws 端点提供 WebSocket 实时通信。与传统的独立 WebSocket 服务器不同,它使用 ws 库的 ​noServer 模式 ​------WebSocket 服务器不监听独立端口,而是挂载在 Fastify 的 HTTP Server 上,通过监听 upgrade 事件处理 WebSocket 握手。

Typescript 复制代码
// packages/kap-server/src/start.ts
const wssV1 = registerWsV1(core, {
  validateCredential,
  registry: connectionRegistry,
  broadcaster,
  fsWatchBridge,
  logger,
});

app.server.on('upgrade', (req, socket, head) => {
  void handleUpgrade(req, socket, head).catch((error) =>
    logger.error({ err: error }, 'ws upgrade handler failed'),
  );
});

升级流程中会执行与 HTTP 路由相同的安全检查:Host/Origin 校验、Bearer Token 认证。所有检查通过后,WebSocket 连接才被建立。

4.2 WsConnectionV1:连接级协议

每个 WebSocket 连接由 WsConnectionV1 实例管理,该实例实现了 BroadcastTarget 接口,能够接收来自 SessionEventBroadcaster 的事件并转发给客户端。

连接建立后,服务器立即发送 server_hello 帧:

Typescript 复制代码
// packages/kap-server/src/transport/ws/v1/wsConnectionV1.ts
this.sendImmediateFrame(
  buildServerHello({
    ws_connection_id: this.id,
    protocol_version: WS_PROTOCOL_VERSION,
    max_event_buffer_size: this.maxBufferSize,
    capabilities: { event_batching: false, compression: false },
  }),
);

4.3 控制帧协议

客户端通过 JSON 帧与服务器通信,支持以下控制帧类型:

帧类型 方向 说明
server_hello Server→Client 连接建立后立即发送,宣告协议版本和能力
client_hello Client→Server 客户端握手,可携带 initial subscriptions 和 cursors
subscribe Client→Server 订阅会话事件,指定 session_id + agents + 事件游标
subscribe_v2 Client→Server v2 订阅:按 transcript grade 分级订阅(text、tool_call、thinking 等)
unsubscribe Client→Server 取消订阅指定会话
unsubscribe_v2 Client→Server 取消 v2 的分级订阅
ack Server→Client 确认客户端的事件序列号
resync_required Server→Client 服务器无法增量补齐事件,客户端需全量重同步
watch_fs_add Client→Server 请求监听文件系统变更
watch_fs_remove Client→Server 取消文件系统监听

4.4 事件广播机制

SessionEventBroadcaster 是事件分发的核心。它维护一个持久化的事件日志(SessionEventJournal),每个会话事件被写入日志后广播给所有订阅该会话的连接。

事件分发分为两个通道:

  • Global 通道 :全局事件(session created/deleted、workspace 变更、配置更新)推送给所有已建立连接的客户端,无需订阅
  • Subscription 通道:会话级事件(token 增量、工具调用、审批请求)仅推送给已订阅该会话的连接

4.5 事件缓冲与背压控制

高频事件(尤其是 token 级别的文本增量)如果逐帧发送会造成大量小包。WsConnectionV1 使用了一个发送缓冲区:

  • 订阅事件的发送采用 16ms 刷新间隔(约 60fps),支持最多 64 帧的批量发送
  • 立即帧(公共事件、控制帧响应)作为 FIFO 屏障,会先刷新缓冲区中的订阅帧
  • socket.bufferedAmount 超过 1 MiB 时触发背压,延迟发送直到缓冲区清空
Typescript 复制代码
// 默认参数
const DEFAULT_FLUSH_INTERVAL_MS = 16;   // 刷新间隔(约 60fps)
const DEFAULT_MAX_BATCH_SIZE = 64;       // 单批最大帧数
const DEFAULT_HIGH_WATER_MARK_BYTES = 1 << 20; // 1 MiB
const DEFAULT_BACKPRESSURE_RETRY_MS = 5;

4.6 Transcript 增量同步

connect_v2 的 subscribe_v2 帧引入了按 Transcript Grade 的分级订阅。客户端可以只订阅自己关心的 Grade(如 texttool_callthinking),服务器只推送对应类型的事件。这大幅减少了不必要的数据传输,尤其是在长对话场景下。

TranscriptService 为每个活跃会话维护一个 TranscriptStore,引擎产生的每个 WireRecord 都会实时投影到 Store 中。当 WebSocket 客户端订阅某个 Grade 时,Store 会从客户端的游标位置开始增量推送,如果游标落后太多则发送 resync_required 要求客户端执行全量重同步。

5. 会话生命周期管理

5.1 会话创建流程

会话创建是 kap-server 中最关键的流程之一。从 REST 请求到引擎实例化,涉及多个步骤:

Typescript 复制代码
// packages/kap-server/src/routes/sessions.ts --- POST /sessions
async (req, reply) => {
  // 1. 解析 cwd:从 workspace_id 或 metadata.cwd 中获取工作目录
  const workDir = workspaceId ? workspace.root : body.metadata.cwd;

  // 2. 注册工作空间(createOrTouch 是幂等的)
  const touched = await core.accessor.get(IWorkspaceService).createOrTouch(workDir);

  // 3. 获取工作空间的生命周期 handler
  const handler = await core.accessor.get(IWorkspaceLifecycleService).handlerFor({ root: workDir });

  // 4. 通过 handler 的 SessionLifecycleService 创建会话
  const handle = await handler.accessor.get(ISessionLifecycleService).create({ workDir });

  // 5. 设置标题、读取元数据
  await handle.accessor.get(ISessionMetadata).setTitle(body.title);
  const meta = await handle.accessor.get(ISessionMetadata).read();

  // 6. 发布 session.created 事件(WebSocket 广播)
  core.accessor.get(IEventService).publish({
    type: 'event.session.created',
    payload: { agentId: 'main', sessionId: session.id, session },
  });
}

5.2 Session Store 持久化

kap-server 的会话数据持久化完全委托给 agent-core-v2 引擎。在 bootstrap() 阶段,引擎通过 IFileSystemStorageService 将存储根路径设定为 <homeDir>。所有会话相关的持久化:

  • 元数据 :通过 ISessionMetadata 保存到 append-log 中(id、title、createdAt、custom metadata)
  • 会话索引ISessionIndex 维护 FileSessionIndex,按 recency 排序
  • Wire Records :每个 Agent 的消息、工具调用、任务状态等以 JSONL 格式写入 agents/<agentId>/wire.jsonl
  • 二进制数据 :上传的文件、图片等通过 IBlobStorageService 存储

会话的 cwd 保存在 ISessionMetadata 的自定义字段中(gap G3 关闭)。即使工作空间被注销,会话仍然可以通过自有的 cwd 信息被列出和访问。

5.3 多 Agent 支持

kap-server 的会话模型支持多个 Agent 共存:

  • Main Agent:每个会话默认有一个主 Agent,负责接收用户 Prompt 并生成回复
  • Subagents / Side-channel :通过 POST /sessions/:id/btw 启动后台 Agent,可以在不干扰主会话的情况下执行独立任务
  • Children Sessions :通过 POST /sessions/:id/children 创建子会话(fork + parent_tag)

每个 Agent 都是一个独立的 Scope 实例,拥有自己的上下文记忆(IAgentContextMemoryService)、工具集和生命周期。WebSocket 的 subscribe 帧通过 agents 字段指定订阅哪些 Agent 的事件。全局搜索扫描所有 Agent 的 WireRecord。

5.4 会话的暂停、恢复与 Fork

kap-server 中的会话并非始终在内存中。当连接断开或会话空闲时,会话 Scope 可以被释放;当客户端再次访问时,通过 resumeSessionById 从磁盘重建。

Fork 操作在 ISessionLifecycleService.fork() 中实现------它会创建一个新会话,复制源会话的上下文历史(作为系统消息注入),使新会话继承源会话的全部对话上下文但拥有独立的对话未来。

6. V2 引擎集成

6.1 引擎初始化

kap-server 在 startServer() 中通过 agent-core-v2bootstrap() 函数创建 Core Scope:

Typescript 复制代码
// packages/kap-server/src/start.ts
const { app: core } = bootstrap(
  {
    homeDir,
    configPath,
    clientIdentity: opts.hostIdentity,
  },
  [
    ...logSeed(logging),                            // 日志配置
    ...hostRequestHeadersSeed(kimiHeaders),         // HTTP 请求头
    ...skillCatalogRuntimeOptionsSeed(skillDirs),   // Skill 目录
    ...hostIdentitySeed(opts.hostIdentity),          // 宿主身份
    ...(opts.seeds ?? []),                           // 额外配置
  ],
);

bootstrap() 返回的 core 是一个 App 级别的 Scope,它包含了所有引擎服务的注册。kap-server 的每个路由 handler 都通过 core.accessor.get(ISomeService) 获取需要的引擎服务实例。

6.2 DI x Scope 在服务层的应用

kap-server 不直接持有引擎状态------所有状态都在 Scope 层次结构中:

scss 复制代码
App Scope (core)
 ├── ISessionIndex         --- 全局会话索引
 ├── IWorkspaceService     --- 工作空间注册表
 ├── IConfigService         --- 配置读写
 ├── IEventService          --- 事件总线
 ├── IProviderDiscoveryService --- Provider 发现
 ├── IWorkspaceLifecycleService
 │    └── handlerFor(root) → Workspace Scope
 │         ├── ISessionLifecycleService --- 会话的创建/fork/归档
 │         │    └── create({ workDir }) → Session Scope
 │         │         ├── ISessionMetadata     --- 会话元数据
 │         │         ├── ISessionContext       --- cwd、workspaceId
 │         │         ├── IAgentLifecycleService --- Agent 生命周期
 │         │         │    └── createMainAgent() → Agent Scope
 │         │         │         ├── IAgentPromptService      --- Prompt 处理
 │         │         │         ├── IAgentContextMemoryService --- 对话历史
 │         │         │         ├── IAgentToolPolicyService   --- 工具策略
 │         │         │         ├── IAgentLoopService         --- Agent 循环
 │         │         │         └── ...
 │         │         └── ...
 │         └── ...
 └── ...

这种三级嵌套 DI 的语义是:App 级别的服务是全局单例,Workspace 级别的服务在同一个工作空间的所有会话之间共享,Session 和 Agent 级别的服务是每个会话/Agent 独立的。kap-server 路由 handler 从 App Scope 进入,通过 handlerForresumeSessionByIdensureMainAgent 等函数逐步下沉到更细粒度的 Scope。

6.3 请求 → Agent → 响应的完整路径

以用户提交一个 Prompt 为例,完整路径如下:

scss 复制代码
POST /api/v1/sessions/abc/prompts  (HTTP)
        │
        ▼
  registerPromptsRoutes → defineRoute (Zod 验证 body/params)
        │
        ▼
  resumeSessionById(core.accessor, sessionId)  --- 获取/冷加载 Session Scope
        │
        ▼
  ensureMainAgent(session)  --- 获取 Main Agent Scope
        │
        ▼
  IAgentPromptService.prompt(content, options)  --- 调度执行
        │
        ├─→ IAgentLoopService  --- Agent 循环(think → act → observe)
        │       │
        │       ├─→ LLM 调用  → token 流
        │       ├─→ Tool 调用  → Bash / File / Search ...
        │       └─→ 事件发射  → IEventService.publish(...)
        │
        ▼
  SessionEventBroadcaster  --- 事件持久化 + 广播
        │
        ├─→ SessionEventJournal  --- 写入事件日志
        └─→ WebSocket 推送  --- 分发给所有订阅的客户端
                │
                ▼
          kimi-web / kimi-inspect  --- 实时渲染

6.4 引擎事件的 WebSocket 转发

引擎的 IEventService 是事件源。kap-server 的 SessionEventBroadcaster 订阅引擎事件总线的 session.* 前缀事件:

  • agent.*agent.turn_startedagent.turn_endedagent.text_deltaagent.tool_call 等 --- 推送给订阅了该会话的 WebSocket 连接
  • session.*session.createdsession.meta.updatedsession.archived --- 全局广播
  • workspace.*workspace.createdworkspace.deleted --- 全局广播

TranscriptService 在这些事件的基础上构建 TranscriptStore,将原始事件转换为结构化的 Transcript 操作(upsert、reset),供 REST transcript 端点和 WebSocket 的 subscribe_v2 使用。

7. 多引擎支持

7.1 V1 与 V2 的架构差异

kap-server 是 agent-core-v2 引擎的服务层,但 kimi-code 历史上还有一个基于 agent-core (V1) 的服务器(packages/server)。两者的架构差异显著:

对比维度 V1 Server (agent-core) V2 Server (kap-server)
DI 容器 IInstantiationService(扁平 DI) DI × Scope(三级嵌套 DI)
事件模型 EventEmitter + wsGatewayService IEventService + SessionEventBroadcaster
会话存储 SessionService(单文件) ISessionMetadata + FileSessionIndex + WireRecord
Agent 模型 单一 Agent 多 Agent(main + subagent + children)
Transcript 无标准 Transcript TranscriptStore + Grade 分级订阅
路由定义 Express 风格 defineRoute(Zod → Swagger)

7.2 引擎切换机制

在 kimi-code CLI 中,引擎切换通过配置项控制:

  • KIMI_CODE_USE_V2 :环境变量,"1" 启用 V2 引擎
  • config.json :配置文件中的 engine_version 字段
  • CLI flag--use-v2 命令行参数

当 V2 引擎被激活时,CLI 的 kimi web 命令调用 startServer 启动 kap-server;否则启动 V1 Server。两者的 /api/v1 接口保持兼容,kimi-web 前端无需感知后端是哪个版本------它通过同一个 API 路径与任一引擎通信。

7.3 开发模式下的双引擎调试

在开发模式下,可以同时运行 V1 和 V2 引擎的服务器:

  • V1 Server 默认在 58627 端口
  • V2 (kap-server) 默认也在 58627 端口,使用 port+1 重试机制:如果端口被占用,自动尝试 58628、58629......最多重试 100 次
  • 两个服务器通过 instanceRegistry 独立注册在 <homeDir>/server/instances/ 下,互不冲突

这种设计使得在迁移期间,前端可以同时连接两个后端进行对比测试。每个 kap-server 实例的注册信息(PID、host、port、启动时间、serverVersion)以 JSON 文件持久化,kimi server pskimi server kill 命令可以列出和管理所有实例。

8. 调试接口

8.1 Debug RPC 接口

kap-server 提供了一套完整的调试 RPC 接口,挂载在 /api/v1/debug/* 路径下。该接口仅在以下条件同时满足时启用:

  1. 启动时传入 --debug-endpoints 参数
  2. 服务器绑定在 loopback 地址(127.0.0.1)
  3. 请确保携带有效的 Bearer Token
Typescript 复制代码
// packages/kap-server/src/start.ts
const debugEndpoints = exposureClass === 'loopback' && opts.debugEndpoints === true;
// ...
if (debugEndpoints === true) {
  registerDebugRoutes(apiV1, core);
}

这些限制确保了调试接口不会在非安全环境下暴露------它允许调用者访问引擎内部的所有 Service,是具有完全权限的管理接口。

8.2 DI 容器反射

Debug 路由实际注册的是 registerServiceDispatcherRoutes------一个基于 DI 反射的 Service 调度器:

Typescript 复制代码
// packages/kap-server/src/transport/registerDebugRoutes.ts
export function registerDebugRoutes(app, core) {
  registerServiceDispatcherRoutes(app, core, '/debug', {
    lookup: resolveAnyScopedServiceId,  // 跨所有 Scope 查找 Service
    describe: describeAllChannels,       // 列出所有可用的 RPC 通道
  });
}

resolveAnyScopedServiceId 不仅能在 App Scope 中查找 Service,还能穿透 Session 和 Agent Scope------通过 session_idagent_id 参数定位到正确的嵌套 Scope,然后从中取出目标 Service 实例。

describeAllChannels 暴露了所有可调用服务通道的完整列表,包括每个通道的输入/输出 Schema 和描述信息。这实际上是一个运行时的 DI 容器反射 API。

8.3 Service 面板

kimi-inspect 调试面板正是通过这组 Debug RPC 接口与 kap-server 交互。它提供两种核心操作:

  • **数据查询(GET)**:读取 Service 的当前状态。例如读取 IAgentContextMemoryService 的对话历史、ISessionMetadata 的元数据、IConfigService 的当前配置
  • **触发按钮(POST)**:调用 Service 的方法。例如触发 compaction、重置对话上下文、切换 permission mode

典型的 debug 请求路径为 /api/v1/debug/<serviceId>/<method>,其中 serviceId 是 DI 注册的 Service 唯一标识,method 是 Service 暴露的 RPC 方法名。

8.4 kimi-inspect 的消费模式

kimi-inspect 是一个独立的 Web 应用,它作为 kap-server 的客户端运行。它通过以下方式消费调试接口:

  1. 启动时 :调用 describeAllChannels 获取完整的 Service 清单,构建左侧导航树
  2. 选中 Service 时:自动调用该 Service 的只读方法来填充数据面板
  3. 用户点击按钮时:发送 POST 请求调用对应的 RPC 方法
  4. 实时更新:通过 WebSocket 订阅会话事件,面板中的数据实时刷新

这种设计使得 kimi-inspect 成为一个完全动态的调试工具------它不需要硬编码任何 Service 的名称或方法,所有能力都通过运行时的 DI 反射发现。

相关推荐
Do1you1believe1light1 小时前
我拆开了 Prime Agent:然后哭着想要给它真正的智能
llm·agent·ai编程
joinwell522 小时前
一个 Agent 说“完成了”,团队为什么没放行?
agent
飞扬的风信子2 小时前
架构文档 — local-model-harness
agent·vibecoding
后端小肥肠2 小时前
自研长篇小说写作 Skills:参考文风 + 自动续篇 + 剧情连续性检测
人工智能·aigc·agent
AI语宙漫游指南2 小时前
开源一个「照妖镜」Skill,从会话日志到“真身与灵魂”对比
人工智能·agent
阿弱2 小时前
从Plan-Execute到混合PEV:一个运维诊断Agent的架构演进实录
llm·agent
Being--2 小时前
搭建OsgEarth验证GIS数据发布服务的Agent
gis·agent·osgearth·ai落地
武子康3 小时前
GPT-Live 与 GPT-Realtime:产品模型和公开 API 不应混写
人工智能·chatgpt·agent
Databend3 小时前
从 Kafka 到 Databend Cloud:万亿级 Agent Trace 接入链路的工程实践
大数据·数据库·agent