Agent 是怎麼做出來的?
一個很強的 LLM,配上一堆工具、一堆很精密的操作規範,然後就變一個 Agent 了。
研究了 OpenClaw 跟 Claude Code 的 source code,在這些 production agent 裡面,harness 做的事情就是在每次 API call 之前,把 system prompt、tool schema、memory、runtime context 組裝好塞進 LLM 的 context window 裡。而那些定義 agent 行為的內容,很多時候就是 ——
一組 .md 檔案
就這樣。一個 LLM 加上一組被精心組裝的 context,它就從一個聊天機器人 promote 成了一個 Agent。但這些檔案怎麼寫、怎麼拼、什麼時候塞進去、塞多少、哪些該 cache 哪些不該,是整個 Agent Engineering 真正在做的事。
這篇從那些具體的檔案開始,一路拆到 agent 的設計框架。
一個 Agent 的三層結構
在拆任何 agent 之前,先建立一個直覺:
- 大腦 — LLM 本身。負責推理、理解、生成回應。但它什麼都不記得,每次對話都是從零開始。它的全部世界就是 context window 裡面的東西
- 身體 — 工具。Browser、file system、code execution、API calls。讓 agent 能跟外界互動,不只是說話
- 骨架(Harness) — 看不到但最重要的一層。它負責在每次 API call 之前,把對的 prompt、對的工具定義、對的記憶、對的使用者資訊,組裝成一個完整的 context,然後餵給大腦
OpenClaw 的 Prompt Files
打開 OpenClaw 的 workspace,會看到一組被注入 prompt 的檔案。README 簡化列出三個核心檔:AGENTS.md、SOUL.md、TOOLS.md。
codebase 實際上支援 8 個 bootstrap filename — 上面三個再加上 IDENTITY.md、USER.md、HEARTBEAT.md、BOOTSTRAP.md、MEMORY.md。
GitAgent spec 跟 Hermes Agent 的設計是把同樣的概念用不同方式組織,例如 GitAgent 把 hard rules 拆到 RULES.md。至於 OpenClaw 龍蝦是怎麼組裝的,一個一個來看看:
👉 SOUL.md — 靈魂
定義 Agent 是誰、用什麼語氣說話、什麼話題可以聊什麼不行、什麼行為可以做什麼不行。
很多人以為 SOUL.md 就是 system prompt 裡面那段「你是一個友善的 AI 助理」。不只,一個寫得好的 SOUL.md 會定義到很細的行為(Behavior)邊界 — 比如「使用者提供模糊的需求時,先做一個合理的嘗試,在結尾附上你的假設,讓使用者可以修正」。這種細粒度的行為定義,決定了 agent 用起來的感覺。
GitAgent spec(gitagent.sh)把 SOUL.md 再進一步拆成兩個層次:
- SOUL.md 留給人格跟溝通風格
- RULES.md 專門放 hard constraints — must-always 跟 must-never 規則
在 multi-agent 系統裡面,多個 agent 可能共用同一套 rules 但有不同的 soul/personality,這時候拆開就很有價值。
👉 TOOLS.md — 身體
定義 agent 能用哪些工具、能碰哪些 API、有什麼存取限制。SOUL.md 跟 TOOLS.md 管的層次完全不同:
- TOOLS.md 回答「你能不能做這件事」— 更準確地說,是 LLM 認知的「能力」邊界。真正的能力住在 OS(安裝了什麼)跟 harness(bash exec policy 允許什麼),TOOLS.md 是讓 LLM 知道那些能力存在的目錄
- SOUL.md 回答「你該不該做這件事」— 「行為」邊界。一個 agent 可能裝了 browser tool 可以上網搜尋,但 SOUL.md 可以說「不主動搜尋使用者的個人資料」。工具提供了,但行為被約束住。
能力跟權限可以個別設定。
👉 AGENTS.md — 工作手冊
操作指令。推理的流程要怎麼走、多步任務怎麼拆解、遇到模糊的請求怎麼處理、如果是 multi-agent 架構的話 agent 之間怎麼協作跟 handoff。
把它理解成「大雜燴 x 工作手冊 x 大雜燴」。
👉 USER.md — Agent 使用者是誰
USER.md 跟 IDENTITY.md 是對稱的:
- IDENTITY.md 是「我(agent)是誰」
- USER.md 是「我(agent)服務的那個人是誰」
👉 IDENTITY.md — 對外的臉
相較於 SOUL 決定這個 Agent 的人格、行為邊界,IDENTITY 是外部怎麼揭露這個 Agent。
IDENTITY.md 跟 SOUL.md 分開是一個設計慣例不是規則 — OpenClaw 的 dev template 就把 Role、Soul、Quirks 全部塞進 IDENTITY.md 裡面。
一個有用的 mental model:
- IDENTITY 管的是「runtime 真的會去讀來顯示給使用者看的東西」— display name、avatar 推到 Telegram / Discord bot profile 上、簽名 emoji
- SOUL 管的是「LLM 在 context window 裡讀的軟性指引」— 口吻、邊界、偏好
如果你要 fork 一個 agent 給朋友用,你會改 IDENTITY 但不一定改 SOUL — 同樣的人格,新身份。
👉 MEMORY.md — 累積的知識
跨 session 的記憶、學到的東西、過去互動中值得保留的資訊。A-MEM 這篇 2025 年的 agentic memory 研究提出用 Zettelkasten 方法讓 agent 動態組織自己的記憶,不只是做 storage/retrieval。
依 Nous Research 的 Hermes Agent repo 描述,它把 execution traces、skill evolution 跟自我改進流程接在一起 — 這比較像 self-improving agent 的前沿實驗方向,而不是所有框架的標配。
👉 BOOTSTRAP.md — 自毀的 onboarding 指令
這個檔案的機制超簡單但很漂亮:
- 新 workspace 建好時 BOOTSTRAP.md 存在 → bootstrap layer 把它載進 system prompt
- Agent 第一次收到訊息時看到這份內容,照著指示做事(跟 user 對話、填寫 IDENTITY.md / USER.md / SOUL.md)
- 指示的最後一行:「Delete this file. You don’t need a bootstrap script anymore — you’re you now.」
- Agent 自己刪掉 BOOTSTRAP.md
- 從此之後的 sessions 裡就沒有它了
沒有特殊模式、沒有 lifecycle hook — 就是「只要它在就會被注入,它叫 agent 刪掉自己」。完全靠 LLM 照指示做。
這個設計最有趣的地方:因為 BOOTSTRAP.md 就是一份 markdown,你可以手寫客製版,把空白 workspace 塑造成任何你要的 agent。甚至可以讓一個 agent 寫 BOOTSTRAP.md 給另一個 agent — main agent 跟你開完會討論好需求,在新 workspace 裡放一份客製的 BOOTSTRAP.md,新 agent 第一次開機就自動走完 setup 然後自毀。不需要特殊 API、不需要 setup wizard,agent 只要會寫 markdown 就可以孵化新的 agent instances。
這就是 agent factory pattern — 把「agent 怎麼被生出來」降成「寫一個 markdown 檔案然後等 LLM 跑完它」。
Claude Code 怎麼做同樣的事
Claude Code 沒有這些分離的 .md 檔,但它用不同的工程手法在解決完全一樣的問題。
核心是 getSystemPrompt() 這個函式(據社群逆向工程與 source map 外洩分析)。裡面有一條隱藏的分界線叫 __SYSTEM_PROMPT_DYNAMIC_BOUNDARY__,把 prompt 切成兩層 cache:
- 分界線之前 — 人格定義、安全規則、22 個模組化的工具指令。全域 cache,TTL 一小時。不管開幾個 session 都共用同一份
- 分界線之後 — CLAUDE.md 的內容、目前的 git status、MCP server 設定、memory index。Per-session cache,TTL 五分鐘
對照一下:
- OpenClaw 的 SOUL.md → Claude Code 的 behavioral rules sections(Intro、System Rules、Tone and Style 等段落)
- OpenClaw 的 TOOLS.md → Claude Code 的「Using Your Tools」system prompt section + tools[] API parameter
- OpenClaw 的 USER.md / project context → Claude Code 的 CLAUDE.md、memory、project instructions 等 session-specific context
- OpenClaw 的 MEMORY.md → Claude Code 的 memory index + autoDream 壓縮系統
- OpenClaw 的 BOOTSTRAP.md → Claude Code 沒有對應(因為每次都是 fresh session)
這裡有一個值得細看的設計。Claude Code 的 tool 資訊其實分成兩個地方:
- Tool schema(JSON 定義 — 每個 tool 的名字、參數、描述)走 API 的 tools[] parameter,跟 system prompt 完全分開。Built-in tools 加上 MCP 帶進來的,數量相當可觀
- Tool 使用指令(「優先用 Read/Edit/Glob/Grep,不要用 Bash 去做同樣的事」)放在 system prompt 裡面的「Using Your Tools」section
這兩層的拆法是優化出來的 — schema 定義走 API parameter 不佔 system prompt 空間,但 LLM 需要的「怎麼聰明地選擇工具」的指引還是放在 system prompt 裡面,可以跟其他行為規則一起被 cache。
OpenClaw 的做法比較直接 — tool 的使用慣例寫在 TOOLS.md 裡面,跟其他 bootstrap files 一起被注入 system prompt。Tool schema 同樣走 API parameter(這是 Anthropic API 的標準做法)。差別在於 Claude Code 對「指令」跟「schema」的分離更精細。
Agent 怎麼開機
Bootstrap 有兩層,在完全不同的世界裡運作,很容易搞混。
👉 第一層:Harness bootstrap — 跟 LLM 無關
啟動 Node.js process、連接 Telegram API、初始化 session store、檢查 API key 有沒有效、確認 model provider 可用。這就是傳統的 application startup,你用任何語言寫任何 server 都要做這些事。LLM 在這個階段完全沒有被呼叫。
👉 第二層:Agent context assembly — LLM 的第一次 API call
Harness 準備好之後,在 LLM 收到第一條使用者訊息之前,把 SOUL.md、AGENTS.md、TOOLS.md 這些檔案的內容拼接進 system prompt,送出第一個 API call。
OpenClaw 的 startupContext 設定會在 /new 或 /reset 時,把最近兩天的 daily memory 作為 one-shot prelude 注入第一輪 prompt。OpenClaw 的 post-compaction 機制會在 context 壓縮後注入提示,讓 agent 重新跑 AGENTS.md 裡定義的 Session Startup sequence。
Claude Code 沒有這些概念,因為每次打 claude 都是全新 session,但 OpenClaw 跟 Hermes Agent 是 persistent agent — 它們預期自己一直活著,所以需要這些 lifecycle 管理機制。這就是為什麼這兩類 agent 後續的 run-time 策略會完全不同。
兩種 Run-time 策略
🦞 OpenClaw:每一輪都重建 prompt
每次使用者說一句話,OpenClaw 就重新讀取所有 .md 檔案,重新組裝完整的 system prompt。好處是中途改了 SOUL.md,下一輪馬上生效;壞處是每輪都有序列化成本。
它靠三個機制減輕這個成本:
- Cache boundary marker —
<!-- OPENCLAW_CACHE_BOUNDARY -->把 prompt 切成 stable prefix + dynamic suffix - 對 prompt section 做 whitespace / 換行正規化 — 對 capability list 排序去重,讓相同語意產生相同的 byte 序列來命中 KV cache
- 可以設 context Injection — "continuation-skip" 讓安全的 continuation turn 跳過重新注入
🤖 Claude Code:凍結 prompt,用 delta 更新
Claude Code 的 getSystemPrompt() 只在 session 開始時呼叫一次,之後就凍結。
中途有東西變了怎麼辦?它不修改 system prompt,它把更新包裝成帶有 isMeta: true 標記的 fake user messages,插進 conversation history。
System prompt 本身永遠不被動到,所以 cache 永遠不會被打破,但代價是:conversation history 會越來越長(因為 delta messages 塞進去了),但 Claude Code 有完整的 compaction pipeline 處理這個問題。
兩種策略的本質差異:
- 一個每次都重新載入所有設定檔
- 一個開機時載入一次之後只傳差異
如果你要做一個 Agent
1. 選擇 LLM Provider
這是第一個決定,因為它決定了你後面所有東西的天花板。不同 model 的 context window 大小不同、function calling 能力不同、支援的 tool 格式不同、延遲跟成本也不同。
不需要一開始就選最貴的,但你要知道你的 agent 需要多少推理能力、需要多大的 context window、需不需要 vision 或 audio。
體感上,我認為 Opus 4.6 的角色扮演能力真的是強到不要不要的。
2. 設計工具群(Tools)
工具是 agent 的身體,沒有工具它就只能說話。兩件事要想清楚:
(a) 工具的內容 — 它需要讀寫檔案嗎?需要上網搜尋嗎?需要呼叫外部 API 嗎?需要執行程式碼嗎?每一個工具都有對應的風險等級 — 讀取是低風險、刪除是高風險、對外發送訊息是需要人工確認的。在設計階段就把這些分級想好。
龍蝦就是有名的權限全開,但是可以透過 Harness 去擋一些操作,所以新聞說什麼某某科技大頭用龍蝦刪除全部郵件?拜託,別傻了,他們怎麼可能不知道要設定行為邊界,根本是打擊競品而已🤫🤫
(b) 讓 agent 知道工具在哪 — Tool schema 走 API 的 tools[] parameter,但 agent「怎麼聰明地選擇工具」的指引要寫進 system prompt。
前面拆 Claude Code 的時候看到,它在 system prompt 裡面有一段「Using Your Tools」專門教 LLM 什麼時候用 Read、什麼時候用 Bash、什麼時候用 Agent tool — 這段指引跟 tool schema 一樣重要。
3. 設計 Agent Profile
這是 agent 的性格跟行為規範,對應到前面講的 SOUL.md 跟 AGENTS.md:
(a) 類型跟流暢度 — 它是一個嚴格按照 SOP 執行的 robot、一個寫 code 為主的 coding agent、還是一個可以自由對話的通用型 agent?這決定了 AGENTS.md 裡面的操作指令要寫多細、給 LLM 多少自主決策空間。
(b) 語氣(Tone) — 寫進 SOUL.md。正式還是口語、簡潔還是詳細、要不要用 emoji。語氣是使用者對 agent 的第一印象,寫得好跟寫得差的 SOUL.md 用起來的感覺天差地遠。
(c) 行為邊界(Behavior Boundary) — 也在 SOUL.md,或者像 GitAgent 那樣拆到獨立的 RULES.md。能聊什麼不能聊什麼、能做什麼不能做什麼、遇到模糊請求時該怎麼處理。
- 能力邊界是 TOOLS.md 管的
- 行為邊界是 SOUL.md 管的
4. 設計 Memory 架構
這是一個超大的 topic,可以獨立寫好幾篇。
短期記憶靠 context window — 但 context window 是有限的,200K tokens 聽起來很多,system prompt + tool definitions + bootstrap files 吃掉一半之後就不多了。
長期記憶需要外部儲存 — memory/ 目錄、database、FTS5 索引;A-MEM 這篇 2025 年的研究提出用 Zettelkasten 方法讓 agent 動態組織記憶,不只是存取。
良好的記憶管理還需要搭配 compaction 策略 — 什麼時候壓縮、什麼資訊可以丟、什麼必須保留 — 來減輕 Context Conflict 對 Agent Performance 造成的影響。
Hermes Agent 嘗試讓 agent 自己決定什麼值得記住,而且記憶會在使用中基於 execution traces 自我改進 — 這是目前 self-improving agent 方向的前沿探索。
如果是 multi-user 場景(像 Telegram bot 同時服務很多人),每個使用者的記憶要隔離。Agent definition 是共用的,per-user memory 是獨立的。
5. 設定 Bootstrap 與 Startup
Agent 怎麼「出生」跟怎麼「醒來」是兩件事。
如果是 session-based 的工具(像 Claude Code),不太需要想這個,但如果是 persistent agent,要區分:
- 出生:BOOTSTRAP.md 是一次性的初始化指令(agent 跑完就自己刪掉)
- 醒來:AGENTS.md 的 Session Startup section 定義每次 session 開始時要做什麼
6. 串接 User 跟 Identity
- IDENTITY.md:決定 agent 叫什麼名字、版本號、model provider
- USER.md:說明使用者是誰、偏好是什麼
讓 agent 知道「我是誰」以及「我在跟誰說話」。
框架跟部署
當 agent 的定義完成之後,決定它要跑在什麼框架下:
- 它的控制流是 deterministic 還是 non-deterministic? 如果流程可以預先定義,用 LangGraph 或 code-based workflow。如果需要 LLM 全權決策,用 prompt-driven(OpenClaw、Hermes)
- 它是 single-agent 還是 multi-agent? 只有在明確需要職責分離或專業化時才拆。John Gall 在《Systemantics》裡面的建議到今天還是成立的 — 從一個能運作的簡單系統開始
- 它需不需要自我改進? 如果需要「越用越強」,看 Hermes Agent 的 GEPA 架構(依 Nous Research repo 標示為 ICLR 2026 Oral)
部署模式是最後一層:
- Gateway 模式 — 像 OpenClaw 的 Gateway 控制平面,一個 agent 透過 channel routing 接入 22+ 平台(Telegram、Discord、Slack、WhatsApp)
- Session-based — 像 Claude Code,每次呼叫都是獨立 session,用完就結束
- Always-on daemon — 像 Hermes Agent,24/7 運行,持久化 session,有 heartbeat 機制
Context Window 是 Agent 的全部世界
SOUL.md、TOOLS.md、AGENTS.md、USER.md、MEMORY.md、BOOTSTRAP.md、IDENTITY.md — 它們跟大腦(LLM)之間是怎麼交涉的?
👉 全部都只是在每次 API call 之前,被塞進 context window 裡面的一群小東西:
Context Window = Agent 執行期的全部
不管架構設計多精密、檔案分得多細、cache 策略多講究 — 最終送進 LLM 的就是一段 text。Agent 的所有行為、知識、能力、限制,都取決於那段 text 裡面寫了什麼。
所以從 context window 出發,可以理解 agent 的每一個設計決策;再從 agent design 往上走,就進入了一個更大的領域 — 怎麼建造那個負責組裝 context 的骨架。
那個領域是 Harness Engineering。
