chore: CRM-NEW baseline

This commit is contained in:
wangliang
2026-10-23 10:35:28 +08:00
commit aa499f6dbf
111 changed files with 15126 additions and 0 deletions
+236
View File
@@ -0,0 +1,236 @@
# 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://127.0.0.1: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://192.168.31.61: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://192.168.31.61: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://127.0.0.1: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://192.168.31.61:9000',
inboxID: 'YOUR_INBOX_UUID'
};
</script>
<script async src="http://192.168.31.61: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://127.0.0.1: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+ |