Dify 自架 Agent 實戰:五道牆與一個假答案

📚 Dify 自架實戰系列
今天:用 Dify 做 agent —— 五道牆、一個假答案、與後端架構(你在這)
RAG / 知識庫:讓 agent 查你自己的文件
重點摘要(TL;DR)
  • 在自架 Dify 上做一個「會查天氣的 Agent」,一個下午撞了五道牆:免費雲端額度、max_tokens 兩難、本機太慢被 timeout、幻覺工具、記憶體爆掉。
  • 最危險的一道:模型吐出一張完美的台北天氣表,底下根本沒查——純幻覺。畫面完美不等於真的做事。
  • 免費 Groq 的 TPM 上限只有 8000,一個帶工具的 agent 請求要 26122 → 直接被擋。
  • 本機 qwen3:14b 在純 CPU 上每輪 5–7 分鐘,agent 要兩輪,跑不完就被 timeout 砍。
  • 結論:agent 要落地,免費雲端帶不動、無 GPU 本機撐不完——中間沒有免費午餐。

這篇是一份誠實的踩坑記錄。起點只是想在自己機器上用 Dify 兜一個最簡單的 Agent:問它「台北今天天氣」,它會自己去網路搜尋、拿真資料回答。聽起來 10 分鐘該搞定,結果一個下午撞了五道牆,還被它騙了一次。每一道牆都用 log 跟資料庫查了真相,數字都是真的。如果你也想自架 Dify 做 agent,這篇幫你先看清楚地雷在哪。

🧭 本文導覽
Part 一 — 背景
Part 二 — 五道牆
Part 三 — 驗證、結論與破關
Part 四 — 後端架構(基礎)
Part 一 — 背景

一句問題,到一個會動手的 Agent

整套環境很單純:一台自架的 Dify(1.14 版,用 Docker 跑在自己的 mini PC 上),對外走 Cloudflare tunnel。目標是建一個 Dify 的「Agent」型應用,掛一顆語言模型,再給它一個 DuckDuckGo 搜尋工具,讓它問到即時資訊時自己去查。Dify 的好處是:非技術的人只要開瀏覽器對話,底層要換雲端還是本機模型、要不要掛 RAG,全在後台調。

Chat 跟 Agent 差在哪:就是「工具」

Agent 就是 chat 多掛了「工具」,而且模型會自己決定何時呼叫它。一個沒有工具的 agent,只是換了殼的 chatbot。這句話是整篇的骨架:接下來每一道牆,其實都是「讓模型真的去用工具」這件事在不同層面壞掉。

Part 二 — 五道牆

牆一:免費 Groq 的 8000 TPM 上限

先用免費的 Groq 掛 gpt-oss-120b。純聊天沒問題,一秒回。但一升級成帶工具的 Agent,對話就回空白。翻 Dify 後端 log,真相很白:

API request failed with status code 413:
Request too large for model `openai/gpt-oss-120b`
service tier `on_demand` on tokens per minute (TPM):
Limit 8000, Requested 26122, please reduce your message size

免費層每分鐘只給 8000 tokens,但一個帶工具的 agent 請求要 26122——超標三倍。為什麼會這麼大?因為每個工具的「使用說明書(schema)」都會塞進 prompt。掛 4 個工具就是 4 份說明書,加上 agent 的思考骨架,一下就破 8000。純聊天沒事、一帶工具就爆,就是這個原因。

牆二:max_tokens 兩難

gpt-oss 是推理模型,回答前會先「想」,這些思考也吃 token。於是 max_tokens 這個參數變成兩難:

max_tokens 結果
設太小(80) 🚫 推理吃光,回空白
設太大(11001) ⚠️ 預留額度太大,撞 TPM 被擋
剛好(約 2048) ✅ 夠想又夠答,不撞牆

關鍵是 Groq 把你「預留的輸出額度」也算進單次請求量。像訂位:兩個人吃飯卻訂 11001 個位子,餐廳直接拒收。

牆三:換本機模型,結果太慢被 timeout 砍

