237 lines
10 KiB
Markdown
237 lines
10 KiB
Markdown
# LibreDesk 后台配置步骤
|
||
|
||
> 面向 `crm-new` 全栈(方案 B:LibreDesk 内置 AI 回复客户)。
|
||
> 本栈已通过 `scripts/setup-defaults.js` 自动建好 Inbox / Assistant / Automation;本文用于手工核对或重建。
|
||
> 登录:用户 `System`,密码见 `.env` 的 `LIBREDESK_SYSTEM_USER_PASSWORD`。
|
||
|
||
## 0. 前置检查
|
||
|
||
```bash
|
||
bash scripts/bootstrap.sh # LibreDesk 已启动
|
||
bash scripts/start-tools.sh # 另开终端,tools 服务 :4010
|
||
curl -s http://localhost:4100/healthz
|
||
```
|
||
|
||
## 1. AI Provider(必须先配)
|
||
|
||
`Admin → AI → Providers`,两个 provider 都要配(LibreDesk 要求 OpenAI 兼容端点):
|
||
|
||
| 项 | Completion | Embedding |
|
||
|---|---|---|
|
||
| Base URL | `https://dashscope.aliyuncs.com/compatible-mode/v1` | 同左 |
|
||
| API Key | DashScope key(与旧项目 `kb.config.json` 同一个) | 同左 |
|
||
| Model | `qwen-plus-latest` | `text-embedding-v4` |
|
||
| Dimensions | — | **1024**(必须与模型输出一致,否则报维度不匹配) |
|
||
| Temperature | 0.3 | — |
|
||
| Max tokens | 800 | — |
|
||
|
||
点 **Test connection** 两个都通过再继续。改 embedding 模型/维度会自动重新嵌入全部 snippets。
|
||
|
||
成本上限在 `config/config.toml` 的 `[ai_agent]`:`max_steps`、`max_history_messages`、`worker_count`。
|
||
|
||
## 2. 知识库(帮助中心文章)
|
||
|
||
本栈已把旧 `customer-service-kb` 导入为**帮助中心文章**(而不是 snippets),原因:只有文章能被 AI 引用(`[[cite:id]]`),并且同时进入帮助中心站内搜索。
|
||
|
||
公开地址:`http://localhost:9000/hc/yehwang-help/en`(1 个帮助中心 / 9 个 collection / 108 篇文章,全部 `published + ai_enabled`)。
|
||
|
||
重新导入(幂等):
|
||
|
||
```bash
|
||
cd /home/dev/code/crm-new
|
||
node scripts/import-kb-helpcenter.js --dry-run # 只解析
|
||
node scripts/import-kb-helpcenter.js # 登录 System 并导入
|
||
```
|
||
|
||
以下为 LibreDesk 原生 snippets 的用法(内部/敏感内容才用):
|
||
|
||
1. **手工**:一条 Q&A 一个 snippet,正文写完整答案(不要写片段)
|
||
2. **Import from URL**:抓取官网 FAQ 页面
|
||
3. **API 批量导入**(迁移旧 KB 时用):
|
||
|
||
```bash
|
||
curl -X POST http://localhost:9000/api/v1/ai/snippets \
|
||
-H "Authorization: token ${LIBREDESK_API_KEY}:${LIBREDESK_API_SECRET}" \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"title":"Minimum order","content":"The minimum order value is €30.","enabled":true}'
|
||
```
|
||
|
||
迁移建议:旧 `customer-service-kb/*.md` 按 `### Q:` 切块,标题用问题,正文用答案,逐条 POST。Import from URL 走 `POST /api/v1/ai/snippets/import-url`。
|
||
|
||
> RAG 差异:LibreDesk 是 **纯向量 top-k**,没有旧 bridge 的「向量+全文+RRF+rerank+翻译兜底」。EU 语种召回需要用真实问题抽检。
|
||
|
||
## 3. 注册业务工具
|
||
|
||
### 方式 A:自动(推荐)
|
||
|
||
1. `Admin → Teammates → System → API Key` 生成 key/secret,填进 `.env`:
|
||
```
|
||
LIBREDESK_API_KEY=...
|
||
LIBREDESK_API_SECRET=...
|
||
```
|
||
2. 执行:
|
||
```bash
|
||
node scripts/register-tools.js
|
||
```
|
||
|
||
### 方式 B:手工
|
||
|
||
`Admin → AI → Tools → New tool`,4 个工具按下面填:
|
||
|
||
| 字段 | search_products | search_orders | search_inventory | create_opportunity |
|
||
|---|---|---|---|---|
|
||
| URL | `http://bridge:4100/tools/search_products` | `.../search_orders` | `.../search_inventory` | `.../create_opportunity` |
|
||
| Method | POST | POST | POST | POST |
|
||
| Header | `X-Tools-Key: <TOOLS_SHARED_KEY>` | 同 | 同 | 同 |
|
||
| Parameters | 见 `GET /tools/manifest` | 同 | 同 | 同 |
|
||
| Require verified contact | 否 | **是** | 否 | **是** |
|
||
| Copilot / Generate reply | 开 | 开 | 开 | 开 |
|
||
| Require agent approval | 否 | 否 | 否 | 否 |
|
||
|
||
`GET http://localhost:4100/tools/manifest`(带 `X-Tools-Key`)会输出每个工具的完整 JSON Schema,可直接复制。
|
||
|
||
## 4. 创建 AI Assistant
|
||
|
||
`Admin → AI → Assistants → New assistant`:
|
||
|
||
| 项 | 建议值 |
|
||
|---|---|
|
||
| Name | `Yehwang Assistant` |
|
||
| Tone / Length | Friendly / Concise |
|
||
| Languages | English, Dutch, German, French, Spanish, Italian(留空=跟随客户) |
|
||
| Max turns | 8–10 |
|
||
| Fallback team | `Support`(先建团队) |
|
||
| Offer handoff | 开 |
|
||
| Tools | 勾选上一步的 4 个工具 |
|
||
|
||
**Instructions 草稿(可直接改)**:
|
||
|
||
```
|
||
You are the Yehwang B2B customer assistant for stainless-steel jewelry wholesale.
|
||
- Always reply in the customer's language.
|
||
- For product questions call search_products; never invent catalog items.
|
||
- For order questions call search_orders. If the result says verification is required,
|
||
ask the customer to verify their email with the one-time code, then retry.
|
||
- For stock questions call search_inventory with the SKU digits.
|
||
- When you have company + contact name + product/need, call create_opportunity once.
|
||
- Never quote prices, discounts or stock that did not come from a tool result.
|
||
- If you cannot help or the customer asks for a human, hand off to the Support team.
|
||
```
|
||
|
||
**Guardrails**:
|
||
|
||
```
|
||
Never reveal another customer's data. Never promise discounts above the published tiers.
|
||
Never create an opportunity before the contact is verified.
|
||
```
|
||
|
||
> AI Assistant 目前是 **beta**,官方建议先在低流量 inbox 验证。
|
||
|
||
## 5. 自动路由(关键)
|
||
|
||
Assistant **只有被分配给会话才会回复**。配置:
|
||
|
||
`Admin → Automations → New rule`
|
||
|
||
- 触发:`new_conversation`
|
||
- 条件:`inbox = Live chat`(如需只处理工作时间,再加 business hours 条件)
|
||
- 动作:`assign_user` → `Yehwang Assistant`
|
||
|
||
可选第二条规则:`conversation_update` + `status = Resolved` → 发送 CSAT。
|
||
|
||
人工一旦在会话里回复,assistant 会自动 handoff 并取消分配。
|
||
|
||
## 6. Live Chat Inbox 与 Widget
|
||
|
||
1. `Admin → Inboxes → New inbox → Live chat`
|
||
- Name:`Website`
|
||
- Brand / Website URL:`https://www.yehwang.com`
|
||
2. **Security** 标签:生成 widget **Secret key**(用于签 JWT,绝不能放前端)
|
||
3. **Installation** 标签复制 snippet:
|
||
|
||
```html
|
||
<script>
|
||
window.LibredeskSettings = {
|
||
baseURL: 'http://localhost:9000',
|
||
inboxID: 'YOUR_INBOX_UUID'
|
||
};
|
||
</script>
|
||
<script async src="http://localhost:9000/widget.js"></script>
|
||
```
|
||
|
||
### 登录用户身份锚定(已实现)
|
||
|
||
bridge 提供 `POST /identity`:站点 JWT → member RPC 取邮箱 → 用 inbox secret 签 LibreDesk widget JWT。
|
||
本地 POC 也可用 `IDENTITY_DEV_MODE=true` 直接传 email 生成。前端拿到 `userJWT` 后传给 widget。
|
||
|
||
### 原始说明(LibreDesk 侧)
|
||
|
||
已在网站登录的客户,服务端用 inbox Secret 签 HS256 JWT 传给 `userJWT`:
|
||
|
||
```js
|
||
// 服务端(Node 示例,密钥只在服务端)
|
||
const payload = {
|
||
external_user_id: String(user.id), // 与旧栈 yw_uid 对齐
|
||
email: user.email, // 这才是可信邮箱
|
||
first_name: user.firstName,
|
||
last_name: user.lastName,
|
||
contact_custom_attributes: { site: 'www', locale: user.locale },
|
||
exp: Math.floor(Date.now() / 1000) + 3600
|
||
};
|
||
// HS256(payload, inboxSecret) → window.LibredeskSettings.userJWT
|
||
```
|
||
|
||
多站点(www / US)建两个 livechat inbox,各自 widget + secret;联系人按 email 全局共享,注意隐私口径。
|
||
|
||
参考 `us-site/ai-snippet.js`(旧栈 Chatwoot 版)需要改写的点:`$chatwoot.setUser` → `userJWT`,`setCustomAttributes` → `contact_custom_attributes`。
|
||
|
||
## 7. Email Inbox(可选)
|
||
|
||
`Admin → Inboxes → New inbox → Other provider`:
|
||
|
||
| 项 | 值 |
|
||
|---|---|
|
||
| IMAP | `imap.163.com:993`,SSL/TLS |
|
||
| SMTP | `smtp.163.com:465`,SSL |
|
||
| 用户名/密码 | 163 邮箱 + 授权码 |
|
||
| Scan interval | `5m`(默认) |
|
||
|
||
接完后旧桥的 `bridge/mail/`(IMAP 轮询 + 自动回复)可以退役;邮件摘要改为定时调 LibreDesk 报表 API。
|
||
|
||
## 8. WhatsApp(当前 v2.9.0-rc.10 已可用)
|
||
|
||
> **版本现状**:本套已运行 `v2.9.0-rc.10`,`channels` 枚举为 `email / livechat / whatsapp`,`whatsapp_templates` 表已就绪。
|
||
> RC 属于预发布版本,生产使用前评估稳定性;回滚见 README「回滚到稳定版」。
|
||
|
||
1. Meta 侧准备:Business Account、WABA ID、Phone Number ID、Permanent Access Token、App Secret、Webhook Verify Token
|
||
2. `Admin → Inboxes → New inbox → WhatsApp`,填上述凭据
|
||
3. Meta App 的 Webhook 指向 `https://你的域名/webhooks/whatsapp`(以实际路由为准),订阅 `messages`
|
||
4. 模板:`whatsapp_templates` 表 + 后台模板管理;24 小时窗口外的主动消息必须用已审核模板
|
||
5. **AI 对 WhatsApp 的支持文档未覆盖**(文档只写 email + live chat),需实测 assistant 是否在 WhatsApp 会话触发
|
||
|
||
切换镜像:`.env` 里改 `LIBREDESK_IMAGE=libredesk/libredesk:v2.9.0-rc.9`(若 Docker Hub 无该 tag,则按官方文档从 `v2.9.0-rc.9` 源码构建)。
|
||
|
||
## 9. 验收清单
|
||
|
||
- [ ] `Admin → AI → Providers` 两个 Test connection 通过
|
||
- [ ] Snippets 至少 10 条,问一个政策问题能引用
|
||
- [ ] Tools 4 个,`crm-tools` 日志能看到调用
|
||
- [ ] Assistant 已建 + automation 已分配
|
||
- [ ] widget 能开聊,收到 AI 回复
|
||
- [ ] 未验证时问订单 → AI 引导验证;验证后能查单
|
||
- [ ] 说“我要人工” → handoff 到 Support 团队
|
||
- [ ] `curl -s http://localhost:4100/healthz` 正常
|
||
|
||
## 10. 常见问题
|
||
|
||
| 现象 | 原因 | 处理 |
|
||
|---|---|---|
|
||
| 登录后立刻掉登录 | 用 http 访问但 cookie 是 Secure | `config.toml` 里 `disable_secure_cookies = true` |
|
||
| 容器反复重启,日志提示 `system user password is not strong` | System 密码不满足规则(10–72 位,含大小写+数字+特殊字符) | 改 `.env` 的 `LIBREDESK_SYSTEM_USER_PASSWORD`,再 `docker compose up -d --force-recreate app` |
|
||
| 工具 401 | `X-Tools-Key` 与 `TOOLS_SHARED_KEY` 不一致 | 核对 `.env` 和工具 Header |
|
||
| 工具 403 verification_required | 未验证联系人 / 工具未开验证 | 先走 OTP 验证,或该工具不需要验证则关掉 `requires_verification` |
|
||
| 工具 503 tools_key_not_configured | tools 服务未配置共享密钥 | 重启 `start-tools.sh` |
|
||
| AI 不回复 | 会话未分配给 assistant / 会话不是 open | 检查 automation 规则与状态 |
|
||
| embedding 维度报错 | dimensions 与模型不符 | `text-embedding-v4` 用 1024 |
|
||
| 容器访问不了 tools | `host.docker.internal` 未解析 | compose 已配 `extra_hosts`;Linux 需 Docker 20.10+ |
|