chatwoot+n8n+dify.md 8.9 KB

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 部署(已完成)

cd /opt/chatwoot
# 管理命令
docker-compose up -d      # 启动
docker-compose down        # 停止
docker-compose restart     # ⚠️ 不重读 .env!改环境变量必须 down + up -d
docker-compose ps          # 查看状态

核心环境变量(.env):SECRET_KEY_BASEPOSTGRES_PASSWORDREDIS_PASSWORDFRONTEND_URL

1.2 SMTP 邮件配置

Chatwoot 必须配 SMTP,客服注册需邮箱验证。

当前使用:阿里云邮件推送

项目
发送地址 zlsh@smtp.zilanlife.com
SMTP 服务器 smtpdm.aliyun.com
端口 465(SSL)
认证方式 plain
密码 M9LV49ujVpxvUbC

备选 QQ 邮箱:zhensolid@vip.qq.com,SMTP 密码 ofgfjztgxvgkbiaasmtp.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):

{
  "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):

{
  "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_typeagent(或等于 contact
  4. ⚠️ 注意:Chatwoot Webhook payload 里代表用户的是 contact,机器人回复是 agentbot先看实际 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 用正则处理:

$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

客户连续对话: 1、Chatwoot 需要配置自定义属性 2、n8n 工作流需要配置 code 属性和写入 dify_id