← 返回主頁
HERMES AGENT SUPPLEMENT · 補充指南

Hermes Agent × Cloudflare:免費掛載多模態 AI 實戰

一篇記錄「OpenRouter 封鎖 → Cloudflare 生態重建」完整歷程嘅技術文件 — 生圖、讀圖、存檔、監控,全部免費額度內運作。

0 · 背景:一次真實嘅封鎖事件

2026-08-01,Hermes Agent 嘅主力 OpenRouter 帳戶突然被 Google、OpenAI、Anthropic 三廠聯合封鎖(403 violation of provider Terms Of Service)。診斷結果:

測試結果結論
OpenAI 系(gpt-image-1 / gpt-5-image-mini)403 TOS帳戶被永久標記(permanently flagged),與 IP / credits / 設定無關,retry 無效
Google 系(gemini-3-pro-image / gemini-3.6-flash vision)403 TOS
Anthropic(claude-sonnet-4)403 TOS
z.ai / Qwen / xAI / Meta 系正常文字 + 讀圖仍然可用

關鍵教訓:唔好將全部 AI 能力押喺單一第三方平台。OpenRouter 係聚合商,帳戶一被標記就全線失效。與其開新帳戶(有同 IP 關聯風險),不如遷去基礎設施商 Cloudflare — 佢係 DNS/CDN 供應商,唔會因「AI 內容政策」封你。

1 · Cloudflare Workers AI 概覽

1.1 免費額度(重點記住)

項目額度備註
Neurons10,000 / 日每日 00:00 UTC 重置,毋須信用卡
並行請求1 個連環 call 會排隊,要設 sleep
超過額度$0.011 / 1,000 neurons要 Workers Paid plan 先可以超
R2 儲存10 GB + 零 egress每月 100 萬次寫入 / 1000 萬次讀取
Paid-only 模型3 個kimi-k2.6 / kimi-k2.7-code / glm-5.2 免費 plan 用唔到

1.2 可用模型(61 個,實測)

🎨 Text-to-Image(11)flux-1-schnell(~58 neurons/張)、flux-2-klein-4b/9b、flux-2-dev、SDXL、leonardo phoenix 等
👁️ Vision(2)llava-1.5-7b(Beta 壞)、moondream3.1(空回傳壞)— 實際用 gemma-4-26b 頂上
🗣️ TTS(4)Deepgram Aura-2(en/es)、MeloTTS(多語言)
🎙️ STT(5)Whisper large-v3-turbo(~42 neurons/分鐘)→ 每日 ~230 分鐘免費轉錄
📝 Text(26)gemma-4 系列、llama-3.3-70b-fp8-fast、deepseek-r1-distill-qwen-32b、mistral-small-3.1
🌐 其他翻譯 m2m100、Embeddings×7、分類、image classification
⚠️ 實測教訓:「官方 model list 有」≠「用得」。moondream3.1 用正確參數(task:query + question)都回傳空 {};llava-1.5 係 Beta 標記 + 400。唯一可靠嘅 vision 係 @cf/google/gemma-4-26b-a4b-it(Text Generation task 但支援圖片輸入)。

2 · 生圖管線(免費,每日 ~170 張)

核心:CF flux-1-schnell 做主力,Pollinations.ai 做後備。Pollinations 完全免費無 key(unlimited-ish),質素中等;CF flux 質素高,有明確每日額度。

2.1 費用估算(實測 pricing 頁)

模型成本每日張數(10k neurons)用途
flux-1-schnell~57.6 neurons/張(1024², 4 steps)~170日常主力
flux-2-klein-4b~104 neurons/張~90快 + 平
flux-2-klein-9b~1,364 neurons/張~7圖生圖專用(貴,慳住用)
leonardo phoenix~540 neurons/張~18高質

2.2 核心 call(直連 API,唔使部署 Worker)

# 生圖 — POST /ai/run/<model>,JSON body
curl -X POST "https://api.cloudflare.com/client/v4/accounts/$CF_ACCOUNT_ID/ai/run/@cf/black-forest-labs/flux-1-schnell" \
  -H "Authorization: Bearer $CF_WORKERS_AI_TOKEN" -H "Content-Type: application/json" \
  -d '{"prompt":"a red apple on a wooden table","steps":4}'
