環境為一台 2 vCPU、8 GB RAM 的 VPS,以寶塔面板加 Docker 部署 AstrBot,接入 LINE Messaging API。先解決「Bot 收得到訊息卻沒有 LLM 回覆」的 Provider 問題,再建立不依賴 Embedding 與 Rerank 的檔案式知識庫:Markdown 保存長篇 SOP、JSON 保存 FAQ、JSONL 保存每次問答紀錄,最後由 AstrBot 的 LLM 依檢索內容整理答案。重點不是追求最複雜的 RAG,而是先做到能部署、能驗證、能查看來源。
AstrBot AI 應用系列導覽
篇次主題性質狀態
0起源:從一場面試的需求討論到自建AI工作流實建主體與思路已完成
1AstrBot & Line BOT:檔案式知識庫試驗技術實作已實作,部分項目驗證中
2外部數據源獲取與多角色技能討論實驗(TradingView 案例)技術實作已實作,部分驗證部分待驗證
3通用產業情報Bot插件及商業化思路商業評估規劃評估,計畫尚未實作

承接起源篇的 MVP 決策,本篇記錄實際部署、排錯與檔案式知識庫插件的設計。內容以實際部署環境與排錯過程為主,適合想在低規格 VPS 上先完成 AI 助理 POC,再逐步導入企業文件、ERP 與 Agent 自動化的讀者。

先說結論:如果 AstrBot 已能接收 LINE 訊息,下一步不要急著安裝 OpenHands 或完整向量資料庫。先把 LLM 回覆、管理員權限、/kb 查詢、Markdown 檢索與 JSON Log 做成小型閉環,最容易驗證,也最符合企業維運習慣。

部署目標:分三階段,不一次把所有AI元件放進生產環境

第一階段:讓 AstrBot 正常工作。確認 LINE 訊息能送進 AstrBot、AstrBot 能用 LLM Provider 回覆一般文字、/help、/provider、/sid 可用,WebUI、Docker Log 與設定檔都能查閱。

第二階段:建立工業用刀具文件助理。不先建立 AstrBot 原生知識庫,而是採用:

Markdown 文件 + JSON FAQ + 簡易 BM25 檢索 + LLM 整理答案

這樣可以避開 Embedding API、Rerank API、向量資料庫與模型維度問題。

第三階段:再評估 OpenHands 或正式 RAG。等檔案式問答完成,再依實際資料量與命中率決定是否加入原生知識庫、Embedding、Rerank、OpenHands、ERP 唯讀 API、GitLab、監控與工單整合。先做 MVP、再依測試結果擴充,比一開始建立多 Agent 平台更容易控制風險。

整體架構

LINE 使用者
    ↓ HTTPS Webhook
LINE Messaging API
    ↓
寶塔 Nginx 反向代理
    ↓
AstrBot Docker 容器
    ├─ LINE Adapter
    ├─ LLM Provider
    └─ astrbot_plugin_tool_kb
         ├─ Markdown 檔案
         ├─ JSON FAQ
         ├─ BM25 檢索
         ├─ LLM 答案整理
         └─ JSONL 問答 Log

知識資料與插件程式分開存放:

AstrBot/data/
├── plugins/
│   └── astrbot_plugin_tool_kb/
│       ├── metadata.yaml
│       ├── main.py
│       └── kb_engine.py
└── tool_kb/
    ├── config.json
    ├── faq.json
    ├── docs/
    └── qa_logs/

這種分離很重要:插件更新時,FAQ、Markdown 文件與問答 Log 不會被覆蓋。

AstrBot 與 LINE 接入

LINE 的基本流程是:建立 Messaging API Channel、取得 Channel Secret 與 Channel Access Token、設定 Webhook URL,再讓 AstrBot 接收事件。依 LINE 官方說明,使用者傳訊息或加入官方帳號時,LINE Platform 會向已註冊的 Webhook URL 發送 HTTP POST 事件,Bot 再依事件內容回覆;回覆時使用事件中的 reply token。

