feat: add portable KB snapshot for environments without old bridge

This commit is contained in:
wangliang
2026-10-23 11:19:49 +08:00
parent a161a0eee9
commit f526696f93
7 changed files with 118 additions and 7 deletions
+5 -1
View File
@@ -85,6 +85,8 @@ crm-new/
│ ├── set-public-url.js # 更新 LibreDesk app.root_url
│ ├── import-kb-helpcenter.js # 旧 KB -> 帮助中心文章(幂等)
│ ├── verify-rag.js # 临时助手 + preview,验证检索/引用
│ ├── export-kb-snapshot.sh # 导出 kb_docs 快照
│ ├── import-kb-snapshot.sh # 无旧 bridge 时导入 KB 快照
│ ├── smoke.sh
│ └── serve-web.sh # 仅本地预览 demo 页面
├── web/ # 站点接入:ai-snippet.js + demo.html(widget JWT 演示)
@@ -93,7 +95,9 @@ crm-new/
│ ├── environments.md # 本地开发 vs 测试/生产:RPC/Cloudflare 隧道差异
│ ├── human-routing.md # Email/WhatsApp 人工团队分配
│ └── plan-a.md # 方案 A:bridge 接管 AI 编排进度
└── deploy/nginx.conf.example
├── deploy/
│ ├── nginx.conf.example
│ └── seeds/kb_docs.sql.gz # KB 快照(361 chunks:292 parent + 69 child)
services/public-gateway/ # 公网路径白名单反向代理(仅 webhook/帮助中心)
```
Binary file not shown.
+39 -3
View File
@@ -162,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
@@ -173,6 +172,43 @@ bash scripts/rebuild-kb-index.sh
node scripts/upgrade-kb-schema.js
```
#### 测试/生产没有旧 bridge 时(推荐)
不要运行 `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;"
```
预期:
```
361 | 292 | 69
```
然后把测试环境 `.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`
#### 全量商品页站点地图
```bash
node scripts/build-site-map.js www us
```
### 6.4 RPC 隧道(仅本地开发)
> 测试/生产不需要这一步;直接配置内网 RPC 地址即可。
+7 -3
View File
@@ -54,11 +54,15 @@ 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
# 从当前环境重新生成快照(可选)
bash scripts/export-kb-snapshot.sh
# 全量商品页站点地图(官网 sitemap → bridge 库)
node scripts/build-site-map.js www us
+13
View File
@@ -0,0 +1,13 @@
#!/usr/bin/env bash
# 从已有环境导出 KB(kb_docs)快照,供没有旧 bridge 的测试/生产环境导入。
# 用法: bash scripts/export-kb-snapshot.sh [输出文件]
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
OUT="${1:-$ROOT/deploy/seeds/kb_docs.sql.gz}"
SRC_CONTAINER="${SOURCE_PG_CONTAINER:-crm-postgres}"
SRC_DB="${SOURCE_PG_DB:-products}"
SRC_USER="${SOURCE_PG_USER:-postgres}"
mkdir -p "$(dirname "$OUT")"
docker exec "$SRC_CONTAINER" pg_dump -U "$SRC_USER" -d "$SRC_DB" \
-t kb_docs --no-owner --no-privileges | gzip -9 > "$OUT"
echo "[export-kb] $SRC_CONTAINER/$SRC_DB.kb_docs -> $OUT ($(du -h "$OUT" | cut -f1))"
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env bash
# 在没有旧 bridge 的环境导入 KB 快照(默认导入 crmnew-postgres/bridge)。
# 用法:
# bash scripts/import-kb-snapshot.sh [seed.sql.gz]
# FORCE=1 bash scripts/import-kb-snapshot.sh # 覆盖已有 kb_docs(会 DROP)
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
SEED="${1:-$ROOT/deploy/seeds/kb_docs.sql.gz}"
TARGET_CONTAINER="${TARGET_PG_CONTAINER:-crmnew-postgres}"
TARGET_DB="${TARGET_PG_DB:-bridge}"
TARGET_USER="${TARGET_PG_USER:-crmnew}"
if [ ! -f "$SEED" ]; then echo "seed not found: $SEED" >&2; exit 1; fi
# 确保数据库存在
if ! docker exec "$TARGET_CONTAINER" psql -U "$TARGET_USER" -d postgres -tAc \
"SELECT 1 FROM pg_database WHERE datname='$TARGET_DB'" | grep -q 1; then
docker exec "$TARGET_CONTAINER" psql -U "$TARGET_USER" -d postgres -c "CREATE DATABASE \"$TARGET_DB\""
fi
docker exec "$TARGET_CONTAINER" psql -U "$TARGET_USER" -d "$TARGET_DB" -c \
"CREATE EXTENSION IF NOT EXISTS vector;" >/dev/null
# 旧 dump 带 tsv trigger,先确保函数存在
docker exec -i "$TARGET_CONTAINER" psql -U "$TARGET_USER" -d "$TARGET_DB" >/dev/null <<'SQL'
CREATE OR REPLACE FUNCTION public.kb_docs_tsv_update() RETURNS trigger AS $$
BEGIN
NEW.text_tsv := to_tsvector('english',
coalesce(NEW.question,'') || ' ' || coalesce(NEW.answer,'') || ' ' ||
coalesce(array_to_string(NEW.keywords,' '),'') || ' ' ||
coalesce(NEW.title,'') || ' ' || coalesce(NEW.section,''));
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
SQL
EXISTS=$(docker exec "$TARGET_CONTAINER" psql -U "$TARGET_USER" -d "$TARGET_DB" -tAc \
"SELECT to_regclass('public.kb_docs') IS NOT NULL")
if [ "$EXISTS" = "t" ]; then
if [ "${FORCE:-0}" != "1" ]; then
echo "[import-kb] kb_docs already exists in $TARGET_DB; refusing to overwrite. Set FORCE=1 to drop it." >&2
exit 1
fi
echo "[import-kb] FORCE=1: dropping existing kb_docs in $TARGET_DB"
docker exec "$TARGET_CONTAINER" psql -U "$TARGET_USER" -d "$TARGET_DB" -c "DROP TABLE IF EXISTS kb_docs CASCADE" >/dev/null
fi
gunzip -c "$SEED" | docker exec -i "$TARGET_CONTAINER" psql -U "$TARGET_USER" -d "$TARGET_DB" -v ON_ERROR_STOP=1 >/dev/null
COUNT=$(docker exec "$TARGET_CONTAINER" psql -U "$TARGET_USER" -d "$TARGET_DB" -tAc "SELECT count(*) FROM kb_docs")
echo "[import-kb] imported kb_docs rows=$COUNT into $TARGET_CONTAINER/$TARGET_DB"
echo "[import-kb] 提示: bridge 的 RAG_PG_URL 应指向该库(容器内通常是 postgres://...@postgres:5432/$TARGET_DB)"
+2
View File
@@ -1,4 +1,6 @@
#!/usr/bin/env bash
# 仅当存在旧 bridge 容器/旧 products 库时使用。
# 没有旧 bridge 的测试/生产环境请用: bash scripts/import-kb-snapshot.sh
# 重建旧 KB 的 parent-child 索引(调用旧 bridge 容器里的 indexer),再回填 text_tsv。
# 旧表会由 indexer 归档为 kb_docs_vN;额外先做一份 kb_docs_backup_<date> 备份。
set -euo pipefail