實(shí)戰(zhàn):用Worker與Durable Object構(gòu)建AI Agent)
1. 從cloudflare-os這個(gè)標(biāo)題說(shuō)起它到底在指什么第一次看到cloudflare-os這個(gè)詞我下意識(shí)以為是 Cloudflare 官方又出了什么新操作系統(tǒng)。翻了一圈資料才反應(yīng)過(guò)來(lái)這更像是一個(gè)社區(qū)里自發(fā)形成的概念標(biāo)簽用來(lái)描述一種把 Cloudflare 全家桶Workers、Durable Objects、KV、R2、D1、Queues、AI Gateway 等當(dāng)成操作系統(tǒng)來(lái)用的開(kāi)發(fā)范式。換句話說(shuō)它不是某個(gè)具體的產(chǎn)品而是一種架構(gòu)思路把邊緣網(wǎng)絡(luò)當(dāng)作內(nèi)核把各類(lèi)綁定binding當(dāng)作系統(tǒng)調(diào)用把 Worker 當(dāng)作進(jìn)程把 Durable Object 當(dāng)作有狀態(tài)的守護(hù)進(jìn)程。這個(gè)思路為什么最近被反復(fù)提起因?yàn)?AI Agent 這類(lèi)應(yīng)用對(duì)基礎(chǔ)設(shè)施的要求和傳統(tǒng) Web 應(yīng)用完全不一樣。傳統(tǒng) CRUD 應(yīng)用是請(qǐng)求-響應(yīng)模型無(wú)狀態(tài)、短生命周期、可預(yù)測(cè)。而 Agent 是長(zhǎng)任務(wù)、多輪工具調(diào)用、需要記憶、需要并發(fā)協(xié)調(diào)、需要流式輸出、需要按 token 計(jì)費(fèi)。你拿一臺(tái)固定區(qū)域的 VPS 去跑很快就會(huì)遇到三個(gè)問(wèn)題一是冷啟動(dòng)和并發(fā)調(diào)度跟不上二是狀態(tài)管理要自己造輪子三是全球用戶(hù)訪問(wèn)延遲參差不齊。Cloudflare 這套東西恰好在這三點(diǎn)上都有對(duì)應(yīng)的原語(yǔ)。Workers 負(fù)責(zé)無(wú)狀態(tài)計(jì)算Durable Objects 負(fù)責(zé)單點(diǎn)強(qiáng)一致?tīng)顟B(tài)KV 負(fù)責(zé)最終一致的讀多寫(xiě)少緩存R2 負(fù)責(zé)對(duì)象存儲(chǔ)D1 負(fù)責(zé)關(guān)系型數(shù)據(jù)Queues 負(fù)責(zé)異步解耦A(yù)I Gateway 負(fù)責(zé)模型調(diào)用的可觀測(cè)性和緩存。把它們組合起來(lái)確實(shí)有了一點(diǎn)操作系統(tǒng)的味道——你不再關(guān)心服務(wù)器在哪、怎么擴(kuò)容、怎么容災(zāi)你只關(guān)心我要調(diào)度哪個(gè)能力。這篇文章我想聊的不是Cloudflare 有多好而是如果你真的打算用這套東西去搭一個(gè) AI Agent 系統(tǒng)哪些地方是坑、哪些設(shè)計(jì)決策要想清楚、哪些能力被高估了、哪些被低估了。適合已經(jīng)寫(xiě)過(guò)至少一個(gè) Worker、對(duì) Agent 有基本概念、準(zhǔn)備把它推到生產(chǎn)環(huán)境的開(kāi)發(fā)者。純新手也能看但可能需要邊看邊查文檔。2. 把邊緣網(wǎng)絡(luò)當(dāng)內(nèi)核這套操作系統(tǒng)的原語(yǔ)到底怎么分工2.1 Worker 是進(jìn)程不是函數(shù)很多人第一次寫(xiě) Worker腦子里還是云函數(shù)的模型一個(gè)請(qǐng)求進(jìn)來(lái)跑一段代碼返回結(jié)束。這個(gè)理解在簡(jiǎn)單場(chǎng)景下沒(méi)錯(cuò)但一旦涉及 Agent就會(huì)出問(wèn)題。Agent 的一次任務(wù)可能持續(xù)幾十秒甚至幾分鐘中間要調(diào)用多次模型、多次工具、多次讀寫(xiě)狀態(tài)。如果你還按一個(gè)請(qǐng)求一個(gè)函數(shù)來(lái)設(shè)計(jì)就會(huì)被迫把整個(gè) Agent 循環(huán)塞進(jìn)一個(gè)請(qǐng)求里然后撞上 CPU 時(shí)間限制和請(qǐng)求超時(shí)。正確的做法是把 Worker 當(dāng)成進(jìn)程調(diào)度器而不是進(jìn)程本身。一個(gè)請(qǐng)求進(jìn)來(lái)Worker 只負(fù)責(zé)解析意圖、創(chuàng)建或喚醒一個(gè) Durable Object、把任務(wù)投遞進(jìn)去然后立刻返回一個(gè)任務(wù) ID 或者建立一條流式連接。真正的 Agent 循環(huán)跑在 Durable Object 里它可以長(zhǎng)時(shí)間存活、可以被多次喚醒、可以主動(dòng)推送結(jié)果。這個(gè)分工想清楚了后面很多設(shè)計(jì)就順了。我見(jiàn)過(guò)太多人把 Agent 邏輯直接寫(xiě)在 fetch handler 里然后抱怨為什么跑一半就斷了。不是平臺(tái)的問(wèn)題是模型用錯(cuò)了。2.2 Durable Object 是這套架構(gòu)里最被低估的原語(yǔ)如果說(shuō) Worker 是進(jìn)程那 Durable Object后面簡(jiǎn)稱(chēng) DO就是帶狀態(tài)的守護(hù)進(jìn)程 單點(diǎn)鎖。每個(gè) DO 實(shí)例有全局唯一的 ID同一時(shí)刻只有一個(gè)實(shí)例在跑所有請(qǐng)求串行進(jìn)入。這個(gè)特性聽(tīng)起來(lái)像限制實(shí)際上是 Agent 場(chǎng)景里最需要的東西。想象一個(gè)多輪對(duì)話 Agent用戶(hù)發(fā)消息Agent 要讀歷史、調(diào)模型、調(diào)工具、寫(xiě)回歷史。如果這些操作并發(fā)進(jìn)來(lái)沒(méi)有串行保證歷史就會(huì)亂。用傳統(tǒng)方案你得自己上分布式鎖、自己處理競(jìng)態(tài)。用 DO天然就是串行的你只要把狀態(tài)放在 DO 的 storage 里讀寫(xiě)都是強(qiáng)一致的。但 DO 也有代價(jià)。它的單點(diǎn)特性意味著吞吐有上限一個(gè) DO 實(shí)例大概每秒能處理幾百到上千個(gè)請(qǐng)求取決于你的邏輯復(fù)雜度。所以設(shè)計(jì)時(shí)要考慮分片一個(gè)用戶(hù)一個(gè) DO還是一個(gè)會(huì)話一個(gè) DO還是一個(gè)租戶(hù)一個(gè) DO我的經(jīng)驗(yàn)是一個(gè)會(huì)話一個(gè) DO最穩(wěn)用戶(hù)級(jí)別的聚合狀態(tài)另開(kāi)一個(gè) DO 或者放 D1。這樣單個(gè)會(huì)話的并發(fā)壓力可控跨會(huì)話的查詢(xún)走 D1。2.3 KV、R2、D1、Queues 各自的邊界這四個(gè)存儲(chǔ)原語(yǔ)經(jīng)常被混用我列個(gè)表說(shuō)清楚它們各自適合什么原語(yǔ)一致性適用場(chǎng)景不適用場(chǎng)景KV最終一致寫(xiě)入后全球生效有延遲配置、feature flag、讀多寫(xiě)少的緩存需要立即讀到剛寫(xiě)入的數(shù)據(jù)R2強(qiáng)一致單區(qū)域大文件、模型產(chǎn)物、日志歸檔高頻小對(duì)象讀寫(xiě)D1強(qiáng)一致單主庫(kù)關(guān)系型數(shù)據(jù)、需要 SQL 查詢(xún)高并發(fā)寫(xiě)入、跨區(qū)域低延遲讀Queues至少一次投遞異步任務(wù)、削峰、解耦需要嚴(yán)格順序或精確一次Agent 場(chǎng)景里最常見(jiàn)的誤用是拿 KV 存會(huì)話狀態(tài)。KV 寫(xiě)入后全球生效有幾十秒延遲你這邊剛寫(xiě)完下一個(gè)請(qǐng)求打到另一個(gè)邊緣節(jié)點(diǎn)讀到舊值A(chǔ)gent 就失憶了。會(huì)話狀態(tài)必須放 DO 或者 D1KV 只適合放那些變了也無(wú)所謂的東西。2.4 AI Gateway 不是必須的但強(qiáng)烈建議加上AI Gateway 的核心價(jià)值不是幫你調(diào)模型而是三件事緩存、限流、可觀測(cè)。Agent 場(chǎng)景里模型調(diào)用是成本大頭緩存能省的錢(qián)很可觀——尤其是那些 system prompt 固定、用戶(hù)問(wèn)題重復(fù)率高的場(chǎng)景。限流能防止某個(gè)用戶(hù)或某個(gè) bug 把你的額度打爆??捎^測(cè)能讓你看到每次調(diào)用的延遲、token 數(shù)、失敗率。我自己的做法是所有模型調(diào)用都走 AI Gateway哪怕只是加一層轉(zhuǎn)發(fā)。多這一跳的延遲可以忽略但換來(lái)的是排查問(wèn)題時(shí)的救命稻草。有一次線上 Agent 突然變慢就是靠 Gateway 的日志發(fā)現(xiàn)某個(gè)工具的返回體異常大把上下文撐爆了。3. 用 Worker DO 搭一個(gè)最小可用的 Agent 骨架3.1 為什么不用現(xiàn)成的 Agent 框架現(xiàn)在 Agent 框架滿(mǎn)天飛LangChain、LlamaIndex、各種國(guó)產(chǎn)的、各種一行代碼搭 Agent的。我的建議是如果你要做生產(chǎn)系統(tǒng)先別急著上框架。原因有三個(gè)。第一框架的抽象層會(huì)掩蓋底層行為。Agent 出問(wèn)題時(shí)你需要在模型返回了什么工具被調(diào)了幾次狀態(tài)在哪一步寫(xiě)壞了這些層面排查??蚣馨堰@些都包起來(lái)了你只能看它給你的日志很多時(shí)候不夠用。第二框架的更新速度跟不上模型和平臺(tái)的變化。你今天用的框架可能下個(gè)月就不維護(hù)了或者某個(gè) API 變了它沒(méi)跟上。生產(chǎn)系統(tǒng)最怕這種依賴(lài)。第三Agent 的核心邏輯其實(shí)不復(fù)雜。無(wú)非是讀狀態(tài) → 調(diào)模型 → 解析工具調(diào)用 → 執(zhí)行工具 → 寫(xiě)狀態(tài) → 循環(huán)。這個(gè)循環(huán)自己寫(xiě)一遍兩百行代碼比學(xué)一個(gè)框架的 API 快。所以我下面給的骨架是裸寫(xiě)的不依賴(lài)任何 Agent 框架。你可以后面按需引入但先理解底層。3.2 項(xiàng)目結(jié)構(gòu)agent-worker/ ├── src/ │ ├── index.ts # Worker 入口路由分發(fā) │ ├── session.ts # Durable Object會(huì)話狀態(tài)與 Agent 循環(huán) │ ├── tools/ │ │ ├── index.ts # 工具注冊(cè)表 │ │ ├── search.ts # 示例工具搜索 │ │ └── calc.ts # 示例工具計(jì)算 │ └── llm.ts # 模型調(diào)用封裝 ├── wrangler.toml └── package.json這個(gè)結(jié)構(gòu)的關(guān)鍵是session.ts里的 DO 承擔(dān)了 Agent 循環(huán)index.ts只做路由和鑒權(quán)。工具用注冊(cè)表模式方便擴(kuò)展。3.3 wrangler.toml 的關(guān)鍵配置name agent-worker main src/index.ts compatibility_date 2024-11-01 [[durable_objects.bindings]] name SESSION class_name SessionDO [[migrations]] tag v1 new_classes [SessionDO] [[kv_namespaces]] binding CACHE id your-kv-id [[d1_databases]] binding DB database_name agent-db database_id your-d1-id [ai] binding AI幾個(gè)容易踩的點(diǎn)compatibility_date一定要寫(xiě)而且盡量用新的否則一些新 API 用不了。DO 的 migration 每次加新類(lèi)都要加 tag不能改舊的。AI binding 是 Workers AI 的綁定如果你用外部模型比如 OpenAI、Anthropic不需要這個(gè)直接 fetch 就行。3.4 DO 里的 Agent 循環(huán)長(zhǎng)什么樣核心邏輯大概是這樣export class SessionDO { state: DurableObjectState; env: Env; messages: Message[] []; constructor(state: DurableObjectState, env: Env) { this.state state; this.env env; this.state.blockConcurrencyWhile(async () { this.messages (await this.state.storage.get(messages)) || []; }); } async fetch(request: Request) { const { input } await request.json(); this.messages.push({ role: user, content: input }); let step 0; while (step 10) { const response await callLLM(this.env, this.messages); this.messages.push(response); if (response.toolCalls response.toolCalls.length 0) { for (const call of response.toolCalls) { const result await executeTool(call.name, call.args); this.messages.push({ role: tool, tool_call_id: call.id, content: JSON.stringify(result), }); } step; continue; } await this.state.storage.put(messages, this.messages); return new Response(JSON.stringify({ reply: response.content })); } return new Response(JSON.stringify({ error: max steps exceeded }), { status: 500 }); } }這段代碼有幾個(gè)設(shè)計(jì)決策值得說(shuō)。blockConcurrencyWhile保證構(gòu)造時(shí)狀態(tài)加載完再處理請(qǐng)求避免競(jìng)態(tài)。step 10是防止 Agent 陷入死循環(huán)生產(chǎn)環(huán)境這個(gè)值要按業(yè)務(wù)調(diào)。每輪循環(huán)都寫(xiě) storage 是浪費(fèi)只在最終返回時(shí)寫(xiě)一次中間狀態(tài)放內(nèi)存——但如果 DO 被驅(qū)逐內(nèi)存會(huì)丟所以關(guān)鍵節(jié)點(diǎn)還是要落盤(pán)。3.5 流式輸出怎么接Agent 場(chǎng)景里流式輸出幾乎是必須的用戶(hù)等 30 秒看不到任何反饋會(huì)以為卡死了。DO 支持返回 ReadableStream你可以把模型的流式響應(yīng)直接透?jìng)鞒鋈?。但要注意一旦開(kāi)始流式輸出就不能再改 HTTP 狀態(tài)碼了所以錯(cuò)誤處理要在流開(kāi)始前做完。我的做法是DO 先做一輪預(yù)檢檢查額度、檢查輸入合法性通過(guò)了再開(kāi)始流式。流中間如果出錯(cuò)發(fā)一個(gè)特殊的 SSE 事件告訴前端出錯(cuò)了前端負(fù)責(zé)展示。這樣用戶(hù)體驗(yàn)最好。4. 狀態(tài)、記憶與并發(fā)Agent 最容易翻車(chē)的地方4.1 短期記憶和長(zhǎng)期記憶要分開(kāi)設(shè)計(jì)Agent 的記憶這個(gè)詞被用爛了實(shí)際上要拆成兩層。短期記憶是當(dāng)前會(huì)話的上下文就是那個(gè) messages 數(shù)組放 DO 內(nèi)存 storage。長(zhǎng)期記憶是跨會(huì)話的知識(shí)比如這個(gè)用戶(hù)偏好簡(jiǎn)潔回答這個(gè)用戶(hù)是開(kāi)發(fā)者放 D1 或者向量庫(kù)。很多人一上來(lái)就搞向量數(shù)據(jù)庫(kù)做長(zhǎng)期記憶結(jié)果發(fā)現(xiàn)召回質(zhì)量差、成本高、還慢。我的建議是先用結(jié)構(gòu)化字段。用戶(hù)偏好、常用工具、歷史摘要這些用 D1 存幾個(gè)字段就夠了查詢(xún)快、可控、可解釋。真正需要語(yǔ)義召回的場(chǎng)景比如幫我找上次討論過(guò)的那個(gè)方案再上向量。4.2 上下文窗口管理是個(gè)工程問(wèn)題不是模型問(wèn)題模型上下文再大也有上限而且越大越貴越慢。Agent 跑多輪之后messages 數(shù)組會(huì)膨脹。你必須主動(dòng)管理。我常用的策略是三層最近 N 輪完整保留更早的輪次做摘要壓縮再早的直接丟棄但保留關(guān)鍵實(shí)體。摘要壓縮用便宜的小模型做比如把 10 輪對(duì)話壓成 200 字。關(guān)鍵實(shí)體人名、項(xiàng)目名、數(shù)字單獨(dú)抽出來(lái)放一個(gè)結(jié)構(gòu)化字段不參與壓縮。這里有個(gè)坑摘要會(huì)丟信息而且丟得不可預(yù)測(cè)。所以涉及金額、日期、ID 這類(lèi)不能錯(cuò)的信息一定要單獨(dú)存不能只靠摘要。4.3 并發(fā)請(qǐng)求下的狀態(tài)一致性同一個(gè)會(huì)話用戶(hù)可能快速發(fā)兩條消息。如果兩條都進(jìn) DODO 是串行處理的第二條會(huì)等第一條跑完。這聽(tīng)起來(lái)對(duì)但實(shí)際體驗(yàn)很差——用戶(hù)發(fā)第二條時(shí)第一條可能還在跑 Agent 循環(huán)要等幾十秒。我的處理方式是DO 內(nèi)部維護(hù)一個(gè)任務(wù)隊(duì)列新消息進(jìn)來(lái)先入隊(duì)返回已收到。Agent 循環(huán)處理完當(dāng)前任務(wù)后檢查隊(duì)列有就繼續(xù)。前端通過(guò) WebSocket 或者輪詢(xún)拿結(jié)果。這樣用戶(hù)感覺(jué)是即時(shí)響應(yīng)實(shí)際是異步處理。另一個(gè)坑是 DO 的 storage 寫(xiě)入有頻率限制。如果你每輪循環(huán)都寫(xiě)高頻會(huì)話下會(huì)撞限流。批量寫(xiě)、延遲寫(xiě)、只寫(xiě)關(guān)鍵狀態(tài)這三點(diǎn)要做到。4.4 工具調(diào)用的冪等性Agent 調(diào)工具可能失敗重試如果工具不冪等就會(huì)重復(fù)執(zhí)行。比如發(fā)郵件這個(gè)工具重試兩次就發(fā)兩封。解決辦法是給每次工具調(diào)用生成一個(gè)唯一 ID工具內(nèi)部用這個(gè) ID 去重。對(duì)于有副作用的工具寫(xiě)數(shù)據(jù)庫(kù)、發(fā)消息、扣款冪等設(shè)計(jì)是必須的不是可選的。我見(jiàn)過(guò)一個(gè)案例Agent 調(diào)支付工具網(wǎng)絡(luò)抖動(dòng)重試用戶(hù)被扣了兩次錢(qián)。這種事故在 Agent 系統(tǒng)里比傳統(tǒng)系統(tǒng)更容易發(fā)生因?yàn)?Agent 會(huì)自作主張重試。5. 部署、觀測(cè)與成本上線之后才是真正的開(kāi)始5.1 本地開(kāi)發(fā)和線上行為的差異wrangler dev本地跑和線上跑行為有差異。最明顯的是 DO 的行為本地是單進(jìn)程模擬線上是真正的分布式。本地測(cè)著沒(méi)問(wèn)題的并發(fā)邏輯線上可能出問(wèn)題。所以關(guān)鍵路徑一定要在 staging 環(huán)境用wrangler deploy --env staging跑一遍。另一個(gè)差異是 KV 的一致性。本地 KV 是立即一致的線上是最終一致。本地測(cè)著寫(xiě)完立刻讀能讀到線上可能讀不到。這個(gè)坑我踩過(guò)排查了半天。5.2 觀測(cè)要抓的三個(gè)指標(biāo)Agent 系統(tǒng)的觀測(cè)我重點(diǎn)關(guān)注三個(gè)每輪循環(huán)的 token 消耗、工具調(diào)用的成功率和延遲、端到端任務(wù)完成率。前兩個(gè)決定成本第三個(gè)決定體驗(yàn)。Cloudflare 自帶的 Analytics 能看到請(qǐng)求量、錯(cuò)誤率、CPU 時(shí)間但看不到業(yè)務(wù)層面的指標(biāo)。我的做法是在 Worker 里埋點(diǎn)把關(guān)鍵事件寫(xiě)到 Analytics Engine 或者直接推到外部比如自建的時(shí)序庫(kù)。別嫌麻煩出問(wèn)題時(shí)這些數(shù)據(jù)是唯一能救你的。5.3 成本控制的幾個(gè)實(shí)操手段Agent 成本主要是模型調(diào)用??刂剖侄伟葱?xún)r(jià)比排序緩存 小模型分流 上下文壓縮 限流。緩存用 AI Gateway 的緩存功能相同輸入直接返回。小模型分流是指簡(jiǎn)單任務(wù)分類(lèi)、抽取、格式化用便宜模型復(fù)雜推理才用大模型。上下文壓縮前面說(shuō)過(guò)。限流是兜底防止異常流量。我算過(guò)一筆賬一個(gè)中等復(fù)雜度的 Agent不做任何優(yōu)化每次任務(wù)大概 0.05 到 0.2 美元。做了緩存和分流之后能降到 0.02 到 0.08。量大了這個(gè)差距很可觀。5.4 冷啟動(dòng)和 DO 驅(qū)逐DO 長(zhǎng)時(shí)間不活動(dòng)會(huì)被驅(qū)逐下次請(qǐng)求要重新加載狀態(tài)。如果你的 DO 構(gòu)造時(shí)要讀大量數(shù)據(jù)冷啟動(dòng)會(huì)慢。解決辦法是構(gòu)造時(shí)只讀必要的最小狀態(tài)其余按需加載。另外 DO 的 storage 讀取是異步的構(gòu)造時(shí)用blockConcurrencyWhile包住避免請(qǐng)求進(jìn)來(lái)時(shí)狀態(tài)還沒(méi)加載完。Worker 本身的冷啟動(dòng)已經(jīng)很快了毫秒級(jí)基本不用管。真正要管的是 DO 的狀態(tài)加載。6. 幾個(gè)我踩過(guò)的坑和對(duì)應(yīng)的解法6.1 坑一把 DO 當(dāng)數(shù)據(jù)庫(kù)用一開(kāi)始我把所有會(huì)話數(shù)據(jù)都塞進(jìn) DO storage覺(jué)得方便。結(jié)果數(shù)據(jù)量一大DO 的 storage 讀寫(xiě)變慢而且沒(méi)法做跨會(huì)話查詢(xún)。后來(lái)改成 DO 只存活躍會(huì)話的上下文歷史歸檔到 D1查詢(xún)走 D1。DO 的 storage 有大小限制別把它當(dāng)無(wú)限倉(cāng)庫(kù)。6.2 坑二忽略 Worker 的 CPU 時(shí)間限制Worker 有 CPU 時(shí)間限制免費(fèi)版 10ms付費(fèi)版 30s 可配。注意是 CPU 時(shí)間不是墻鐘時(shí)間。等模型響應(yīng)的時(shí)間不算 CPU但 JSON 解析、字符串處理、加密這些算。我有一次在 Worker 里做大量 JSON 處理直接撞限制。解決辦法是把重計(jì)算移到 DO 或者用流式處理別一次性加載大對(duì)象。6.3 坑三工具描述寫(xiě)得太隨意Agent 靠工具描述來(lái)決定調(diào)哪個(gè)工具。描述寫(xiě)得模糊Agent 就會(huì)亂調(diào)。比如你有個(gè)工具叫search描述寫(xiě)搜索信息Agent 不知道搜什么、什么時(shí)候搜。正確的寫(xiě)法是寫(xiě)清楚這個(gè)工具做什么、什么時(shí)候用、輸入格式、返回什么、有什么限制。工具描述是 prompt 工程的一部分要認(rèn)真寫(xiě)。6.4 坑四沒(méi)有超時(shí)和重試策略模型調(diào)用、工具調(diào)用、外部 API 調(diào)用都要有超時(shí)。沒(méi)有超時(shí)一個(gè)卡住的調(diào)用會(huì)把整個(gè) Agent 循環(huán)拖死。重試要有退避策略不能無(wú)腦重試。我的默認(rèn)配置是模型調(diào)用超時(shí) 30s重試 2 次指數(shù)退避工具調(diào)用超時(shí) 10s重試 1 次外部 API 按對(duì)方文檔來(lái)。6.5 坑五日志里泄露敏感信息Agent 的 messages 里可能有用戶(hù)隱私、API key、內(nèi)部數(shù)據(jù)。日志默認(rèn)會(huì)記錄請(qǐng)求體一不小心就泄露了。我的做法是日志只記元數(shù)據(jù)長(zhǎng)度、hash、工具名不記內(nèi)容確需記內(nèi)容的先脫敏。這個(gè)在合規(guī)要求高的場(chǎng)景是硬性要求。7. 這套架構(gòu)適合什么、不適合什么聊了這么多技術(shù)細(xì)節(jié)最后說(shuō)點(diǎn)判斷層面的東西。Cloudflare 這套邊緣操作系統(tǒng)不是銀彈它有明確的適用邊界。適合的場(chǎng)景全球用戶(hù)、對(duì)延遲敏感、流量波動(dòng)大、團(tuán)隊(duì)小不想管服務(wù)器、Agent 任務(wù)以 IO 等待為主調(diào)模型、調(diào) API。這些場(chǎng)景下它的彈性、全球分布、按量計(jì)費(fèi)優(yōu)勢(shì)明顯。不適合的場(chǎng)景需要長(zhǎng)時(shí)間 CPU 密集計(jì)算比如本地跑推理、需要特定硬件GPU、需要復(fù)雜的事務(wù)跨多個(gè)數(shù)據(jù)源、團(tuán)隊(duì)已經(jīng)有成熟的 K8s 體系且遷移成本高。這些場(chǎng)景下硬上 Cloudflare 會(huì)別扭。我自己的判斷標(biāo)準(zhǔn)是如果我的 Agent 任務(wù) 90% 的時(shí)間在等外部響應(yīng)那 Cloudflare 是優(yōu)選如果 90% 的時(shí)間在算那要找別的地方。這個(gè)標(biāo)準(zhǔn)幫我省了很多糾結(jié)。另外提醒一句這套東西的生態(tài)還在快速變化。今天的最佳實(shí)踐半年后可能就過(guò)時(shí)了。保持關(guān)注官方 changelog別把架構(gòu)設(shè)計(jì)得太死留好替換空間。我一般會(huì)把模型調(diào)用、存儲(chǔ)訪問(wèn)、工具執(zhí)行都封裝成接口底層實(shí)現(xiàn)可替換。這樣平臺(tái)變了、模型換了上層邏輯不用動(dòng)。寫(xiě)到這里關(guān)于 cloudflare-os 這個(gè)概念的拆解基本覆蓋了從架構(gòu)選型到上線運(yùn)維的主要環(huán)節(jié)。如果你正準(zhǔn)備用這套東西搭 Agent建議先從最小骨架跑通再逐步加狀態(tài)、加工具、加觀測(cè)。別一上來(lái)就設(shè)計(jì)大而全的架構(gòu)Agent 系統(tǒng)的復(fù)雜度是長(zhǎng)出來(lái)的不是設(shè)計(jì)出來(lái)的。