免費雲端帶不動,那換本機。用 Ollama 跑 qwen3:14b。好消息:它真的呼叫了工具、也真的拿到台北天氣的真資料(從資料庫的 agent 步驟紀錄可以看到 ddgo_search 的真實搜尋結果)。壞消息:它太慢了。從 Ollama 端撈每一輪 LLM 的實際耗時:

/api/chat  200  6m55s    ← qwen3:14b 一輪,跑完
/api/chat  200  5m14s    ← qwen3:14b 一輪,跑完
/api/chat  499  3m48s    ← 沒跑完,連線被砍
/api/chat  499  2m34s    ← 沒跑完,連線被砍
/api/chat  200   33s     ← qwen2.5:7b(小模型,快 10 倍)

純 CPU 上,14B 單一輪就要 5–7 分鐘。而 agent 至少要跑兩輪(決定呼叫工具 + 讀結果寫答案),整條 10–15 分鐘起跳,遠超連線的容忍度。結果就是:它做對了最難的部分(真的查到資料),卻倒在最後一哩——最終答案還沒寫完就被砍,資料庫存下的答案是空的。「會做對事,但慢到做不完。」

牆四:幻覺工具——最危險的一道

回到 gpt-oss,用一句很鬆的提示詞(「你可以用工具」)再試。這次它秒回,還吐出一張無懈可擊的台北天氣表:各時段氣溫、降雨機率、濕度、風向。看起來完美——但我起了疑心,去查資料庫。真相:

證據 數字 意義
agent 步驟的 tool 欄 沒執行任何工具
input tokens 159 若真查,結果塞回來會是幾千 token
延遲 2 秒 一發直生,沒有「查→等→再答」兩輪

那張漂亮的表,整個是編的。氣溫、降雨全是模型憑記憶掰出來、看起來很專業的假數字。這是 agent 最危險的坑:hallucinated tool use(假裝用了工具)。如果當下看到漂亮結果就喊成功,上線後 agent 就會拿編造的數據去做決策。畫面完美,不等於真的做事。

牆五:記憶體爆掉,整台 502

中途一度整個 Dify 對外 502(Cloudflare 顯示 Host Error)。查下去是記憶體爆了在瘋狂 swap:qwen3:14b(15GB)+ qwen2.5:7b + Dify + 其他服務,把 31GB 塞爆,swap 打到 7.7/8GB。容器都還「Up」,但 api 被 swap 拖到回不了話,nginx 就給 502。這不是 bug,是硬體天花板——一台共用的小機器,同時扛本機 LLM 跟一堆服務,本來就不夠。

Part 三 — 怎麼驗證 + 結論

怎麼確認 agent 真的查了(而不是編的)

這是整篇最實用的一段。不要只看畫面,要看紀錄。Dify 把 agent 每一步存在 message_agent_thoughts 表。真呼叫工具會有 toolobservation;沒有就是它在編。三個交叉指標:

  • agent 步驟裡有沒有 tool + observation:空的 = 沒查。
  • input tokens:真查會把搜尋結果(幾千 token)塞回 prompt;只有一兩百 = 沒查。
  • 延遲:真 agent 是兩輪(查→等→再答);一發秒回、又沒 tool 紀錄 = 幻覺。

把這三個當成 agent 上線前的驗收清單,幻覺就藏不住。

提示詞該怎麼寫:講「行為」,不要硬寫工具名

實驗發現一件反直覺的事:提示詞裡寫死工具名字(例如「使用 duckduckgo Search 工具」)反而讓模型回空白——因為那個工具的真實函數名是 ddgo_search,字串對不上,加上某些模型的 function-call 格式 Dify 接不乾淨。正確做法是描述你要它做的行為,工具讓 Dify 自己去配對:

你是即時資料查詢助手,一律用繁體中文回答。

規則:
1. 使用者問到天氣、新聞、股價等「會變動的即時資訊」時,
   你必須先上網搜尋最新資料,再根據搜尋到的內容回答。
2. 只能依據搜尋結果回答,不可使用你自己記憶中的舊資料。
3. 回答最後一定要附上你參考的來源網址。
4. 若真的搜尋不到,就老實說「查不到」,嚴禁自己編造數字。

第 3 條「附上來源網址」是最實用的幻覺偵測器:真查才有真網址,編的貼不出來。

選型結論:沒有免費午餐

