Gary
Hsieh
2026 · taipeiloading
回到文章列表
軟體工程AI 趨勢2026-04-30

Agent 是怎麼做出來的?

Agent 是怎麼做出來的?

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 之前,先建立一個直覺:

  1. 大腦 — LLM 本身。負責推理、理解、生成回應。但它什麼都不記得,每次對話都是從零開始。它的全部世界就是 context window 裡面的東西
  2. 身體 — 工具。Browser、file system、code execution、API calls。讓 agent 能跟外界互動,不只是說話
  3. 骨架(Harness) — 看不到但最重要的一層。它負責在每次 API call 之前,把對的 prompt、對的工具定義、對的記憶、對的使用者資訊,組裝成一個完整的 context,然後餵給大腦

OpenClaw 的 Prompt Files

打開 OpenClaw 的 workspace,會看到一組被注入 prompt 的檔案。README 簡化列出三個核心檔:AGENTS.mdSOUL.mdTOOLS.md

codebase 實際上支援 8 個 bootstrap filename — 上面三個再加上 IDENTITY.mdUSER.mdHEARTBEAT.mdBOOTSTRAP.mdMEMORY.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 指令

這個檔案的機制超簡單但很漂亮:

  1. 新 workspace 建好時 BOOTSTRAP.md 存在 → bootstrap layer 把它載進 system prompt
  2. Agent 第一次收到訊息時看到這份內容,照著指示做事(跟 user 對話、填寫 IDENTITY.md / USER.md / SOUL.md)
  3. 指示的最後一行:「Delete this file. You don’t need a bootstrap script anymore — you’re you now.」
  4. Agent 自己刪掉 BOOTSTRAP.md
  5. 從此之後的 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 資訊其實分成兩個地方:

  1. Tool schema(JSON 定義 — 每個 tool 的名字、參數、描述)走 API 的 tools[] parameter,跟 system prompt 完全分開。Built-in tools 加上 MCP 帶進來的,數量相當可觀
  2. 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,下一輪馬上生效;壞處是每輪都有序列化成本。

它靠三個機制減輕這個成本:

  1. Cache boundary marker<!-- OPENCLAW_CACHE_BOUNDARY --> 把 prompt 切成 stable prefix + dynamic suffix
  2. 對 prompt section 做 whitespace / 換行正規化 — 對 capability list 排序去重,讓相同語意產生相同的 byte 序列來命中 KV cache
  3. 可以設 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。

#AI#Agent#LLM#Claude Code#Claude