🤖 智能客服系统(Intelligent Customer Service)

简体中文 · English

基于 FastAPI + RAG 的多模型智能客服平台。 装完依赖点一下运行,剩下全在网页上配 —— 不改配置文件,不跑初始化脚本。

status python tests license


目录

  • 三步跑起来
  • 效果预览
  • 核心特性
  • 页面导览
  • 架构
  • 目录结构
  • 支持的模型厂商
  • 向量数据库
  • 智能分词(结构感知切分)
  • 回答策略:严格 RAG 还是允许自主回答
  • 嵌入到你的网站
  • API 速查
  • 配置项参考
  • 常见问题
  • 开发与测试
  • 生产部署

三步跑起来

1. 装依赖

cd backend
python3 -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install -r requirements.txt
 

2. 启动

PyCharm:右键 backend/run.py → Run

命令行

python run.py
 

启动后会打印:

==============================================================
  🤖 IntelligentCustomerService
==============================================================
  ⚙️  管理后台   http://localhost:8000/admin/     ← 从这里开始
  🪟  组件演示   http://localhost:8000/widget/demo/
  📖  API 文档   http://localhost:8000/docs
--------------------------------------------------------------
  ⚠  尚未配置对话模型 API Key
     → 打开管理后台「模型配置」填写即可,无需改文件
==============================================================
 

缺依赖时会提示当前解释器对应的安装命令;也可以 python run.py --install 自动装。

3. 打开管理后台配置

浏览器访问 http://localhost:8000/admin/

顺序 做什么
1️⃣ 页面顶部若出现黄色横幅 → 点 「🚀 一键初始化」(建表 + 建目录 + 写默认配置)
2️⃣ 进 「模型配置」 → 选厂商 → 填 API Key → 「🔌 测试连接」 → 「💾 保存」
3️⃣ 同页 「🧬 向量模型」 → 「⬆︎ 复用对话模型的 Key / URL」 → 「🔌 测试并探测维度」
4️⃣ 进 「知识文档」 → 拖入 txt/md/docx/xlsx/pdf → 自动解析入库
5️⃣ 进 「聊天预览」 → 直接提问验证

完全不需要编辑 .env、执行 init_db.py 或任何脚本。

命令行参数
 
 

 


效果预览

🤖 模型配置
15 项厂商预设,选厂商自动填 Base URL 和模型;带连接测试与维度探测
🔍 RAG 设置
回答策略开关、检索参数、切分策略,还能预览切分效果

f3ccefef3e365e7a6a5baa1495cca29b_003b1787756952.png

17315f81b3f5ac34aa4769cf1b0d409d_c8bc1787757454.png

🧠 向量库
Chroma / Qdrant / Milvus 三选一,各自参数按需显示
💬 客服信息
名称、头像、欢迎语、联系方式,改一次对所有已嵌入站点生效

30ec21eda55b9240dbcb7bc471468d47_ai_kefu_xl.png

490626af4a247a1a32d68381d69b0294_ai_kefu_config.png

🪟 聊天预览
后台内直接测 RAG 问答,答案带 Markdown 渲染和可点击链接
🌐 嵌入指南
script / iframe / 小程序三种方式,代码一键复制

c06e53a81198e2b269e177b6642cf1c5_ai_kefu_view.png

4a93cb51f30c042968d61c8244e74c17_ai_kefu_jieru.png

嵌入到网站后的实际效果 —— 右下角浮动按钮,点击弹出聊天窗口:

31f70010bede4111632c7e558fd077f6_ai_kefu_yanshi.png


核心特性

