Dify + LangBot + Tg + Firefly III + Firefly III mcp + llamacp + gemma4-e2b-it 建置一個家庭記帳
這個組合有點長,不過過程很簡單,只需要你安裝 docker,後面通通都是一路順暢的,不管如何,我只能先假設你已經有安裝 docker,我的執行環境是 windows。
安裝Firefly III
下面給出 Firefly III 的 docker-compose.yml 內容,這可以從官方文件中下載取得:
services:
app:
image: fireflyiii/core:latest
hostname: app
container_name: firefly_iii_core
restart: always
volumes:
- firefly_iii_upload:/var/www/html/storage/upload
env_file: .env
networks:
- firefly_iii
ports:
- 8099:8080
depends_on:
- db
db:
image: mariadb:lts
hostname: db
container_name: firefly_iii_db
restart: always
env_file: .db.env
networks:
- firefly_iii
volumes:
- firefly_iii_db:/var/lib/mysql
cron:
#
# To make this work, set STATIC_CRON_TOKEN in your .env file or as an environment variable
# The STATIC_CRON_TOKEN must be *exactly* 32 characters long
# Use this URL for inspiration: https://www.random.org/strings/?num=1&len=32&digits=on&upperalpha=on&loweralpha=on&unique=on&format=html&rnd=new
#
image: alpine
restart: always
container_name: firefly_iii_cron
env_file: .env
command: ["sh", "-c", "apk add tzdata && \
(ln -s /usr/share/zoneinfo/$$TZ /etc/localtime || true) && \
echo \"0 3 * * * wget -qO- http://app:8080/api/v1/cron/$$STATIC_CRON_TOKEN;echo\" \
| crontab - && \
crond -f -L /dev/stdout"]
networks:
- firefly_iii
depends_on:
- app
volumes:
firefly_iii_upload:
firefly_iii_db:
networks:
firefly_iii:
driver: bridge
官方文件有特別提到要兩個 env 檔,記得下載,然後參數做相對應的調整:
Download configuration files
There are two configuration files you need to run this Docker Compose file. Download all files and save them in the same folder as the Docker Compose file.
The first file contains Firefly III variables and can be downloaded from the Firefly III repository. Save it as a new file called .env.
The second file contains the database variables and can be downloaded from the Docker repository. Save it as a new file called .db.env.
調整完畢之後就可以執行 docker compose up -d,第一個登入的帳號就是管理者,然後你可以直接把註冊取消,這樣子就不怕有人偷偷再去註冊帳號。
登入之後系統會要求設置新的帳戶:

語系問題不用擔心,按下 Submit 之後就會轉成繁體中文了,不過前提是你要記得選擇正確語系就是。
帳戶中可以看到有一個預設的 現金皮夾 跟我們剛剛設置的 兆豐銀行,這依各自的現況處理就好:

取得個人 token
稍後我們要配置 firefly iii mcp,這需要先取得個人的 token,選項\個人檔案\OAuth,然後點擊『建立新權杖』,名稱自己設置,很長的一串,不要懷疑,就是這一串,複製出來,然後放記事本等等用。

啟動 firefly iii mcp
version: '3.8'
services:
mcp:
image: node:20-alpine
container_name: firefly_mcp
restart: unless-stopped
ports:
- "3100:3000"
command: >
sh -c "npx --yes @firefly-iii-mcp/server
--pat $$FIREFLY_III_PAT
--baseUrl $$FIREFLY_III_BASE_URL
--port 3000
--preset full
--logLevel info
--tools transactions,accounts,summary"
environment:
FIREFLY_III_BASE_URL: "http://192.168.1.243:8099"
FIREFLY_III_PAT: 貼上你自己的token
啟動 llamacpp
我的習慣是先自己手動下載模型,下載的部份可以安裝 hf cli來處理,很方便,可以參考官方文檔先安裝,然後下載模型:
hf download unsloth/gemma-4-E2B-it-GGUF gemma-4-E2B-it-Q8_0.gguf --local-dir D:\models\gemma-4-E2B
模型放那就自行決定,我是放在D:\models\gemma-4-E2B。
然後就啟動 llamacpp:
docker run --name=llama-cpp --volume D:/models/gemma-4-E2B:/mnt/model --network=bridge --workdir=/app -p 11435:8080 --runtime=runc --detach=true ghcr.io/ggml-org/llama.cpp:server-cuda -m /mnt/model/gemma-4-E2B-it-Q8_0.gguf --host 0.0.0.0 --port 8080 -ngl 99 --jinja --reasoning off
啟動 Dify
官方說明:https://docs.dify.ai/zh/self-host/quick-start/docker-compose
首先把程式庫下載:
git clone --branch "$(curl -s https://api.github.com/repos/langgenius/dify/releases/latest | jq -r .tag_name)" https://github.com/langgenius/dify.git
切換目錄:
cd dify/docker
複製文件:
cp .env.example .env
啟動:
docker compose up -d
第一個註冊 dify 的帳號就是管理者,然後登入之後就先做模型的配置,先點擊右上的人名,然後點擊設置:

點擊模型供應商,先選擇安裝 OpenAI-API-compatible:

這邊你也可以安裝ollama,不過效率上的問題,我還是比較愛 llamacpp 或是 llama-swap,有試著安裝 vllm,不過響應的是未支援 gemma4 系列模型,我就沒有再試下去了。
接下來就可以新增模型,把路由指向剛剛啟動的 llamacpp,前面的名稱我是設置 gemma4:

不要讓它思考,它思考之後是一團糟。
設置 agent
先把剛剛設置的 firefly mcp加進來,點擊『工具』,然後『新增MCP』

路由指向啟動 mcp 服務的位址:

成功的話就會看到下面圖示:

接下來設置 agent,點擊『工作室』,點『對於初學者』,然後點擊『Agent』:

點擊『工具』->『新增』->『CurrentTime』->『CurrentTime』
點擊『工具』->『新增』->『MCP』:

把工具加一加應該就會是下面這個樣子:

請注意,那個『CurrentTime』很重要,一定要加進來,不然機器不會知道今天是什麼時候。
然後提示詞是這樣的:
你是記帳助手。每次記帳前,必須先呼叫 list_account 取得帳戶清單,再用語意對應 source_name。
## 固定執行順序
### 記帳(三步,缺一不可)
Step 1:呼叫 Current Time 取得當前時間
Step 2:呼叫 list_account 取得帳戶清單
→ 只能選 type 為 asset 的帳戶作為 source_name
→ 禁止選 type 為 cash account / expense account / revenue account 的帳戶
Step 3:呼叫 store_transaction,date 使用 Step 1 結果,source_name 使用 Step 2 結果
語意對應規則:
現金/錢包/cash → 選清單中含「現金」或「cash」的帳戶
銀行/帳戶 → 選清單中含銀行名稱的帳戶
信用卡/card → 選清單中含「信用卡」或「card」的帳戶
沒有明確提到 → 選清單中第一個 asset 類型帳戶
### 查詢摘要
觸發詞:本月、這個月、花了多少、支出統計
呼叫:get_basic_summary
參數:
- start: 本月第一天(YYYY-MM-01)
- end: 今天(YYYY-MM-DD)
### 查交易列表
觸發詞:查帳、列出、最近幾筆
呼叫:list_transaction
參數:limit=10
## store_transaction 參數規則
呼叫時必須使用以下 JSON 格式:
{
"transactions": [
{
"date": "從 Current Time 取得的時間,格式 YYYY-MM-DDTHH:MM:SS+08:00",
"description": "用途描述",
"source_name": "從 list_account 結果中取得的真實名稱",
"type": "withdrawal / deposit / transfer",
"amount": "金額數字",
"category_name": "餐飲 / 交通 / 購物 / 居家 / 收入 / 其他",
"destination_name": "店家或收款對象名稱"
}
]
}
注意:
- 必須包在 transactions 陣列裡
- 不要外層再包 store_transaction 或 requestBody
- 直接傳遞這個 JSON 物件作為工具參數
## 缺資訊時只問一個問題
缺金額 → 「金額是多少?」
缺帳戶且語意無法判斷 → 「用哪個帳戶?」
## 禁止行為
- 禁止在未呼叫 list_account 前就呼叫 store_transaction
- 禁止自創帳戶名稱
- 禁止猜測金額
- 禁止一次呼叫多個工具
- 禁止輸出工具呼叫以外的說明文字
- 禁止省略 category_name,無法判斷時預設「其他」
最後,你的模型記得指向剛剛配置的模型:

現在就可以來測試了:

回頭確認 fireflly 是否確實有這筆記錄:

工具調用偶有問題,真的是要多次調整就是,這就自己測試的時候看發生什麼事,從日誌確認問題,然後就丟給其它語言模型調整就好。
確認之後就可以發佈這個 dify 的服務,點擊發佈,然後發佈更新:

發佈之後就再點擊發佈,然後點擊『訪問API』,點擊『API金鑰』:

建立取得 token,然後先貼到你的記事本,等等要用。
安裝 LangBot
官方程式庫:https://github.com/langbot-app/LangBot
直接把這個程式庫 clone 到地本端,然後執行 docker compose up -d:
git clone https://github.com/langbot-app/LangBot
cd LangBot/docker
docker compose up -d
登入之後,在機器人的下拉旁有一個小小的『+』:

很重要的是,你必需要先用 teletram 自己跟 botfather 要一個機器人的 token:

建立好機器人之後,先設置一個流水線,一樣的,在『流水線』旁有一個小『+』,點擊,然後配置:

- 名稱自己設置
- AI 能力的部份,把 Runner 修正為
Dify Service API,然後路由指向 dify 的服務,API Key 就是剛剛那串
設置好之後就可以儲存,然後把這流水線跟機器人做綁定:

綁定後記得按下保存。
測試
好了,現在,我在 tg 上測試打一句『在星巴巴買咖啡200元,現金支付』
我們看 langbot 的日誌:

然後 dify 的日誌:

最後 firefly 的記錄:

完成!
