iT邦幫忙

2026 iThome 鐵人賽

DAY 2
0

開場故事

我很喜歡把 AI Agent 想成一個人。

不是因為它真的有情緒,而是因為這樣比較好理解它到底在幹嘛。你如果把它當成一個會回答問題的黑盒子,很多行為會看不懂;但如果你把它當成一個有腦袋、有工作區、有記憶、還有執行邊界的角色,你就會慢慢看出它的設計邏輯。

假設今天你第一次走進一間新公司。

你不會先問印表機在哪裡,你會先問:

  • 這間公司怎麼分工?
  • 誰有權決策?
  • 誰負責執行?
  • 每個部門的工作資料放哪裡?
  • 重要事情會不會留下紀錄?

OpenClaw 也是一樣。

第 1 天我們知道它不是單純聊天,而是會工作、會分派、會留下紀錄的系統。那第 2 天就要往前一步,看看這個系統的腦袋到底怎麼切層。

今天要解的問題

  • OpenClaw 的整體架構怎麼分層?
  • 一個 agent 的 workspace、session store、skills、model 權限怎麼對應?
  • 為什麼 main 不是唯一主角?
  • 子代理、路由、記憶、工具為什麼要拆開?
  • 如果要用一張圖理解 OpenClaw,應該怎麼畫?

架構總覽

如果把 OpenClaw 的整體架構縮成一句話,我會這樣說:

它是一個把「工作怎麼分工」翻成「AI 怎麼跑」的系統。

這句話不是口號,因為從 source code 看,它真的把責任拆得很明確。

一個 agent 不是只有模型而已,它還有:

  • workspace
  • agent dir
  • session store
  • skills snapshot
  • model visibility
  • delivery route

這些東西合起來,才是一個完整的 agent。

原始碼節錄

先看 runtime 入口怎麼把這些東西組起來。agentCommandInternal 會先準備執行環境,再進入 session admission,接著才處理 skills、模型、與送達。

📄 原始碼:src/agents/agent-command.ts:955-1001

async function agentCommandInternal(initialOpts, runtime = defaultRuntime, deps) {
	const resolvedDeps = await resolveAgentCommandDeps(deps);
	const isRawModelRun = initialOpts.modelRun === true || initialOpts.promptMode === "none";
	const suppressVisibleSessionEffects = initialOpts.sessionEffects === "internal";
	const preserveUserFacingSessionModelState = initialOpts.preserveUserFacingSessionModelState === true;
	const prepared = await prepareAgentCommandExecution(initialOpts, runtime);
	const lifecycleAbortController = new AbortController();
	const opts = {
		...prepared.opts,
		abortSignal: prepared.opts.abortSignal ? AbortSignal.any([prepared.opts.abortSignal, lifecycleAbortController.signal]) : lifecycleAbortController.signal
	};
	const { body, transcriptBody, cfg, configuredThinkingCatalog, normalizedSpawned, agentCfg, thinkOverride, thinkOnce, verboseOverride, timeoutMs, runTimeoutOverrideMs, sessionId, sessionKey, sessionStore, storePath, isNewSession, persistedThinking, persistedVerbose, sessionAgentId, outboundSession, workspaceDir, cwd, agentDir, runId, isSubagentLane, acpManager, acpResolution, pluginsEnabled, manifestMetadataSnapshot, modelManifestContext } = prepared;
	let lifecycleGeneration = opts.lifecycleGeneration ?? captureAgentRunLifecycleGeneration(runId);
	...
}

這段一開始就告訴你:OpenClaw 的 agent 不是只有一個模型呼叫。

它先準備一整個執行包,裡面有:

  • workspaceDir
  • agentDir
  • sessionStore
  • storePath
  • sessionKey
  • sessionId
  • agentCfg
  • cfg

也就是說,這不是「模型要不要回答」而已,而是「這次 run 的整個生態系要怎麼組」。

再往下看,它會先把 skills snapshot 拉出來,然後再決定要用哪些能力。

📄 原始碼:src/agents/agent-command.ts:1400-1428

const skillFilter = resolveEffectiveAgentSkillFilter(cfg, sessionAgentId);
const currentSkillsSnapshot = sessionEntry?.skillsSnapshot;
const [{ getRemoteSkillEligibility, resolveReusableWorkspaceSkillSnapshot }, { canExecRequestNode }] = await Promise.all([loadSkillsRuntime(), loadExecDefaultsRuntime()]);
const skillSnapshotState = resolveReusableWorkspaceSkillSnapshot({
	workspaceDir,
	config: cfg,
	agentId: sessionAgentId,
	existingSnapshot: isNewSession ? void 0 : currentSkillsSnapshot,
	skillFilter,
	eligibility: { remote: getRemoteSkillEligibility({ advertiseExecNode: canExecRequestNode({
		cfg,
		sessionEntry,
		sessionKey,
		agentId: sessionAgentId
	}) }) },
	watch: false
});
const needsSkillsSnapshot = isNewSession || !currentSkillsSnapshot || skillSnapshotState.shouldRefresh;
const skillsSnapshot = skillSnapshotState.snapshot;
if (skillsSnapshot && sessionStore && sessionKey && needsSkillsSnapshot && !suppressVisibleSessionEffects) {
	...
}

