| 篇次 | 主題 | 性質 | 狀態 |
|---|---|---|---|
| 0 | 起源:從一場面試的需求討論到自建AI工作流實建 | 主體與思路 | 已完成 |
| 1 | AstrBot & Line BOT:檔案式知識庫試驗 | 技術實作 | 已實作,部分項目驗證中 |
| 2 | 外部數據源獲取與多角色技能討論實驗(TradingView 案例) | 技術實作 | 已實作,部分驗證部分待驗證 |
| 3 | 通用產業情報Bot插件及商業化思路 | 商業評估 | 規劃評估,計畫尚未實作 |
承接起源篇的 MVP 決策,本篇記錄實際部署、排錯與檔案式知識庫插件的設計。內容以實際部署環境與排錯過程為主,適合想在低規格 VPS 上先完成 AI 助理 POC,再逐步導入企業文件、ERP 與 Agent 自動化的讀者。
/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。
接入步驟
- 登入 LINE Developers Console。
- 建立或選擇 Provider。
- 建立
Messaging APIChannel(不是LINE LoginChannel)。 - 取得
Channel Secret。 - 在 Messaging API 頁面簽發
Channel Access Token。 - 在 AstrBot WebUI 的機器人設定新增 LINE 平台。
- 填入 Token 與 Secret。
- 複製 AstrBot 產生的 Webhook URL。
- 回 LINE Developers Console 貼上 Webhook URL。
- 按
Verify,確認 Webhook 成功。 - 開啟
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 Unauthorized | API Key 錯誤或失效 |
| 403 Forbidden | 沒有模型權限或帳戶受限 |
| 404 model not found | Model ID 錯誤 |
| Connection refused | Docker 網路或 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 後端用量,不一定是同一種權限。
- Google AI Pro:提供 Gemini、NotebookLM、Google Antigravity、Gemini Code Assist 與儲存空間等較高使用權限,但不等於 Gemini API 的付費額度。要給 AstrBot 或 OpenHands 使用,仍需建立 API Key、Google Cloud Project 與獨立 Billing。
- 阿里雲 Token Plan:以 Credits 統一計量,可能有專用 API Key,但要先確認套餐是否允許自訂後端、自動化腳本與長時間 Agent。有 API Key 不代表可無限制使用。
- OpenAI 對話 Key 與 Embedding:真正的 OpenAI API 通常可用同一組 Key 呼叫對話與 Embedding,但兩者的模型與端點要分開設定(對話為
/v1/chat/completions或/v1/responses,Embedding 為/v1/embeddings)。
在 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 很快會變成難以維護的條件堆疊。插件改採以下做法:
- 正規化文字。
- 移除部分問句贅詞。
- 將中文切成雙字組。
- 將英文、型號、料號保留為完整 Token。
- 提高標題與 FAQ 關鍵字權重。
- 用 BM25 類分數排序。
- 用
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 類檢索不是完整語意搜尋,複雜或換句話問的問題命中率會比向量檢索差;轄人工轉接與價格交期規則查詢目前都還沒實作,只是過渡性的固定提示句。
常見問題
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,明確告知使用者「找不到答案」並引導轉人工,避免模型自由發揮沒有依據的內容。
.md 原始檔(見 markdown/astrbot-01-vps-line-bot-file-kb.md),供後續匯入 WordPress 或歸檔使用。