# 回傳 {"result":{"image":"<base64>"}} → base64 解碼即係圖片

3 · 圖生圖(FLUX.2 嘅隱藏技巧)

⚠️ 最易踩嘅坑:CF 嘅 flux-2-klein-9b 收圖生圖,但唔係 JSON — 用 JSON 傳 image 會出 400 Type mismatch。佢嘅 schema 係 multipart/form-data
# 正確做法:-F multipart,image 用檔案上傳
curl -X POST ".../ai/run/@cf/black-forest-labs/flux-2-klein-9b" \
  -H "Authorization: Bearer $CF_WORKERS_AI_TOKEN" \
  -F "prompt=同一個場景,但女仔而家伏喺沙灘上,golden hour" \
  -F "image=@reference.jpg"        # ← multipart 檔案,唔係 base64!
# → 直接回傳編輯後嘅圖(base64)

呢個係成個遷移最關鍵嘅發現:img2img 用 multipart,txt2img 用 JSON。用 Python requests 就係 files={"image": (name, f, "image/jpeg")} + data={"prompt": ...}

4 · 讀圖管線(雙 gemma-4 通道)

Hermes 嘅 vision fallback 原本會跌返去主 model(deepseek-v4-pro),而 deepseek 係純文字 — 收咗圖但「睇唔到」(實測佢嘅 reasoning 話 I don't see any image attached)。解法:顯式設定 aux vision provider。

# config.yaml — 主力:OpenRouter gemma-4:free(26B,免費 :free 唔受三廠封鎖影響)
auxiliary:
  vision:
    provider: openrouter
    model: google/gemma-4-26b-a4b-it:free

後備:CF 版同一個 model(@cf/google/gemma-4-26b-a4b-it,OpenAI-compatible messages 格式)— 寫成 cf_vision.py,gemma 主力失效時自動頂上。性能排名(實測):

排名模型規格實測
🥇 主力gemma-4-26b-a4b-it:free(OpenRouter)26B(4B active MoE)詳細準確
🥈 後備gemma-4-26b-a4b-it(CF)同一 model 唔同 host正常
moondream3.1 / llava-1.5(CF)9B / 7B空回傳 / 400

4.1 實戰:表格圖 → 結構化數據(消委會《選擇》月刊)

vision 管線最實用嘅場景:直接讀表格圖,輸出結構化 JSON。消委會《選擇》測試報告嘅品牌表(牌子/型號/售價/評分)好多時只存在於 PDF 頁面圖,或者 OCR 出嚟錯晒 — 用 vision 讀圖最穩陣。方法係同一 OpenAI-compatible messages 格式(image_url data URL base64),CF gemma-4-26b 直連 /ai/run 就做到,唔使部署 Worker。

# 表格圖 → JSON(CF gemma-4 直連,無需 Worker)
import base64, urllib.request, json
b64 = base64.b64encode(open("p5.png", "rb").read()).decode()
body = {"messages": [{"role": "user", "content": [
    {"type": "text", "text": PROMPT},
    {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{b64}"}}]}]}
# POST /accounts/$CF_ACCOUNT_ID/ai/run/@cf/google/gemma-4-26b-a4b-it

實測(2026-08-03,14 款雲端儲存服務真實表格頁):

模型合成測試表真實消委會頁備註
gemma-4-26b-a4b-it(CF)✅ 100%✅ OneDrive / SurDoc 等免費 neurons 內,每日 10k
grok-4.5(OpenAI 兼容 API)✅ 100%收費 API 都得
deepseek-v4-flash / pro❌ 收圖睇唔到純文字 model,忽略圖像
qwen3-vl-30b(CF)❌ 400list 有但 plan 用唔到(No route)

提示詞關鍵:嚴格 JSON array、品牌名中文優先、價格只取數字(HK$1,299 → 1299)、is_recommended=總評最高(並列都要)、is_warning=致癌物/超標、冇品牌表輸出 []。表格橫跨多頁 → 每 3 頁一組 chunk,合併再去除重。

⚠️ 表格提取三個坑:max_tokens 要 ≥8000 — 長表格(58 行)嘅合法回應 >4000 tokens,max_tokens=4000 會喺 JSON 中間截斷 → parse fail(flash 同 pro 都中);② vision 幻覺 — 讀表格會編造型號/分數,必須同文章敘述、樣本數交叉驗證先信;③ 表格頁要搵位 — 表通常喺文章中後段(p5/p6),逐頁試或者先用文字敘述定位。

5 · 存檔系統(Drive + R2 雙軌)

📁 Google Drive(5TB)每次生圖自動 upload 去 AI-images/YYYY-MM/,並寫入 images_index.jsonl 記錄 prompt + Drive link。用現有 google-workspace OAuth,零新設定。
☁️ Cloudflare R2(10GB)ai-images bucket,S3-compatible API(boto3)。超過 50%(5GB)自動刪最舊到 4GB,每日 03:00 cron。
# R2 = S3-compatible:endpoint 用 account ID
endpoint = f"https://{R2_ACCOUNT_ID}.r2.cloudflarestorage.com"
s3 = boto3.client("s3", endpoint_url=endpoint,
                  aws_access_key_id=R2_ACCESS_KEY_ID,      # 32 字元
                  aws_secret_access_key=R2_SECRET_ACCESS_KEY)  # 64 字元
s3.create_bucket(Bucket="ai-images")   # 免費 plan 都得
s3.upload_file(path, "ai-images", name)  # 零 egress 費用

6 · 監控(watchdog 模式)

兩個 cron 都用「靜默 unless 有事」模式(stdout 空 = 唔推 Telegram):

Job頻率行為
cf-quota-monitor每小時cf_usage.log(每張圖自動記錄 neurons),>80%(8,000)先推警報 + model 分佈 + 剩餘張數
r2-cleanup每日 03:00R2 用量 >5GB → 刪最舊到 4GB,有刪先推報告
# cf_usage.log 一行一個記錄(生圖時自動寫)
2026-08-01 12:45 flux-1-schnell 57.6
2026-08-01 12:58 flux-2-klein-9b 1545.0

7 · 文件清單(要準備啲咩)

7.1 Credentials(4 樣)

憑證攞法用途
CF Account IDDashboard 右欄所有 API 嘅 path 前綴
CF Workers AI TokenMy Profile → API Tokens → Workers AI 模板(Account → Workers AI → Edit)生圖 / 讀圖 / TTS / STT
R2 S3 Token(Access Key + Secret)R2 → Manage R2 API Tokens(唔係 Profile API Tokens!)圖片存檔(Access=32字元 / Secret=64字元)
Google OAuth(client_secret + token)Google Cloud Console → OAuth 2.0 ClientDrive 存檔(google-workspace skill 管理)
⚠️ 三個 R2/CF 權限陷阱:① Workers AI token 唔包 R2(要另外開);② R2 S3 token 必須喺 R2 dashboard 開,Profile 嘅 cfut_ token 用唔到;③ Access Key 同 Secret 長度唔同(32 vs 64),貼錯會出 Credential access key has length 64, should be 32

7.2 .env 變數(5 組)

CF_WORKERS_AI_TOKEN=cfut_xxxxxxxx...        # Workers AI
CF_ACCOUNT_ID=your_account_id...            # Account ID
R2_ACCOUNT_ID=your_account_id...            # = Account ID(endpoint 用)
R2_ACCESS_KEY_ID=your_access_key...         # 32 字元
R2_SECRET_ACCESS_KEY=your_secret_key...     # 64 字元
OPENROUTER_API_KEY=sk-or-...                # gemma-4:free 讀圖(保留)

7.3 Scripts(4 個,全部喺 ~/scripts/)

Script功能
gen_image.py生圖(CF flux 主 → Pollinations 後備)+ img2img(--ref)+ 自動存 Drive/R2 + usage log
cf_vision.pyCF gemma-4 讀圖(後備通道)
r2_storage.pyR2 upload / usage / cleanup(>5GB 刪舊)
cf_quota_monitor.py每日 neurons 用量統計 + 80% 警報

注意:gen_image.py 要用 hermes venv python(有 PIL 先可以 crop 比例),/usr/bin/python3 冇 PIL。

8 · 踩坑合集(全部親測)

9 · 快速開始(3 步)

  1. 攞憑證:CF Workers AI token + R2 S3 token(見 §7.1),寫入 ~/.hermes/.env
  2. 放 Scriptsgen_image.py / cf_vision.py / r2_storage.py~/scripts/,用 hermes venv python 執行
  3. python gen_image.py "prompt" 1024 1024 /tmp/a.png --ref ref.jpg → 自動生圖 + 存 Drive + 存 R2
# 一條 command 完成:生圖 + 雙備份 + 用量記錄
python ~/scripts/gen_image.py "a cyberpunk cat in neon Tokyo" 1024 1024 /tmp/cat.png
# [cloudflare-flux] /tmp/cat.png
# [drive] archived -> https://drive.google.com/file/d/...
# [r2] archived

10 · 補充建議(由可用變成 production-ready)

以下係工程師覆核後嘅補充 — 聚焦「可用 → production-ready」嘅細節:憑證最小權限、重試策略、成本控制、後備深度、雙軌對賬。

10.1 憑證安全:Token 最小權限 + Rotation

10.2 重試策略:唔係淨係 sleep

免費 tier 得 1 個並行,實際會遇到三種情況:

情況HTTP Status處理建議
Rate limit429Retry-After header,跟佢等
排隊中(極慢)200timeout=60s,超時即視為失敗 fallback
模型暫時不可用500 / 503即時 fallback 去 Pollinations,唔使 retry
# gen_image.py 加 retry decorator,但 429 唔應該 blind retry
@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=2, max=10),
    retry=retry_if_exception_type((
        requests.exceptions.Timeout,
        requests.exceptions.HTTPError
    ))
)

重點:429 要讀 Retry-After,否則會越踩越重。

10.3 Flux steps × neurons 嘅非線性關係

§2.1 嘅 57.6 neurons 係 4 steps 數值 — steps 對成本影響好大:

Steps~Neurons/張質量建議場景
1~20草稿級快速 preview、測試 prompt
4~58可用日常主力(原指南建議)
8~110較好重要輸出
20~260最佳極少需要,不如用 flux-2-dev

慳 neurons 技巧:batch 生成(例如一次出 10 張變體),可以先用 step=1 做 preview,用戶揀中先出 step=4/8,慳大量 neurons。

10.4 Pollinations fallback 嘅隱藏限制

建議 fallback 順序:CF flux → Pollinations → 本地 SD(如有)→ 文字描述代替

10.5 R2 與 Drive 雙軌嘅一致性

# gen_image.py 生成後寫 manifest.jsonl(每行一條,方便日後對賬)
{"timestamp":"...","prompt":"...","drive_id":"...","r2_key":"...","md5":"...","model":"flux-1-schnell","neurons":57.6}

R2 cleanup 刪舊檔時,最好連 manifest 一齊標記 deleted: true,而唔係真係刪 manifest entry,保留 audit trail。

10.6 圖片 metadata:EXIF 寫入 prompt

# 用 PIL 將 prompt、model、timestamp 寫入 PNG 嘅 tEXt chunk
from PIL import Image, PngImagePlugin
img = Image.open("/tmp/cat.png")
metadata = PngImagePlugin.PngInfo()
metadata.add_text("prompt", prompt)
metadata.add_text("model", "flux-1-schnell")
metadata.add_text("generated_at", datetime.utcnow().isoformat())
img.save("/tmp/cat.png", pnginfo=metadata)

咁樣即使 manifest 遺失,都可以從圖片本身讀返原始 prompt,方便 reproduce。

10.7 CF Workers AI 嘅「隱藏」endpoint:AI binding

原指南用直連 API(/ai/run/...)。如果已部署 Cloudflare Worker,可以用 AI binding:

// worker.js
const response = await env.AI.run(
    '@cf/black-forest-labs/flux-1-schnell',
    { prompt: "..." }
)

好處:唔使管理 token(binding 用 account 權限)、可以做 caching、rate limiting、auth 層。壞處:要部署 Worker,多一層 infra。對於 Hermes 嘅 use case,直連 API 已經夠簡潔;但如果將來要開 API 畀多人用,binding 方式會更易管理 quota。

總結:fallback 要夠深。由 OpenRouter 三廠封鎖學到嘅教訓,同樣適用於 CF(免費 tier 有 quota、有並行限制、有偶發性 500)。多一層後備,少一層深夜 debug。

鍾意呢份指南?請我飲杯咖啡 ☕

☕ 請我喝杯咖啡