Kimi Agent SDK 深度解析:MoonshotAI 的 CLI-as-Engine Agent 架構
在 AI Agent 框架百花齊放的當下,MoonshotAI 推出的 Kimi Agent SDK 走了一條截然不同的路。它不是又一個自行實作 Agent Loop 的框架,而是將已有的 Kimi Code CLI 作為底層引擎,透過薄薄一層語言原生客戶端暴露給應用程式。這種「CLI-as-Engine」的架構哲學,決定了它從 Wire Protocol 到工具系統的每一個設計抉擇。
本文將從原始碼角度,逐層拆解 Kimi Agent SDK 的核心設計。
一、定位與架構哲學
Kimi Agent SDK 是 MoonshotAI 為 Kimi Code CLI 提供的多語言 SDK 套件,支援 Go、Node.js (TypeScript) 與 Python 三種語言。它的核心定位非常明確:不是 Agent 框架,而是 Agent 引擎的 wrapper。
與 LangGraph、CrewAI、OpenAI Agents SDK 等框架不同,Kimi Agent SDK 本身不實作任何 Agent 邏輯。真正的 Agent loop、tool execution、memory management 全部發生在 Kimi CLI 內部。SDK 的職責是:
- 啟動並管理 CLI 子進程
- 透過 JSON-RPC 2.0 Wire Protocol 進行雙向通訊
- 串流事件處理(文字、思考、工具呼叫、核准請求)
- 外部工具註冊與呼叫代理
- Session 生命週期管理
這意味著 SDK 與 CLI 之間有嚴格的責任邊界:SDK 負責「通訊與呈現」,CLI 負責「思考與行動」。
二、整體架構:CLI-as-Engine
整個架構可以用以下分層表示:
Application Code (Go / Node.js / Python)
|
Kimi Agent SDK <-- thin client
|
Wire Protocol (JSON-RPC 2.0 over stdio)
|
kimi CLI 子進程 <-- 真正的 Agent 引擎
|
LLM API (Moonshot / OpenAI / Anthropic / Google / etc.)
架構圍繞三個核心概念展開:
- Session — 與 CLI 進程的連線。管理底層進程的啟動、恢復(resume)和關閉。
- Turn — 一次對話來回(user prompt 到 agent response)。每個 Turn 包含串流式的事件輸出。
- Step — Turn 內的處理步驟。Agent 推理、呼叫工具、產生輸出時,一個 Turn 可能包含多個 Step。
CLI-as-Engine 的優勢在於:SDK 與 CLI 行為保證一致,所有設定、內建工具、MCP 伺服器完全復用,CLI 版本升級時 SDK 自動受益,且大幅降低了 SDK 層的維護負擔。
劣勢則是:Go 和 Node.js 版本必須在環境中安裝 kimi CLI,SDK 功能受限於 CLI 所暴露的能力,跨進程通訊也讓除錯變得更加繁瑣。
三、Wire Protocol:雙向 JSON-RPC 2.0
SDK 與 CLI 之間的通訊協議是整個架構的骨幹。目前的協議版本為 1.3,基於 JSON-RPC 2.0,透過 CLI 進程的 stdin/stdout 進行。
3.1 SDK 發送給 CLI 的 RPC 方法
initialize:握手階段,傳遞協議版本和外部工具定義prompt:發送使用者輸入,啟動一個新的 Turncancel:取消當前正在執行的 Turnreplay:重放歷史事件(Wire 1.3 新增)
3.2 CLI 發送給 SDK 的通知與請求
event:串流事件通知(單向,不需回應)request:需要 SDK 回應的請求,包含ApprovalRequest(核准請求)和ToolCallRequest(外部工具呼叫請求)
3.3 事件類型系統
事件分為兩大類。第一類是資訊性事件(Events),不需回應:
| 事件 | 說明 |
|---|---|
TurnBegin / TurnEnd | Turn 開始/結束 |
StepBegin / StepInterrupted | Step 開始/中斷 |
ContentPart | 文字、思考 (think)、圖片、音訊等內容 |
ToolCall / ToolCallPart / ToolResult | 工具呼叫與結果 |
StatusUpdate | Token 使用量與 context 使用率 |
CompactionBegin / CompactionEnd | Context 壓縮事件 |
SubagentEvent | 子 Agent 巢狀事件 |
第二類是請求事件(Requests),必須回應,否則 Session 會無限期阻塞:
ApprovalRequest:請求使用者核准(如執行 shell 命令、修改檔案)ToolCallRequest:外部工具呼叫請求(由 SDK 自動攔截並處理)
3.4 Go 的 JSON-RPC 2.0 Codec 實作
Go SDK 的 jsonrpc2.Codec 實作值得特別關注。它在一個 io.ReadWriteCloser(即 stdin/stdout)上同時扮演 client 和 server 角色:
codec := jsonrpc2.NewCodec(&stdio{stdin, stdout},
jsonrpc2.ClientMethodRenamer(...), // Go RPC 方法名 -> JSON-RPC 方法名
jsonrpc2.ServerMethodRenamer(...), // JSON-RPC 方法名 -> Go RPC 方法名
)
這個 Codec 支援串流操作(StreamOpen / StreamSync / StreamClose)、方法名稱雙向重新命名,以及完整的生命週期管理(graceful shutdown、idle timeout),同時復用了 Go 標準庫的 net/rpc 介面,但完全自訂了編解碼邏輯。這是一個精巧的工程設計。
四、Agent Loop 執行流程
Agent Loop 由 CLI 內部驅動,SDK 側的執行流程如下:
1. 建立 Session(啟動 kimi CLI 子進程)
2. 發送 Initialize RPC(握手、註冊外部工具)
3. 發送 Prompt RPC(使用者輸入)
4. 接收串流事件:
a. TurnBegin -> 標記 Turn 開始
b. StepBegin -> 新的推理/工具步驟開始
c. ContentPart -> 輸出文字或思考過程
d. ToolCall -> Agent 呼叫工具
e. ToolResult -> 工具返回結果
f. ApprovalRequest -> 等待使用者核准(必須回應)
g. ToolCallRequest -> 外部工具呼叫(SDK 自動處理)
h. StatusUpdate -> Token/Context 使用量更新
i. CompactionBegin/End -> Context 壓縮
j. TurnEnd -> Turn 結束
5. 取得 PromptResult(finished / cancelled / max_steps_reached)
6. 繼續下一個 Turn,或關閉 Session
這裡有幾個關鍵設計約束需要特別注意:
- Sequential Prompts:必須依序發送 Prompt,等前一個 Turn 完成(或取消)後才能開始下一個。
- Must Consume:必須消耗完所有事件或明確 Cancel,否則會阻塞。
- Must Respond:
ApprovalRequest必須回應,否則 Session 無限期等待。 - Resource Cleanup:必須 Close Session,確保 CLI 子進程正確終止。
4.1 Go: Turn 事件遍歷核心
Turn.traverse() 是 Go SDK 事件處理的核心,透過 channel 實現串流消費:
func (t *Turn) traverse(incoming <-chan wire.Message, steps chan<- *Step) {
// 等待 TurnBegin
msg := <-incoming
if _, is := msg.(wire.TurnBegin); !is { return }
for msg := range incoming {
switch x := msg.(type) {
case wire.TurnEnd:
return // Turn 完成
case wire.Request:
outgoing <- x // ApprovalRequest 轉發到 step.Messages
case wire.Event:
switch x.EventType() {
case wire.EventTypeStepBegin:
close(outgoing)
outgoing = make(chan wire.Message)
steps <- &Step{Messages: outgoing}
case wire.EventTypeStatusUpdate:
// CAS loop 原子性累計 Token 使用量
update := x.(wire.StatusUpdate)
// ...
default:
outgoing <- x // ContentPart, ToolCall, etc.
}
}
}
}
Go SDK 使用 range 迭代 channel 消費串流,搭配 sync/atomic 做無鎖狀態管理。當收到 StepBegin 事件時,關閉舊的 Step channel 並建立新的,讓消費者自然知道步驟切換。
4.2 Turn 取消機制
Go 版本支援三種取消方式:
// 1. 直接取消
turn.Cancel()
// 2. 透過 context 取消
ctx, cancel := context.WithCancel(parentCtx)
defer cancel()
// 3. 超時自動取消
ctx, cancel := context.WithTimeout(parentCtx, 30*time.Second)
defer cancel()
取消後 Session 仍然可用,可以繼續發送新的 Prompt。
五、工具系統
5.1 內建工具
Kimi CLI 內建了豐富的工具集,包括:Shell(執行命令)、ReadFile / WriteFile / StrReplaceFile(檔案操作)、Glob / Grep(搜尋)、SearchWeb / FetchURL(網頁)、Task(子 Agent 任務)、SetTodoList(Todo 管理)。這些工具在 CLI 內部執行,SDK 只接收事件通知。
5.2 外部工具:三種語言的不同風格
外部工具是 SDK 最具特色的擴展機制,三種語言各自採用了最符合語言慣例的實作方式。
Go 版本 — 泛型加反射,自動產生 JSON Schema:
type WeatherArgs struct {
Location string `json:"location" description:"City name"`
Unit string `json:"unit,omitempty" description:"Temperature unit"`
}
tool, _ := kimi.CreateTool(getWeather,
kimi.WithName("get_weather"),
kimi.WithDescription("Get current weather"),
)
session, _ := kimi.NewSession(kimi.WithTools(tool))
CreateTool 使用 Go 1.18+ 泛型 CreateTool[T any, U any],透過 reflect 從 struct tag 自動生成 JSON Schema。omitempty 或指標類型自動標記為 optional,函式名稱透過 runtime.FuncForPC 自動偵測。這是三種語言中技術上最優雅的實作。
其 Schema 生成邏輯遞迴處理 struct、指標、slice 等型別:
func generateSchema(t reflect.Type, fieldDescs map[string]string) (*jsonSchema, error) {
switch t.Kind() {
case reflect.Struct:
schema.Type = "object"
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
jsonName, desc, isRequired := parseFieldTags(field)
fieldSchema := generateSchema(field.Type, nil) // 遞迴
schema.Properties[jsonName] = fieldSchema
if isRequired { required = append(required, jsonName) }
}
case reflect.Ptr:
return generateSchema(t.Elem(), fieldDescs) // 展開指標
case reflect.Slice:
schema.Type = "array"
schema.Items = generateSchema(t.Elem(), nil)
}
}
Node.js 版本 — 使用 Zod schema,透過 zod-to-json-schema 轉換:
const weatherTool = createExternalTool({
name: 'get_weather',
description: 'Get weather information',
parameters: z.object({
city: z.string().describe('City name'),
unit: z.enum(['celsius', 'fahrenheit']).optional(),
}),
handler: async (params) => ({
output: `Weather in ${params.city}: 22 degrees`,
message: 'Weather fetched successfully',
}),
});
Node.js 版本同時支援 Zod v3 和 v4,對生態系的相容性考量相當周到。
Python 版本 — 使用 Pydantic model 加 agent YAML 檔:
class Params(BaseModel):
directory: str = Field(default=".", description="The directory to list files from.")
class Ls(CallableTool2):
name: str = "Ls"
description: str = "List files in a directory."
params: type[Params] = Params
async def __call__(self, params: Params) -> ToolReturnValue:
files = os.listdir(params.directory)
return ToolOk(output="\n".join(files))
Python 的自訂工具需要在 agent YAML 檔案中以 module:ClassName 格式註冊,而非直接傳入 SDK。這與 Go/Node.js 的方式有本質差異。
5.3 外部工具呼叫流程
Model 決定呼叫外部工具
-> CLI 發送 ToolCallRequest (JSON-RPC request) 到 SDK
-> SDK 自動攔截並呼叫已註冊的函式
-> SDK 回傳 ToolResult 到 CLI
-> CLI 將結果送回 Model
Go 版本在 Responder.Request() 中比對工具名稱、反序列化參數、呼叫函式、包裝結果。Node.js 版本在 ProtocolClient.handleToolCallRequest() 中完成相同邏輯。
值得注意的是,外部工具需要 Wire Protocol Version >= 1.1。SDK 在初始化時自動偵測版本,舊版 CLI 會靜默忽略外部工具定義。
5.4 核准流程
內建工具執行前可能觸發核准請求。SDK 提供三種回應選項:
approve:核准本次操作approve_for_session:核准並自動核准後續類似操作reject:拒絕操作
此外也支援 auto_approve / yolo 模式,自動核准所有請求,適用於 CI/CD 等無人互動場景。
六、記憶體與上下文管理
6.1 Session 持久化
對話歷史由 Kimi CLI 管理,儲存在本地檔案系統。各語言 SDK 提供不同層級的 Session 管理能力:
~/.kimi/
config.toml # 設定檔
mcp.json # MCP 伺服器設定
sessions/
{workDir_hash}/ # 按工作目錄分組
{sessionId}/
context.jsonl # 對話歷史
Go SDK 透過 WithSession(id) 指定現有 Session ID 恢復對話;Node.js SDK 提供 listSessions()、deleteSession()、parseSessionEvents() 等完整管理工具;Python SDK 則支援 Session.resume() 方法。
6.2 Context 壓縮
當 context window 使用率接近 100% 時,CLI 會自動觸發 context compaction:發送 CompactionBegin 事件,將舊訊息壓縮為摘要,再發送 CompactionEnd 事件。SDK 透過 StatusUpdate 事件追蹤 context_usage(0.0 到 1.0 的浮點數)。
6.3 Token 使用量追蹤
type TokenUsage struct {
InputOther int // 一般輸入 token
Output int // 輸出 token
InputCacheRead int // 快取讀取 token
InputCacheCreation int // 快取建立 token
}
6.4 迴圈控制
type LoopControl struct {
MaxStepsPerRun int // 每次執行最大步數(預設 25)
MaxRetriesPerStep int // 每步最大重試次數(預設 3)
}
Python 額外支援 max_ralph_iterations 參數,用於 Ralph Loop 模式的迭代次數控制。
七、三語言實作差異
Kimi Agent SDK 的三種語言實作不僅是語法層面的差異,在架構層面也有根本性的不同。
7.1 通訊機制
Go 和 Node.js 版本都透過 stdio 子進程通訊,遵循標準的 Wire Protocol。但 Python 版本是唯一不走 stdio 的:它直接 import kimi_cli.app.KimiCLI,在同一個進程中運行 Agent 引擎。
class Session:
def __init__(self, cli: KimiCLI):
self._cli = cli # 直接持有 KimiCLI 實例
@staticmethod
async def create(work_dir, ...):
cli_session = await CliSession.create(work_dir_path, session_id)
cli = await KimiCLI.create(cli_session, config=config, ...)
return Session(cli)
這意味著 Python 版本與 CLI 的耦合度最高(pyproject.toml 中版本鎖定為 kimi-cli>=1.12.0,<1.13.0),但省去了 IPC 開銷,效能可能最好。
7.2 併發模型
三種語言各自採用最自然的併發機制:
- Go:channel + goroutine。
Turn.Steps是<-chan *Step,Step.Messages是<-chan wire.Message,使用range迭代消費。 - Node.js:自訂的
createEventChannel<T>()實作AsyncIterable,支援Symbol.asyncIterator和Symbol.asyncDispose。 - Python:基於 asyncio 的 async generator,使用
async for消費串流。
7.3 差異摘要
| 面向 | Go | Node.js | Python |
|---|---|---|---|
| 與 CLI 通訊 | stdio + JSON-RPC 2.0 | stdio + JSON-RPC 2.0 | 直接 import CLI |
| 併發模型 | channel + goroutine | AsyncIterator | asyncio generator |
| Schema 驗證 | 反射 + struct tag | Zod | Pydantic |
| 外部工具定義 | 泛型函式 | Zod schema + handler | agent YAML + Pydantic |
| 額外功能 | 精簡核心 | VSCode Extension, storage | 高/低階雙層 API |
| 最低版本 | Go 1.22+ | ES2022+ | Python 3.12+ |
Go SDK 最精簡,只有六個核心檔案加上 wire 層;Node.js SDK 最豐富,附帶完整的 VSCode Extension;Python SDK 則提供高階 prompt() 函式和低階 Session 類別的雙層 API。
八、技術亮點
8.1 Ralph Loop 模式
Ralph Loop 是一種「迭代驗證」模式,核心原則是永遠不信任 Agent 輸出,用外部命令驗證:
- 發送任務 prompt
- Agent 執行
- 執行外部驗證命令(如跑測試、lint 檢查)
- 若驗證失敗,帶著失敗結果重新 prompt
- 重複直到驗證通過或達到最大迭代次數
這對 CI/CD 自動化場景特別實用,確保 Agent 產出的程式碼符合品質要求。
8.2 多供應商支援
雖然是 MoonshotAI 的產品,但 Kimi Code CLI 支援配置多種 LLM 供應商:Moonshot AI(自家)、OpenAI(Legacy 和 Responses API)、Anthropic、Google GenAI / Gemini、Vertex AI。SDK 只是透傳設定,不介入供應商選擇。
8.3 MCP 原生整合
原生支援 Model Context Protocol 伺服器,設定透過 mcp.json 或程式碼傳入,支援 HTTP 和 stdio 兩種傳輸方式,並支援 OAuth 認證。Node.js SDK 另外提供 authMCP()、testMCP()、resetAuthMCP() 等管理函式。
8.4 子 Agent 與 KAOS 沙箱
透過 SubagentEvent 支援巢狀 Agent 任務,事件可以遞迴包裝。Python 範例中還展示了 KAOS(Kimi Agent OS)沙箱後端支援,包含 BoxLite(本地輕量沙箱)、E2B(雲端沙箱)和 Sprites 三種後端,同一套工具可在不同沙箱環境隔離執行。
8.5 Thinking 模式
支援模型思考/推理過程的暴露。ContentPartTypeThink 事件包含模型的內部推理,可在 Session 建立時啟用或停用,還支援加密思考內容(encrypted 欄位),兼顧了透明度與安全性。
九、限制與觀察
9.1 主要限制
- CLI 依賴:Go/Node.js 版本必須安裝 Kimi CLI,Python 版本則需要
kimi-cli和kosong套件,對部署環境有明確要求。 - Python 版本鎖定:
kimi-cli>=1.12.0,<1.13.0和kosong>=0.42.0,<0.43.0,版本範圍極為狹窄,升級風險高。 - Python 版本限制:需要 Python >= 3.12,使用了
match/case等較新語法。 - 無獨立 Agent 邏輯:SDK 不實作 Agent loop,無法脫離 CLI 獨立使用。
- 除錯困難:Go/Node.js 版本的跨進程通訊增加了除錯的複雜度。
9.2 與其他框架的比較
- vs OpenAI Agents SDK:OpenAI 的 SDK 直接與 API 通訊,Kimi 透過 CLI 中介。OpenAI 版本更輕量,但 Kimi 版本繼承了 CLI 的全部能力。
- vs LangGraph:LangGraph 提供圖狀態機編排,Kimi SDK 只暴露線性的 Session/Turn/Step 模型。
- vs CrewAI:CrewAI 著重多 Agent 協作,Kimi SDK 透過
Task工具和SubagentEvent提供類似但更受限的能力。 - vs Claude Code SDK:架構理念最為接近(CLI 作為引擎),但 Kimi Agent SDK 是目前少數公開此架構的實作。
9.3 適用場景
Kimi Agent SDK 最適合以下場景:已有 Kimi Code 使用者希望程式化存取 Agent 能力、CI/CD 自動化(Ralph Loop 模式)、自訂 IDE 整合(Node.js SDK + VSCode Extension 提供完整範本)、以及需要沙箱隔離的執行環境(KAOS 後端)。
十、總結
Kimi Agent SDK 的「CLI-as-Engine」架構是一個大膽的設計選擇。它放棄了 SDK 層的自主性,換取了與 CLI 的完全一致性和低維護成本。Wire Protocol 的抽象讓多語言支援成為可能,而三種語言各自遵循語言慣例的實作(Go 的泛型反射、Node.js 的 Zod、Python 的 Pydantic)則展現了團隊對各語言生態的理解。
從工程角度看,Go SDK 的 JSON-RPC 2.0 雙向 Codec、外部工具的泛型 Schema 生成、以及 channel-based 的串流消費模式,都是值得學習的精巧設計。Python SDK 直接 import CLI 而非走子進程的架構差異,則是一個有趣的折衷。
對於已經在使用 Kimi Code CLI 的開發者而言,這個 SDK 提供了程式化存取 Agent 引擎的最短路徑。但對於希望從零搭建 Agent 系統的團隊來說,它的 CLI 依賴可能是一個需要考量的限制。無論如何,CLI-as-Engine 這個架構模式本身值得 Agent 框架設計者參考 — 在 Agent 能力快速迭代的當下,讓 SDK 保持「薄而穩定」,將複雜度集中在一處,或許是一種更務實的策略。