路線 帶工具跑得動? 代價
免費雲端(Groq) 🚫 TPM 撞牆 免費但帶不動工具
付費雲端 要錢
本機 CPU(小模型) ⚠️ 勉強 慢、吃記憶體
本機 GPU ✅ 無額度限制 要買機器
一句話心法:agent 要真的做事,不能只靠免費雲端額度;沒 GPU 的本機又撐不完思考。要嘛付費解限,要嘛上 GPU——這就是「本地 agent 需要專用機器」的實證理由。

第六幕:終於,一次真的成功

把五道牆的教訓全用上,配方其實很簡單:本機小模型(會老實查)+ 講行為的提示詞(要求上網搜尋、附來源)+ 只掛一個搜尋工具(請求不爆)+ 調大的連線 timeout(讓慢模型跑得完)。再問一次「台北今天天氣」,這次它回:「已使用搜尋工具」,附上 AccuWeather、中央氣象局等真實來源連結——不再是那張憑空編的假表。

最漂亮的是:用來抓幻覺的同一套指標,反過來證明了這次是真的。同樣去查資料庫,每一個當初的紅燈都翻綠:

指標 幻覺那次(假表) 這次(真成功)
工具呼叫紀錄 🚫 空 ✅ 真呼叫搜尋工具
輸入 tokens 159 1130(搜尋結果塞回來了)
延遲 2 秒(一發編) 171 秒(查→等→答)
答案 🚫 憑空的假天氣表 ✅ 真摘要 + 真來源連結
破關心得:從零到一,做出一個「經得起查證」的 agent,難的不是把它兜起來,是證明它真的做了事。而驗證的方法,跟抓它說謊的方法,是同一個。

第七幕:終極幻覺 —— 工具全失敗,它還是編了

再往下玩,加了第二個工具(網頁讀取),讓它「搜尋 → 打開網址 → 抓真實數字」。這次 agent 的機制完全正確:資料庫顯示兩個工具都真的被呼叫、跑了 5 次迭代。但每一步都失敗了:

步驟1  搜尋工具    → ❌ 202 Ratelimit(被限流)
步驟2  網頁讀取    → ❌ Reached maximum retries(動態頁抓不到)
步驟3  搜尋工具    → ❌ 202 Ratelimit(再試,還是被擋)
步驟4  網頁讀取    → ❌ Reached maximum retries(再試,還是失敗)
步驟5  Final Answer→ 「晴朗、溫度介於 21 至 30 度之間,參考中央氣象局」

那個答案看起來完美、還引用了真實的中央氣象局網址。但去資料庫測謊:「21」和「30」完全沒出現在任何工具抓回的內容裡——四次工具全部失敗,它一個字都沒查到,卻編了一個看起來權威的假天氣。

最該記住的一條:提示詞叫它「查不到就說查不到、禁止編造」,弱模型(7B)在工具全失敗時,照樣編。
這比前面的幻覺更危險——因為流程全對、工具真的呼叫了、還引用真來源,只有最後的內容是假的。只看畫面 100% 會相信。

所以結論再往上升一層:玩、學、非關鍵用途,7B + 好提示詞夠用;但攸關安全、會拿去做決策的場景,不能只靠模型自律,要在程式層驗證——直接檢查「工具有沒有真的回傳內容」,沒內容就不讓它回答。看紀錄,不看畫面。

Part 四 — 後端架構(基礎)

你的一句話,在後端跑過幾層

前面談「怎麼用、踩什麼坑」。這一段往下挖一層,回答一個更基礎的問題:你在網頁打一句話,它怎麼一路傳到你自己機器上的 Ollama、又怎麼回來?這張圖是為了修前面那些坑、一層一層實際挖出來、驗證過的真實鏈路——不是示意圖。

Dify 自架後端架構:瀏覽器經 Cloudflare、nginx、Dify api、plugin_daemon、ollama-bridge 到本機 Ollama 的完整鏈路
你的一句話在後端跑過的六層。Agent Loop 住在 Dify api;ollama-bridge 是連到本機 Ollama 的關鍵中繼。

「中間有一個 API 後端在做這件事」的直覺完全對——只是它不是一個,是一串:api 是大腦(對話邏輯 + Agent Loop 都在這),plugin_daemon 是它伸出去接「模型」和「工具」的手。

