首页 › AI Agent实战项目案例库 › 智能客服实战项目 › Agent智能体客服:基于Dify0-1搭建部署实战复盘

Agent智能体客服:基于Dify0-1搭建部署实战复盘

先说结果​

我给 codex.chatgpt-plus.top 上线了一个 Dify 智能体客服。​

​

飞书文档 - 图片

​

最终效果是:​

•

网站右下角出现 Dify 悬浮客服入口​

•

用户可以直接问注册、充值、API Key、调用报错、余额、节点状态等问题​

•

客服接入的是 Dify Chatflow​

•

网站后端不需要改源码​

•

Caddy 负责把 HTML 页面请求转给一个本地注入服务​

•

API 和静态资源仍然走原来的后端,不影响业务请求​

​

整个过程里,Codex 做了几件事:​

•

分析现有网站架构​

•

设计 Dify Chatflow 客服方案​

•

生成知识库和 Prompt​

•

SSH 登录服务器​

•

备份 Caddy 和站点相关文件​

•

写了一个本地 HTML 注入代理​

•

修改 Caddy 路由​

•

排查 Dify token、CSP、systemd、Python 兼容问题​

•

最后完成验证和回滚方案​

​

一句话总结:​

​

🌐

​

•

不是“让 AI 给你建议”,而是让 Codex 直接参与上线。​

​

​

为什么不用直接改前端源码?​

​

🌐

因为这个网站不是一个普通静态站。​

上线前先查了一下,发现 Caddy 配置不是 root /var/www/html 这种静态目录,而是:​

​

​

代码块​

PowerShell

reverse_proxy localhost:8080​

​

也就是说,网站本体跑在 Docker 容器里,Caddy 只是反向代理。​

进一步检查后发现:​

•

Caddy 在服务器上运行​

•

后端服务是 Docker 容器​

•

容器镜像是类似 backend-app 的应用​

•

前端 HTML 是应用动态返回的​

•

容器里没有常规的 dist/index.html 可以直接改​

​

所以如果硬改容器内部文件,会有两个问题:​

容器重启或升级后改动可能丢失​

不知道镜像构建链路,盲改风险很高​

​

最后选了一个更稳的方案:​

在 Caddy 和后端之间加一个本地 HTML 注入代理。​

只有浏览器访问页面 HTML 时,才经过注入代理;API、静态资源、健康检查继续直连后端。​

整体架构​

上线后的结构大概是这样:​

​

飞书文档 - 图片

​

​

🌐

核心点是:​

•

GET / 这种页面请求走注入服务​

•

