merge: 拉取 origin/main(KB snapshot + 在线 FAQ 同步 + 环境文档)

This commit is contained in:
wangliang
2026-10-23 11:32:01 +08:00
30 changed files with 2083 additions and 33 deletions
+124
View File
@@ -0,0 +1,124 @@
# 环境差异:本地开发 / 测试 / 生产
> 结论:`rpc-tunnel.sh` 和 `public-https.sh` 是**本地开发联调工具**,测试/生产环境不应依赖它们。
## 1. 对比表
| 能力 | 本地开发(当前机器) | 测试 / 生产 |
|---|---|---|
| 业务 RPC | 用 SSH 隧道 `scripts/rpc-tunnel.sh`,因为 RPC 端口外网不可达 | **不需要隧道**,直接填内网 RPC 地址(服务 DNS / VPC / 专线) |
| RPC 地址 | `jsonrpc://<tunnel-gateway>:24503` 等隧道网关地址 | `jsonrpc://<rpc-host>:24503` 等真实内网地址 |
| 公网 HTTPS | Cloudflare Quick Tunnel + `scripts/public-https.sh` | **不需要 Quick Tunnel**,用正式域名 + Ingress/Nginx/ALB + TLS |
| WhatsApp webhook | 临时 Quick Tunnel URL,重启会变 | 正式域名,例如 `https://crm.example.com/webhooks/whatsapp/...` |
| 公网路径白名单 | `public-gateway`(本地 compose 服务) | 由 Ingress/Nginx 统一处理,或保留 gateway 作为内部服务 |
| Demo 页面 | `scripts/serve-web.sh`,:8088 | 不需要 |
| 数据库/Redis | compose 内 Postgres/Redis,宿主机端口仅绑 `127.0.0.1` | 使用托管数据库/Redis 或内网集群,不暴露宿主机端口 |
| 环境变量 | `.env` 指向本地/测试地址 | `.env` 指向测试/生产真实地址 |
| 密钥 | 本地 `.env` | Secret Manager / CI/CD Secret,不入库 |
## 2. RPC:本地隧道 vs 测试/生产直连
### 本地开发
RPC 端口外网不可达时,才需要:
```bash
bash scripts/rpc-tunnel.sh --apply
```
它会:
- 在本机建 SSH 隧道到远端 RPC
- 把 `.env` 的 RPC URL 改为隧道网关地址
- 重建 bridge
### 测试 / 生产
**不要运行 `rpc-tunnel.sh`。**
直接配置:
```env
RECOMMEND_URL=jsonrpc://<recommend-service>:24503
ORDER_API_URL=jsonrpc://<order-service>:24505
MEMBER_RPC_URL=jsonrpc://<member-service>:24506
INVENTORY_API_URL=jsonrpc://<inventory-service>:24509
```
要求:
- bridge 容器能直接访问这些地址
- 测试/生产网络放行对应端口
- 不要指向开发机的 SSH 隧道网关
如果测试/生产网络确实隔离,应该用 **VPC 对等连接 / 专线 / VPN / 内网反向代理**,而不是开发机上的 SSH 隧道。
## 3. 公网 HTTPS:Quick Tunnel vs 正式域名
### 本地开发
只有本地联调 WhatsApp/公网 webhook 时才需要:
```bash
bash scripts/public-https.sh
```
特点:
- Cloudflare Quick Tunnel
- URL 每次重启可能变化
- 需要重新更新 LibreDesk `root_url` 和 Meta webhook
- 只适合临时联调
### 测试 / 生产
**不要使用 Cloudflare Quick Tunnel。**
使用:
- 正式域名(`crm.example.com`)
- Ingress / Nginx / ALB / API Gateway
- 正式 TLS 证书
- 固定公网出口
配置:
```env
PUBLIC_BASE_URL=https://crm.example.com
```
并同步:
- LibreDesk `app.root_url`
- Meta WhatsApp callback URL
- `public-gateway` 的上游地址(如果保留)
### public-gateway 的去留
`services/public-gateway` 只负责路径白名单:
```
/webhooks/whatsapp/
/hc/
/widget*
/static/public/
```
测试/生产可以:
- 继续保留它,放在 Ingress 后面
- 或者把同样的路径规则直接写进 Ingress/Nginx
Quick Tunnel 只是本地把请求转发进来的手段,不是生产架构的一部分。
## 4. 测试/生产上线检查
- [ ] 未运行 `rpc-tunnel.sh`
- [ ] RPC URL 指向内网真实地址,不是 `172.23.0.1`
- [ ] 未运行 `public-https.sh`
- [ ] `PUBLIC_BASE_URL` 是正式 HTTPS 域名
- [ ] LibreDesk `root_url` 是正式域名
- [ ] Meta webhook 是正式域名
- [ ] 数据库/Redis 不暴露公网
- [ ] 不使用 `serve-web.sh` 的 8088 demo
- [ ] 密钥来自 Secret Manager / CI Secret,不在仓库和镜像里
+100 -15
View File
@@ -53,6 +53,17 @@ Email (inbox 2) / WhatsApp (inbox 3)
---
## 2.1 环境差异(本地开发 vs 测试/生产)
> 详见 [environments.md](environments.md)。
- `scripts/rpc-tunnel.sh`:**仅本地开发**,因为 RPC 端口外网不可达
- `scripts/public-https.sh`:**仅本地联调**,Cloudflare Quick Tunnel
- 测试/生产:RPC 直接配内网地址,公网 HTTPS 用正式域名 + Ingress/Nginx/ALB
- 测试/生产不应运行上述两个脚本
---
## 3. 访问入口
| 服务 | 地址 | 备注 |
@@ -97,13 +108,13 @@ Email (inbox 2) / WhatsApp (inbox 3)
- [ ] `.env` 已备份,且权限为 `600`
- [ ] `docker compose config -q` 通过
- [ ] RPC 隧道可用(商品/订单/库存)
- [ ] 本地开发:RPC 隧道可用;测试/生产:RPC 内网地址可直达
- [ ] LibreDesk webhook `Bridge AI` 为启用状态
- [ ] LibreDesk 规则 1 关闭
- [ ] 规则 4/5 指向 `Wholesale Support`
- [ ] agent1/agent2 可登录,必要时设为在线
- [ ] WhatsApp access token 未过期(当前 token 有到期时间)
- [ ] 公网 URL 与 Meta webhook 已同步
- [ ] 本地开发:Quick Tunnel 与 Meta webhook 已同步;测试/生产:正式域名与 Meta webhook 已同步
- [ ] 163 SMTP / IMAP 可用
- [ ] 已做数据库备份
- [ ] bridge 测试通过
@@ -151,10 +162,9 @@ node scripts/configure-email.js
### 6.3 数据准备
```bash
# 全量商品页站点地图(每周/商品大更新后)
node scripts/build-site-map.js www us
#### 有旧 bridge / 旧 products 库时
```bash
# 重建 KB parent-child 索引(KB 更新后;会先备份旧表)
bash scripts/rebuild-kb-index.sh
@@ -162,9 +172,80 @@ bash scripts/rebuild-kb-index.sh
node scripts/upgrade-kb-schema.js
```
### 6.4 RPC 隧道
#### 测试/生产没有旧 bridge 时(推荐)
商品/订单/库存依赖本机到内网的 RPC 隧道:
不要运行 `rebuild-kb-index.sh`。直接导入仓库里的 KB 快照:
```bash
# 默认导入到 crmnew-postgres / bridge 库
bash scripts/import-kb-snapshot.sh
# 或导入到 products 库
TARGET_PG_DB=products bash scripts/import-kb-snapshot.sh
# 验证
docker exec crmnew-postgres psql -U crmnew -d bridge -tAc \
"select count(*), count(*) filter (where chunk_type='parent'), count(*) filter (where chunk_type='child') from kb_docs;"
```
预期:
```
367 | 296 | 71
```
然后把测试环境 `.env` 的 `RAG_PG_URL` 指向该库,例如:
```env
RAG_PG_URL=postgres://crmnew:<password>@postgres:5432/bridge
```
> 快照文件:`deploy/seeds/kb_docs.sql.gz`(只包含 `kb_docs` 知识库,不含邮件/客户数据)
> 当前环境如需重新生成:`bash scripts/export-kb-snapshot.sh`
#### 在线 FAQ 同步(不依赖旧 bridge)
测试/生产如果网络可以访问官网 FAQ,可直接:
```bash
# 在宿主机执行时,RAG_PG_URL 用宿主机可达地址
RAG_PG_URL=postgres://crmnew:<password>@127.0.0.1:5440/bridge \
node scripts/sync-kb-online.js
# 如果脚本跑在 bridge 容器内,则用容器内地址
# RAG_PG_URL=postgres://crmnew:<password>@postgres:5432/bridge
```
建议 cron 每周一次:
```cron
0 3 * * 1 cd /home/dev/code/crm-new && RAG_PG_URL=... node scripts/sync-kb-online.js
```
如果官网抓取被 WAF 拦截,可先用本地源文件重建:
```bash
node scripts/sync-kb-online.js --local-only --force
```
注意:
- 需要 `RAG_PG_URL` 指向目标库
- 需要 `EMB_*`(DashScope embedding)
- 旧的 `kb_docs` 会备份为 `kb_docs_v<timestamp>`
- `bridge/kb/11-site-map.md` 目前是静态类目地图,不随官网自动更新
#### 全量商品页站点地图
```bash
node scripts/build-site-map.js www us
```
### 6.4 RPC 隧道(仅本地开发)
> 测试/生产不需要这一步;直接配置内网 RPC 地址即可。
本地 RPC 端口外网不可达时才需要:
```bash
bash scripts/rpc-tunnel.sh
@@ -172,7 +253,11 @@ bash scripts/rpc-tunnel.sh
隧道断了会导致 `search_products/search_orders/search_inventory` 失败。
### 6.5 公网 HTTPS / WhatsApp webhook
### 6.5 公网 HTTPS / WhatsApp webhook(仅本地联调)
> 测试/生产不要用 Cloudflare Quick Tunnel;使用正式域名 + Ingress/Nginx/ALB + TLS。
本地联调:
```bash
bash scripts/public-https.sh
@@ -308,10 +393,10 @@ bridge 关键日志:
### 外部依赖巡检
- RPC 隧道进程
- 本地开发:RPC 隧道进程
- 本地开发:Cloudflare tunnel 状态
- 测试/生产:内网 RPC 可达性、Ingress/证书、WhatsApp token 剩余有效期
- 163 SMTP/IMAP
- WhatsApp token 剩余有效期
- Cloudflare tunnel 状态
- 未分配/团队队列积压
---
@@ -386,8 +471,8 @@ docker compose stop bridge
### 高
1. **单点**:bridge 只有一个实例;bridge 挂了 Live chat 无 AI 回复。
2. **RPC 隧道**:依赖本机 SSH 隧道,断了商品/订单/库存工具不可用。
3. **公网 URL**:Cloudflare Quick Tunnel URL 不固定,重启可能失效。
2. **RPC 隧道(仅本地开发)**:依赖本机 SSH 隧道,断了商品/订单/库存工具不可用。测试/生产应直连内网 RPC。
3. **公网 URL(仅本地开发)**:Cloudflare Quick Tunnel URL 不固定,重启可能失效。测试/生产使用正式域名。
4. **WhatsApp token**:临时 token 有到期时间,需要提前续期。
5. **Email 历史数据为空**:`kb_mail_docs` 只有测试邮件,真实客户历史未 ingest。
@@ -453,8 +538,8 @@ TWENTY_BASE_URL / TWENTY_API_KEY
```
scripts/bootstrap.sh
scripts/rpc-tunnel.sh
scripts/public-https.sh
scripts/rpc-tunnel.sh # 仅本地开发
scripts/public-https.sh # 仅本地联调
scripts/build-site-map.js
scripts/rebuild-kb-index.sh
scripts/e2e-widget-jwt.js
+2 -1
View File
@@ -51,9 +51,10 @@ LIBREDESK_WEBHOOK_ID=1
- [x] 上下文摘要/压缩(>24 条,保留最近 16 条)
- [x] Prompt 注入防护(消息检测 + 工具结果信任边界)
- [x] 全量商品页站点地图(www 32,691 / us 22,625,商品页 32,051/22,305)
- [x] Hybrid RAG:text_tsv/parent_id/chunk_type,292 parent + 69 child,向量+全文+RRF+父块扩展
- [x] Hybrid RAG:text_tsv/parent_id/chunk_type,296 parent + 71 child,向量+全文+RRF+父块扩展
- [x] 购买意向 post-LLM 追问兜底(产品+数量触发,缺公司/联系方式时多语言硬追问)
- [x] 商机补齐:内容指纹去重、跨渠道复用/同步、阶段推进、CRM 故障 fail-closed
- [x] 在线 FAQ/KB 同步(不依赖旧 bridge,`sync-kb-online.js`)
- [x] `search_email_history`:已验证客户邮件历史,强制按 verified email scope
- [x] 发送前输出护栏:句子级自动重写 + URL 白名单 + 价格/库存数字必须有工具证据
- [x] Email/WhatsApp 人工接管:Wholesale Support 团队 + assign_team 规则(AI 不再分配)
+19 -7
View File
@@ -54,11 +54,21 @@ node scripts/setup-defaults.js
# Twenty:创建初始 workspace + 在库内生成 API key(不走 UI)
node scripts/twenty-bootstrap.js
# 重建 KB parent-child 索引(旧 bridge indexer + 回填 text_tsv,自动备份)
# 有旧 bridge 时:重建 KB parent-child 索引(自动备份)
bash scripts/rebuild-kb-index.sh
# 升级旧 kb_docs 支持 Hybrid RAG(text_tsv/parent_id/chunk_type)
node scripts/upgrade-kb-schema.js
# 没有旧 bridge 时:直接导入 KB 快照(测试/生产常用)
bash scripts/import-kb-snapshot.sh
# 或指定目标库:TARGET_PG_DB=products bash scripts/import-kb-snapshot.sh
# 在线 FAQ 同步 + 重建 KB(不依赖旧 bridge)
# 宿主机执行时 RAG_PG_URL 用 127.0.0.1:5440/bridge
RAG_PG_URL=postgres://crmnew:<password>@127.0.0.1:5440/bridge node scripts/sync-kb-online.js
# 仅用本地 bridge/kb 重建
node scripts/sync-kb-online.js --local-only --force
# 从当前环境重新生成快照(可选)
bash scripts/export-kb-snapshot.sh
# 全量商品页站点地图(官网 sitemap → bridge 库)
node scripts/build-site-map.js www us
@@ -77,10 +87,12 @@ node scripts/eval-offline.js
# 真实模型离线评测(fake LibreDesk,不写真实会话;会调 LLM/RPC)
node scripts/eval-live.js
# 公网 HTTPS(WhatsApp webhook 需要):Cloudflare Quick Tunnel + 路径白名单网关
# 公网 HTTPS(仅本地联调需要):Cloudflare Quick Tunnel + 路径白名单网关
# 测试/生产:不要跑这个脚本,使用正式域名 + Ingress/Nginx + TLS
bash scripts/public-https.sh
# 测试服 RPC 端口外网被封:建 SSH 隧道并让 bridge 指向隧道(网关 IP)
# 仅本地开发:测试服 RPC 端口外网被封时建 SSH 隧道
# 测试/生产:不要跑这个脚本,直接把 RPC URL 配成内网可达地址
bash scripts/rpc-tunnel.sh --apply
# 配置 163 SMTP(自动重启 LibreDesk)
@@ -168,6 +180,6 @@ ss -ltnp | grep -E ':(9000|3100|4100|5440|6390)\s'
| 管理员后台实时更新不工作 | 通过 http + IP 访问时 agent websocket 拒绝非 HTTPS 来源 | POC 可忽略;生产用 HTTPS 或经 localhost 访问 |
| collect_info 槽位丢失 | Redis 不可用,退回了进程内存 | 检查 `REDIS_URL=redis://redis:6379/3` 和 `docker logs crmnew-bridge` 的 lead store 告警 |
| 多站点商品推荐串站 | `bridge/config/sites.json` 的 inbox 映射没配 | 把对应 inbox 数字 ID 指到 us/eu/www profile,重建 bridge |
| WhatsApp webhook 收不到 | 没有公网 HTTPS / Meta 回调地址不对 | 跑 `bash scripts/public-https.sh`,把输出的 `.../webhooks/whatsapp/<inbox_id>` 配到 Meta;quick tunnel URL 每次重启会变 |
| WhatsApp webhook 收不到 | 没有公网 HTTPS / Meta 回调地址不对 | 本地联调跑 `bash scripts/public-https.sh`;测试/生产使用正式域名,不要用 Quick Tunnel |
| 公网访问到管理后台 | 网关白名单配置 | `services/public-gateway` 只放行 `/webhooks/whatsapp/*`、`/hc/*`、`/widget*`、`/static/public/*`,其余 404 |
| AI 回复"系统暂时无法查询订单" | 测试服 24503/24505/24506/24509 外网 TCP 被封,bridge 8s 超时 | 跑 `bash scripts/rpc-tunnel.sh --apply`,bridge RPC 指向 docker 网关(隧道只绑网关,不暴露 LAN) |
| AI 回复"系统暂时无法查询订单" | RPC 不可达,bridge 8s 超时 | 本地开发跑 `bash scripts/rpc-tunnel.sh --apply`;测试/生产检查内网 RPC 地址/网络策略,不要用开发机隧道 |