接入步驟

  1. 登入 LINE Developers Console。
  2. 建立或選擇 Provider。
  3. 建立 Messaging API Channel(不是 LINE Login Channel)。
  4. 取得 Channel Secret。
  5. 在 Messaging API 頁面簽發 Channel Access Token。
  6. 在 AstrBot WebUI 的機器人設定新增 LINE 平台。
  7. 填入 Token 與 Secret。
  8. 複製 AstrBot 產生的 Webhook URL。
  9. 回 LINE Developers Console 貼上 Webhook URL。
  10. 按 Verify,確認 Webhook 成功。
  11. 開啟 Use webhook。

AstrBot 位於 VPS 時,Webhook 必須能從公網以 HTTPS 存取。寶塔面板可負責網域 DNS、SSL 憑證、Nginx 反向代理、Webhook 路徑轉發,以及 WebUI 的 IP 白名單或 VPN 限制。

第一道驗收

LINE → /help → AstrBot 有回覆
LINE → 一般文字 → AstrBot 有 LLM 回覆

這兩項沒通過前,不繼續做知識庫插件。

先解決 LLM 不回覆的問題

典型狀況是:

IM Bot 可以收到訊息
但 AstrBot 沒有 LLM 回覆
也無法執行需要模型判斷的指令

這代表 IM 通道與 LLM 層是兩個不同的問題:

IM Adapter 正常 ≠ LLM Provider 正常

檢查順序

1. 測試內建指令。先執行 /help 與 /provider,後者可查看或切換目前會話的 LLM Provider。

2. 檢查 WebUI 的模型服務商。進入「模型提供商/服務提供商 → 對話 → 新增」,確認 API Base URL、API Key、模型名稱正確,Provider 可取得模型列表,模型已啟用且已指定為對話模型。AstrBot 官方文件說明可使用 OpenAI、Google GenAI、Anthropic 格式,也能接入相容這些格式的服務商。

3. 檢查 Docker Log。

docker ps --format 'table {.Names}\t{.Image}\t{.Status}'
docker logs --tail 200 <astrbot容器名稱>
docker logs -f --tail 100 <astrbot容器名稱>
docker logs <astrbot容器名稱> 2>&1 | grep -Ei \
'provider|model|llm|401|403|404|timeout|connection|error|exception'
Log可能原因
No available provider沒有可用的對話 Provider
401 UnauthorizedAPI Key 錯誤或失效
403 Forbidden沒有模型權限或帳戶受限
404 model not foundModel ID 錯誤
Connection refusedDocker 網路或 Base URL 錯誤
timeout模型回應太慢、網路或資源不足

Docker 內外的 localhost 差異

若 Ollama 在另一個容器,AstrBot 裡填 http://localhost:11434/v1 通常是錯的,因為 localhost 指向 AstrBot 自己的容器。兩個服務在同一個 Docker Network 時,應使用服務名稱:

http://ollama:11434/v1

若 Ollama 在宿主機,則要從 AstrBot 容器測試宿主機的 Gateway IP。

Token 與 API 的實際判斷

評估 DeepSeek、阿里雲 Token Plan 與 Google AI Pro 時得到一個重要結論:消費者訂閱、互動式工具額度與一般 API 後端用量,不一定是同一種權限。

在 AstrBot 內,對話、Embedding、Rerank 三種 Provider 應分開確認。OpenAI Compatible 只代表格式相容,不代表該 Provider 同時支援 /v1/embeddings 與 /rerank。

檔案式知識庫設計

不先建立原生知識庫,而是模擬簡化版 RAG:

問題
  ↓
Markdown/JSON/問答 Log 搜尋
  ↓
挑出相關片段
  ↓
把片段送給 LLM
  ↓
依文件規則整理答案
  ↓
列出來源