這段很關鍵。

因為它證明 OpenClaw 的技能不是臨時查表而已,而是會形成一份可重用的 snapshot,並且跟 session 綁在一起。

這代表:

  • 同一個 agent 有自己的技能視圖
  • 新 session 與舊 session 的技能狀態可以不同
  • 技能不是全域亂開,而是有 filter 的

再看模型與可見性控制。

📄 原始碼:src/agents/agent-command.ts:1502-1564

const configuredDefaultRef = resolveDefaultModelForAgent({
	cfg,
	agentId: sessionAgentId,
	allowPluginNormalization: pluginsEnabled,
	...modelManifestContext
});
const runContext = resolveAgentRunContext(opts);
const { provider: defaultProvider, model: defaultModel } = normalizeAgentCommandDefaultModelRef(cfg, configuredDefaultRef.provider, configuredDefaultRef.model, modelManifestContext);
let provider = defaultProvider;
let model = defaultModel;
const hasAllowlist = agentCfg?.models && Object.keys(agentCfg.models).length > 0;
let visibilityPolicy = createModelVisibilityPolicy({
	cfg,
	catalog: [],
	defaultProvider,
	defaultModel,
	allowManifestNormalization: true,
	allowPluginNormalization: pluginsEnabled,
	...modelManifestContext
});
if (hasAllowlist) {
	modelCatalog = pluginsEnabled ? loadManifestModelCatalog({
		config: cfg,
		workspaceDir
	}) : [];
	visibilityPolicy = createModelVisibilityPolicy({
		cfg,
		catalog: modelCatalog,
		defaultProvider,
		defaultModel,
		agentId: sessionAgentId,
		allowManifestNormalization: true,
		allowPluginNormalization: pluginsEnabled,
		...modelManifestContext
	});
}

這段在告訴你:OpenClaw 每個 agent 看到的模型集合不一定一樣。

它會根據 agent config、workspace、manifest、plugin normalization 來決定:

  • 預設模型是什麼
  • 哪些模型可見
  • 哪些 override 合法

這就是為什麼它是 multi-agent 系統,而不是單一 prompt 包裝器。

白話拆解

我常常把這一層想成一間公司裡的「部門制度」。

1. workspace 像部門辦公室

每個 agent 都有自己的 workspace。

這很像每個部門都有自己的辦公室、文件櫃、SOP、筆記本。你不會期待財務和研發共用同一個抽屜還完全不出事。

OpenClaw 把 workspace 當成 agent 的基本工作地盤,這樣每個角色的背景資訊、備註、bootstrap files 才能真的分開。

2. session store 像會議紀錄

session 不是只記聊天內容,它還記狀態。

這包括:

  • 這個 session 是否新開
  • 它的 sessionId 是什麼
  • 技能 snapshot 是什麼
  • 模型 override 是什麼
  • 最近的 interaction 是什麼

所以 session 不是訊息容器而已,而是工作狀態容器。

3. skills snapshot 像部門當下可用的工具箱

不是所有工具每次都現查。

OpenClaw 會把可用 skills 先整理成 snapshot,這樣 agent 在執行時知道自己能用哪些工具。這很像每個部門的工具箱不同,而且工具箱內容會被版本化。

4. model visibility 像授權名單

不是所有 agent 都能看到所有模型。

有些模型被 allowlist 限制,有些可以靠 manifest 或 plugin normalization 進來,有些只能在特定情境可見。

這種設計的本質不是麻煩,而是避免 agent 一時失控把不該用的模型也用掉。

設計取捨

好處

  • 每個 agent 有自己的工作邊界
  • workspace、session、skills、model 都不會混成一坨
  • 之後要擴充新 agent 時,不必重寫整個系統
  • 問題發生時比較容易定位是 workspace、session、skills 還是 model 的問題

代價

  • 前期概念比較多
  • 讀 code 不能只看一個入口
  • workspaceDirsessionStoreagentDirskillsSnapshot 這些東西要一起理解

但這就是成熟系統的樣子。

它不是只有一個黑盒,而是每一層都有責任。

今天的結論

  • OpenClaw 的腦袋不是單一模型,而是一整套 runtime 與 workspace 邊界
  • agentCommandInternal 先準備執行環境,再處理 session 與技能
  • skills 不是臨時查表,而是有 snapshot 與 filter 的
  • model 可見性不是全開,而是受 config、manifest、plugin normalization 控制
  • 第 2 天最值得記住的是:OpenClaw 是「分工系統」,不是「單一大腦」

下一步

第 3 天我會接著看第一個任務是怎麼被接進來的。

因為把腦袋分層看懂之後,下一個問題就會變成:

入口進來的訊息,到底是怎麼落到真正的 session 與 run 上的?

那就是下一篇要看的重點。


上一篇
第 1 天:我想跟一個 AI Agent 認識,先從 OpenClaw 開始
下一篇
第 3 天:它怎麼接到第一個任務,從入口開始看
系列文
30 天走進 OpenClaw:一個 AI Agent 的誕生、掙扎與進化3
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言