飞书+N8N+ezBookkeeping

N8N

创建 docker-compose.yml 文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
version: '3.8'

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    container_name: n8n
    restart: unless-stopped
    ports:
      - "5678:5678"
    volumes:
      - n8n_data:/home/node/.n8n  # 数据卷
      - ./n8n-files:/files        # 添加本地文件目录映射
    environment:
      - NODE_ENV=production
      - N8N_PORT=5678
      - N8N_PROTOCOL=http
      - WEBHOOK_URL=http://localhost:5678/

volumes:
  n8n_data:

ezBookkeeping

ezBookkeeping文档

部署

创建 docker-compose.yml 文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
version: "2"
services:
  ezbookkeeping:
    image: mayswind/ezbookkeeping
    container_name: ezbookkeeping
    hostname: "ezbookkeeping"
    ports:
      - "8080:8080"
    environment:
      - "TZ=Asia/Shanghai"                            # 时区
      - "EBK_SERVER_DOMAIN=xxxxxx"                    # 访问 ezBookkeeping 使用的域名
      - "EBK_SERVER_ROOT_URL=https://xxxxxx"          # 在浏览器中访问 ezBookkeeping 的完整路径(例如 https://ezbookkeeping-demo.mayswind.net/)。
      - "EBK_SERVER_ENABLE_GZIP=true"                 # 是否开启 gzip 压缩
      # ------------------------------------------------------------------
      - "EBK_DATABASE_TYPE=mysql"                     # 数据库
      - "EBK_DATABASE_HOST=host.docker.internal:3306" # 使用的是宿主机的数据库
      - "EBK_DATABASE_NAME=ezbookkeeping"             # 数据库名称
      - "EBK_DATABASE_USER=xxx"                       # 数据库用户名
      - "EBK_DATABASE_PASSWD=xxx"                     # 数据库密码
      # ------------------------------------------------------------------
      - "EBK_LOG_MODE=file"                           # 日志输出类型
      - "EBK_SECURITY_SECRET_KEY=xxxxxx"              # 加密密钥
      - "EBK_SECURITY_TOKEN_EXPIRED_TIME=xxxxxx"      # 令牌过期时间
      # ------------------------------------------------------------------
      - "EBK_MCP_ENABLE_MCP=true"                     # 启用MCP
      - "EBK_MCP_MCP_ALLOWED_REMOTE_IPS="             # 留空表示允许所有IP访问MCP
      # ------------------------------------------------------------------
      - "EBK_LLM_TRANSACTION_FROM_AI_IMAGE_RECOGNITION=true"        # 启用收据图片识别的大语言模型
      - "EBK_LLM_MAX_AI_RECOGNITION_PICTURE_SIZE=4294967295"        # 最大允许的交易图片文件大小
      - "EBK_LLM_IMAGE_RECOGNITION_LLM_PROVIDER=openai_compatible"  # 兼容OpenAI
      - "EBK_LLM_IMAGE_RECOGNITION_OPENAI_COMPATIBLE_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1"
      - "EBK_LLM_IMAGE_RECOGNITION_OPENAI_COMPATIBLE_API_KEY=xxxxxx"
      - "EBK_LLM_IMAGE_RECOGNITION_OPENAI_COMPATIBLE_MODEL_ID=qwen3-vl-plus"
    volumes:
      - "./storage:/ezbookkeeping/storage"  # 对象存储根路径
      - "./log:/ezbookkeeping/log"          # 日志文件
    restart: unless-stopped

AI识图

图2

MCP

图3 图4

cpolar

图1

具体教程见 Cloudreve 部署指南 第四步 HTTPS访问

飞书

创建应用:进入飞书开放平台开发者后台 - 飞书开放平台,点击创建企业自建应用,填入相应的信息后点击创建。

图5 图6

点击权限管理 -> 开通权限 -> 搜索消息/图片 -> 勾选所有权限(应用和用户身份权限下的所有消息权限) -> 确认开通权限。

图7 图8

在 N8N 中创建工作流

图24

Webhook

提供一个触发 URL,这个后续需要配置到飞书应用的事件配置中,接收来自飞书的消息事件。

图9

Respond to Webhook

该节点直接返回 code 200,因为当飞书发送事件以后,有一个 3s 的等待时间,超时了会重复调用,所以当我们接收到请求以后,先直接返回,然后再走后续的流程。

图10

配置回调地址

在事件配置中,修改订阅方式,选择将事件发送至开发者服务器,填入指向 N8N Webhook 节点的 URL,然后点击保存。

图11

在应用后台配置事件订阅:点击事件与回调 -> 事件配置 -> 添加 -> 添加接收消息(im.message.receive_v1)事件。

图12

思路:飞书应用负责把消息推过来,N8N 工作流负责处理逻辑,DeepSeek 提供结果,最后再通过飞书接口回到用户。

发布:点击版本管理与发布 -> 创建版本 -> 填入信息并发布。

WorkFlow

文本消息

get_image_text(Edit Fields)

提取消息idimage_key文本消息

图13

if

判断消息类型是图片还是文本。

图14

AI Agent

包含LLMMCPToolsMemory

图18 图15
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# 角色
你是专业的智能记账助手“小易”,专门通过ezBookkeeping工具帮助用户记录收支。你的回复需亲切、简洁,并直接聚焦于用户的记账需求。

# 核心工作流程
1.  **解析请求**:分析`<message>`标签内的用户输入,判断其记账意图(例如:新增记录、查询等)。
2.  **执行操作**    - **记录收支**:若用户意图为新增记录,确保关键参数完整。若缺少时间,自动调用`Date_Time`工具获取。
    - **参数不完整**:如果发现缺失`type`, `amount`, `category_name`, `account_name`等**核心参数**,**立即停止**工具调用,并清晰告知用户具体缺少哪些信息,引导用户补充。
3.  **生成回复**    - **成功记录后**:基于工具返回的成功结果(如`{"success":true,"account_balance":"-100.00"}`),**必须**向用户确认操作成功,并可简要提示最新账户余额。**严禁**在回复中提及任何工具调用的原始日志、输入(Input)或结果(Result)。
    - **无需工具时**:对于问候或简单咨询,直接友好回应。

# 回复格式与严格约束
- 所有回复必须是面向用户的自然语言,**严禁**在最终回复中出现任何形式的工具调用过程日志(如`[Used tools: ...]`等代码块)。
- 回复应简洁,例如:“✅ 记账成功!在‘食品’类别下支出10元(微信支付),当前余额为-100元。”

<message>
{{ $('get_image_text').item.json.body.event.message.text }}
</message>

DeepSeek

国内模型只支持 DeepSeek。

图16

MCP

Credential for Bearer Auth 中只粘贴 ezBookkeeping 给出的 MCP 配置中 Bearer 后面的部分。

图17

Memory

chat_id 作为记忆区分依据。

图19

Date & Time

时区设置为 Asia/Shanghai。

图20

HTTP(获取 tenant_access_token)

请求飞书接口获取 tenant_access_token:

  • HTTP URL:https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal
  • HTTP Method:POST
图21

HTTP(发送回复到飞书)

将 DeepSeek 回复发送到飞书:

  • HTTP URL:https://open.feishu.cn/open-apis/im/v1/messages/:message_id/reply
  • HTTP Method:POST
图22 图23

图片消息

HTTP Request

自建应用获取 tenant_access_token

请求

基本
HTTP URL https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal
HTTP Method POST

请求头

名称 类型 必填 描述
Content-Type string 固定值:“application/json; charset=utf-8”

请求体

名称 类型 必填 描述
app_id string 应用唯一标识,创建应用后获得。有关app_id 的详细介绍。请参考通用参数介绍
示例值: “cli_slkdjalasdkjasd”
app_secret string 应用秘钥,创建应用后获得。有关 app_secret 的详细介绍,请参考通用参数介绍
示例值: “dskLLdkasdjlasdKK”
图25

get_key_token(Edit Fields)

提取 tenant_access_token 和 image key

图26

HTTP Request(获取上传图片的二进制)

获取消息中的资源文件

请求

基本
HTTP URL https://open.feishu.cn/open-apis/im/v1/messages/:message_id/resources/:file_key
HTTP Method GET

请求头

名称 类型 必填 描述
Authorization string tenant_access_token
值格式:“Bearer access_token”
示例值:“Bearer t-g1044qeGEDXTB6NDJOGV4JQCYDGHRBARFTGT1234”
Content-Type string 固定值:“application/json; charset=utf-8”

路径参数

名称 类型 描述
message_id string 待查询的消息 ID。
示例值:“om_dc13264520392913993dd051dba21dcf”
file_key string 待查询资源的 Key。
注意:路径参数 file_key 和 message_id 需要匹配。
示例值:“file_456a92d6-c6ea-4de4-ac3f-7afcf44ac78g”

查询参数

名称 类型 必填 描述
type string 可选值有:
- image:对应消息中的图片或富文本消息中的图片。
- file:对应消息中的文件、音频、视频(表情包除外)。
示例值:“image”
图27 图28

HTTP

上传图片到 pictshare

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
version: '3.8'

services:
  pictshare:
    image: hascheksolutions/pictshare:2
    ports:
      - "8081:80"
    volumes:
      - ./data:/var/www/data
    environment:
      - TITLE=xxxxxx
      - URL=https://xxxxxx/
      - MAX_UPLOAD_SIZE=50
      # 添加上传密码保护
      - UPLOAD_CODE=xxxxxx
      # 添加删除密码保护
      - MASTER_DELETE_CODE=xxxxxx
      # 可选:限制上传IP范围(如果需要)
      # - ALLOWED_SUBNET=192.168.1.0/24

请求

基本
HTTP URL https://xxxxxx/api/upload.php
HTTP Method POST
图29

HTTP

请求阿里百炼模型解析图片

实现思路:拿到图片的解析内容后调用 AI Agent 调用 MCP

遇到问题:图片地址给到模型后,模型需要下载图片,但 pictshare 返回的图片响应头中没有 Content-Length 字段,导致报错

解决方案:需要更换图床方案


0%