這個方案沒有 Embedding、Rerank、向量資料庫與模型微調,但有:可直接查看的原始文件、可用 Git 管理的 Markdown、可讀的 FAQ JSON、可追蹤的問答 JSONL,也不必先處理向量維度或增加本地模型服務。

Markdown 文件

長篇內容拆成有標題的章節:

---
title: 加工異常排除
keywords: 崩刃, 積屑瘤, 磨耗, 顫振
status: sample
version: V0.1
---
# 加工異常排除

## 刀刃崩刃

常見原因包含:進給過大、斷續切削衝擊、夾持不穩。
具體調整數值請依公司切削參數表。

插件依 #、##、### 切段,回答時標示:

來源:docs/03_加工異常排除.md / 加工異常排除 > 刀刃崩刃

JSON FAQ

固定問答、刀具型號與公司專用詞適合放在 JSON:

[
  {
    "id": "faq-001",
    "enabled": true,
    "category": "車削刀片",
    "title": "CNMG120408 是什麼規格",
    "question": "CNMG120408 是什麼規格",
    "keywords": ["CNMG120408", "刀片規格", "ISO 1832"],
    "answer": "CNMG120408 為 ISO 1832 型號,08 為刀鼻半徑 0.8 mm。",
    "source": "docs/02_車削刀片型號解讀.md",
    "updated_at": "2026-09-29"
  }
]

優點:適合精確型號查詢、關鍵字可提高權重、方便用 Git 追蹤差異、不必重處理整份文件。

同義詞

工業現場常有俗稱、正名與不同字形,以 synonyms.json 統一搜尋:

{
  "刀粒": "刀片",
  "牙刀": "螺絲攻",
  "鏽": "銹"
}

插件流程與部署目錄

插件主程式負責四件事:

main.py
├─ 接收 /kb 指令
├─ 監聽一般訊息
├─ 呼叫檔案檢索器
└─ 呼叫 AstrBot LLM 整理答案

