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识图
MCP
cpolar
具体教程见 Cloudreve 部署指南 第四步 HTTPS访问
飞书
创建应用:进入飞书开放平台开发者后台 - 飞书开放平台,点击创建企业自建应用,填入相应的信息后点击创建。
点击权限管理 -> 开通权限 -> 搜索消息/图片 -> 勾选所有权限(应用和用户身份权限下的所有消息权限) -> 确认开通权限。
在 N8N 中创建工作流
Webhook
提供一个触发 URL,这个后续需要配置到飞书应用的事件配置中,接收来自飞书的消息事件。
Respond to Webhook
该节点直接返回 code 200,因为当飞书发送事件以后,有一个 3s 的等待时间,超时了会重复调用,所以当我们接收到请求以后,先直接返回,然后再走后续的流程。
配置回调地址
在事件配置中,修改订阅方式,选择将事件发送至开发者服务器,填入指向 N8N Webhook 节点的 URL,然后点击保存。
在应用后台配置事件订阅:点击事件与回调 -> 事件配置 -> 添加 -> 添加接收消息(im.message.receive_v1)事件。
思路:飞书应用负责把消息推过来,N8N 工作流负责处理逻辑,DeepSeek 提供结果,最后再通过飞书接口回到用户。
发布:点击版本管理与发布 -> 创建版本 -> 填入信息并发布。
WorkFlow
文本消息
get_image_text(Edit Fields)
提取消息id、image_key、文本消息。
if
判断消息类型是图片还是文本。
AI Agent
包含LLM、MCP、Tools、Memory。
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。
MCP
Credential for Bearer Auth 中只粘贴 ezBookkeeping 给出的 MCP 配置中 Bearer 后面的部分。
Memory
chat_id 作为记忆区分依据。
Date & Time
时区设置为 Asia/Shanghai。
HTTP(获取 tenant_access_token)
请求飞书接口获取 tenant_access_token:
- HTTP URL:https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal
- HTTP Method:POST
HTTP(发送回复到飞书)
将 DeepSeek 回复发送到飞书:
- HTTP URL:https://open.feishu.cn/open-apis/im/v1/messages/:message_id/reply
- HTTP Method:POST
图片消息
HTTP Request
自建应用获取 tenant_access_token
请求
请求头
| 名称 |
类型 |
必填 |
描述 |
| Content-Type |
string |
是 |
固定值:“application/json; charset=utf-8” |
请求体
| 名称 |
类型 |
必填 |
描述 |
| app_id |
string |
是 |
应用唯一标识,创建应用后获得。有关app_id 的详细介绍。请参考通用参数介绍 示例值: “cli_slkdjalasdkjasd” |
| app_secret |
string |
是 |
应用秘钥,创建应用后获得。有关 app_secret 的详细介绍,请参考通用参数介绍 示例值: “dskLLdkasdjlasdKK” |
get_key_token(Edit Fields)
提取 tenant_access_token 和 image key
HTTP Request(获取上传图片的二进制)
获取消息中的资源文件
请求
请求头
| 名称 |
类型 |
必填 |
描述 |
| 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” |
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 |
HTTP
请求阿里百炼模型解析图片
实现思路:拿到图片的解析内容后调用 AI Agent 调用 MCP
遇到问题:图片地址给到模型后,模型需要下载图片,但 pictshare 返回的图片响应头中没有 Content-Length 字段,导致报错
解决方案:需要更换图床方案