ollama-bridge:被 127.0.0.1 擋住的那道橋

Ollama 預設只聽 127.0.0.1,不對外。而 Dify 跑在 Docker 容器裡,連不到宿主機的 127.0.0.1。它怎麼還用得到模型?靠中間那個 ollama-bridge 容器跑一行 socat:在宿主機開一個容器看得到的埠(11435),轉發到 127.0.0.1:11434。所以 Dify 的 Base URL 是 http://172.24.0.1:11435,不是直連 Ollama。少了這座橋,容器永遠連不到只聽本機的 Ollama。

Agent 不是一個「地方」,是一個「迴圈」——它可以住 server

這是自架這一趟最打破認知的一點。很多人以為 agent 得在自己桌面跑一個東西下指令。但今天證明:那個「想 → 做 → 看 → 再想」的迴圈,可以放在 server 端跑,網頁只是前臺。而且它三件事是解耦的:

前臺(輸入) 迴圈(協調·便宜) 推理服務(會回答) 硬體(算力·貴)
網頁 / 桌面 / 手機 Dify api(這裡在 server) Ollama / vLLM / 雲端 API GPU / CPU
關鍵區分:GPU 本身不會回答任何東西,它只是算力。真正「回答」的是推理服務(Ollama / vLLM / 雲端 API)——它載入模型、跑運算、吐出字。所以迴圈呼叫的是「推理服務」,不是直接呼叫 GPU;GPU 只是推理服務使喚的苦力。

關鍵洞見:迴圈本身很便宜,它只做「解析、判斷該呼叫什麼、把結果餵回」;真正吃算力的是模型推理。所以迴圈可以跑在一台普通的小機器上,推理丟給後面的推理服務(Ollama,跑在 GPU/CPU 上)——迴圈當「指揮」,推理服務當「苦力」。這就是為什麼 server 端 agent 不用很強的機器。

所以「要不要有 agent」要拆兩層:使用者端不用裝 agent,web chat 就好;系統裡有 agent loop,只是它藏在 server 端。對使用者是聊天,對系統背後有一個迴圈在跑——這正是 Dify 的價值。

這跟 A2A 與 harness 的關係

把這個迴圈抽象成一句話:協調者反覆呼叫一個「能力」、把結果餵回、再決定下一步,直到完成。這個形狀,跟 A2A(Agent-to-Agent)一模一樣——差別只在「被呼叫的那端」是誰:agent loop 呼叫的是「模型 + 死工具」,A2A 呼叫的是「另一個會思考的 agent」。把工具換成 agent,內圈就長成外圈。

harness(像 Pi、DeepSeek Harness)是什麼?就是「把這個迴圈包成程式」。同一個 loop,兩種包裝:

把 loop 包成 給誰用
Dify平台 + GUI + 工具市場不會寫 code 的人
Harness(Pi 等)CLI / 函式庫(可程式化)工程師(嵌進程式、CI、多 agent 編排)

所以「要不要另外一個 harness」的答案很清楚:目標是「給人用的 agent(一人一個、網頁對話)」→ Dify 的 loop 夠了,不需要 harness;要無 GUI、在程式裡、可編排、可嵌入地跑 loop(把 agent 當函式庫、做複雜 A2A 編排)→ 才輪到 harness。一句話定位:Dify = 應用層平台(loop 給人用);Harness = 開發者的 loop 引擎(loop 給程式用)。

下一篇進 RAG:讓 agent 從「查網路」切換成「查你自己的文件」。

延伸閱讀:A2A 採購 Agent 實戰:逼 Agent 真去查價地端 Agentic RAG:斷網怎麼上線真實手冊 RAG 一日實戰:15 個坑全記錄

留言

在〈Dify 自架 Agent 實戰:五道牆與一個假答案〉中有 2 則留言

  1. […] 框架, LLM 應用, 實戰案例 📚 Dify 自架實戰系列 ① 用 Dify 做 agent:五道牆、假答案、後端架構 ② RAG / 知識庫:讓 agent 查你自己的文件(你在這) ③ 更多主題(規劃中) […]

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *