2026-10-29 16:49:51 +08:00
1
2026-10-29 16:49:51 +08:00
1
2026-10-29 16:49:51 +08:00
1
2026-10-29 16:49:51 +08:00
1
2026-10-29 16:49:51 +08:00

柏悦智能物流客服系统

基于 Flask + DeepSeek 的中欧/英国跨境物流智能客服,支持多轮对话、运费试算、运单查询、历史会话管理。

功能

  • 多轮上下文:能理解"那空运呢""这个多少钱"这类追问
  • 知识库优先:优先使用本地知识库回答,减少模型编造
  • 追问兜底:当前问题没命中关键词时,用上一句提问去检索
  • 运费试算:识别重量/尺寸/渠道,按报价表阶梯单价计算并展示完整明细
  • 运单号查询:发送 8~20 位运单号,返回轨迹卡片;先展示最近节点,可展开全部轨迹
  • 历史会话:会话保存到 SQLite,支持打开、搜索、删除
  • 交互:停止生成、复制(纯文本)、重答、多行输入、回到底部
  • 中英文切换:右上角「中/EN」按钮或快捷键 Ctrl + L
  • 异常处理:接口超时、Key 失效、中断时给出明确提示与重试
  • 深色模式:右上角切换,偏好本地保存
  • 响应式:窄屏下侧栏自动变为抽屉
  • 附件预览:发送前查看文件名或缩略图,可移除待发送附件
  • 客服工作台:默认展示会话列表与全高聊天区,统计收在「数据概览」,服务资料按需展开;支持会话搜索、多行回复和切换会话保留草稿,常用回复先填入再发送
  • 手机客服接待:会话列表与聊天整屏切换,返回列表保留草稿;回复框固定在聊天底部,可从列表或聊天打开服务资料

报价数据

代码标注的报价来源为 炜易达 VIP 报价表(2026-10-15 9:00 执行版),覆盖 8 条渠道。以下逐渠道列出代码中的重量档位;按计费重量选择不大于该重量的最高档位:

渠道 重量档位 → 基础单价(元/kg) 参考时效
欧洲海运快线 21KG+ → 12.3;101KG+ → 10.3;500KG+ → 10.2;2000KG+ → 10.0 开船后 38-45 天
义乌中欧铁路 21KG+ → 15.5;100KG+ → 13.5;1000KG+ → 13.5 发车后 36-40 天
中欧卡航 21KG+ → 19.4;101KG+ → 17.4;500KG+ → 17.4;2000KG+ → 17.3;4000KG+ → 17.3 发车后 16-20 天
欧洲空运 21KG+ → 39;45KG+ → 38;71KG+ → 37;101KG+ → 36 10-13 天
英国海运 21KG+ → 12.8;101KG+ → 10.9;301KG+ → 10.9 约 40 天
英国铁路 21KG+ → 18.0;101KG+ → 16.2;301KG+ → 16.2 25-30 天
中英卡航 21KG+ → 21.4;101KG+ → 19.4;301KG+ → 19.4 20-22 天
英国空运 22KG+ → 48;51KG+ → 44;101KG+ → 42 8-10 天

计费规则(均来自报价表):

  • 运费 = 阶梯单价 × 计费重量,按重量落入的档位取价
  • 计费重量 = 实重与材积重取大,材积 = 长×宽×高(cm) ÷ 6000(1CBM = 167KG)
  • 最低起收档 21KG(英国空运 22KG)
  • 铁路、卡航单件计费重不足 13KG 加收超轻费 5 元/kg;空运单件不足 12KG 按 12KG 计费
  • 偏远地址 +7 元/kg,单票最低 250 元

基础报价维护在 logistics_chat/pricing.py 的 RATES 字典中;修改价格时同步知识资料,避免调整计算逻辑。

calc_freight() 的 total 当前仅为基础运费。超轻费、偏远费及产品附加费以说明或单独结果展示,尚未统一计入 total;上述业务规则不能理解为已全部自动结算。

扩展数据(logistics_chat/rates_extra.py)

从同一份报价表提取、目前已支持:

  • 海外仓卡派按方计费:0.5CBM+ / 1CBM+ 两档,按提问里的国家自动匹配仓点分组
  • 产品附加费:47 类产品(手机 5 元/kg、电池 1-2 元/kg、玩具 2 元/kg 等)
  • DPD 岛屿偏远判断:12 个国家的岛屿/偏远邮编,命中即提示 35 欧/件

用法示例:

提问 效果
2方 海运 到德国海外仓多少钱 按 1CBM+ 档计算并列出德国仓点分组
寄手机到德国要加什么费用 给出 5 元/kg 附加费
邮编07000 算偏远吗 命中意大利撒丁岛,提示 35 欧/件

⚠️ 报价表含商业价格与联系人信息,公开发布前请脱敏或替换为示例数据。

运行环境与启动

项目使用 Python、Flask、SQLite 和 DeepSeek API,无需前端构建。建议使用独立虚拟环境;所有应用启动命令均在项目根目录执行。

Windows

py -3 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
Copy-Item .env.example .env # 仅首次运行;已有 .env 时跳过
# 编辑 .env,填写 DEEPSEEK_API_KEY 后再启动
.\.venv\Scripts\python.exe am.py

上述命令固定使用项目 .venv,不受其他已激活环境影响。可选的一键入口 start.bat 按已激活的 VIRTUAL_ENV、项目 .venv、py -3、PATH 中的 python 顺序逐个验证 Python 3。使用它之前先退出不需要的旧环境,或检查诊断结果是否指向预期解释器。启动.bat 调用同一入口:

.\start.bat

仅检查并打印选中的解释器,不安装依赖或启动服务:

.\start.bat --check-python

浏览器访问 http://127.0.0.1:5000;客服登录页为 http://127.0.0.1:5000/admin。

Linux / macOS

python3 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
cp .env.example .env # 仅首次运行;已有 .env 时跳过
# 编辑 .env,填写 DEEPSEEK_API_KEY 后再启动
.venv/bin/python am.py

配置说明

  • 本地密钥放在项目根目录的 .env 中:首次运行复制 .env.example,填写 DEEPSEEK_API_KEY=你的密钥。.env 已被 Git 忽略,示例文件中的值应保持为空。
  • 应用启动时自动读取根目录 .env,不依赖终端的当前目录;am.py、Windows 启动脚本和 WSGI 应用工厂均使用同一配置入口。修改密钥后须重启服务。
  • 配置优先级为:显式传给 create_app 的配置 > 进程环境变量 > .env > 空值。环境变量即使为空也会覆盖 .env;本地填写后仍提示未配置时,请检查并移除旧的空环境变量。
  • 部署环境仍可注入 DEEPSEEK_API_KEY。PowerShell 的 $env:DEEPSEEK_API_KEY 只影响当前终端及其子进程,双击启动脚本可直接使用 .env,无需配置系统环境变量。
  • 密钥申请或更换可在 DeepSeek 平台 完成;不要把密钥写入脚本、提交到 Git,或打印到日志。
  • 当前服务监听 0.0.0.0:5000,局域网设备可能访问。仅供本机开发时,将 logistics_chat/config.py 中默认的 HOST 设置为 "127.0.0.1"。
  • 历史启动脚本曾提交明文密钥。当前文件已移除该配置,但 Git 历史仍保留旧内容,应在平台作废旧密钥,并在 .env 或部署环境中配置新密钥。

Jenkins 灰度部署

现有灰度环境按 Jenkins 部署指南 发布:构建和测试镜像,SSH 发送至专用 Compose 服务,再配置独立域名的 HTTPS 和全站访问密码。密钥由 Jenkins 注入,数据和证书保存在独立宿主机目录;启动失败时恢复之前的应用和站点。面向客户开放前仍需补齐鉴权和数据隔离。另附 Linux 单机参考。

目录结构

baiyue-logistics-chat/
├── am.py                     CLI/WSGI 兼容入口
├── Jenkinsfile               灰度构建、测试及受管发布
├── Dockerfile                应用、测试及证书运维镜像
├── .dockerignore             显式限制构建上下文
├── rates_extra.py            扩展数据旧导入路径的兼容转发
├── logistics_chat/
│   ├── __init__.py           create_app 应用工厂
│   ├── config.py             .env、环境变量与绝对路径配置
│   ├── db.py                 SQLite、历史持久化、备份
│   ├── knowledge.py          知识与关键词检索
│   ├── pricing.py            运费解析与计算
│   ├── rates_extra.py        扩展报价唯一数据源
│   ├── tracking.py           模拟轨迹与卡片协议
│   ├── ai_client.py          模型 HTTP、压缩和追问
│   ├── chat_service.py       问答与 SSE 编排
│   ├── history_service.py    会话 CRUD
│   ├── human_service.py      人工会话
│   ├── business_service.py   登录、统计、订单、留言、导出
│   ├── file_service.py       附件与清理
│   ├── hooks.py              限流和缓存头
│   ├── runtime.py            服务启动
│   └── routes/               HTTP Blueprints
├── templates/                客户、登录、客服工作台 HTML
├── static/
│   ├── css/                  theme.css 共享主题 + chat/admin/admin_login 页面样式
│   ├── js/                   对应经典页面脚本
│   └── fa.jpg
├── scripts/                  人工会话检查/关闭 CLI
├── deploy/                   灰度 Compose、发布/回退、证书及单机参考
├── tests/                    规则、存储、HTTP/SSE、启动与维护回归
├── docs/                     architecture.md、knowledge.md
├── examples/requests/        人工接口示例
├── uploads/.gitkeep          本地附件不纳入版本控制
├── start.bat                 可选 Windows 启动检查
├── 启动.bat                  兼容入口,调用 start.bat
├── requirements.txt
├── .env.example
├── .gitignore
├── AGENTS.md
└── README.md

运行后还会生成 history.db、logs/ 和 backups/,这些运行数据以及虚拟环境均由 Git 忽略。已经上传的本地文件在本次目录整理中保留。

测试

先安装项目依赖,再使用同一个项目虚拟环境运行:

.\.venv\Scripts\python.exe -m pytest -v

也可执行 .\.venv\Scripts\python.exe -m unittest discover -s tests -v。Linux/macOS 将解释器替换为 .venv/bin/python。纯规则和维护 CLI 本身仅依赖标准库,整套业务测试还需要 Flask 等项目依赖。

安装 Node.js 后,Python 测试还会运行 tests/frontend/admin.test.cjs,验证发送失败保留草稿、重复点击、切换会话、输入法及手机抽屉;也可单独执行 node --test tests/frontend/admin.test.cjs,无需安装 npm 依赖。未安装 Node.js 时该项明确跳过。

覆盖范围包括配置文件加载与优先级、运费边界与单位换算、知识检索、运单识别、旧 SQLite schema 迁移、事务回滚、附件、人工状态、历史、CSV、SSE 压缩/追问/异常/取消,以及 Windows 解释器选择。Windows 启动测试在其他系统上跳过,三个页面的外置资源也由接口测试检查。

模型请求使用模拟响应,数据库和附件使用临时目录;这不代表完成真实 DeepSeek 或真实物流接口联调。旧文档提及的原始 52 个业务测试和 29 个场景记录未随仓库提供,当前结果以实际测试输出为准。

维护与调试

在根目录执行:

py -3 scripts/inspect_human_sessions.py
py -3 scripts/close_active_sessions.py

两个脚本默认定位到仓库根目录的 history.db,不依赖调用时的工作目录,也可用 --db "D:\data\history.db" 指定已有数据库。检查脚本只读;关闭脚本将所有 active 人工会话标记为 closed,保留 waiting 会话和聊天消息。数据库不存在时会报错退出,不会误建空库。

人工客服接口请求示例见 examples/requests/README.md。知识资料见 docs/knowledge.md,实际知识内容维护在 logistics_chat/knowledge.py 的 knowledge_list 中。

模块定位、文件归属和后续拆分规范见 docs/architecture.md。该文档与当前已拆分的目录保持同步。

主要接口

方法 路径 说明
GET / 客户聊天页面
GET / POST /stream_chat SSE 流式对话;POST JSON 接收 msg、conv_id
POST /api/new_chat 新建会话并保存欢迎语,返回 id、welcome
GET /api/get_history 会话列表
GET /api/get_messages?conv_id= 单个会话的消息
DELETE /api/del_history?id= 删除单个会话和消息
DELETE /api/clear_all 清空聊天历史
POST /api/upload 上传图片、PDF、TXT、CSV,最大 10MB
POST /api/human/request 申请人工客服
POST /api/human/accept 客服接待
POST /api/human/send 发送人工消息
GET /api/human/poll 轮询人工消息
POST /api/human/close 关闭人工会话
POST /api/human/transfer 将接待中的会话转回排队列表
POST /api/human/note 保存会话备注
POST /api/human/recall 按 mid 撤回客服消息
POST /api/rate 提交人工服务评价(sid、1–5 的 stars、comment)
GET /api/agents/list 客服列表,不包含密码
GET /api/search_chat?q= 搜索历史消息,最多返回 50 条
GET /admin 客服登录页面
POST /admin/login 校验客服账号密码
GET /admin/dashboard 客服工作台
GET /api/export_chat 导出 Excel;?format=csv 保留 CSV 导出

人工客服每天 8:00–22:00 接受新申请,由服务端校验时间;其余时间可提交离线留言。客服工作台保留白色界面,转接后由其他客服在排队列表主动接入。页面的铃铛按钮可开启浏览器通知,页面切到后台时提示排队或新消息;实际通知能力取决于浏览器权限。

SSE 每帧为一条 JSON,主要事件包括:

data: {"t": "正文片段"}
data: {"e": "错误提示"}
data: {"card": {...}}
data: {"replace": "精简后的全文"}
data: {"suggest": ["相关追问"]}
data: {"d": 1}

数据库与运行数据

首次启动会自动创建 chat_history、messages、feedback、human_sessions、human_messages、ratings、agents、orders 和 tickets 九张表,并兼容已有数据,不预置账号或演示数据。本地入口使用根目录 history.db,Linux 部署工厂另存至专用数据目录。客服账号需由管理员在实际环境中配置。会话备注保存在 human_sessions.note;消息撤回事件通过 human_messages.recalled_id 指向原消息,轮询客户端按编号更新。运单卡片以 __CARD__{json} 形式保存,前端据此恢复展示。

普通导入 am.py 或 logistics_chat 不创建运行数据。显式调用 create_app() 或访问 WSGI 兼容入口 am.app 时,默认初始化 SQLite、创建正常运行日志、备份数据库并清理修改时间超过 7 天的上传文件。测试须事先配置临时数据库、附件、日志和备份目录;INITIALIZE_RUNTIME=False 可禁止自动初始化,此时调用方负责准备 schema。历史会话的自动清理仍已关闭。

当前限制

  • 运单轨迹为模拟数据,尚未接入真实物流查询接口。
  • 不预置客服账号;应用内客服登录仍沿用旧账号校验逻辑。公网自用验收可按部署指南使用全站访问密码进入工作台。
  • 后台登录尚未建立完整会话鉴权,管理页面和接口缺少登录校验。
  • 运费数字由 Python 计算后交给模型组织说明;附加费是否适用仍需结合具体货物和地址核对。
  • 回答提示词目标为 120–350 字;代码压缩阈值为中文 800、英文 1400 字符,超过阈值最多尝试压缩两次。
  • 服务优先使用 Waitress 的 8 个线程;缺少 Waitress 时会回退到 Flask 开发服务器。公网部署前还需完善鉴权及部署配置。
S
Description
柏悦智能物流客服系统Flask+SQLite+SSE流式对话
Readme
1 MiB
Languages
HTML 56.9%
Python 42.1%
Batchfile 1%