模块 能力
📄 文档知识库 txt / md / docx / xlsx / pdf 解析 → 结构感知切分 → 向量化 → 入库;MD5 去重;断点续传
🧠 智能分词 识别【章节】、Markdown 标题、第X章、Q&A、Excel 工作表,沿语义边界切分,每片带标题上下文
🤖 多模型 15 项厂商配置:DeepSeek、千问/百炼、火山方舟(包月/按量分开)、智谱、Kimi、千帆、OpenAI、Claude、Gemini、Ollama、胜算云、优云智算、2 个自定义
🔁 双协议 OpenAI /chat/completions 与 Anthropic /messages 可切换;切协议自动更新 Base URL
🗂 三种向量库 Chroma(默认,本地文件)/ Qdrant / Milvus(含 Lite 零安装)
🎯 回答策略可选 默认严格 RAG(资料外一律拒答);可开关允许 AI 自主回答
⚡ 流式输出 SSE 实时 token;429 自动重试不中断
🪟 可嵌入组件 单文件 JS(零依赖、免构建),内置 Markdown 渲染 + 链接可点击
📲 跨平台 网站 / 微信小程序 web-view / Electron / Tauri / iOS / Android
⚙️ 全网页配置 模型、向量库、RAG 参数、客服信息全部页面可改,改完即生效无需重启

页面导览

打开 /admin/ 后左侧 8 个菜单:

菜单 作用
📊 概览 系统状态、当前模型、向量库、文档数
🤖 模型配置 对话模型(厂商/协议/Key/模型/温度)+ 向量模型;带连接测试与维度自动探测
🧠 向量库 Chroma / Qdrant / Milvus 切换及各自参数
🔍 RAG 设置 回答策略开关 + Top-K/阈值 + 切分策略;带切分预览
📄 知识文档 拖拽上传、实时入库进度、失败可续传、删除
💬 客服信息 客服名称、头像、欢迎语、联系方式(组件自动读取)
🪟 聊天预览 iframe 内嵌真实组件,直接测 RAG 问答
🌐 嵌入指南 三种嵌入方式的代码,一键复制

页面右上角还有三个常驻工具:

工具 说明
🟢 后端状态 每 15 秒自检一次。离线时鼠标悬停可看完整错误
⬆︎ 检测更新 比对当前版本与 GitHub 最新 Release,有新版时按钮上出现红点
☕ 打赏支持 微信 / 支付宝 / QQ 赞赏码

检测更新需要先配置仓库:在 backend/.env 里加 APP_GITHUB_REPO=owner/repo。 未配置时按钮会给出配置指引,不会报错。

只检测不改代码 —— 发现新版会展示更新说明和更新命令,由你决定何时执行。 自动 git pull 会覆盖本地未提交的修改,还可能因依赖变更导致服务起不来, 不适合放在一个按钮后面。


架构

┌──────────── 浏览器 ────────────┐        ┌─────────── FastAPI 后端 ───────────┐
│  customer-service.js(零依赖)  │  HTTP  │  api · services · adapters          │
│   浮动按钮 + 聊天窗 + 文件上传  │ ◀────▶ │  vector_store · embeddings          │
│   SSE 流式 + Markdown 渲染     │  SSE   │  parsers · prompts · models         │
└────────────────────────────────┘        └──┬────────┬──────────┬─────────────┘
                                             │        │          │
                                        SQLite    Chroma /    LLM 厂商
                                        /MySQL    Qdrant /    (15 项配置)
                                        (会话)    Milvus
 

LLM 适配器(async + SSE,429 自动重试):

BaseProvider
  ├── OpenAIStyleProvider     → POST {base}/chat/completions
  └── AnthropicStyleProvider  → POST {base}/messages
                                (system 为顶级字段;同时发 x-api-key 与
                                  Authorization: Bearer 以兼容各家网关)
build_provider() 按 protocol 分发
 

目录结构

