部署日期: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 冲突。
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
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
⚠️ 新域名邮件可能进垃圾箱,正常现象。
Chatwoot 后台 → Settings → Integrations → Webhooks → Add new webhook:
message_createdChatwoot 收到用户消息 → 推送到这个 URL → n8n 接收处理。
Chatwoot 后台 → Settings → API Access → Generate new token:
| 项目 | 值 |
|---|---|
| 当前 Token | mmFb9KQVxKFemRBQ168w3Tzb |
用于 n8n 回复消息时调用 Chatwoot API。
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 回复发回对话
| 配置项 | 值 | 说明 |
|---|---|---|
| HTTP Method | POST | |
| Path | 自动生成 | |
| Respond | Immediately | 🔴 必须!Chatwoot 5s 超时,不设会重试→循环 |
| Response Code | 200 |
生成两个 URL:Test(草稿测试)和 Production(发布后用)。
Chatwoot 里填 Production URL。
| # | 条件 | 操作符 | 值 | 目的 |
|---|---|---|---|---|
| 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,不会重试。
| 配置项 | 值 |
|---|---|
| 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):
{
"inputs": {},
"query": "{{ $json.body.content }}",
"response_mode": "blocking",
"user": "{{ $json.body.sender.name }}"
}
| 参数 | 说明 |
|---|---|
query |
用户发来的消息文本 |
response_mode |
blocking = 等 Dify 回复完再继续(简单可靠) |
user |
会话标识,用发送者名字区分用户 |
| 配置项 | 值 |
|---|---|
| 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):
{
"content": "{{ $json.answer.replace(/<think>[\\s\\S]*?<\\/think>/g, '').trim() }}"
}
$json.answer 是上一节点(Dify HTTP Request)返回的回复文本。正则移除 <think>...</think> 思考过程标签。
Dify 后台(http://47.109.158.218:8088)→ 创建应用 → 聊天助手:
应用内 → 左侧菜单 API 访问 → 生成密钥:
| 项目 | 值 |
|---|---|
| API Key | app-ieGbmugS3yP7tzFESP56KWD7 |
| API 端点 | http://47.109.158.218:8088/v1/chat-messages |
这个 Key 填到 n8n 节点 5 的 Authorization 里。
现象:用户发一条消息,Dify 不停回复同一句,Chatwoot 里消息不断刷。
原因:n8n 回复给 Chatwoot 的消息又被 Chatwoot 当成新消息,再次触发 Webhook → 循环。
解决步骤:
sender_type 字段sender_type ≠ agent(或等于 contact)contact,机器人回复是 agent 或 bot。先看实际 payload 里字段名再设 Filter。如果你的 webhook payload 没有 sender_type 而是其他字段(如 message_type = outgoing / incoming),用它来区分。
现象:/accounts/undefined/conversations/...
原因:用了 $json.body.account.id 但 HTTP Request 节点拿到的 $json 不是 Webhook 的原始数据(中间有 Filter/Set 改了结构)。
解决:改用跨节点引用 $('Webhook').item.json.body.account.id
\<think\> 标签已在节点 6 用正则处理:
$json.answer.replace(/<think>[\s\S]*?<\/think>/g, '').trim()
如果 Dify 开启了思考模式(DeepSeek-R1 等),输出会带有推理过程。
原因: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 |
客户连续对话: 1、Chatwoot 需要配置自定义属性 2、n8n 工作流需要配置 code 属性和写入 dify_id