/../assets/* 静态资源不走注入​

•

/api/*、/v1/* 业务接口不走注入​

•

注入服务只改 HTML,不碰业务接口​

•

这比“全站代理重写所有响应”安全得多。​

​

​

第一步:先搭 Dify Chatflow​

客服不是随便丢一个大 Prompt 就完事。​

​

🌐

一个网站客服至少要处理这些问题:​

​

•

注册登录​

•

充值不到账​

•

API Key 怎么创建​

•

API 调用报错​

•

余额和账单​

•

服务状态​

•

备用节点​

•

退款、风控、封号、投诉转人工​

​

​

我最开始给 Dify 设计的是一个更完整的 Chatflow:​

​

​

但实际上,第一版为了快速上线,先用了最小可用流程:​

​

代码块​

PowerShell

开始 -> 知识检索 -> LLM -> 直接回复​

​

这已经能覆盖很多基础问答。​

后续再加分类器、变量、转人工节点,会更完整。​

​

第二步:准备知识库​

客服的质量很大程度取决于知识库。​

​

🌐

我为这个客服准备了一份 knowledge-base.md,内容包括:​

​

•

平台基本信息​

•

文档入口​

•

服务状态页​

•

API Base URL​

•

备用节点​

•

创建 API Key 的步骤​

•

常见 API 报错排查​

•

充值不到账处理方式​

​

​

最重要的是安全边界:​

客服不能索要用户密码、API Key 原文、Cookie、完整支付凭证、身份证件、私钥。​

这点一定要写进 Prompt 和知识库里。​

​

第三步:设计客服 Prompt​

核心系统提示词大概是这个方向:​

​

代码块​

PowerShell

你是 示例 API 平台 网站客服。​

​

你的职责:​

​

这类客服 Prompt 的重点不是“会说话”,而是:​

知道什么能答,什么不能答。​

特别是涉及支付、退款、风控、封号时,AI 不能乱承诺。​

​

第四步:拿 Dify 嵌入代码​

Dify 发布后,会给一段类似这样的代码:​

​

代码块​

XML

​

<script​

src="https://udify.app/embed.min.js"​

id="YOUR_WEBAPP_TOKEN"​

defer>​

​

​

这里有一个很容易踩的坑:​

Dify 的嵌入 token 不一定是 。​

我一开始就踩了。​

最开始复制了一个 形式的值,结果网站报:​

​

代码块​

PowerShell

App with code not found​

​

这说明:​

•

token 不是 WebApp 嵌入 token​

•

或者 token 和 baseUrl 不属于同一个 Dify 环境​

•

或者 App 没发布​

后来换成 Dify 官方“嵌入网站”里给的短 token,问题才解决。​

​

所以这里一定要记住:​

复制 Dify 发布面板里的完整嵌入代码,不要自己猜 token。​

​

第五步:服务器部署前先备份​

这是 Codex 做上线时最重要的一步。​

在改服务器之前,先备份:​

​

代码块​

Bash

mkdir -p /srv/backups/customer-service/$(date +%Y%m%d-%H%M%S)​

cp -a /etc/caddy/Caddyfile.example /srv/backups/customer-service/.../Caddyfile.example.bak​

cp -a /srv/backend-app/deploy/docker-compose.yml.example /srv/backups/customer-service/.../docker-compose.yml.example.bak​

cp -a /srv/backend-app/deploy/data/app-config.yaml /srv/backups/customer-service/.../app-config.yaml.bak​

​

另外还打包了数据目录,但排除了日志:​

​

代码块​

PowerShell

tar --exclude='data/logs' -czf backend-data-no-logs.tgz -C /srv/backend-app/deploy data​

​

为什么这么谨慎?​

因为这次改的是线上入口层,一旦 Caddy 配错,网站首页就可能 502。​

上线不是炫技,先给自己留退路。​

​

第六步:写一个本地 HTML 注入服务​

核心逻辑是:​

本地监听 127.0.0.1:18080​

收到 HTML 页面请求​

去请求原来的 localhost:8080​

如果响应是 text/html,就在 前插入 Dify 脚本​

顺便补充 CSP,允许 https://udify.app​

返回给浏览器​

这个服务用 Python 写,部署在:​

​

代码块​

PowerShell

/srv/customer-service/html_inject_proxy.py​

​

配置放在:​

​

代码块​

PowerShell

/srv/customer-service/customer-service.env​

​

里面只保存 Dify WebApp token 和基础地址:​

​

代码块​

PowerShell

​

然后用 systemd 托管:​

​

代码块​

PowerShell

/etc/systemd/system/codex-customer-service-injector.service​

​

启动:​

​

代码块​

PowerShell

systemctl daemon-reload​

​

验证:​

​

代码块​

PowerShell

systemctl is-active codex-customer-service-injector.service​

curl -sS -H 'Accept: text/html' http://127.0.0.1:18080/ | grep embed.min.js​

​

​

第七步:改 Caddy,只让 HTML 走注入服务​

Caddy 原来是:​

​

代码块​

PowerShell

reverse_proxy localhost:8080​

​

改成:​

​

代码块​

Bash

@customer_service_html {​

method GET HEAD​

not path /../assets/* /api/* /v1/* /health /logo.png /favicon.ico /robots.txt /sitemap.xml​

}​

​

handle @customer_service_html {​

reverse_proxy localhost:18080​

}​

​

handle {​

reverse_proxy localhost:8080​

}​

​

这里非常关键。​

不能让所有请求都走注入服务,否则 API 流式响应、模型调用、静态资源都有可能被误处理。​

​

🌐

所以要把这些路径排除:​

•

/../assets/*​

•

/api/*​

•

/v1/*​

•

/health​

•

/logo.png​

•

/favicon.ico​

​

改完后必须验证:​

​

代码块​

PowerShell

caddy validate --config /etc/caddy/Caddyfile.example​

systemctl reload caddy​

​

然后测试:​

​

代码块​

PowerShell

curl -k -sS https://codex.chatgpt-plus.top/ | grep embed.min.js​

curl -k -sS -o /dev/null -w "%{http_code}" https://codex.chatgpt-plus.top/../assets/index-xxx.js​

​

最终验证结果:​

​

代码块​

PowerShell

caddy_active=active​

injector_active=active​

public_status=200​

public_has_new_token=2​

public_has_embed=1​

asset_status=200​

​

这说明:​

首页正常​

Dify 脚本注入成功​

静态资源不受影响​

​

中间踩了哪些坑?​

这部分最有价值。​

坑 1:把 Dify token 搞错了​

一开始用了 ,结果页面报:​

​

代码块​

PowerShell

App with code <wrong-app-code> not found​

​

解决方式:​

必须使用 Dify 发布面板给的 WebApp 嵌入 token。​

不要用 API Key,不要用应用 ID,不要用 URL 里的 UUID。​

​

坑 2:CSP 报 unpkg.com 被拦​

页面出现过:​

​

代码块​

PowerShell

Connecting to https://unpkg.com/...wasm.map violates CSP​

​

这个看起来吓人,但它不是主因。​

这是 Dify iframe 里加载 wasm sourcemap 被它自己的 CSP 拦了,通常不影响客服功能。​

​

真正导致不可用的是上面的:​

App with code ... not found​

排障时一定要分清楚主错误和噪音错误。​

​

坑 3:Python 版本不支持 list[str]​

服务器上的 Python 是 3.8,脚本里写了:​

​

代码块​

PowerShell

def add_csp_source(policy: str, directive: str, sources: list[str]) -> str:​

​

结果服务启动失败:​

​

代码块​

PowerShell

TypeError: 'type' object is not subscriptable​

​

解决:​

​

代码块​

PowerShell

​

这就是线上环境和本地开发环境不一致的典型坑。​

​

坑 4:Caddy 路由一度回到了原始状态​

中间发现线上首页没有注入,检查 Caddyfile.example 后发现还是:​

​

代码块​

PowerShell

reverse_proxy localhost:8080​

​

也就是说注入路由没在当前配置里。​

解决方式是重新插入:​

​

代码块​

PowerShell

​

然后重新:​

​

代码块​

PowerShell

caddy validate --config /etc/caddy/Caddyfile.example​

systemctl reload caddy​

​

​

坑 5:敏感配置不能随便打印​

这次排查里有一次误把 app-config.yaml 的敏感字段输出到了终端,包括数据库凭据和应用签名密钥。​

这件事要严肃处理。​

上线后建议:​

•

轮换数据库凭据​

•

轮换应用签名密钥​

•

轮换 root 密码​

•

后续不要用 root 密码直连​

•

改成专用部署用户 + SSH key + sudo​

这也是使用 AI 上线时要特别注意的一点:​

•

Codex 能干活,但你要给它安全边界。​

​

最终回滚方案​

任何线上改动都要有回滚命令。​

这次回滚很简单:​

​

代码块​

PowerShell

cp -a /srv/backups/customer-service/xxxx/Caddyfile.example.bak /etc/caddy/Caddyfile.example​

​

如果只是换 Dify token,不需要改 Caddy,只要:​

​

代码块​

PowerShell

sed -i 's/^DIFY_WEBAPP_TOKEN=.*/DIFY_WEBAPP_TOKEN=新的token/' /srv/customer-service/customer-service.env​