intelligent-customer-service/
├── backend/
│   ├── run.py                        ← 一键启动(PyCharm 右键 Run)
│   ├── requirements.txt
│   ├── .env.example                  (可选;页面配置优先于此)
│   ├── docker-compose.yml            MySQL + Redis + Qdrant + Milvus
│   ├── src/
│   │   ├── main.py                   FastAPI app factory
│   │   ├── api/                      admin · chat · config · documents · models · sessions
│   │   ├── services/                 document · rag · llm · embedding · session
│   │   ├── adapters/                 base · openai · anthropic · factory
│   │   ├── vector_store/             base · chroma · qdrant · milvus · factory
│   │   ├── embeddings/               base · openai_compatible_embedder
│   │   ├── parsers/                  txt(含 md) · docx · xlsx · pdf
│   │   ├── prompts/system_prompts.py RAG 约束 + 自主回答提示词
│   │   ├── models/                   SQLAlchemy ORM
│   │   ├── core/                     config · database · registry · exceptions
│   │   ├── utils/                    text_splitter(结构感知)· sse · hash · obfuscation
│   │   └── tests/                    36 个测试
│   ├── scripts/
│   │   ├── init_db.py                建表(一键初始化已覆盖,一般不用手跑)
│   │   ├── check_env.py              依赖/配置自检
│   │   ├── ingest_docs.py            批量导入
│   │   └── ingest_retry.py           ← 大知识库自动重试入库
│   └── samples/                      示例知识文档
├── frontend/
│   ├── admin/
│   │   ├── index.html                管理后台
│   │   └── embed.html                独立聊天页(预览 / iframe 用)
│   └── widget/
│       ├── customer-service.js       嵌入组件(零依赖)
│       ├── selftest.mjs              ← 组件自检(17 项断言)
│       └── demo/                     嵌入演示
└── docs/
    ├── API.md · DEPLOYMENT.md · EMBED_GUIDE.md
    └── qqmu-knowledge-base/          示例知识库(脚本可重新生成)
 

支持的模型厂商

页面下拉按「厂商 / 自定义」分组,选厂商自动填 Base URL 和默认模型;点 🔄 可从你的账号拉取真实可用的模型列表。

厂商 协议 说明
DeepSeek(深度求索) openai 性价比高
阿里云 · 通义千问 / 百炼 openai 共用 DashScope 兼容地址
火山方舟 · 包月套餐 openai + anthropic /api/plan/v3/api/plan/v1,模型填 ark-code-latest
火山方舟 · 豆包(按量) openai /api/v3
智谱 GLM openai  
Kimi(Moonshot) openai  
百度千帆(ERNIE) openai v2 端点
OpenAI openai 国内需代理
Anthropic Claude anthropic 官方 Messages 协议
胜算云(模型路由) openai 聚合多家
优云智算 ⚠ openai  
Google Gemini ⚠ openai 通过 OpenAI 兼容端点
Ollama(本地部署)⚠ openai localhost:11434,Key 随便填
自定义(OpenAI 协议) openai vLLM / one-api / LiteLLM / 自建网关
自定义(Anthropic 协议) anthropic 任何 Anthropic 兼容层

⚠ 标记表示预填地址/模型未经实测核实,页面会显示橙色提示。请对照厂商文档确认,或点 🔄 拉取真实模型列表。其余各项均已实际验证可用。

⚠️ 火山方舟用户注意

ARK 有两个计费不同的产品,务必选对:

你的情况 选哪项 Base URL
买了 Coding Plan 包月套餐 火山方舟 · 包月套餐 /api/plan/v3(OpenAI)或 /api/plan/v1(Anthropic)
按量付费 火山方舟 · 豆包 /api/v3

包月套餐模型固定填 ark-code-latest,路由到哪个具体模型在火山控制台选。 用错地址会产生额外费用。


向量数据库

页面「向量库」菜单切换,切换后需重启后端并重新入库文档(向量数据不跨库迁移)。

类型 说明 需要额外服务?
Chroma(默认) 本地文件持久化到 ./data/chroma_db ❌ 开箱即用
Qdrant Rust 实现,生产级 ✅ docker compose up -d qdrant
Milvus 企业级;填 .db 路径走 Milvus Lite(零安装),填 http://host:19530 连服务器,也支持 Zilliz Cloud 视模式而定

智能分词(结构感知切分)

默认策略。相比按字数硬切,它沿语义边界切分并保留标题上下文。

以 samples/sample_knowledge.txt(595 字)为例:

  固定窗口 结构感知
