重點摘要(TL;DR)
前 8 篇是藍圖 。本篇是實作真實版 :在 Mini PC(無 GPU、32GB RAM、Ryzen 7)用 364 行 FastAPI 跑通搬離方法論,真能接 Claude Code。
核心邏輯:Gateway 看 prompt 內容,命中 A 級字典 → 地端最強模型(14b) ;其他 → cloud Claude(若有 API key)或 fallback 地端。
關鍵設計原則(別搞錯):A 級資料用地端最強模型,不是最弱 。敏感資料因為更重要,需要更可靠的回答。小模型只能當分類器或 fail-safe。
真接 CC 的關鍵:用 Anthropic 原生 /v1/messages endpoint,不是 OpenAI 的 /v1/chat/completions,並做完整翻譯層(request / response / tool use / SSE)。
Harness 三 agent 永遠走 cloud (地端跑不動三 agent 並行 + long context),只是輸入經 Gateway 強脫敏 — 這是搬離後最關鍵的工作流保護。
本文是腦子系統九部曲實證篇 。前八篇:Why / How / Scale / Tools / ERP / Self-Service / ISO / Execution 。
一、為什麼寫這篇 — 從藍圖到實作真實版
前 8 篇腦子系統累積了大量「應該怎樣 」的論述:Why / How / Scale / Tools / ERP / Self-Service / ISO / Execution。對真正要動手的人,這些都還是紙上的東西 。
本篇是分水嶺 — 用一台 Mini PC(沒 GPU,32GB RAM,Ryzen 7 4700U,2020 年款)跑通可以真的接 Claude Code 的搬離 Gateway ,證明:
不需要 GPU,純 CPU 也能 host gateway logic
不需要 LiteLLM / Portkey 等大框架,純 Python 364 行搞定
不需要 ANTHROPIC_API_KEY 也能跑(有 fallback 模式)
CC + Agent Team + Harness 工作流不變,只改 BASE_URL
二、5 條設計原則(別搞錯)
原則 1:A 級資料地端,不可協商
A 級的定義是「送出去會出事 」 — 客戶機密、財報、製程 know-how。這個層級不能因為 cloud 模型強就送出。地端是底線。
原則 2:A 級用地端最強 模型,不是最弱
這條最容易搞錯。直覺是「敏感資料 = 風險高 = 用小模型」,但 logic 應該倒過來:敏感資料因為更重要,需要更可靠的回答 。
情境
地端模型選擇
理由
A 級主處理
地端最強 (14b / 32b / 80B-A3B)
資料越敏感,回答越要可靠
分級判斷器
小模型(0.5b / 1.7b)or regex
分類本身不需要強能力
Fail-safe 容錯
小模型保守路由
寧可路由保守不要錯放
原則 3:路由邏輯走字典 + regex,不靠 LLM
分級判斷不該交給 LLM(慢、不確定、可被 prompt injection 騙)。改用字典 + regex,毫秒級完成,可審計。
原則 4:Anthropic 原生 endpoint(/v1/messages),不是 OpenAI 的 /v1/chat/completions
CC 用 Anthropic Messages API,你 Gateway 必須 expose /v1/messages,不是 OpenAI 的 endpoint。並且做完整 Anthropic ↔ OpenAI 翻譯(因為地端 Ollama 用 OpenAI compatible 格式)。
原則 5:沒 API key 也能跑(fallback 地端)
Gateway 設計成:有 ANTHROPIC_API_KEY 就 C 級走真 cloud Claude;沒有就 fallback 走地端。讓你能純地端先驗證 logic,再加 cloud 。
2.1 雙維度決策表(敏感度 × 可用性)— 別搞混
fallback 不只看「cloud 有沒有 key」,還要看「資料能不能上 cloud」。雙維度決策才完整:
分級
主路由
Fallback
關鍵保護
A 級
地端最強(14b/32b/80B)
沒 fallback — 地端跑不動 = 等 / 改題目
即使有 cloud key 也不走 cloud
B 級
地端優先
地端不可用 → 脫敏後 cloud
能脫敏才 fallback,不能脫敏寧願報錯
C 級
cloud 優先
沒 key → 地端
純技術問題,無敏感度
常見誤解:有 cloud key 就什麼都走 cloud 。錯。A 級即使有 key 也不該走 cloud — 因為「資料外洩風險 > 模型能力差異」。Gateway 的職責就是替你擋住這個誘惑 :你 prompt 命中 A 級字典,Gateway 不問你「要不要送 cloud」,直接路由到地端。
本版實作狀態 :A 級 + C 級已實作完整;B 級的「地端優先 + cloud fallback + 脫敏」是 TODO,本版 B 級 keyword 命中時邏輯等同 A 級(全地端)。完整 B 級實作見最末「待補的東西」章節。
三、364 行 Gateway 完整實作
結構:
gateway.py(364 行)
├─ Classifier (~30 行)— 抽 messages 文字 + 字典命中
├─ Anthropic→OpenAI Req (~80 行)— system / messages / tool_use / tool_result 翻譯
├─ OpenAI→Anthropic Resp (~40 行)— content blocks / stop_reason / usage
├─ SSE Streaming (~40 行)— 6 種 Anthropic 事件 from OpenAI delta
├─ Backend Forwarders (~80 行)— Ollama / Anthropic 雙路 forward + fallback
└─ Main Endpoint (~30 行)— /v1/messages,分類後派到對應 forward
3.1 核心邏輯(主要 dispatcher)
@app.post("/v1/messages")
async def messages(request: Request):
auth = request.headers.get("authorization", "")
if MASTER_KEY not in auth and not ANTHROPIC_API_KEY:
raise HTTPException(401, "bad master key")
body = await request.json()
original_model = body.get("model", "claude-opus-4-7")
decision, keyword = classify(body.get("messages", []), body.get("system"))
if decision == "A":
log.warning(f"[A-LEVEL] 命中 '{keyword}' → 地端 {MODEL_A_LEVEL}")
return await forward_to_ollama(body, MODEL_A_LEVEL, original_model)
else:
log.info(f"[C-LEVEL] → cloud {original_model}" if ANTHROPIC_API_KEY else f"[C-LEVEL] no key → local fallback")
return await forward_to_anthropic(body, request, original_model)
3.2 Anthropic ↔ OpenAI 翻譯的 4 個關鍵點
# 1. Anthropic system 是 top-level → OpenAI 是 system message
sys = body.get("system")
if isinstance(sys, str):
openai_messages.append({"role": "system", "content": sys})
# 2. Anthropic tool_use 是 content block → OpenAI 是 message 上的 tool_calls
if btype == "tool_use":
tool_calls.append({
"id": block["id"],
"type": "function",
"function": {"name": block["name"],
"arguments": json.dumps(block["input"])}
})
# 3. Anthropic tool_result 在 user message 內 → OpenAI 是 role:tool 獨立 message
if btype == "tool_result":
openai_messages.append({
"role": "tool",
"tool_call_id": block["tool_use_id"],
"content": str(result_content)
})
# 4. SSE 翻譯:OpenAI delta 累積 → Anthropic 6 種事件
# message_start → content_block_start → content_block_delta(每個 token)
# → content_block_stop → message_delta(stop_reason)→ message_stop
3.3 Forwarder(雙路 + fallback)
async def forward_to_ollama(body, target_model, original_model):
"""A 級 → 翻譯成 OpenAI format,forward to Ollama 地端強模型。"""
openai_body = anthropic_to_openai_request(body, target_model)
is_stream = openai_body.get("stream", False)
if is_stream:
return StreamingResponse(stream_anthropic_from_openai(...))
async with httpx.AsyncClient(timeout=600) as client:
r = await client.post(f"{OLLAMA_URL}/v1/chat/completions", json=openai_body)
return JSONResponse(openai_to_anthropic_response(r.json(), original_model))
async def forward_to_anthropic(body, request, original_model):
"""C 級 → 直接 proxy 到 api.anthropic.com,沒 key 就 fallback 地端。"""
if not ANTHROPIC_API_KEY:
return await forward_to_ollama(body, ANTHROPIC_FALLBACK_MODEL, original_model)
headers = {"x-api-key": ANTHROPIC_API_KEY, "anthropic-version": "2023-06-01"}
if body.get("stream"):
# SSE 直接透傳(Anthropic format,不用翻譯)
return StreamingResponse(...)
async with httpx.AsyncClient(timeout=600) as client:
r = await client.post("https://api.anthropic.com/v1/messages", json=body, headers=headers)
return JSONResponse(r.json())
v2.3 完整 Gist(674 行 gateway + 24 個 pytest + benchmark + demo + README,5 個檔案) :
👉 https://gist.github.com/tm731531/c82c51ae2a73bfe640dec5b61e5a542a
Gist 含 README + 5 步驟啟動 + 測試 curl 範例 + 已知限制。clone 下來改字典即可用。
3.1 v2 → v2.1 changelog(review 後修)
v2 上 Gist 後又收到 review,點出 3 個有實際影響的 bug,其中 1 個是安全問題。**全修了**:
🔴 Bug 1(安全) :Auth 邏輯反了 — 原本「沒設 cloud key 才檢查 master_key」意思是「接了 cloud 反而不檢查」,任何人能燒你 quota。修法 :無條件檢查 master_key,並兼容 x-api-key + Authorization: Bearer 兩種 header。實測 no-key/wrong-key 都回 401
🔴 Bug 2(功能) :Streaming 模式 tool use 完全不工作 — 原本 stream_anthropic_from_openai 只翻譯 text delta,沒處理 delta.tool_calls。CC 的 Read/Edit/Bash 都是 tool use → A 級 + streaming 時 CC 卡住。修法 :加 tool_calls delta 累積邏輯,追蹤 tool_call_index → our_block_index mapping,送 content_block_start (tool_use) + input_json_delta 事件序列。約 +60 行
🟡 Bug 3 :streaming 模式 stop_reason 寫死成 end_turn,即使 OpenAI 端因 max_tokens 截斷或 tool_calls 收尾也誤標。修法 :streaming 過程累積最後 finish_reason,結束時用真實值映射(stop→end_turn / length→max_tokens / tool_calls→tool_use)
+ 結構改進 :content blocks 改 lazy open(只在真有內容時送 content_block_start),text 跟 tool 可正確交錯;dead import 清掉;docstring 改寫(原版誤稱用 sse-starlette)
從 v1(80 行,描述跟 code 矛盾) → v2(364 行,文字宣稱) → v2 Gist(394 行,實際存在但 3 bug) → v2.1(502 行,bug 修完) 。三天四個版本,每一輪 review 都點出真實問題。這個迭代過程本身就是 brain 系統「review-driven development」的最佳示範 。
四、CC + Agent Team + Harness 三件事的協作
4.1 CC 接 Gateway(0 行 code 改動)
# Terminal 設環境變數
export ANTHROPIC_BASE_URL=http://localhost:4000
export ANTHROPIC_AUTH_TOKEN=sk-walsin-test
# 跑 CC 跟原本一樣
claude
CC 完全不知道後面接的是 Gateway。所有 prompt 自動經分類 → 路由。
4.2 Agent Team 走 Gateway(子進程繼承 BASE_URL)
你在 CC 裡 spawn 7 個 opus agent 並行 — 每個 sub-agent 共用同一個 BASE_URL (從父 process 繼承)。Gateway 對每個 agent 的 prompt 獨立分類:
你 (CC main)
├─ Agent 1 (opus): "review 這份 SAP API 設計" → C 級 → cloud Claude
├─ Agent 2 (opus): "找 [client_alpha] 客訴 case" → A 級 → 地端 14b
├─ Agent 3 (opus): "寫 Kafka consumer" → C 級 → cloud Claude
├─ Agent 4 (opus): "看 [project_xxx] 的合約" → A 級 → 地端 14b
├─ Agent 5-7 (opus): 其他 C 級任務 → cloud Claude
大多數 Agent Team 任務不命中 A 級字典,99% 體感跟原本一樣。少數命中的會走地端,慢一點但隔離。
4.3 Harness 三 agent — 永遠走 cloud(關鍵保護)
Anthropic 2026/3 發布的三 agent harness (Planner / Generator / Evaluator)是給 cloud 設計的。地端 80B-A3B 跑三 agent 並行 = GPU 排隊,根本跑不動。
正解:Harness 永遠走 cloud,但輸入經 Gateway 強脫敏 。
用戶: "幫我 refactor [project_xxx] 的支付模組"
↓
Gateway 偵測 [project_xxx](A 級字典)
↓
若強脫敏成功 → "幫我 refactor [PROJECT] 的支付模組" → cloud Claude(三 agent)
若無法脫敏 → 整個任務改地端 14b sequential 跑(慢但安全)
↓
Planner: 拆 task → Generator: 寫 code → Evaluator: 檢查
↓
結果經 Gateway 回到用戶
Harness 的價值在 long context + 複雜 reasoning ,地端在這兩點本就弱。硬搬就是自虐。脫敏走 cloud 才是對的策略。
4.4 三件事的協作全景
你 (CC main session, ANTHROPIC_BASE_URL=gateway)
│
├─ 普通 prompt → Gateway → 路由 → 對應 backend
│
├─ Spawn Agent Team(7 個 opus 並行)
│ ├─ 每個 sub-agent 繼承 BASE_URL
│ ├─ Gateway 對每個 prompt 獨立分類
│ └─ A 級走地端 14b,C 級走 cloud Claude
│
└─ Spawn Harness(Planner / Generator / Evaluator)
├─ 三 agent 共用 BASE_URL
├─ Gateway 強制路由全 cloud(脫敏後)
└─ 因為地端跑不動三 agent 並行
五、Brain 系統整合(sensitivity_level frontmatter)
你的 brain markdown 系統(~/.claude/projects/.../memory/)是搬離的核心資產。整合方式:
5.1 brain frontmatter 加分級欄位
# 一般 brain(C 級,可上 cloud)
---
name: kafka_consumer_pattern
type: technical
sensitivity_level: C
---
Kafka consumer 群組 rebalance 機制...
# 敏感 brain(A 級,只地端 + 強模型)
---
name: client_alpha_oncall_pattern
type: business_incident
sensitivity_level: A
applies_to: [bu_xxx]
---
[client_alpha] 客訴流程,聯絡窗口...
5.2 build.sh 編譯時依分級過濾
#!/bin/bash
# 編譯雙版本 CLAUDE.md
# Cloud-bound CLAUDE.md(沒 A 級)
find brain/ -name "*.md" \
| xargs grep -L "sensitivity_level: A" \
| xargs cat > .claude/CLAUDE.md.cloud
# Local-bound CLAUDE.md(全部,A 級也進)
cat brain/**/*.md > .claude/CLAUDE.md.local
# Gateway 看員工任務目標選對應 CLAUDE.md
5.3 brain 的 A 級關鍵字自動同步到 Gateway 字典
# 從所有 A 級 brain 抽出 client name / project code 等
grep -h "sensitivity_level: A" -A 20 brain/**/*.md \
| grep -oP '\[client_\w+\]|\[project_\w+\]' \
| sort -u > /tmp/A_keywords.txt
# Gateway 啟動時 load
A_KEYWORDS = open("/tmp/A_keywords.txt").read().splitlines() + DEFAULT_A_KEYWORDS
5.4 公開版 brain repo 自動過濾
如果你的 brain 有公開版(教學分享 / 開源),build script 自動排除 sensitivity_level: A 條目,只發 B / C。不用手動審 brain 是否能公開 。
這是brain 系統跟 Gateway 的接合點 :你寫 brain 時標分級,Gateway 自動知道哪些字串該擋,公開版自動過濾。一個 frontmatter 欄位,三個地方用 。
六、放大邏輯 — 個人 → 80 人 → 萬人
面向
個人(本文實證)
80 人公司
萬人集團
Gateway 實作
364 行 FastAPI
LiteLLM Docker
K8s HPA + Portkey
A 級字典
3-10 個關鍵字
100 個
1000+ 自動同步 brain
A 級 backend
Ollama Qwen3:14b(CPU)
Ollama Qwen3:32b(1x 4090)
中央 GPU H100 跑 80B-A3B + 區域副本
C 級 backend
cloud Claude(個人 API key)or fallback 地端
Anthropic Enterprise
Anthropic Enterprise + Azure / Bedrock 多家
脫敏
無
字典 + regex
Microsoft Presidio + LLM 兜底
認證
master key
員工 SSO
SSO + Token Impersonation
Audit log
stdout
SQLite / OpenSearch
三軌制 + WORM + HSM mapping
治理
0
Working Group
三道防線
時程
30-60 分鐘
2-3 個月
12 個月
預算
0
~30 萬 NTD
4000-6000 萬 NTD
核心邏輯一模一樣 (看 prompt → 字典分類 → 路由)。差的只是:
規模(字典條數、並發、儲存)
治理(Working Group、三道防線、ISO 認證)
合規(SOX / J-SOX / 個資法 / GDPR)
能力 backend(14b vs 80B-A3B)
七、能力降級補償策略
實際擔心:地端模型比 Claude Opus 4.7 弱,搬完會不會生產力崩 ?
實話:會降,看你會不會用補償工具 。具體 benchmark 沒跑(個人 mini PC 沒 GPU 跑不了 32B+ 對比),但業界經驗的補償清單:
地端弱的地方
補償工具
效果
Long context 弱
RAG (Chroma / Qdrant) + chunking
context 不全進 LLM,只進 top-K
Reasoning 弱
Chain-of-thought structured prompt
強制分步,單步難度降
Tool use 不穩
function calling 限縮 5-10 個 tools
減少選擇,提升正確率
並行 Agent 跑不動
改 sequential workflow
一個跑完再下一個
跨檔 refactor 弱
限定 working set(≤ 5 檔)
降低 context
Memory 弱
brain markdown 強制 inject
永遠帶 context
而且這只用在 5% A 級任務,其他 95% 還是 cloud。整體生產力下降可控,具體百分比待 SWE-bench Lite 子集 + 真實工作流 case 量化 。
八、5 步驟讓你今晚就跑起來
裝 Ollama + 拉模型 :
ollama pull qwen3:14b # A 級主處理(地端最強)
ollama pull qwen3:1.7b # 可選,當分類器 fail-safe
裝 Python 套件 :
pip install --user fastapi uvicorn httpx
存 364 行 gateway.py (本文第三章 + 完整版見 GitHub Gist)
跑起來 :
# 沒 API key 也能跑(fallback 地端)
python3 gateway.py &
curl -s http://localhost:4000/health # 確認 OK
# 有 API key 完整版
ANTHROPIC_API_KEY=sk-ant-... python3 gateway.py &
CC 切過去 :
export ANTHROPIC_BASE_URL=http://localhost:4000
export ANTHROPIC_AUTH_TOKEN=sk-walsin-test
claude # 跟原本一樣寫 code
30-60 分鐘搞定 。設定完後 99% 工作跟原本一樣,只有 prompt 命中 A 級字典時自動切地端。
九、跑不起來時會看到什麼(失敗模式排查)
Gist 證明能跑,失敗模式證明跑過。下面是實作過程實際踩過的 7 個錯誤:
錯誤訊息 / 症狀
根本原因
排查指令
connection reset by peer + log 完全空
Container 還在 init(LiteLLM 啟動慢 30s-1min),或 Python stdout buffering
docker exec <container> ps auxf 看 PID 1 是否還在跑;加 PYTHONUNBUFFERED=1
404 Not Found from CC
Gateway 用 OpenAI /v1/chat/completions,CC 打 Anthropic /v1/messages
看 Gateway log 有沒有「POST /v1/messages」;改用本文 Anthropic 原生 endpoint
httpx.ReadTimeout 在 forward_to_ollama
Ollama 模型在 CPU 第一次 load 太慢(超過 timeout)
ollama run <model> "warm" 先暖機;timeout 從 300 改 600
OCI runtime exec failed: "curl" not found
LiteLLM image 沒裝 curl,內部 health check 工具有限
用 host 端 curl 測 http://localhost:4000/health 不要 docker exec
{"detail": "bad master key"}
CC 設了 ANTHROPIC_AUTH_TOKEN 但 Gateway 沒 match
echo $ANTHROPIC_AUTH_TOKEN 跟 Gateway 的 MASTER_KEY 對
CC 卡住沒回應(streaming 不出來)
SSE 翻譯漏了 message_stop 事件,client 等不到結束
Gateway log 看最後送出的 event;確認 6 種事件全送(message_start → content_block_start/delta/stop → message_delta → message_stop)
A 級 prompt 沒命中字典(看到走 C 級)
字典 keyword 是 case-sensitive 漏了 re.IGNORECASE,或字典裡沒這條
curl -s gateway.../health 看 keywords_count;echo $PROMPT | grep -i <keyword>
十、Gist 上線前檢查清單(13 條)
從文章第一版到本版踩過的所有雷,清單化:
Authorization header 兩種格式都要兼容 :CC 可能送 x-api-key: xxx 或 Authorization: Bearer xxx,Gateway 都要認
anthropic-version header 別漏 :Anthropic API 要求 anthropic-version: 2023-06-01(或更新),proxy 過去要保留
system 欄位三種型別都要處理 :Anthropic 的 system 可以是 string、list of {type:text,text:…},或 unset
tool_use ID 不能掉 :翻譯後對應的 tool_calls 要保留同一個 ID,不然 client 對不上 tool_result
tool_result 在 user message 內,翻譯後要拆成獨立 role:tool message
SSE 6 個事件全送 :message_start → content_block_start → content_block_delta(每個 token)→ content_block_stop → message_delta → message_stop,漏一個 client 卡死
SSE event 名稱要寫 event:,data: 兩行 :不是只送 data,Anthropic SSE 格式有 event 名
Ollama 連線斷掉時 fallback 邏輯不能 race :用 try/except 包 forward_to_ollama,失敗才 fallback,不要兩個 task 同時跑
timeout 要設 600 秒以上 :CPU 跑 14b 慢,300 秒會 timeout
master_key 預設值不要外洩 :Gist 上的 sk-walsin-test 是 placeholder,部署前換掉
A 級字典不能放 secret :keyword 本身會出現在 log,別放真實 client name(用 placeholder 例如 [client_alpha])
health endpoint 不檢查 master_key :不然 monitoring 工具會 401
關 Gateway 用 SIGTERM 不要 SIGKILL :kill 不加 -9 讓 uvicorn 優雅關閉,避免 streaming response 中斷
十一、TODO 全部 close(v2.2 update)
原本標的 4 個 TODO 全做完了,本版升 v2.2(620 行)。逐項說:
原 TODO
v2.2 處理
行數
B 級「地端優先 + cloud fallback + 脫敏」
✅ 完整實作:ollama_alive() 健康檢查 → 失敗 sanitize_anthropic_body() → fallback cloud;sanitize 沒命中拒絕(503)
+90 行
Benchmark
✅ benchmark_runner.py 獨立檔(258 行):跑 SWE-bench Lite 子集 + 自家 prompts × 多 model,輸出 markdown 報表。不打分,只跑數據 (讓人類自己判斷,避免 premise drift)
258 行新檔
Asciinema 60 秒 demo
✅ demo_record.sh:health → C 級 → A 級 → auth fail 4 個 step,可直接跑或 asciinema rec -c 包起來錄影
110 行新檔
Token usage 真實計算
✅ 用 tiktoken 估算累積 text + tool args,取代原本的 chunk count(嚴重低估)
+20 行
11.1 v2.1 → v2.2 主要新邏輯
elif decision == "B":
# v2.2 完整 B 級實作
if await ollama_alive():
return await forward_to_ollama(body, MODEL_B_LEVEL, original_model)
# 地端死了,看能不能 fallback cloud
if not (ANTHROPIC_API_KEY and B_LEVEL_CLOUD_FALLBACK):
raise HTTPException(503, "B-level: local unavailable, cloud fallback disabled")
sanitized_body, hit = sanitize_anthropic_body(body)
if not hit:
# 地端死 + 脫敏沒命中 = B 字典跟脫敏字典不一致,寧願報錯
raise HTTPException(500, "B-level: local down + sanitization mismatch")
return await forward_to_anthropic(sanitized_body, request, original_model)
11.2 Sanitization 字典(v2.2 新增)
SANITIZE_MAP = {
r"\[internal_process\]": "[PROCESS]",
r"\[vendor_quote\]": "[QUOTE]",
r"\[employee_name\]": "[PERSON]",
# 通用 PII patterns
r"\b[\w.+-]+@[\w-]+\.[\w.-]+\b": "[EMAIL]",
r"\b(?:\d{1,3}\.){3}\d{1,3}\b": "[IP]",
r"\b\d{4}-\d{4}-\d{4}-\d{4}\b": "[CARD]",
}
實作策略:regex-based 簡單脫敏 (快、可審計);生產環境建議升 Microsoft Presidio(NER + checksum + 多語言)。
11.3 Benchmark Runner 跑法
# 跑全部 prompts × 你已 pull 的 ollama 模型
python3 benchmark_runner.py
# 加 cloud Claude 對比(有 ANTHROPIC_API_KEY 才能)
ANTHROPIC_API_KEY=sk-ant-... python3 benchmark_runner.py \
--models qwen3:14b,qwen3:4b \
--anthropic-models claude-opus-4-7
# 只跑 SWE-bench Lite 子集
python3 benchmark_runner.py --suite swe --output report.md
跑出來是 markdown 報表,每 model × 每 prompt 的 latency / tokens / 截斷回應。故意不打分 — 因為「能力 = X%」這種宣稱本身就是 review 點過的 premise drift 風險。**跑數據給人看,人類自己判斷**,比 AI 講百分比有 integrity。
11.4 Demo 錄影
# 純跑(看 terminal output)
bash demo_record.sh
# 用 asciinema 錄影
asciinema rec -c "bash demo_record.sh" walsin-demo.cast
asciinema upload walsin-demo.cast # (可選)上傳分享
4 個 step:health check → C 級 prompt → A 級 prompt(命中字典)→ 沒帶 key 401。每一步都看到 x-gateway-decision + x-gateway-model headers。
11.5 v2.2 → v2.3 self-review 後再清 7 個漏洞
「考試不能邊改邊考」 — 我自己當最嚴格 reviewer 把 v2.2 從頭審一次,找到 7 個應修的(不是別人指出),全清:
優先
問題
v2.3 修法
🔴 P0
Auth substring match 漏洞 — MASTER_KEY not in auth 太寬,sk-test-extra 也通過
secrets.compare_digest 精確比對 + Bearer 解析
🔴 P0
SSE 透傳格式錯 — aiter_lines + "\n" 會剝掉 \n\n event 結尾
改 aiter_bytes 直通,SSE 格式 byte-for-byte 完整
🔴 P0
Sanitize 漏 tool_use input + tool_result content — 只處理 text block
改遞迴 _sanitize_value 處理任意巢狀 dict / list / str
🟡 P1
MASTER_KEY 預設 hardcoded,生產環境壞習慣
沒設環境變數時 log warning,提示部署前必設
🟡 P1
demo_record.sh 缺 pre-flight,gateway 沒啟動 script crash
開頭加 curl /health,失敗給友善提示 + 啟動指令
🟡 P1
/health 沒回報 ollama 狀態,monitoring 不夠
加 ollama: alive/down + b_level_model + b_cloud_fallback 配置
🟡 P1
B 級走 cloud(脫敏後)client 不知道
回應加 X-Gateway-Sanitized: 1 header,透明度
11.6 24 個 pytest 全綠(v2.3 新)
$ pip install --user pytest pytest-asyncio
$ MASTER_KEY=sk-test-secret python3 -m pytest test_gateway.py -v
test_gateway.py::TestClassify::test_C_level_default PASSED
test_gateway.py::TestClassify::test_A_level_keyword_match PASSED
test_gateway.py::TestClassify::test_A_level_in_system PASSED
test_gateway.py::TestClassify::test_A_level_in_list_content PASSED
test_gateway.py::TestClassify::test_B_level_match PASSED
test_gateway.py::TestClassify::test_A_takes_precedence_over_B PASSED
test_gateway.py::TestMasterKey::test_correct_bearer PASSED
test_gateway.py::TestMasterKey::test_correct_bare PASSED
test_gateway.py::TestMasterKey::test_empty PASSED
test_gateway.py::TestMasterKey::test_wrong PASSED
test_gateway.py::TestMasterKey::test_substring_extra_suffix_blocked PASSED ← v2.3 修
test_gateway.py::TestMasterKey::test_substring_prefix_blocked PASSED ← v2.3 修
test_gateway.py::TestMasterKey::test_lower_case_bearer PASSED
test_gateway.py::TestSanitization::test_string_email PASSED
test_gateway.py::TestSanitization::test_string_ip PASSED
test_gateway.py::TestSanitization::test_string_no_hit PASSED
test_gateway.py::TestSanitization::test_recursive_dict PASSED
test_gateway.py::TestSanitization::test_recursive_list PASSED
test_gateway.py::TestSanitization::test_anthropic_body_text_block PASSED
test_gateway.py::TestSanitization::test_anthropic_body_tool_use_input_v23 PASSED ← v2.3 修
test_gateway.py::TestSanitization::test_anthropic_body_tool_result_v23 PASSED ← v2.3 修
test_gateway.py::TestRequestTranslation::test_system_string_to_message PASSED
test_gateway.py::TestRequestTranslation::test_tool_use_to_tool_calls PASSED
test_gateway.py::TestRequestTranslation::test_tool_result_becomes_separate_message PASSED
============================== 24 passed in 0.61s ==============================
4 個 v2.3 安全修正關鍵 test 全綠 — 證明 substring 攻擊擋下、tool_use input 真的會被 sanitize。
11.7 真的還剩什麼不會做(誠實)
SWE-bench 完整跑數據 :需要 GPU 跑 32B+,我這台 mini PC 不行。Runner 寫好了,你有 GPU 自己跑
真錄 asciinema 公開連結 :script 寫好(含 v2.3 pre-flight check),你自己 run + upload
Microsoft Presidio 升級 :regex 已夠 demo,生產時換成 NER + checksum
httpx async mock 整合測試 :現在的 24 個 unit test 涵蓋純函式,async stream 整合測試還沒寫
策略:能在我環境做的全做,不能做的寫好工具讓你自己做 。每一輪迭代都比上一輪誠實。
十二、5 個學到的事(實作後)
Gateway 路由邏輯不複雜 (364 行 Python 含完整翻譯層 + SSE),別被 LiteLLM / Portkey / Kong 這些大框架嚇到
CC 工作流不用改 (只改 BASE_URL),搬離成本低於想像。但要真接 CC 必須做 Anthropic 原生 endpoint + 完整翻譯層
A 級資料用地端最強 ,不是最弱。敏感資料因為更重要,需要更可靠回答 — 這條最容易搞反
Mini PC 雖弱但能跑 (CPU 跑 14b 約 1-3 tok/s,慢但能用),證明搬離方法論不需要先投資 GPU
Harness 不該硬搬地端 (三 agent 並行 + 長 context 是 cloud 的價值,脫敏走 cloud 才是對的)
結語:從藍圖到可執行的搬離
前 8 篇腦子系統告訴你「應該怎樣」。本篇告訴你「實際怎樣 」。
364 行 Python + Mini PC + Ollama + Claude Code = 搬離方法論的可執行實作。
這不是教你「怎麼蓋萬人企業 AI 治理」 — 那是另外 8 篇的事。
這是教你「怎麼今晚就在自己電腦上跑通搬離 logic 」 — 證明你的方法論不只是紙上的。
有了這個實作,你才有立場跟集團 IT 提 PoC,跟 CFO 提預算,跟法遵提合規。
下一步:你的 mini PC 有沒有變慢?Agent Team 還能 spawn 嗎?Brain 還在嗎?都沒事 — 因為 Gateway 是個獨立 process,不影響任何沒設 BASE_URL 的工作流 。你想停掉就 kill 一個 process,連配置都不用改。
這就是搬離方法論的真實樣子:低風險、可逆、漸進、實作在前、規模在後 。
延伸閱讀:腦子系統九部曲