把「AI 搜不到」的鍋,從模型換到搜尋後端
在一台只有 8GB VRAM 的開發機上,要做一套完全地端、不受第三方過濾的 AI 搜尋與素材蒐集系統。這是從一句模糊的提問走到一份可交接專案的完整歷程 —— 包含兩次推翻自己的判斷。
| 硬體 | RTX 4060 8GB · i5-11400F 6C/12T · 32GB RAM |
| 專案 | local-search-stack |
| 狀態 | Phase 0 完成 · 擱置中 |
目錄
- 起點:一句模糊的提問
- 第一版答案,後來被自己作廢
- 需求翻轉:素材、趨勢、尺度
- 關鍵洞見:過濾點不在模型
- 模型分工:誰該無審查,誰不該
- 8188 MiB 的天花板
- 讓任何 Agent 都能接手
- Healthcheck 打臉現場
- 現況與下一步
- 附錄:決策速查表
第 0 章 · 起點:一句模糊的提問
最初的問題只有一句:「有沒有適合地端版的那種搜尋能力很強的 AI 開源模型?」
「搜尋能力」這四個字至少有兩種解讀,而且會導向完全不同的答案:
- 模型會用工具去搜 —— agentic search、deep research、多步驟工具呼叫
- 檢索本身準 —— embedding + rerank,決定 RAG 的品質上限
兩者都需要,所以兩邊都答。但真正把答案定住的是第二個問題:這台機器到底是什麼規格?
第 1 章 · 第一版答案,後來被自己作廢
先跑 nvidia-smi 和 Get-CimInstance 抓規格,結果第一個坑就出現了。
Get-CimInstance Win32_VideoController | Select AdapterRAM
→ 4 GB ✗ 錯的
nvidia-smi --query-gpu=memory.total --format=csv
→ 8188 MiB ✓ 正確
AdapterRAM 是 32-bit 有號整數,超過 4GB 就溢位。差一倍的 VRAM 會導向完全不同的模型選型結論,這種誤差沒抓到就整份建議報廢。
派子 Agent 交叉查證,然後抓到第二個坑
接著用 ai-cli 派兩個不同供應商的 agent 平行查證「2026 年 8 月最新的地端 agentic 模型」,prompt 裡明確要求「務必實際做網路搜尋,不要憑記憶回答」。
| 子 Agent | 回傳結果 | 來源 URL 顆粒度 | 判定 |
|---|---|---|---|
| gemini-3.1-pro-high | Qwen2.5-7B · Llama-3.1-8B · Gemma-2-9B(2024 年的模型) | 只給 huggingface.co/models 首頁 | 整份捨棄 |
| gpt-5.6-terra | Qwen3.5-9B · ToolMind-Web-3B,附 BFCL 66.1 / τ² 79.1 | 具體到 model card 與 benchmark 頁 | 採用 |
教訓: 子 agent 說「我查過了」不代表它真的查了。這是 LLM 最容易產生的一種幻覺,因為它符合 prompt 的期待格式,卻沒有外部訊號能否證它。
判斷依據要放在可驗證的產出上,不是放在 agent 的自述上。 最有效的單一指標是 URL 的顆粒度:只給首頁 = 沒查;給到 model card、特定 issue、benchmark 頁 = 有查。
第一版答案於是成形:ToolMind-Web-3B 當主力、Qwen3.5-9B 當通用、bge-reranker 補檢索精度。
然後使用者追加了三個條件,整份答案的重心就換了。
第 2 章 · 需求翻轉:素材、趨勢、尺度
追加的需求是:
- 要能搜合法成人內容
- 要能搜跨領域的近期熱門趨勢與新聞 —— 國際、科技、KPOP 演藝圈
- 要能搜出影片與照片,因為是要當素材
直覺反應是去找 uncensored / abliterated 模型。這個直覺是錯的,而想通這件事就是整個專案的轉折點。
第 3 章 · 關鍵洞見:過濾點不在模型
擋住搜尋的不是 LLM,是搜尋後端。
如果去接 Tavily / Brave Search API / Perplexity API,過濾發生在 API 那一端 —— 換再無限制的模型,拿到的候選結果一樣早就被濾掉了。
反過來,自架 SearXNG 把 safe_search: 0 打開,用原廠模型照樣搜得到。
search:
safe_search: 0 # 0=不過濾 1=中等 2=嚴格
formats:
- html
- json # 沒這行,Agent 呼叫 API 會拿到 403
server:
limiter: false # 不關會被自己的 agent 擋掉
image_proxy: false # 關掉才拿得到原始圖片 URL 給下載器
image_proxy: false 這點容易漏:開著的話回傳的是 SearXNG 代理過的 URL,下載器(gallery-dl / yt-dlp)拿不到真正的來源。
選 SearXNG 的實際理由
- 支援 269 個搜尋引擎,預設啟用 82 個
- 原生涵蓋 Naver 全類別(general / news / images / videos)—— KPOP 韓文內容的關鍵
- 原生有 Bilibili、Baidu images、Bing images/videos/news
- 無 API key、無按次計費、查詢不集中外流給單一供應商
誠實的限制: SearXNG 只拿掉「本地端」這一層過濾。查詢仍會送往上游站,各站自身的地區、年齡、登入限制依然存在。另外官方設定沒有 Daum 和 Weibo 引擎,需要用
site:weibo.com語法走 Bing/Baidu 繞。
一般化的啟示:遇到「AI 拿不到某類資料」時,先問過濾點在哪一層 —— 模型?API?還是資料源本身?換模型往往是最沒效的那一層。
第 4 章 · 模型分工:誰該無審查,誰不該
既然搜尋層已經不過濾了,模型層還需要 abliterated 嗎?需要,但只有一半需要。
abliteration 的副作用
Abliteration 的原理是用 orthogonalisation 找出「拒絕方向」的 activation pattern,再把該方向從每個權重矩陣投影掉。副作用是這個操作可能一併削掉格式遵循、planning、tool selection 的能力。
| abliteration 手法 | 拒答率 | 能力損傷 |
|---|---|---|
| Gemma 4 12B Heretic | 0 / 100 | 幾乎無損 |
| Gemma 4 E4B Heretic | 3 / 100 | 小 |
| Gemma 4 31B MeroMero | 15 / 100 | 中 |
| huihui 系列 | 低 | tool-calling 明顯退化 |
planner 根本不需要無審查
planner 的輸出長這樣:
{"name": "search_media",
"arguments": {"query": "뉴진스 무대", "category": "images"}}
它不產生內容,只產生結構化呼叫。內容過濾對它根本不生效。所以分工是:
PLANNER 原廠模型 ToolMind-Web-3B 工具能力最強者勝出
GENERATOR uncensored Gemma-4-E4B-uncensored 只負責寫,不呼叫工具
把無審查需求集中在唯一真正需要的那一顆,風險最小,而且能力退化的代價不會落在最需要精準的環節上。
待驗證的部分也照實記錄了:abliteration 對 tool-calling 的退化程度沒有公開 benchmark,得自己量測。若實測發現退化不明顯,這個分工就可以簡化掉。
第 5 章 · 8188 MiB 的天花板
所有模型決策最後都收斂到同一個數字。扣掉 Windows 桌面/DWM 的佔用,模型實際可用約 7.2GB,而且「模型檔大小」不等於「執行 VRAM」—— 還要加 KV cache 和 CUDA buffer,通常多抓 1–2GB。
開機常態佔用 8188 MiB TOTAL
├─ llama-server E4B :18082 ████████████████ 3225 MB
├─ llama-server E2B :18081 ████████ 1713 MB
├─ dwm.exe ███ 583 MB
└─ 剩餘 ████████ 1667 MB ← 只剩 1.7 GB
結論很直接:一次只能載一顆模型,用 llama.cpp 手動切換。
跑得動的
| 角色 | 模型 | 執行 VRAM | 重點 |
|---|---|---|---|
| planner | ToolMind-Web-3B Q4_K_M | 2.5–3.5 GB | 專為 search-agent 做 SFT+RL,能連跑數百次工具呼叫 |
| planner 備 | Qwen3.5-9B Q4_K_M | 7.0–7.8 GB | BFCL-v4 66.1,但 ctx 必須限 4K–8K |
| generator | Gemma-4-E4B-uncensored | 4.97 GB | Heretic 系手法,能力損傷小 |
| VLM | Qwen3-VL-2B-Instruct | 2–3 GB | 批次打標;GGUF 版需另抓 mmproj |
跑不動的
最值得記住的反例是 Qwen3.5-35B-A3B:它是 MoE,「3B 激活」聽起來很省,但 Q4_K_M 單檔就是 21.2GB —— 激活參數少不代表記憶體需求小,權重仍要全部載入。32GB RAM 勉強能 offload,但只有 4–8 tok/s,做不了工具迴圈。
第 6 章 · 讓任何 Agent 都能接手
架構定案後的下一個要求是:非預期關閉時,新 session 要能無縫續做。而且續作者不一定是同一個 agent —— 可能 Claude Code 開頭、Codex 接手。
解法是單一事實來源加捷徑:真正的說明放 AGENTS.md,CLAUDE.md 和 .codex/config.md 各三行指向它。捷徑絕不複製內容,否則會產生兩份會漂移的事實來源。
1. cat AGENTS.md 架構、硬體、設計原則
2. cat STATE.md 目前階段、下一步任務代號
3. cat PLAN.md 該任務的步驟與驗收條件
4. git log --oneline -15 實際做到哪
5. ./scripts/healthcheck.ps1 實測環境,與 STATE.md 對帳
6. 從第一個未完成任務繼續 → 完成後立刻更新 STATE.md + commit
當機情境下最關鍵的是衝突處理原則,這三條必須明文寫進去,不然新 agent 會自己亂猜:
STATE.md≠ 實際環境 → 相信實際環境,然後修正 STATE.mdgit log≠STATE.md→ 相信 git log(當機時 STATE.md 可能沒寫入)- 對話記憶 ≠ 檔案 → 相信檔案
另外每個任務都配驗收條件。沒有驗收條件的 checklist,接手者無法判斷前一個 agent 是真做完還是做一半。
第 7 章 · Healthcheck 打臉現場
寫完 healthcheck.ps1 後跑第一次,當場推翻了自己前面的判斷。
原本用 Get-Command 掃 PATH,結論是「環境是乾淨的,什麼都沒裝」,於是規劃了「從零安裝 llama.cpp CUDA build」。
| 我原本以為 | 實際 |
|---|---|
| llama.cpp 未安裝 | D:\OpenLLM\runtime\llama.cpp\b10549\ —— 只是不在 PATH,而且有兩個 instance 正在跑 |
| 無任何模型 | Gemma-4-E4B / E2B uncensored 已下載 |
| ffmpeg / yt-dlp 未裝 | 都已安裝(chocolatey / Python Scripts) |
更巧的是,既有的 Gemma-4-E4B-uncensored 正好就是計畫要下載的 generator。整個 Phase 2 有一半是白規劃的。
最貴的假設:「環境是乾淨的」。 盤點成本 5 分鐘,規劃錯的成本是整個 Phase。
healthcheck 該掃的不只 PATH,還要掃常見安裝路徑、用 nvidia-smi 查 VRAM、查目前有哪些 process 在吃 GPU、遞迴找既有模型檔、讀執行中 server 的 CommandLine 拿埠號。
這也順帶暴露了 VRAM 的真實可用量:兩個常駐 server 加 DWM 佔掉 5521 MiB,開機狀態其實只剩 1.7GB。前面規劃的「7.2GB 可用」是在沒有其他程式佔用的前提下才成立。
第 8 章 · 現況與下一步
最終定案的五層架構:
搜尋層 SearXNG 自架 · safe_search:0 · 269 引擎 ← 真正的關鍵
規劃層 ToolMind-Web-3B 原廠模型,負責 tool calling
生成層 Gemma-4-E4B-uncensored 只寫文字,不呼叫工具
抓取層 yt-dlp(1500+ 站)+ gallery-dl(200+ 站)
打標層 Qwen3-VL-2B ffmpeg 抽影格 → caption → tag → JSON
| Phase | 內容 | 狀態 |
|---|---|---|
| P0 | 需求確認 · 硬體盤點 · 架構定案 | 完成 |
| P1 | SearXNG 自架 ← 下一步 | 未開始 |
| P2 | llama.cpp + 模型 | 一半已由既有環境滿足 |
| P3 | yt-dlp + gallery-dl | 缺 gallery-dl |
| P4 | Qwen3-VL 打標流水線 | 未開始 |
| P5 | media gateway(4 個結構化工具) | 未開始 |
| P6 | 30–50 組真實查詢驗收 | 未開始 |
下一步是 P1 裝 WSL2 + Docker 把 SearXNG 起起來 —— 因為那一層才是整個專案能不能成立的關鍵,模型層反而已經有一半現成的。
專案自 2026-08-23 起擱置,優先做提醒事項 MCP。脈絡全部落在檔案裡,續作入口是 AGENTS.md 的 RESUME PROTOCOL。
附錄 · 決策速查表
| ADR | 決策 | 一句話理由 |
|---|---|---|
| 001 | 自架 SearXNG,不用第三方搜尋 API | 過濾發生在 API 端,換模型無效 |
| 002 | planner / generator 分離 | abliteration 會傷 tool-calling,而 planner 不需要無審查 |
| 003 | 一次只載一顆,llama.cpp 手動切換 | 7.2GB 可用,任兩顆都塞不下;vLLM 不支援 Windows |
| 004 | 模型不得取得任意 shell | 下載工具會碰 cookies;正確性不該寄託在模型是否受限 |
| 005 | 不把整支影片餵進 VLM,改抽影格 | 8GB 撐不住影片級 context;抽 8–24 格就夠標註 |
| 006 | 文件必須 agent-neutral | 續作者可能是 Codex;不能有兩份會漂移的說明 |
| 007 | 沿用既有 D:\OpenLLM | healthcheck 發現 runtime 與 generator 早就在本機 |
三個可帶走的通則
- 先問過濾點在哪一層,再決定要換什麼。換模型常是最沒效的那一層。
- 子 agent 的自述不是證據,URL 顆粒度才是。派兩個不同供應商交叉比對。
- 先實測,再規劃。「環境是乾淨的」是最貴的假設。