Dify 自架實戰 · 架構補充

Dify 完整架構:一個自架 AI Agent 平台的所有零件

你在網頁打一句話,背後有 13 個容器在協作。這頁把 Dify 自架的完整組件架構、一次對話的生命週期、以及 RAG 文件怎麼變成可查的知識,一次畫給你看——全部照真實跑起來的環境整理,不是示意。

🏗️ 完整組件架構:13 個容器各司其職

使用者 應用 / 服務(對話邏輯在這) 隔離 / 安全層 資料層(存放) 外部能力(模型 / 工具)
flowchart TB
  U(["🖥️ 瀏覽器 · 使用者"]):::result
  NG["nginx
反向代理 · 對外入口"]:::proc subgraph APP["應用層"] direction TB WEB["web
Next.js 前端 UI"]:::proc API["api ⭐
對話邏輯 · Agent Loop(ReAct)"]:::proc WSK["api_websocket
即時串流推送"]:::proc WK["worker
Celery 非同步任務"]:::proc WB["worker_beat
排程"]:::proc end subgraph EXEC["外掛 / 執行層"] direction TB PD["plugin_daemon
模型 & 工具外掛執行"]:::proc SB{"sandbox
程式碼節點安全執行"}:::decision SP{"ssrf_proxy
工具連外安全代理"}:::decision end subgraph STORE["資料層"] direction TB PG[("postgres
app · 對話 · 訊息 · 步驟")]:::infra RD[("redis
快取 · Celery broker")]:::infra VDB[("weaviate
向量庫 · RAG")]:::infra end subgraph EXT["外部能力"] direction TB LLM["推理服務
Ollama / 雲端 API"]:::data TOOLS["工具
搜尋 · 網頁讀取 · 自訂 API"]:::data end NET(["🌐 網際網路"]):::result U -->|HTTPS| NG NG --> WEB NG --> API NG --> WSK API --- PG API --- RD API -->|要用模型 / 工具| PD API -->|程式碼節點| SB WK --- RD WK -->|RAG 建索引| VDB WK --> PD API -->|檢索| VDB PD -->|推論| LLM PD -->|呼叫工具| TOOLS TOOLS --> SP SP -.安全連外.-> NET LLM -.結果.-> PD PD -.結果回饋.-> API classDef proc fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#17335e classDef data fill:#fef3c7,stroke:#d97706,stroke-width:2px,color:#78350f classDef decision fill:#ede9fe,stroke:#7c3aed,stroke-width:2px,color:#4c1d95 classDef result fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#14532d classDef infra fill:#e5e9f0,stroke:#475569,stroke-width:2px,color:#1e293b style APP fill:#f5f8ff,stroke:#cbd5e1,color:#475569 style EXEC fill:#faf7ff,stroke:#cbd5e1,color:#475569 style STORE fill:#f8fafc,stroke:#cbd5e1,color:#475569 style EXT fill:#fffdf5,stroke:#cbd5e1,color:#475569

重點:api 是大腦,Agent Loop 住在這;plugin_daemon 是它伸出去接「模型」和「工具」的手;真正回答的是外部的推理服務(Ollama/雲端),不是某顆 GPU 自己。

🔁 一次對話的生命週期(帶工具的 Agent)

flowchart LR
  A(["① 使用者送出
「台北今天天氣」"]):::result B["② api 收到
啟動 Agent Loop"]:::proc C{"③ 想:該做什麼?"}:::decision D["④ 呼叫工具
經 plugin_daemon"]:::proc E["⑤ 觀察結果
塞回上下文"]:::data F["⑥ 呼叫模型
經推理服務生成"]:::proc G(["⑦ 回答 + 來源"]):::result A --> B --> C C -->|需要即時資料| D --> E --> C C -->|夠了,生成答案| F --> G classDef proc fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#17335e classDef data fill:#fef3c7,stroke:#d97706,stroke-width:2px,color:#78350f classDef decision fill:#ede9fe,stroke:#7c3aed,stroke-width:2px,color:#4c1d95 classDef result fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#14532d

這個「想 → 做 → 看 → 再想」的迴圈就是 Agent 的靈魂,一圈圈跑在 api 裡,直到有答案或撞迭代上限。帶工具比純聊天慢,就是因為它來回好幾圈。

📚 RAG:文件怎麼變成「可查的知識」

flowchart LR
  DOC(["📄 上傳文件
PDF · Word · 網頁"]):::result CHUNK["切塊
worker 處理"]:::proc EMB["算向量
embedding 模型"]:::data V[("存進 weaviate
向量庫")]:::infra Q(["🙋 使用者提問"]):::result QEMB["問題也算成向量"]:::data RET["檢索:找語意最近的幾塊"]:::proc ANS(["塞進 prompt → 模型照小抄回答"]):::result DOC --> CHUNK --> EMB --> V Q --> QEMB --> RET V --> RET --> ANS classDef proc fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#17335e classDef data fill:#fef3c7,stroke:#d97706,stroke-width:2px,color:#78350f classDef result fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#14532d classDef infra fill:#e5e9f0,stroke:#475569,stroke-width:2px,color:#1e293b

建索引(上傳當下做一次)由 worker 非同步處理;查詢(每次提問)由 api 去 weaviate 撈最相關的幾塊當「小抄」。注意 embedding 也要一個模型——雲端不一定有,本機常用 bge-m3

🧱 每個容器在做什麼

容器職責
nginx入口反向代理,把請求分派給 web / api
web應用Next.js 前端,使用者看到的介面
api應用對話邏輯、Agent Loop(ReAct 迭代)、檢索——整個平台的大腦
api_websocket應用即時串流推送(邊生成邊顯示)
worker應用Celery 非同步任務(RAG 建索引、批次)
worker_beat應用排程任務
plugin_daemon執行模型供應商外掛、工具外掛的執行環境
sandbox安全程式碼節點的隔離執行(不讓任意 code 碰主機)
ssrf_proxy安全工具連外時的安全代理,擋 SSRF 攻擊
db (postgres)資料app 設定、對話、訊息、agent 步驟紀錄
redis資料快取 + Celery 的訊息 broker
weaviate資料向量資料庫,RAG 的知識存這裡
ollama-bridge外部把容器接到只聽 127.0.0.1 的本機 Ollama(socat 轉發)
一句話心法:Dify 不是「一個程式」,是一組各司其職的容器。看懂 api(大腦)→ plugin_daemon(接手)→ 推理服務(回答) 這條主線,再加上 worker + weaviate 那條 RAG 支線,你就抓住了整個自架 AI Agent 平台的骨架。

📚 回課綱總表 →