|
|
@@ -1,48 +1,269 @@
|
|
|
-一 部署系统
|
|
|
-
|
|
|
-二 chatwoot 配置
|
|
|
-必须配置邮箱,因为客服注册,需要使用邮箱认证
|
|
|
-例如:阿里云邮件推送和 QQ 邮箱
|
|
|
-# 阿里云邮箱
|
|
|
-阿里云:`https://dm.console.aliyun.com/`
|
|
|
-发送地址:`zlsh@smtp.zilanlife.com`
|
|
|
-SMTP 密码:`M9LV49ujVpxvUbC`
|
|
|
-SMTP服务地址: smtpdm.aliyun.com ,SMTP服务端口号:25或80或465(SSL加密)。
|
|
|
-# QQ 邮箱
|
|
|
-SMTP 密码:ofgfjztgxvgkbiaa
|
|
|
-
|
|
|
-三 n8n 配置
|
|
|
-
|
|
|
-工作流配置:
|
|
|
-使用 webhook 生成地址 作为 chatwoot 的机器人地址,分测试和正式版
|
|
|
-生成 一个过滤
|
|
|
-{{ $json.body.message_type }} 等于incoming 说明:避免机器人自己聊天
|
|
|
-{{ $json.body.private }} 等于false 说明:避免客服的私聊模式进入工作流
|
|
|
-{{ $json.body.conversation.status }} 等于 pending 说明:当客服介入聊天后,工作流停止
|
|
|
-
|
|
|
-生成 HTTP Request 关联 dify
|
|
|
-Method 选择 post
|
|
|
-URL 选择 http://47.109.158.218:8088/v1/chat-messages 说明:这个是 dify 的聊天信息
|
|
|
-开启Send Headers
|
|
|
-设置Authorization 为Bearer app-ieGbmugS3yP7tzFESP56KWD7 说明 这个是 dify 的聊天api-key
|
|
|
-设置Content-Type 为application/json
|
|
|
-开启Send Body
|
|
|
-选择 json
|
|
|
-配置 json
|
|
|
-```
|
|
|
-{{ { "inputs": {}, "query": $json.body.content, "response_mode": "blocking", "user": $json.body.account.name } }}
|
|
|
-```
|
|
|
-
|
|
|
-生成 HTTP Request 关联 chatwoot
|
|
|
-Method 选择 post
|
|
|
-URL 选择 `http://47.109.158.218:3000/api/v1/accounts/{{ $('Webhook').item.json.body.account.id }}/conversations/{{ $('Webhook').item.json.body.conversation.id }}/messages`
|
|
|
-说明:这个是 chatwoot 的聊天信息,其中`{{ $('Webhook').item.json.body.account.id }}`是跨表获取的 webhook 第一次传入的参数
|
|
|
-开启Send Headers
|
|
|
-设置api_access_token 为mmFb9KQVxKFemRBQ168w3Tzb 说明 这个是 chatwoot 的访问令牌
|
|
|
-设置Content-Type 为application/json
|
|
|
-开启Send Body
|
|
|
-Body Content Type为JSON
|
|
|
-Specify Body为Using Fields Below
|
|
|
-配置content为{{ $json.answer }}
|
|
|
-
|
|
|
-四 dify 配置
|
|
|
+# Chatwoot + n8n + Dify 智能客服
|
|
|
+
|
|
|
+> 部署日期:2026-06-24~25 · 更新:2026-06-25
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 架构概览
|
|
|
+
|
|
|
+```
|
|
|
+用户 → Chatwoot(:3000) → Webhook → n8n(:5678) → Dify(:8088) → n8n → Chatwoot API → 用户
|
|
|
+ ↑ │
|
|
|
+ └──────── 机器人回复不会再触发 Webhook ──────────────┘
|
|
|
+ (Filter 过滤 sender_type ≠ "contact")
|
|
|
+```
|
|
|
+
|
|
|
+| 组件 | 服务器 | 端口 | 路径/管理 |
|
|
|
+|------|--------|------|-----------|
|
|
|
+| Chatwoot | aliyun2 (47.109.158.218) | 3000 | `/opt/chatwoot/`,docker-compose |
|
|
|
+| n8n | aliyun2 | 5678 | `/www/dk_project/dk_app/n8n/n8n_zZ2Y/`,宝塔 Docker |
|
|
|
+| Dify | aliyun2 | 8088 | v1.11.2,12 容器 |
|
|
|
+
|
|
|
+Chatwoot 数据库端口 5433(Postgres)/ 6380(Redis),避免与 Dify 的 5432/6379 冲突。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 一、Chatwoot 配置
|
|
|
+
|
|
|
+### 1.1 部署(已完成)
|
|
|
+
|
|
|
+```bash
|
|
|
+cd /opt/chatwoot
|
|
|
+# 管理命令
|
|
|
+docker-compose up -d # 启动
|
|
|
+docker-compose down # 停止
|
|
|
+docker-compose restart # ⚠️ 不重读 .env!改环境变量必须 down + up -d
|
|
|
+docker-compose ps # 查看状态
|
|
|
+```
|
|
|
+
|
|
|
+核心环境变量(`.env`):`SECRET_KEY_BASE`、`POSTGRES_PASSWORD`、`REDIS_PASSWORD`、`FRONTEND_URL`
|
|
|
+
|
|
|
+### 1.2 SMTP 邮件配置
|
|
|
+
|
|
|
+Chatwoot 必须配 SMTP,客服注册需邮箱验证。
|
|
|
+
|
|
|
+**当前使用:阿里云邮件推送**
|
|
|
+
|
|
|
+| 项目 | 值 |
|
|
|
+|------|-----|
|
|
|
+| 发送地址 | `zlsh@smtp.zilanlife.com` |
|
|
|
+| SMTP 服务器 | `smtpdm.aliyun.com` |
|
|
|
+| 端口 | 465(SSL) |
|
|
|
+| 认证方式 | plain |
|
|
|
+| 密码 | `M9LV49ujVpxvUbC` |
|
|
|
+
|
|
|
+备选 QQ 邮箱:`zhensolid@vip.qq.com`,SMTP 密码 `ofgfjztgxvgkbiaa`,`smtp.qq.com:465`
|
|
|
+
|
|
|
+> ⚠️ 新域名邮件可能进垃圾箱,正常现象。
|
|
|
+
|
|
|
+### 1.3 创建 Webhook(机器人)
|
|
|
+
|
|
|
+Chatwoot 后台 → Settings → Integrations → Webhooks → Add new webhook:
|
|
|
+
|
|
|
+1. 将 n8n 的 **Production Webhook URL** 填入
|
|
|
+2. 勾选事件:`message_created`
|
|
|
+3. 保存
|
|
|
+
|
|
|
+Chatwoot 收到用户消息 → 推送到这个 URL → n8n 接收处理。
|
|
|
+
|
|
|
+### 1.4 获取 API 访问令牌
|
|
|
+
|
|
|
+Chatwoot 后台 → Settings → API Access → Generate new token:
|
|
|
+
|
|
|
+| 项目 | 值 |
|
|
|
+|------|-----|
|
|
|
+| 当前 Token | `mmFb9KQVxKFemRBQ168w3Tzb` |
|
|
|
+
|
|
|
+用于 n8n 回复消息时调用 Chatwoot API。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 二、n8n 工作流配置
|
|
|
+
|
|
|
+### 节点结构
|
|
|
+
|
|
|
+```
|
|
|
+Webhook(触发器)
|
|
|
+ │ Respond: Immediately ← 🔴 必须!否则 Chatwoot 超时重试→死循环
|
|
|
+ │
|
|
|
+ ├─ IF: message_type == "incoming" ← 只处理用户消息
|
|
|
+ ├─ IF: private == false ← 排除私聊模式
|
|
|
+ └─ IF: conversation.status == "pending" ← 客服介入后停止
|
|
|
+ │
|
|
|
+ ▼
|
|
|
+HTTP Request → Dify ← 调 Dify Chat API,blocking 模式
|
|
|
+ │
|
|
|
+ ▼
|
|
|
+HTTP Request → Chatwoot ← 把 Dify 回复发回对话
|
|
|
+```
|
|
|
+
|
|
|
+### 节点详细配置
|
|
|
+
|
|
|
+#### 节点 1:Webhook 触发器
|
|
|
+
|
|
|
+| 配置项 | 值 | 说明 |
|
|
|
+|--------|-----|------|
|
|
|
+| HTTP Method | POST | |
|
|
|
+| Path | 自动生成 | |
|
|
|
+| **Respond** | **Immediately** | 🔴 必须!Chatwoot 5s 超时,不设会重试→循环 |
|
|
|
+| Response Code | 200 | |
|
|
|
+
|
|
|
+生成两个 URL:**Test**(草稿测试)和 **Production**(发布后用)。
|
|
|
+
|
|
|
+Chatwoot 里填 Production URL。
|
|
|
+
|
|
|
+#### 节点 2-4:IF 过滤器(三个串连)
|
|
|
+
|
|
|
+| # | 条件 | 操作符 | 值 | 目的 |
|
|
|
+| --- | -------------------------------------- | ----- | ---------- | ------------- |
|
|
|
+| 2 | `{{ $json.body.message_type }}` | Equal | `incoming` | 只要用户消息,不要系统通知 |
|
|
|
+| 3 | `{{ $json.body.private }}` | Equal | `false` | 排除客服私聊模式 |
|
|
|
+| 4 | `{{ $json.body.conversation.status }}` | Equal | `pending` | 客服接手后停止机器人 |
|
|
|
+
|
|
|
+三个都通过 → 流向 Dify。
|
|
|
+
|
|
|
+> 🔴 注意:Webhook 的 Respond 已设为 Immediately,所以即使 Filter 拦截了消息,Chatwoot 也已拿到 200,不会重试。
|
|
|
+
|
|
|
+#### 节点 5:HTTP Request → Dify
|
|
|
+
|
|
|
+| 配置项 | 值 |
|
|
|
+|--------|-----|
|
|
|
+| Method | POST |
|
|
|
+| URL | `http://47.109.158.218:8088/v1/chat-messages` |
|
|
|
+
|
|
|
+**Headers:**
|
|
|
+
|
|
|
+| Key | Value |
|
|
|
+|-----|-------|
|
|
|
+| Authorization | `Bearer app-ieGbmugS3yP7tzFESP56KWD7` |
|
|
|
+| Content-Type | `application/json` |
|
|
|
+
|
|
|
+**Body (JSON):**
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "inputs": {},
|
|
|
+ "query": "{{ $json.body.content }}",
|
|
|
+ "response_mode": "blocking",
|
|
|
+ "user": "{{ $json.body.sender.name }}"
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+| 参数 | 说明 |
|
|
|
+|------|------|
|
|
|
+| `query` | 用户发来的消息文本 |
|
|
|
+| `response_mode` | `blocking` = 等 Dify 回复完再继续(简单可靠) |
|
|
|
+| `user` | 会话标识,用发送者名字区分用户 |
|
|
|
+
|
|
|
+#### 节点 6:HTTP Request → Chatwoot(回复消息)
|
|
|
+
|
|
|
+| 配置项 | 值 |
|
|
|
+|--------|-----|
|
|
|
+| Method | POST |
|
|
|
+| URL | `http://47.109.158.218:3000/api/v1/accounts/{{ $('Webhook').item.json.body.account.id }}/conversations/{{ $('Webhook').item.json.body.conversation.id }}/messages` |
|
|
|
+
|
|
|
+> ⚠️ 必须用 `$('Webhook')` 跨节点引用而非 `$json`。因为 Dify 返回后数据已变成 Dify 的响应结构,`$json.body` 里没有 Chatwoot 的 account_id。`$('Webhook')` 强制回到源头拿原始数据。
|
|
|
+
|
|
|
+**Headers:**
|
|
|
+
|
|
|
+| Key | Value |
|
|
|
+|-----|-------|
|
|
|
+| api_access_token | `mmFb9KQVxKFemRBQ168w3Tzb` |
|
|
|
+| Content-Type | `application/json` |
|
|
|
+
|
|
|
+**Body (JSON):**
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "content": "{{ $json.answer.replace(/<think>[\\s\\S]*?<\\/think>/g, '').trim() }}"
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+`$json.answer` 是上一节点(Dify HTTP Request)返回的回复文本。正则移除 `<think>...</think>` 思考过程标签。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 三、Dify 配置
|
|
|
+
|
|
|
+### 3.1 创建聊天应用
|
|
|
+
|
|
|
+Dify 后台(`http://47.109.158.218:8088`)→ 创建应用 → 聊天助手:
|
|
|
+
|
|
|
+1. 选择模型(如 DeepSeek)
|
|
|
+2. 编写系统提示词(Prompt)
|
|
|
+3. 可选添加知识库
|
|
|
+4. 发布应用
|
|
|
+
|
|
|
+### 3.2 获取 API Key
|
|
|
+
|
|
|
+应用内 → 左侧菜单 **API 访问** → 生成密钥:
|
|
|
+
|
|
|
+| 项目 | 值 |
|
|
|
+|------|-----|
|
|
|
+| API Key | `app-ieGbmugS3yP7tzFESP56KWD7` |
|
|
|
+| API 端点 | `http://47.109.158.218:8088/v1/chat-messages` |
|
|
|
+
|
|
|
+> 这个 Key 填到 n8n 节点 5 的 Authorization 里。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 四、常见问题与排错
|
|
|
+
|
|
|
+### 🔴 Q1:机器人自言自语无限循环
|
|
|
+
|
|
|
+**现象**:用户发一条消息,Dify 不停回复同一句,Chatwoot 里消息不断刷。
|
|
|
+
|
|
|
+**原因**:n8n 回复给 Chatwoot 的消息又被 Chatwoot 当成新消息,再次触发 Webhook → 循环。
|
|
|
+
|
|
|
+**解决步骤:**
|
|
|
+
|
|
|
+1. Webhook 节点 → **Respond: Immediately**(Chatwoot 秒拿 200,不再重试)
|
|
|
+2. n8n workflow **执行历史**里查看死循环的 payload → 找 `sender_type` 字段
|
|
|
+3. Filter 节点加条件:`sender_type` ≠ `agent`(或等于 `contact`)
|
|
|
+4. ⚠️ 注意:Chatwoot Webhook payload 里代表用户的是 `contact`,机器人回复是 `agent` 或 `bot`。**先看实际 payload 里字段名再设 Filter。**
|
|
|
+
|
|
|
+如果你的 webhook payload 没有 `sender_type` 而是其他字段(如 `message_type` = `outgoing` / `incoming`),用它来区分。
|
|
|
+
|
|
|
+### 🟡 Q2:URL 里字段变成 undefined
|
|
|
+
|
|
|
+**现象**:`/accounts/undefined/conversations/...`
|
|
|
+
|
|
|
+**原因**:用了 `$json.body.account.id` 但 HTTP Request 节点拿到的 $json 不是 Webhook 的原始数据(中间有 Filter/Set 改了结构)。
|
|
|
+
|
|
|
+**解决**:改用跨节点引用 `$('Webhook').item.json.body.account.id`
|
|
|
+
|
|
|
+### 🟡 Q3:Dify 回复包含 `\<think\>` 标签
|
|
|
+
|
|
|
+已在节点 6 用正则处理:
|
|
|
+```js
|
|
|
+$json.answer.replace(/<think>[\s\S]*?<\/think>/g, '').trim()
|
|
|
+```
|
|
|
+
|
|
|
+如果 Dify 开启了思考模式(DeepSeek-R1 等),输出会带有推理过程。
|
|
|
+
|
|
|
+### 🟡 Q4:n8n Webhook URL 改了不生效
|
|
|
+
|
|
|
+**原因**:n8n 里有两个 URL(Test / Production),改了 Chatwoot 里填的 URL 后要确认对应的是 n8n **当前发布**版本。
|
|
|
+
|
|
|
+**检查**:n8n 右上角 → 确认已发布(Active),再看 Webhook 节点的 Production URL。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 五、速查
|
|
|
+
|
|
|
+| 需要 | 去哪 |
|
|
|
+|------|------|
|
|
|
+| Chatwoot 后台 | `http://47.109.158.218:3000` |
|
|
|
+| n8n 后台 | `http://47.109.158.218:5678` |
|
|
|
+| Dify 后台 | `http://47.109.158.218:8088` |
|
|
|
+| Chatwoot API Token | `mmFb9KQVxKFemRBQ168w3Tzb` |
|
|
|
+| Dify API Key | `app-ieGbmugS3yP7tzFESP56KWD7` |
|
|
|
+| Chatwoot 重启 | `cd /opt/chatwoot && docker-compose down && docker-compose up -d` |
|
|
|
+| n8n 容器名 | `n8n_zz2y-n8n_zZ2Y-1` |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 关联笔记
|
|
|
+
|
|
|
+- [[家庭网络配置手册]]
|
|
|
+- [[服务器清单]]
|