kb_engine.py
├─ 讀取 Markdown
├─ 讀取 faq.json
├─ 讀取 qa_logs/*.jsonl
├─ 切分章節
└─ 以 BM25 類似方法排序

/kb 指令

保留明確指令作為第一階段驗證入口。

/kb CNMG120408 是什麼規格
/kb 刀片崩刃怎麼辦

一般使用者可查詢 /kb <問題>;以下指令僅限管理員:

/kb stats
/kb reload
/kb log 5
/kb approve <log_id>
/kb reject <log_id>

為什麼用 BM25 類檢索

單純寫 if "崩刃" in question: return answer 很快會變成難以維護的條件堆疊。插件改採以下做法:

  1. 正規化文字。
  2. 移除部分問句贅詞。
  3. 將中文切成雙字組。
  4. 將英文、型號、料號保留為完整 Token。
  5. 提高標題與 FAQ 關鍵字權重。
  6. 用 BM25 類分數排序。
  7. 用 coverage 作為命中門檻。

這不是完整語意搜尋,但比固定 if 判斷容易擴充與檢查。

部署目錄

宿主機的 AstrBot 資料目錄(以下以 <site> 代表網站目錄名稱):

/www/wwwroot/<site>/astrbot/data

plugins 與 tool_kb 兩個目錄要並列,不是把 tool_kb 放進 plugins:

/www/wwwroot/<site>/astrbot/data/
├── plugins/
│   └── astrbot_plugin_tool_kb/
│       ├── metadata.yaml
│       ├── main.py
│       └── kb_engine.py
└── tool_kb/
    ├── config.json
    ├── faq.json
    ├── docs/
    │   ├── 01_刀具分類與選型.md
    │   ├── 02_車削刀片型號解讀.md
    │   ├── 03_加工異常排除.md
    │   └── 04_換刀與刀具管理SOP.md
    └── qa_logs/

先確認容器掛載,並先備份:

docker inspect <astrbot容器名稱> --format '{json .Mounts}'

ASTRBOT_DATA=/www/wwwroot/<site>/astrbot/data
tar czf ~/astrbot_data_backup_$(date +%Y%m%d_%H%M%S).tgz \
  -C "$ASTRBOT_DATA" .

插件放到 ${ASTRBOT_DATA}/plugins/astrbot_plugin_tool_kb/,資料放到 ${ASTRBOT_DATA}/tool_kb/。最容易犯的錯是多包一層:

常見踩坑:目錄多包一層

錯誤:data/plugins/astrbot_plugin_tool_kb/astrbot_plugin_tool_kb/main.py
正確:data/plugins/astrbot_plugin_tool_kb/main.py

LINE 自動應答與 LLM 答案整理

自動應答設定

自動應答設計成「所有訊息先查檔案」,但初始設定先關閉:

{
  "auto_reply": false,
  "auto_reply_private": true,
  "auto_reply_group": false,
  "fallback_mode": "pass",
  "min_coverage": 0.25
}

開啟後,一般訊息的流程是:

收到訊息
  ↓
以 / 或 ! 開頭 → 交給指令流程
  ↓
搜尋 Markdown、FAQ、問答 Log
  ↓
最高 coverage 未達門檻
  ├─ fallback_mode=pass:不攔截,交給 AstrBot 原流程
  └─ fallback_mode=not_found:回覆固定句並停止事件
  ↓
命中
  ↓
LLM 整理答案 → 回覆來源 → stop_event()

真正意義/優缺點分析

  • 這套做法的重點不是追求最複雜的 RAG,而是先做到能部署、能驗證、能查看來源、能隨時關閉自動應答、不影響原本 AstrBot 的運作。
  • 優點:檔案式知識庫完全避開 Embedding、Rerank、向量資料庫的前期複雜度,用 Git 就能管理版本與差異;JSONL 問答 Log 讓每次互動都可追蹤、可人工覆核。
  • 優點:插件與資料分離存放,插件更新不會覆蓋資料,這是維運角度很重要的設計決策。
  • 缺點與代價:BM25 類檢索不是完整語意搜尋,複雜或換句話問的問題命中率會比向量檢索差;轄人工轉接與價格交期規則查詢目前都還沒實作,只是過渡性的固定提示句。
心得:如果 AstrBot 已能接收 LINE 訊息,下一步不要急著安裝 OpenHands 或完整向量資料庫。先把 LLM 回覆、管理員權限、/kb 查詢、Markdown 檢索與 JSON Log 做成小型閉環,最容易驗證,也最符合企業維運習慣。

常見問題

Q:為什麼不先用 AstrBot 原生知識庫?
A:原生知識庫通常需要 Embedding 與向量資料庫,前期設定與除錯成本較高。檔案式知識庫(Markdown+JSON+BM25)能更快驗證「有沒有用」,等資料量與命中率需求明確後再升級到語意檢索也不遲。

Q:IM Bot 收到訊息卻沒有 LLM 回覆,第一步該查哪裡?
A:先用 /provider 確認目前 Provider 設定,再查 Docker Log 搜尋 401/403/404/timeout 等關鍵字,IM 通道正常不代表 LLM Provider 正常,這是兩個獨立的檢查點。

Q:fallback_mode 應該設 pass 還是 not_found?
A:測試階段用 pass 比較安全,命中率不足時交回原本的 LLM 回覆;正式對外建議改用 not_found,明確告知使用者「找不到答案」並引導轉人工,避免模型自由發揮沒有依據的內容。

延伸閱讀:承接自《AI 應用系列 0|起源:從一場面試的需求討論到自建AI工作流實建》;下一篇《AI 應用系列 2|實作:外部數據源獲取與多角色技能討論實驗(TradingView 案例)》。
本篇文章同時提供 .md 原始檔(見 markdown/astrbot-01-vps-line-bot-file-kb.md),供後續匯入 WordPress 或歸檔使用。