systemctl restart codex-customer-service-injector.service​

​

​

这次上线的关键经验​

Codex 不只是写代码,它可以参与真实运维​

这次它做的不只是“生成一段 HTML”。​

​

🌐

它参与了:​

•

服务器探测​

•

Caddy 配置分析​

•

Docker 架构判断​

•

备份​

•

写注入代理​

•

systemd 服务​

•

CSP 排查​

•

线上验证​

•

回滚方案​

​

这已经接近一个小型 DevOps 协作流程。​

​

不要一上来就改源码​

很多时候,源码不在你手里,或者改源码成本很高。​

这次用“Caddy + 本地注入服务”的方式,绕开了容器镜像和前端构建链路。​

​

🌐

这类方案适合:​

不方便重构前端​

前端在容器镜像里​

只是想快速加一个全站客服​

需要可回滚​

​

智能体客服的核心不是“智能”,而是“边界”​

​

🌐

​

客服最怕什么?​

不是答得不够花哨。​

而是乱答:​

​

​

​

所以一个好客服 Prompt,一定要写清楚:​

​

代码块​

PowerShell

哪些能回答​

哪些不能回答​

哪些必须转人工​

哪些信息不能收集​

​

​

每一步都要验证​

上线过程中一直在做这些验证:​

​

代码块​

PowerShell

systemctl is-active caddy​

systemctl is-active codex-customer-service-injector.service​

​

不要凭感觉上线。​

验证结果比“我觉得没问题”可靠。​

给你一份可复用清单​

如果你也想用 Codex 给网站上线智能体客服,可以照这个清单走:​

Dify 侧​

创建 Chatflow​

配置知识库​

配置 LLM Prompt​

发布 WebApp​

复制“嵌入网站”完整代码​

确认 token 不是 API Key​

服务器侧​

备份 Caddyfile.example​

备份站点配置​

确认网站是静态目录还是反向代理​

如果是静态站,直接加 embed 代码​

如果是反向代理,考虑 HTML 注入代理​

修改 Caddy 前先 validate​

reload 后测试首页和静态资源​

安全侧​

不打印密钥​

不把 API Key 放前端​

不让 AI 索要用户敏感信息​

操作后轮换高危凭据​

保留回滚命令​

​

最后​

这次最大的感受是:​

以前上线一个客服,可能要自己查文档、写代码、改服务器、排查 CSP、重启服务、看日志。​

现在可以把 Codex 当成一个“能动手的搭档”:​

你给目标,它做探测;​

你给边界,它做修改;​

你给权限,它做验证;​

中间出错,它继续定位和修复。​

真正的变化不是“AI 会聊天”。​

真正的变化是:​

AI 开始能把一个想法推进到线上。​

而这,才是 Codex 最值得被认真使用的地方。​

​