如果今天你不是在跟一個聊天模型互動,而是在跟一個真的會做事、會排隊、會記得 session、還會把結果送回來的 AI Agent 互動,你第一個想知道的通常不是「它多會講」,而是:
我寫這 30 天系列的起點,就是這三個問題。
OpenClaw 最吸引我的地方,不是它會回答,而是它很像一個真的有運作規則的系統。它不是把模型包成一個 API 就結束,而是把「接任務、排隊、執行、送達、留下紀錄」整套流程接起來。
所以第 1 天我不想只講設定或名詞。我想直接看 source code 怎麼把一個 run 接起來,怎麼建立 lane,怎麼做 admission,怎麼確認這個 session 現在真的可以開始工作。
如果只看設定,你會以為自己看懂了;但真正決定行為的,是 code 裡的接收、驗證、排隊和放行。
runEmbeddedAgent 怎麼把一次執行接起來?sessionLane 和 globalLane 是怎麼把工作排好?beginSessionWorkAdmission 在擋什麼?如果把 OpenClaw 拆成一句話,我會說:
它是一個把「對話」做成「有序工作流」的系統。
OpenClaw 不是看到訊息就直接丟模型,而是先進到 agent runtime,再依序處理:
這也就是為什麼我覺得它比較像一個公司,而不是一個聊天玩具。
而且這一篇我不想只停在「它像什麼」,我想直接看它怎麼做。
先看 runtime 的入口。runEmbeddedAgent 不是直接開跑,它會先拿 config、建立 lifecycle,然後把工作交給內部流程。
export function runEmbeddedAgent(
paramsInput: RunEmbeddedAgentParams,
): Promise<EmbeddedAgentRunResult> {
const internalParamsInput = paramsInput as RunEmbeddedAgentInternalParams;
const requestedProvider = normalizeOptionalString(internalParamsInput.provider);
const requestedModel = normalizeOptionalString(internalParamsInput.model);
const needsConfiguredDefault =
!internalParamsInput.config && !requestedProvider && !requestedModel;
const config =
internalParamsInput.config ??
(needsConfiguredDefault ? (getRuntimeConfigSnapshot() ?? undefined) : undefined);
const lifecycleGeneration =
internalParamsInput.lifecycleGeneration ??
captureAgentRunLifecycleGeneration(internalParamsInput.runId);
return withAgentRunLifecycleGeneration(lifecycleGeneration, () =>
runEmbeddedAgentInternal({
...internalParamsInput,
config,
lifecycleGeneration,
}),
);
}
這段最重要的不是「它有一個 function」,而是它先做了三件事:
runEmbeddedAgentInternal
也就是說,OpenClaw 不是先跑模型,而是先把這次跑步的規則框好。
接著看它怎麼把工作排進 session lane 與 global lane。
const sessionLane = resolveSessionLane(params.sessionKey?.trim() || params.sessionId);
const globalLane = resolveGlobalLane(params.lane);
這兩行看起來很短,但意思很重:
sessionLane 是同一個 session 的排隊線globalLane 是更大的全域排隊線如果同一個 session 正在跑,新的工作就不能隨便插隊;如果全域已經很忙,也要先照整體節奏走。
再往下看,真正進入工作前,還會做 session admission 與 session store 檢查:
const sessionWorkAdmission = await beginSessionWorkAdmission({
scope: storePath ?? `agent:${sessionAgentId}`,
identities: [sessionKey, sessionId],
signal: opts.abortSignal,
onInterrupt: () => lifecycleAbortController.abort(createAgentRunRestartAbortError()),
assertAllowed: () => {
const currentEntry =
sessionStoreRuntime && storePath && sessionKey
? sessionStoreRuntime.loadSessionEntry({
storePath,
sessionKey,
readConsistency: "latest",
})
: sessionEntry;
if (!currentEntry && preparedSessionId) {
throw new Error(`Session "${sessionKey ?? sessionId}" changed while starting work. Retry.`);
}
const matchesIntentionalRollover =
isNewSession && currentEntry?.sessionId === preparedSessionId;
if (
currentEntry &&
currentEntry.sessionId !== sessionId &&
!matchesIntentionalRollover
) {
throw new Error(`Session "${sessionKey ?? sessionId}" changed while starting work. Retry.`);
}
const archivedSessionError = resolveSessionWorkStartError(
sessionKey ?? sessionId,
currentEntry,
);
if (archivedSessionError) throw new Error(archivedSessionError);
sessionEntry = currentEntry;
},
});
這段的語氣很像在說:
「先確認這個 session 真的還是你要處理的那個 session,再開始做。」
這就是 OpenClaw 很核心的氣質:它不是急著跑,而是先保證沒有跑錯地方。
最後補一段真正的 admission controller。這邊可以更直接看出,OpenClaw 不是只靠設定,而是把設定轉成實際的 gate。
export async function beginSessionWorkAdmission(params: {
scope: string;
identities: Iterable<string | undefined>;
assertAllowed: () => Promise<void> | void;
revalidateAllowed?: () => Promise<void> | void;
onInterrupt?: () => void;
signal?: AbortSignal;
}): Promise<SessionWorkAdmissionLease> {
if (isGatewaySubordinateWorkAdmissionClosed()) {
throw new GatewayDrainingError();
}
const identities = normalizeSessionIdentities(params.scope, params.identities);
return await runExclusiveSessionLifecycle({
scope: params.scope,
identities: params.identities,
signal: params.signal,
run: async () => {
await params.assertAllowed();
if (isGatewaySubordinateWorkAdmissionClosed()) {
throw new GatewayDrainingError();
}
...
},
});
}
這段在做的事很像門禁:
assertAllowed,通過了才真的放行也就是說,設定不是答案,設定只是原料;真正的規則,是 code 把它變成了 gate。
我很喜歡把這一層想成一支在比賽的隊伍。
runEmbeddedAgent 像賽事報名你不能一進場就衝。
你要先知道:
runEmbeddedAgent 做的就是這件事。它不是模型本體,而是把賽事規則先定好。
如果同一個 session 同時兩個 turn 一起跑,結果通常很慘。
OpenClaw 用 lane 來保證:
這很像工地現場先分區,再讓機具進場,不是所有人一起往裡衝。
beginSessionWorkAdmission 這段很重要。
它在做的不是「把事情啟動」,而是「確認這次啟動沒有衝突」。
如果 session 已經變了、已經被封存了、或者不是你現在該接的那個,系統會直接擋下來。
這就是為什麼 OpenClaw 很像一個正式制度,而不是臨時湊出來的腳本。
captureAgentRunLifecycleGeneration 跟 withAgentRunLifecycleGeneration 這種東西,像是在幫每一次 run 打上世代號碼。
這樣做的好處是:
這就像行車紀錄器,出事時才知道是哪一段流程在動。
但這個代價值得。
因為 AI Agent 真正難的地方,從來不是「叫模型說話」,而是「讓它穩定地做事」。
runEmbeddedAgent 先建立 config 與 lifecycle,再進入實作beginSessionWorkAdmission 把設定轉成真的 gate第 1 天先不要急著把每個函式背起來。
先記住一件事就夠了:
OpenClaw 不是先回答,而是先排隊、先確認、再執行。
第 2 天我會接著看,這個秩序到底是怎麼被拆成幾層架構的。