片段数 2 6
问题 四个章节混在一片;另一片从 Q3 中间开始,丢了【常见问题】上下文 每章节独立成片,标题完整保留
问「保修期」Top-1 得分 0.719 0.791

能识别的结构【章节】 · Markdown #~######(含层级) · 第X章 · Q:/A: 问答对 · ## Sheet:(Excel) · ## Page N(PDF)

编号列表如 1. 整机保修期为 12 个月。 不会被误判成标题。

在页面上调:「RAG 设置 → 文本切分」

  • 切分策略 — 结构感知 / 固定窗口
  • 标题前缀开关 — 长章节被拆时每片带 [技术规格] 前缀
  • 🔍 预览切分效果 — 选文档或粘贴文本,立刻看到片段数、长度分布、章节归属,不用真的入库

回答策略:严格 RAG 还是允许自主回答

「RAG 设置 → 回答策略」的开关,默认关闭

  关闭(默认) 开启
知识库有相关内容 依据资料回答 依据资料回答,资料不足时可补全
知识库没有相关内容 「抱歉,知识库中没有相关信息」 用模型自身知识回答
可追溯性 ✅ 每句都能追溯到你的文档 ❌ 用户分不清哪句来自资料
适用场景 价格、政策、承诺等 通用问答、技术咨询

实测(问「珠穆朗玛峰的海拔」):

关闭:🚫 抱歉,知识库中没有相关信息,我无法回答。
开启:✅ 珠穆朗玛峰的最新海拔高程为 8848.86米,这是2020年12月中尼共同宣布的…
 

开启后站内问题不受影响 —— 「有没有404页面模板」照样从知识库回答。

为什么需要 relevance_threshold(0.76)

 

 

 
 

 


嵌入到你的网站

方式 1:<script> 标签(最简单)

<script src="http://localhost:8000/widget/customer-service.js?v=1"></script>
<script>
  CustomerService.init({
    apiUrl: 'http://localhost:8000',
    accent: '#0a66c2',
    position: 'right',      // 'left' | 'right'
    enableUpload: true,
  });
</script>
 

客服名称、头像、欢迎语不用写在这里 —— 组件会自动读取「客服信息」页的配置, 改一次对所有已嵌入站点生效。 ?v=1 是缓存版本号,更新组件后递增它。

方式 2:iframe(完全隔离)

<iframe src="http://localhost:8000/embed?api=http://localhost:8000"
        style="position:fixed;right:20px;bottom:20px;width:400px;height:636px;
               border:0;background:transparent;">
</iframe>
 

尺寸要给够、背景要透明:展开后的面板需要 400 × 636 (面板 360×540 + 按钮位 76 + 边距 20)。给小了面板会被裁掉; 不设 background: transparent 的话,多余区域会露出 iframe 底色,看起来像一块白板。

/embed 支持 api · title · accent · position · autoOpen · upload · bg 参数。

方式 3:小程序

<web-view src="https://你的域名/embed?api=https://你的API域名" />
 

记得把域名加入小程序后台的业务域名白名单。

Widget 配置项

选项 默认 说明
apiUrl http://localhost:8000 后端地址
title / subtitle 读后端配置 标题(传了会覆盖后端)
avatar 读后端配置 头像 URL,加载失败退回首字
welcome 读后端配置 首条欢迎语
accent #0a66c2 主题色
position right 浮动按钮位置
autoOpen false 加载后自动展开
enableUpload true 显示文件上传按钮
useServerConfig true 是否从 /api/config 拉取客服信息
sessionId null 恢复历史会话
onReady null 初始化完成回调
CustomerService.open() / close() / toggle() / sendMessage(text) / destroy()
 

组件内置 Markdown 渲染(加粗/列表/标题/代码块/引用)和链接自动可点击

详见 docs/EMBED_GUIDE.md(含 Electron / Tauri / iOS / Android / CSP)。


API 速查

Swagger:http://localhost:8000/docs · 详细文档:docs/API.md

方法 路径 用途
GET /health 健康检查
GET /api/admin/status 安装状态检查(页面横幅用)
POST /api/admin/init 一键初始化(幂等)
GET /api/admin/version 检测更新(比对 GitHub 最新 Release)
GET PUT /api/config 读取 / 更新全部配置
GET /api/config/providers 厂商注册表
POST /api/documents/upload 上传文档(multipart)
POST /api/documents/process 切分 + 向量化 + 入库(支持续传)
POST /api/documents/split-preview 预览切分效果(不入库)
GET /api/documents/list 文档列表(含入库进度)
DELETE /api/documents/{id} 删除文档及其向量
GET /api/documents/parsers 支持的文件格式
POST /api/chat 一次性问答(JSON)
POST /api/chat/stream 流式问答(SSE)
GET POST /api/sessions 会话列表 / 创建
GET /api/sessions/{id}/messages 会话历史
POST /api/sessions/{id}/close 关闭会话
GET /api/models 模型 + 向量库总览
POST /api/models/available 拉取厂商真实模型列表
POST /api/models/test 测试对话模型连接
POST /api/models/test-embedding 测试向量模型并探测维度
GET /api/models/vector-db 向量库列表

静态页面(后端直接提供,无需另起服务器):

路径 说明
/ 首页(快捷入口)
/admin/ 管理后台
/embed 独立聊天页(iframe 用),保留查询参数
/widget/customer-service.js 嵌入组件
/widget/demo/ 嵌入演示
/docs · /redoc Swagger / ReDoc

SSE 事件/api/chat/stream):

event: meta      → 首个事件,{session_id}
event: token     → 增量文本,{text}
event: sources   → 来源列表(含 heading / score / filename)
event: done      → 结束,{ok}
event: error     → 出错,{message}
 

配置项参考

页面配置优先于 .env —— 正常使用完全不必碰 .env。以下供部署脚本 / CI 参考。

展开 .env 全部配置项
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     

⚠️ backend/data/app.db 里存着你在页面填的 API Key(base64 混淆,等同明文)。 已在 .gitignore 中排除,不要提交到公开仓库


常见问题

启动报「缺少依赖」但我装过了

 

 
 

 

没有 API Key 能跑吗

 

问什么都回「知识库中没有相关信息」
  1.  
  2.  
  3.  
  4.  

 

入库很慢 / 中途失败

 

 

 
 

 

改了向量库 / Embedding 模型后检索不对

 

 

火山方舟报 401

 

  •  
  •  

 

聊天时报 429

 

SSE 在 Nginx 后面断流

 

 
 

 

改了前端却没变化

 

Python 3.14 装不上某些包

 


开发与测试

# 后端:36 个测试
cd backend
python -m pytest src/tests/ -q

# 前端组件自检:17 项断言,在真实 DOM 里跑完整 SSE 流程
cd frontend/widget
npm install       # 装 jsdom
npm test

# 环境自检
cd backend && python scripts/check_env.py
 

组件自检值得一说:node -c 只做语法检查,检不出「模板字符串被内部反引号截断」 这类会让整个 widget 运行时崩溃的错误。npm test 会真正执行渲染路径。


生产部署

完整步骤(Nginx 配置、HTTPS、防火墙、备份、升级、故障排查)见 docs/DEPLOYMENT.md。下面是可直接照做的最短路径。

部署前的三个关键认识

  1. 只有 Nginx 该暴露公网 —— 应用绑 127.0.0.1:8000,管理后台没有登录,直接对外等于把 API Key 配置页开放给所有人
  2. SSE 必须在 Nginx 关闭缓冲 —— 否则回答不会逐字出现,而是等全部生成完才一次性蹦出来(最常见的坑)
  3. API Key 存在 backend/data/app.db(base64 混淆,等同明文)—— 已被 .gitignore 排除,别提交

方案 A:Docker Compose(推荐)

# 1. 装 Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER          # 重新登录生效

# 2. 拉代码
cd /opt && git clone https://github.com/vfaner/intelligent-customer-service.git intelligent-customer-service
cd intelligent-customer-service

