從 LangGraph 到 Claude Code:Agent 開發分成兩個世界嗎
2026 年中,agent 開發的選擇比過去多很多,但工具之間的差異也大到讓人困惑。先認識場上的主要框架。
LangChain 與 LangGraph: LangChain 是目前最大的 LLM 應用開發生態,最初以 chain 的概念串接 LLM 與外部工具,提供 prompt template、output parser、retriever、memory 等標準元件,搭配上千個第三方整合,讓開發者可以快速組裝 RAG、chatbot 與簡單的 agent。隨著 agent 需求複雜化(條件分支、人工介入、錯誤重試等場景),團隊推出了 LangGraph,以有向圖(directed graph)重新定義控制流。開發者定義 StateGraph,畫出 node 與 edge,每個 node 是一個 Python 函式,conditional edge 處理路由,state schema 以 TypedDict 管理全域狀態。LangGraph 還內建 checkpointing(可在任意節點暫停與恢復)和 human-in-the-loop 支援,部署方面有 LangGraph Platform,搭配 LangSmith 做 tracing 與 eval。課堂與企業多從這裡入門,原因是它把每一個決策點都攤開在程式碼裡。
Google Agent Development Kit(ADK): ADK 是 Google 在 2025 年推出的 agent 開發框架,定位介於 LangGraph 和 Claude Code 之間。同樣 code-first,但抽象層更高:開發者把帶型別註記與 docstring 的函式交給 Agent,tool schema 自動生成,tool-use 迴圈由 Runner 內建處理。ADK 原生支援 multi-agent 階層(parent-child agent 組合)、內建 eval 工具,以及 Event Compaction,自動將較舊互動摘要為精簡 state 以節省 token。語言支援涵蓋 Python、TypeScript、Go、Java、Kotlin,部署路徑是 Vertex AI Agent Engine,跨組織互通透過現由 Linux Foundation 治理的 A2A 協定。整體體感比 LangGraph 高一層:少了自建 loop 的負擔,但仍保有程式碼層的控制力。
Claude Code: Claude Code 是 Anthropic 推出的 CLI agent,也是 harness 模式的代表產品(關於 harness 的概念,我另外寫了一篇)。開發者不寫流程圖,而是以 markdown 檔宣告行為:CLAUDE.md 定義專案層級的行為準則與防護規則,skills/ 放領域知識與可執行腳本,agents/ 定義可被派發的 subagent。模型在這些邊界內自主決定執行順序。內建 tool 涵蓋檔案讀寫(Read、Write、Edit)、shell(Bash)、搜尋(Glob、Grep、WebSearch)等,外部 API 透過 MCP(Model Context Protocol) 接入。
Claude Code 的一個核心機制是 hooks,也就是開發者自訂的 shell 指令,會在特定生命週期事件自動觸發。目前有六個事件點:PreToolUse(tool 執行前攔截,可阻擋或改寫)、PostToolUse(tool 執行後,可做 lint、auto-format)、UserPromptSubmit(使用者送出 prompt 時)、Stop(agent 結束時)、Notification(等待使用者輸入時通知)、SubagentStop(subagent 結束時)。其中 PreToolUse 的設計特別值得注意:exit code 2 會阻擋 tool 並把錯誤訊息回饋給模型,而且這個阻擋即使在 --dangerously-skip-permissions 模式下也無法繞過,等於是開發者能寫進去的硬性保證。2026 年初 Anthropic 又加入了 HTTP hooks(把事件 POST 到遠端 endpoint)和 async hooks(背景執行不阻塞 agent),進一步擴展了可控範圍。
模型方面,Claude Code 設計上以 Anthropic 的 Claude 系列為主,但透過 LiteLLM 或設定 ANTHROPIC_BASE_URL 環境變數,可以接入 GPT、Gemini、DeepSeek、本地模型(Ollama、LM Studio)等任何支援 Anthropic Messages API 格式的服務。要把這套模式嵌入自有服務,對應路徑是 Claude Agent SDK(前身叫 Claude Code SDK,2026 年 3 月更名),本質是同一套 harness 以 library 形式開放,適合嵌入 CI/CD 或自有應用。
OpenClaw: OpenClaw 是同一模式面向個人助理的開源實例,以 AGENTS.md、SOUL.md、MEMORY.md 構成 markdown 工作區,提供內建 tool、session 管理與訊息閘道。形狀與 Claude Code 高度一致,差別在於場景:Claude Code 面向開發工作流,OpenClaw 面向日常的個人助理任務。
我的背景幾乎以前兩者為主。課堂上用 LangGraph 做 multi-agent 架構,實習專案也建在 LangGraph 上,之後在技術活動接觸了 ADK。但打開發者社群大家拿 Claude Code 的 skills 與 subagents 玩出各種變形,OpenClaw 蔚為風潮,彷彿一個 agent 的全部就是幾個 .md 檔。
那些 markdown 檔究竟是什麼?它們跟課堂上的 graph 是同一種東西嗎? 我拿同一個 travel agent 在兩種模式下各實作了一次,從 node 如何呼叫 LLM、tool 如何被執行、subagent 如何被派發的層次來回答。
1. 差異的核心:誰擁有 agent loop
所有 agent 的執行核心都是同一個循環:Plan → Act → Observe,重複至任務完成。課堂與社群的分歧,不在於這個 loop 本身,而在於它由誰實作、由誰決定下一步:
- Framework(LangGraph、ADK): loop 由開發者的程式碼定義。開發者畫出 node 與 edge,LLM 只是 graph 中的一個節點,路由、狀態轉移與終止條件皆為顯式程式碼。控制流在開發者手上。
- Harness(Claude Code、OpenClaw): loop 由模型驅動。開發者不定義流程,而是以 markdown 宣告行為:該做什麼、不該做什麼、品質標準為何。模型在這些邊界內自主決定執行順序,控制流在模型手上。
「Agent harness」在 2026 年上半年成為顯學,Addy Osmani 給出的定義最為簡潔:Agent = Model + Harness。模型之外的一切,包括工具、權限、context 管理、sandbox 與錯誤恢復,都屬於 harness。他進一步主張,普通的模型配上出色的 harness,勝過出色的模型配上糟糕的 harness。文中記錄了一個團隊在完全不更動模型的前提下,僅靠調整 harness 便將自家 coding agent 從 Terminal Bench 的 Top 30 推進至 Top 5。
對 Claude Code 原始碼的分析則揭示了另一個事實:一個 production agent 的絕大部分程式碼,屬於權限控管、context 管理、tool routing 與恢復機制這類 harness 基礎設施,真正的模型決策邏輯僅占極小比例。這正好解釋了前述的落差。使用 LangGraph 時,這些基礎設施由開發者實作;使用 Claude Code 時,它們由 Anthropic 實作並維護,開發者的工作面縮減至行為宣告層。
以下以機制文件最完整的 Claude Code 作為解剖對象,結論對 OpenClaw 同樣成立。
2. 同一個 Travel Agent,兩種實作
抽象比較的說服力有限,以下直接對照同一個需求在兩種模式下的形狀。需求為多角色旅遊規劃 agent:意圖分析 → 搜尋 → 行程規劃 → 辯論式審查 → 輸出防護。LangGraph 版本取自我的課程專案,是實際運行過的系統。
2.1 LangGraph 版:一切都是顯式的
系統由 9 個 node 組成:input guard、intent profile、search、orchestrator、planner、replanner、debate、explain、output guard,以 orchestrator 為中心做 conditional routing,專案含測試約 23,000 行 Python。graph 定義的核心如下:
def build_travel_graph():
builder = StateGraph(State)
builder.add_node("input_guard", input_guard_node)
builder.add_node("intent_profile", intent_profile_node)
builder.add_node("search", search_node)
builder.add_node("orchestrator", orchestrator_node)
builder.add_node("planner", planner_node)
builder.add_node("replanner", replanner_node)
builder.add_node("debate", debate_node)
builder.add_node("output_guard", output_guard_node)
builder.add_edge(START, "input_guard")
builder.add_edge("input_guard", "orchestrator")
# 每個 specialist 完成後回到 orchestrator
builder.add_conditional_edges(
"orchestrator",
orchestrator_routing, # 開發者實作的路由函式
{"planner": "planner", "debate": "debate", "END": END, ...},
)
return builder.compile()
這段程式碼編譯出來的 graph 長這樣(類似 LangGraph 自身的視覺化輸出):
Node 如何呼叫 LLM
在 LangGraph 中,node 就是一個 Python 函式:接收當前 state,做任意運算(通常包含一次以上的 LLM 呼叫),回傳對 state 的更新。LLM 呼叫是顯式的一行 invoke,以我的 planner 為例,推理步驟直接要求結構化輸出:
def planner_node(state: State) -> dict:
prompt = build_planner_prompt(state) # 從 state 組出上下文
response = llm.invoke(
[SystemMessage(content=prompt)],
response_format={"type": "json_object"}, # 強制 JSON,方便寫回 state
)
itineraries = parse_itineraries(response)
return {"itineraries": itineraries} # 回傳值即 state 更新
注意這裡沒有任何魔法:LLM 收到什麼 context、輸出被塞進 state 的哪個欄位,全部由開發者決定。這是 framework 模式的第一層顯式性。
Tool 如何被呼叫:兩種路徑
第二層顯式性在 tool。LangGraph 的 tool 呼叫有兩種路徑,對應「誰決定呼叫」這個問題的兩種答案。
路徑一:LLM 決定(bind_tools 模式)。 把 tool schema 綁定到 LLM 上,模型輸出 tool_calls,由開發者(或 prebuilt 的 ToolNode)執行後把結果以 ToolMessage 回灌,再次呼叫 LLM,直到模型不再要求 tool:
llm_with_tools = llm.bind_tools([search_flights, search_hotels, search_weather])
def research_node(state: State) -> dict:
messages = state["messages"]
while True:
response = llm_with_tools.invoke(messages)
messages.append(response)
if not response.tool_calls: # 模型不再需要 tool,結束
break
for call in response.tool_calls: # 逐一執行模型要求的 tool
result = TOOLS[call["name"]].invoke(call["args"])
messages.append(ToolMessage(content=result, tool_call_id=call["id"]))
return {"messages": messages, "research": response.content}
值得注意的是:這個 while 迴圈,就是 harness 一詞所指的「agent loop」的最小版本。用 LangGraph 時這是開發者親手寫的(或用 create_react_agent 這類 prebuilt 元件生成),迴圈上限、逾時、錯誤重試也都由開發者決定。
路徑二:程式碼決定。 我的專案大多採用這條路:node 內由 Python 直接呼叫 tool 函式,LLM 只負責前後的推理與整理。tool 權限用一個顯式的白名單 dict 管理:
# agent_tools.py:顯式的 per-agent tool 權限
TOOLS_BY_AGENT: Dict[str, Dict[str, Callable]] = {
"planner_agent": {
"search_weather": search_weather,
"search_flights": search_flights,
"search_hotels": search_hotels,
"web_search": web_search,
},
"research_agent": { ... },
}
def get_tools_for_agent(agent_name: str) -> Dict[str, Callable]:
# 未註冊的 agent 預設沒有任何 tool
return TOOLS_BY_AGENT.get(agent_name, {})
路徑二犧牲了彈性(tool 的使用時機寫死在程式裡),換來完全的可預測性:哪個 agent 能碰哪個 tool、何時呼叫、參數怎麼組,全部可以單元測試。對 guard 類節點與金流類操作,這種確定性是必要的。
顯式性的完整清單
graph 之外,系統還維護一個 30 餘欄位的 state schema,包含 budget、debate_count、replan_attempts、threat_blocked 等欄位,每個 node 對 state 的讀寫構成顯式契約。整理起來,LangGraph 模式下開發者親手持有四樣東西:
- Loop: 自己寫(或用 prebuilt 生成),上限與終止條件是程式碼
- Tool: 顯式註冊與綁定,權限是白名單 dict
- Context: 進 LLM 的每一段 prompt 由開發者組裝,state 是唯一的真相來源
- 路由: orchestrator 的每一條轉移是 conditional edge
優勢是每一項都可測試、可審計:迴圈上限(max_replan_attempts: 2)寫死在 state 中,是不依賴模型配合的硬性保證;CI/CD、red team 測試、OWASP 檢查全部掛載於明確的節點邊界。成本則是每新增一項能力,state schema、node、edge、routing 四處都得動,而且系統寫到後期會浮現一種微妙的感受:orchestrator 的路由邏輯,本質上是在以程式碼重新實作模型原本就能自行完成的決策。
2.2 Claude Code 版:行為宣告,流程交給模型
同一需求在 harness 模式下不存在 graph,實作產物是一組行為宣告:
.claude/
├── CLAUDE.md # 專案層級行為準則(≈ system prompt + 防護規則)
├── skills/
│ └── travel-planning/
│ └── SKILL.md # 規劃流程知識:步驟、輸出格式、品質標準
└── agents/
├── researcher.md # subagent:搜尋航班/住宿,回傳結構化結果
├── planner.md # subagent:產出行程草案
└── critic.md # subagent:辯論式審查,評分與修改建議
Loop 在哪裡:harness 內建的 tool-use 循環
Claude Code 的核心機制,是把 2.1 路徑一那個 while 迴圈完全內建。每一輪的流程固定為:
- 模型輸出回應,其中可能包含一個或多個
tool_use區塊(例如「呼叫 WebSearch,參數是 …」) - Harness 攔截該區塊,先過權限層:settings 中的 allow/deny 規則、目前的 permission mode、以及 PreToolUse hook(可用任意程式碼審核甚至改寫這次呼叫)
- 通過後執行 tool,將
tool_result寫回 context - 模型讀到結果,決定下一步:繼續呼叫 tool、修正做法,或結束任務
這個循環由 harness 持有,開發者看不到也不需要寫。與 LangGraph 的對應關係精確而完整:bind_tools 對應內建 tool 清單、開發者手寫的 while 對應 harness loop、TOOLS_BY_AGENT 白名單對應權限層。差別在於表達媒介,一邊是 Python,一邊是設定與 markdown。
Tool 從哪裡來:三層來源
- 內建 tool: Read、Write、Edit、Bash、Glob、Grep、WebSearch 等,涵蓋檔案系統、shell 與網路,開箱即用
- MCP servers: 以 Model Context Protocol 掛載外部服務,航班、訂房這類第三方 API 在這一層接入;對模型而言它們與內建 tool 無異
- Skills 附帶的 scripts: skill 除了知識文件,也可以夾帶可執行腳本,由模型在需要時透過 Bash 呼叫
travel agent 需要的 search_flights、search_hotels 在 LangGraph 版是開發者寫的 Python 函式加白名單註冊;在這裡則是一個 MCP server 的兩個 endpoint,模型自己決定何時呼叫、如何組參數。
Subagent 如何被派發
Subagent 是理解 harness 模式的關鍵:對模型而言,派發 subagent 本身也是一次 tool call(Claude Code 中的 Task tool)。主 agent 判斷「這件事該交給 critic」,於是發出一個帶著任務描述的 tool call;harness 收到後,以 critic.md 的內容作為 system prompt,啟動一個擁有獨立 context window 的子執行環境,結束後把結果濃縮成單一訊息回傳主 agent。
---
name: critic
description: 審查行程草案,從預算、可行性、偏好符合度評分
tools: Read, WebSearch # tool 白名單:此 subagent 只能用這兩個
---
你是行程審查員。收到行程草案後:
1. 檢查預算是否超支、交通銜接是否可行
2. 給出 0-100 分,低於 75 分必須附上具體修改指示
3. 最多審查兩輪,第二輪後無論分數皆放行並註明風險
frontmatter 的 tools: 欄位就是這個 subagent 的 tool 白名單,功能與 TOOLS_BY_AGENT dict 完全等價。而 context 隔離取代了 state schema 的角色:LangGraph 用 30 個欄位讓 9 個 node 共享狀態,Claude Code 讓每個 subagent 各自帶開一個乾淨的 context,只把結論帶回來。前者精確但要維護 schema,後者省事但資訊傳遞的顆粒度由模型的摘要品質決定。
保證強度:硬保證與軟約定
關鍵在 critic.md 的最後一行。LangGraph 版以 max_replan_attempts: 2 這個 state 欄位結構性保證的迴圈上限,在這裡是一句自然語言指示。模型多數情況下會遵守,但這份保證是機率性的,而非結構性的。這是兩種模式最根本的差異:framework 寫在程式碼裡的限制是硬保證,harness 寫在 markdown 裡的指示是軟約定。 hooks 機制可以把部分軟約定升級回硬保證(如前述,PreToolUse hook 的 exit code 2 連 skip-permissions 都擋不掉),但在預設狀態下,行為邊界的強度取決於模型的指令遵循能力。
實作量的落差需要正確解讀:markdown 模式並未消除基礎設施,而是將 loop、tool routing、權限與 context 管理轉移給 harness 供應商實作與維護。開發者交出的是控制權,換回的是迭代速度。若要將這套模式嵌入自有的服務,對應路徑是 Claude Agent SDK,Anthropic 官方即將其定位為通用 agent harness。
3. Google ADK:兩者之間的中間路線
ADK 的定位介於 framework 與 harness 之間:code-first 如前者,內建基礎設施的完整度則趨近後者。實際使用後的體感是它比 LangGraph 高一層。tool 的接入方式最能說明這一點,把帶型別註記與 docstring 的 Python 函式直接交給 Agent,tool schema 的生成、tool-use 迴圈的執行、結果的回灌,全部由 Runner 處理:
def search_flights(origin: str, destination: str, date: str) -> dict:
"""Search available flights between two cities on a given date."""
...
agent = Agent(
model="gemini-2.5-pro",
instruction="你是旅遊規劃助理,先查航班與天氣再產出行程。",
tools=[search_flights, search_hotels, search_weather],
)
對照前兩節:LangGraph 中這個 loop 是開發者手寫的 while,Claude Code 中它藏在 harness 裡,ADK 中它由 Runner 提供,但開發者仍然在程式碼層,可以攔截事件、掛 callback、組合 multi-agent 階層。定義的是 agent 的組成,而非流程圖;graph 式 routing 為選配能力,而非必經之路。官方 quickstart 支援 Python、TypeScript、Go、Java、Kotlin 五種語言,入門門檻確實比 LangGraph 低不少。
ADK 近期的重點投資也全數落在基礎設施層。Event Compaction 自動將較舊互動摘要為精簡 state,以降低長對話的 token 成本,這正是 harness 模式引以為傲的「context 管理內建」。現由 Linux Foundation 治理的 A2A 協定,搭配 Vertex AI Agent Engine 的託管部署,則瞄準跨組織 multi-agent 互通,也就是課堂上 A2A travel 範例背後真正想解的問題。
三者的定位可以濃縮為一句:LangGraph 提供最大控制,ADK 提供控制加基礎設施,Claude Code 提供基礎設施加速度。
4. 選型準則
選型取決於三個問題:流程是否需要 deterministic、失敗的代價多高、團隊的技術生態偏好。
| 維度 | LangGraph | Google ADK | Claude Code | Agent SDK | OpenClaw |
|---|---|---|---|---|---|
| 本質 | 圖形化 agent framework | Code-first agent framework | 互動式 CLI agent | Claude Code 的 library 版本 | 個人助理 harness |
| 控制流歸屬 | 開發者程式碼 | 開發者程式碼(loop 內建) | 模型 | 模型(由應用程式驅動) | 模型 |
| Tool 呼叫 | bind_tools 或程式碼直呼,迴圈自建 | 函式交給 Agent,Runner 執行迴圈 | 模型發起,harness 攔截與執行 | 同 Claude Code | 模型發起,harness 執行 |
| Tool 權限 | 白名單 dict(自行實作) | 程式碼層控制 | settings + frontmatter + hooks | 程式碼層 hooks + settings | markdown 工作區宣告 |
| 迴圈保證 | 結構性(state + edge) | 結構性 | 軟約定(指示 + hooks 可升級為硬保證) | 同 Claude Code | 軟約定 |
| Context 管理 | 自行組裝 prompt 與 state | Event Compaction 內建 | Harness 內建,subagent 隔離 | 同 Claude Code | Harness 內建 |
| 可測試性 | 逐 node 單元測試 | 內建 eval 工具 | 以端到端為主 | 可嵌入 CI/CD | 以端到端為主 |
| 模型支援 | 任意模型 | Gemini、Claude(via Vertex)、Ollama、LiteLLM 等 | Claude 為主,可透過 LiteLLM 接其他模型 | 同 Claude Code | 多模型 |
| 部署 | 自架 / LangGraph Platform | Vertex AI Agent Engine | 本機 | 自架,嵌入自有服務 | 本機 / 自架 |
| 上手至第一個 agent | 天 | 小時 | 分鐘 | 小時(需寫程式) | 分鐘 |
| 適用場景 | 合規、金融、高風險流程 | GCP 生態的 production 服務 | 探索、內部工具、開發自動化 | 嵌入應用或跑在 CI | 個人助理、日常任務自動化 |
具體判斷:
- 選 framework(LangGraph): 流程錯誤會造成真實損失(金流、合規)、需要逐步審計、需要向非 AI 工程師解釋系統行為。企業與課堂從這裡教起,原因正是這類場景對保證強度的要求。
- 選 ADK: 位於 GCP 生態、需要託管部署但不願自行實作 context 管理與 eval 基礎設施、或需要 A2A 跨組織互通。
- 選 Claude Code: 任務本質開放(研究、程式開發、資料探索)、流程本來就該由模型判斷、或想在最短時間內驗證一個 agent 構想。需要嵌入自有服務時,改用 Agent SDK。
- 選 OpenClaw: 需要的是個人助理而非開發工具,日常任務自動化、資訊整理、跨平台訊息管理等場景。
- 混用為常態: 先以 Claude Code 或 OpenClaw 快速驗證行為,確認後將需要硬保證的部分固化為 LangGraph/ADK 的服務。
結論
Markdown 之外,是一整套始終存在、只是不再由開發者實作的 harness 基礎設施。在 LangGraph 裡親手寫的 tool-use 迴圈、那份 TOOLS_BY_AGENT 白名單、那些組裝 prompt 的程式碼,在 Claude Code 裡以 harness loop、frontmatter 權限與 context 管理的形式繼續運作,只是實作者從開發者變成了 Anthropic。LangGraph 與 ADK 也並非落伍,而是把控制權留在開發者手上,並以程式碼量作為代價。
課堂教的 graph 與社群玩的 markdown,其實是同一個 agent loop 的兩種所有權模型。搞清楚這一點,選型就從陣營之爭還原為工程權衡。拿一個熟悉的題目在兩種模式下各做一次,差異自然浮現。