# 3. 新建 backend/Dockerfile 和 docker-compose.prod.yml
#    (完整内容见 docs/DEPLOYMENT.md 的「方案 A」一节)

# 4. 配置环境
cp backend/.env.example backend/.env
nano backend/.env
#   必改:APP_ENV=production · APP_SECRET_KEY=<随机生成>
#         DATABASE_URL=mysql+aiomysql://cs_user:密码@mysql:3306/cs_db
#         CORS_ORIGINS=https://你的域名
#   生成 SECRET_KEY:
#   python3 -c "import secrets; print(secrets.token_urlsafe(48))"

# 5. 启动
docker compose -f docker-compose.prod.yml up -d --build
curl -fsS http://127.0.0.1:8000/health     # 应返回 {"status":"ok"}
 

方案 B:systemd + Nginx

# 1. 装依赖(Ubuntu/Debian)
sudo apt install -y python3.12 python3.12-venv nginx git

# 2. 建专用用户 + 拉代码
sudo useradd -r -s /bin/false -d /opt/ics csapp
sudo mkdir -p /opt/ics && cd /opt/ics && sudo git clone https://github.com/vfaner/intelligent-customer-service.git .
sudo chown -R csapp:csapp /opt/ics

# 3. 装 Python 依赖
cd /opt/ics/backend
sudo -u csapp python3 -m venv .venv
sudo -u csapp .venv/bin/pip install -r requirements.txt
sudo -u csapp cp .env.example .env && sudo nano .env

# 4. 写 /etc/systemd/system/ics.service(见 docs/DEPLOYMENT.md 的完整模板)
#    要点:User=csapp · 只绑 127.0.0.1:8000 · Restart=always · ProtectSystem=strict
sudo systemctl enable --now ics
 

Nginx(无论哪种方案都必须)

server {
    listen 443 ssl http2;
    server_name 你的域名;
    client_max_body_size 25M;

    # ⚠ SSE 流式问答:关闭缓冲,否则回答不逐字出现
    location /api/chat/stream {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_cache off;
        chunked_transfer_encoding off;
        proxy_read_timeout 300s;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
 

HTTPS 证书

Widget 嵌入 HTTPS 站点时接口也必须是 HTTPS(浏览器拦截混合内容),基本必选:

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d 你的域名 -d www.你的域名
 

保护管理后台(三选一)

管理后台没有内置登录,按安全级别从高到低:

方式 做法
SSH 端口转发(推荐) 不对外开放;ssh -L 8000:127.0.0.1:8000 user@服务器,本地打开 localhost:8000/admin/
IP 白名单 Nginx 里 /admin/ 加 allow 你的IP; deny all;
Basic 认证 htpasswd + auth_basic,同时保护 /api/config /api/admin 写接口

首次上线验证

# 服务活着
curl -fsS https://你的域名/health

# 模型连通(先在管理后台填好 Key)
curl -sS -X POST https://你的域名/api/models/test -H 'Content-Type: application/json' -d '{}'

# SSE 真的是流式(token 应逐条出现,不是一次性吐出)
curl -N -sS -X POST https://你的域名/api/chat/stream \
     -H 'Content-Type: application/json' -d '{"message":"你好"}'
 

安全清单

  •  APP_SECRET_KEY 换成随机值
  •  APP_ENV=production 且 APP_DEBUG=false(debug 会在报错时泄露栈信息)
  •  CORS_ORIGINS 限定为实际域名(不要留 *
  •  管理后台已加访问控制(上面三选一)
  •  应用只监听 127.0.0.1;数据库/Redis/向量库不映射到公网端口
  •  启用 HTTPS
  •  不用 root 跑应用
  •  给 /api/chat* 加 Nginx 限流(防刷爆 LLM 账单)
  •  确认 .gitignore 生效:git check-ignore -v backend/data/app.db
  •  定期备份 backend/data/(脚本见 DEPLOYMENT.md),并实际验证过能恢复
  • 注意文档内容可能带 prompt injection