|
|
2 weeks ago | |
|---|---|---|
| docs | 2 weeks ago | |
| evaluations | 3 weeks ago | |
| frontend | 2 weeks ago | |
| migrations | 3 weeks ago | |
| oms_migrations | 3 weeks ago | |
| ops | 3 weeks ago | |
| scripts | 2 weeks ago | |
| src | 2 weeks ago | |
| tests | 2 weeks ago | |
| .dockerignore | 3 weeks ago | |
| .env.agent.example | 3 weeks ago | |
| .env.example | 3 weeks ago | |
| .env.oms.example | 3 weeks ago | |
| .gitignore | 3 weeks ago | |
| .python-version | 3 weeks ago | |
| AGENTS.md | 3 weeks ago | |
| Dockerfile | 3 weeks ago | |
| README.md | 2 weeks ago | |
| alembic.ini | 3 weeks ago | |
| compose.runtime.yaml | 3 weeks ago | |
| compose.scale.yaml | 3 weeks ago | |
| compose.yaml | 3 weeks ago | |
| oms-alembic.ini | 3 weeks ago | |
| pyproject.toml | 3 weeks ago | |
| uv.lock | 3 weeks ago |
智服中台面向多商家电商客服与售后场景,将消费者咨询、订单查询、知识检索、换货申请、人工审批和 OMS 履约连接为完整业务流程。项目包含消费者 H5、商家后台、平台后台、Agent 服务、独立 OMS 服务,以及模型用量、费用和运行监控能力。
源码阅读:八条阅读路线与文件、函数追踪流程图。
以下为当前本机演示环境的访问地址与账号密码,地址均通过 127.0.0.1 在运行项目的电脑上访问。
| 服务/角色 | 访问地址 | 演示账号 | 密码 |
|---|---|---|---|
| 消费者 H5 | 进入商城 | customer01 |
JJJkewsWJfHeNcmVLmuzgwmx |
| 商家管理员 | 商家后台 | admin01 |
JJJkewsWJfHeNcmVLmuzgwmx |
| 客服 | 商家后台 | staff01 |
JJJkewsWJfHeNcmVLmuzgwmx |
| 审批主管 | 商家后台 | supervisor01 |
JJJkewsWJfHeNcmVLmuzgwmx |
| 费用管理 | 商家后台 | finance02 |
JJJkewsWJfHeNcmVLmuzgwmx |
| 平台管理员 | 平台后台 | platform-admin |
3TnCh2YxrsBsoRyrV0MRiL4q16NWKggO |
| Grafana | 监控面板 | zhifu |
zhifu_local_only |
| Prometheus | 指标查询 | 无需登录 | 无需密码 |
| Alertmanager | 告警管理 | 无需登录 | 无需密码 |
| RabbitMQ | 消息管理 | zhifu |
zhifu_local_only |
商家后台登录时,商家标识统一填写 ac700000-2026-4000-8000-000000000001。客服、审批主管、商家管理员和费用管理账户共用该入口,登录后按账户权限展示功能。
Grafana 支持匿名只读访问,管理操作使用表中的账号登录。消费者与商家凭据保存在 .work/frontend-accounts.json,平台凭据保存在 .work/platform-accounts.json;首次在新环境准备账户时,脚本生成该环境的密码,以对应账户文件为准。
每次上课前,在项目根目录使用 PowerShell 7 执行 ./scripts/start_course_demo.ps1。入口创建本次课程独立客户和已签收两天的键盘订单,同时登记 OMS 与平台,并在课堂期间持续同步。账户与订单信息保存在 .work/course-demo/active.json,使用方法见 课程演示数据。
| 使用者 | 入口与职责 |
|---|---|
| 消费者 | 浏览商品与分类、查询本人订单、咨询 AI、补充申请信息、确认换货方案、查询工单、请求人工协助、管理沟通习惯 |
| 商家管理员 | 管理店铺、员工权限、渠道、服务资料、售后规则、Agent 发布配置和模型费用 |
| 客服 | 查看授权店铺会话、接管与回复、查询关联订单和工单、创建或修订售后方案 |
| 审批主管 | 查看授权范围内的待办并批准或拒绝售后申请 |
| 平台管理员 | 管理商家接入、启停状态、资源额度、渠道投递、运行概览和操作审计 |
商家管理员、客服和主管共用商家后台,菜单、数据与操作由账户授权决定。平台后台使用独立账户和会话。消费者、商家、平台分别保存登录状态,浏览器令牌保存在内存,刷新页面需要重新登录。
主要业务能力:
一次换货申请依次经过订单与规则查询、方案创建、客户确认、主管审批、异步履约和结果查询。Agent 使用授权工具查询或创建方案;客户确认和主管审批由对应身份通过业务接口完成。网络结果未知时,系统保留原操作标识并查询外部结果。
商城中的购物车、交易支付、营销、地址、收藏等栏目按页面说明展示业务范围。项目中的 OMS 使用独立数据库和 HTTP 接口;接入商家已有 OMS 时,需要适配订单、商品明细、客户身份、凭据和履约状态。
| 部分 | 使用的技术与职责 |
|---|---|
| 前端 | Vue 3、Vue Router、Vite;后台使用 Element Plus,H5 使用 Vant,图标使用 @lucide/vue |
| 平台 API | Python 3.12、FastAPI、Pydantic、SQLAlchemy、asyncmy;处理身份、业务、权限和事务 |
| Agent | LangChain、LangGraph、OpenAI 兼容模型接口;工作进程从持久任务中领取并执行运行 |
| 平台与 OMS 数据库 | 两套 MySQL 8.4,分别维护业务数据和独立 Alembic 迁移 |
| 缓存 | 独立 Redis 8.2,使用 allkeys-lru 管理可重建缓存 |
| 持久状态 | 独立 Redis 8.2,启用 AOF 和 noeviction;提供协调状态、RedisJSON、Search 和 LangMem 记忆存储 |
| 可靠消息 | RabbitMQ 4.2、MySQL Outbox、消费收据和外部操作记录 |
| 知识检索 | Milvus 3.0.1、etcd、MinIO;BGE-M3 生成 1024 维向量,中文 BM25 与 RRF 合并检索结果 |
| 监控与入口 | Prometheus、Alertmanager、Grafana;HAProxy 为多个 API 容器提供入口 |
五类常驻工作进程分别为 agent、memory、fulfillment、knowledge、channel-delivery,负责模型执行、记忆提取、售后履约、旧知识版本清理和渠道结果发送。
| 路径 | 内容 |
|---|---|
frontend/ |
三个产品入口、公共组件、API 调用和浏览器功能测试 |
src/zhifu/core/ |
配置、数据库连接、错误响应、接口定义和指标 |
src/zhifu/modules/ |
身份、售后、Agent、会话、知识、记忆、渠道、商家、平台、商品与费用模块 |
src/zhifu/oms/ |
独立 OMS 服务及凭据登记命令 |
src/zhifu/operations/ |
发布检查、工作进程入口、额度管理与恢复命令 |
src/zhifu/monitoring/ |
任务、心跳与模型用量 exporter |
migrations/、oms_migrations/ |
平台和 OMS 的数据库迁移 |
ops/ |
容器环境示例、HAProxy、Prometheus、Alertmanager 与 Grafana 配置 |
scripts/ |
开发数据准备、OpenAPI 导出、备份与恢复验证 |
tests/、evaluations/ |
功能、集成、容量、恢复和模型评测资料 |
docs/ |
设计依据、接口说明和专项操作说明 |
.work/ |
被版本控制忽略的模型缓存、开发凭据、备份和中间文件 |
pyproject.toml 限定为 >=3.12,<3.13。uv.lock。--wait,多副本配置还使用 !reset。frontend/package-lock.json 固定。tools、tool_calls、tool 消息和 usage 的 OpenAI 兼容模型服务,以及有效 API Key。默认推理配置使用 CPU。运行配置为 BGE 服务设置 6 GiB 内存上限,为 API、OMS、exporter 和每类工作进程分别设置 1 GiB 上限;数据库、Milvus 和监控还需要额外资源。部署前根据服务数量、知识规模和并发目标分配内存、CPU 与持久存储。
以下本机命令使用 PowerShell,从项目根目录执行;前端命令所在目录会单独说明。逐条执行命令,出现非零退出状态时处理具体错误后继续。示例配置中的本机密码仅用于开发环境。
首次部署复制配置文件,已有文件继续使用原内容:
if (-not (Test-Path .env)) { Copy-Item .env.example .env }
if (-not (Test-Path .env.oms)) { Copy-Item .env.oms.example .env.oms }
if (-not (Test-Path .env.agent)) { Copy-Item .env.agent.example .env.agent }
New-Item -ItemType Directory -Force .work | Out-Null
if (-not (Test-Path .work/runtime.env)) { Copy-Item ops/runtime.local.env.example .work/runtime.env }
uv sync --locked
宿主机命令分别读取 .env、.env.oms 和 .env.agent。容器通过 .work/runtime.env 注入环境变量,服务地址使用 Docker 服务名。两种配置需要指向同一组业务数据和同一模型配置。
| 配置 | 宿主机开发值 | 容器配置值 |
|---|---|---|
ZHIFU_DATABASE_URL |
平台 MySQL:127.0.0.1:13306/zhifu |
mysql:3306/zhifu,完整连接串见示例文件 |
OMS_DATABASE_URL |
OMS MySQL:127.0.0.1:13307/oms |
mysql-oms:3306/oms |
ZHIFU_CACHE_URL |
redis://127.0.0.1:16379/0 |
redis://redis-cache:6379/0 |
ZHIFU_STATE_URL |
redis://127.0.0.1:16380/0 |
redis://redis-state:6379/0 |
ZHIFU_BROKER_URL |
RabbitMQ:127.0.0.1:15672 |
rabbitmq:5672,使用 amqp:// 连接串 |
KNOWLEDGE_MILVUS_URL |
http://127.0.0.1:19530 |
http://milvus:19530 |
KNOWLEDGE_INFERENCE_URL |
http://127.0.0.1:8200 |
http://inference:8200 |
AGENT_MODEL_NAME、AGENT_MODEL_URL |
在 .env.agent 中配置 |
在 .work/runtime.env 中配置 |
AGENT_CREDENTIAL_ENV |
保存模型密钥的环境变量名称 | API、Agent、记忆和发布检查使用的环境变量名称 |
MySQL 连接串必须使用 mysql+asyncmy://用户名:密码@主机:端口/数据库。缓存和持久状态必须使用两个独立 Redis 服务。宿主机的知识配置通过进程环境变量设置,KnowledgeSettings 不读取上述 .env 文件;各配置文件只填写其对应设置类支持的字段。
模型示例配置使用 deepseek-flash 和 DEEPSEEK_API_KEY。将自己的密钥注入当前进程;已经配置 Windows 用户环境变量时可以使用:
if (-not $env:DEEPSEEK_API_KEY) {
$env:DEEPSEEK_API_KEY = [Environment]::GetEnvironmentVariable('DEEPSEEK_API_KEY', 'User')
}
if (-not $env:DEEPSEEK_API_KEY) { throw '请配置 DEEPSEEK_API_KEY 后继续' }
使用其他供应商时,同步调整模型名称、地址、AGENT_CREDENTIAL_ENV 和 AGENT_MODEL_EXTRA_BODY。后者为 JSON 对象,默认可设为 {}。容器中需要存在 AGENT_CREDENTIAL_ENV 指定的实际密钥变量;自定义变量可以放入受保护的运行环境文件。现有 Compose 对 DEEPSEEK_API_KEY 的显式注入读取启动命令所在终端,因此该变量需要在当前终端中有效。
docker compose config --quiet
docker compose up -d --wait
docker compose ps
默认启动平台 MySQL、OMS MySQL、两套 Redis、RabbitMQ、etcd、MinIO 和 Milvus,创建 zhifu-platform_default 网络及持久数据卷。monitoring、fault-tests、replica-tests profile 按需启用。
本机下载固定版本模型到 .work/models:
uv run python -c "from sentence_transformers import SentenceTransformer; SentenceTransformer('BAAI/bge-m3', revision='5617a9f61b028005a4858fdac845db406aefb181', cache_folder='.work/models', device='cpu')"
容器使用只读模型目录,并设置 HF_HUB_OFFLINE=1。需要保留完整缓存目录,包括模型快照及其引用文件;容器用户 UID 10001 必须具有读取权限。下载完成后设置 Compose 参数:
$env:ZHIFU_RUNTIME_ENV = (Resolve-Path .work/runtime.env).Path
$env:ZHIFU_MODEL_PATH = (Resolve-Path .work/models).Path
$env:ZHIFU_DEPENDENCY_NETWORK = 'zhifu-platform_default'
这些变量在后续迁移、启动、发布检查和停止命令所在终端中都需要保留。ZHIFU_RUNTIME_ENV 和 ZHIFU_MODEL_PATH 在 Compose 解析时即为必填项。
docker build -t zhifu-platform:local .
docker build --build-arg DEPENDENCY_GROUP=inference -t zhifu-inference:local .
docker compose -f compose.runtime.yaml config --quiet
docker compose -f compose.runtime.yaml run --rm migrate
docker compose -f compose.runtime.yaml run --rm migrate-oms
docker compose -f compose.runtime.yaml run --rm migrate python -m zhifu.modules.knowledge.vector
平台和 OMS 分别迁移至镜像中的 Alembic head。API 启动不执行数据库结构变更。知识初始化创建 KNOWLEDGE_COLLECTION 指定的集合,默认名称为 zhifu_knowledge_v1;集合已存在时加载该集合。
docker compose -f compose.runtime.yaml --profile inference up -d --wait api oms operations inference
docker compose -f compose.runtime.yaml run --rm release-check
docker compose -f compose.runtime.yaml ps
release-check 在 60 秒期限内检查两套数据库版本、Redis、RabbitMQ、Milvus 集合与向量维度、真实 BGE 请求、API readiness、OMS 健康状态及模型配置。任意检查失败返回非零退出状态。该命令会计算本地文本向量,生成模型只检查配置与凭据是否存在。
本机访问端口如下,均绑定 127.0.0.1:
| 服务 | 端口或路径 |
|---|---|
| 平台 API | 28000;/health/live、/health/ready |
| OMS | 28100;/health |
| BGE-M3 | 28200;/health/ready |
| 运行 exporter | 28300;/metrics |
| 平台 / OMS MySQL | 13306 / 13307 |
| 缓存 / 持久 Redis | 16379 / 16380 |
| RabbitMQ AMQP / 管理界面 | 15672 / 15673 |
| Milvus / Milvus 健康检查 | 19530 / 19091 |
平台 /health/ready 检查 MySQL 和两套 Redis。完整依赖可用性还需要结合发布检查、向量服务状态和工作进程指标判断。
在本机 development/test 数据库中执行:
uv run python scripts/prepare_frontend_accounts.py
uv run python scripts/prepare_storefront_data.py
uv run python scripts/prepare_platform_data.py
脚本创建独立开发商家的账户、商品和示例订单,使用实际数据库保存数据。商家与消费者凭据保存在 .work/frontend-accounts.json,平台凭据保存在 .work/platform-accounts.json,渠道 SERVICE 凭据保存在 .work/storefront-channel.json。账户文件需要限制访问权限。
开发账户包括 customer01、staff01、supervisor01、admin01、finance02,平台账户为 platform-admin。这些脚本只允许 development/test 环境;示例订单不包含独立 OMS 的履约登记。完整换货流程还需要按照后文配置 OMS,并持续同步可信订单。
docker compose -f compose.runtime.yaml --profile workers up -d agent memory fulfillment knowledge channel-delivery
docker compose -f compose.runtime.yaml ps
docker compose -f compose.runtime.yaml logs --tail 100 agent memory fulfillment knowledge channel-delivery
有待处理咨询或已授权记忆任务时,agent 和 memory 会调用配置的生成模型。启动前确认租户额度、凭据及预算。OMS 履约密钥需要注入使用连接器的 API、Agent 和 fulfillment;渠道签名密钥需要注入 API 与 channel-delivery,变量名称与对应业务配置中的 credential_env 一致。
进入 frontend 目录:
Set-Location frontend
if (-not (Test-Path .env.local)) { Copy-Item .env.example .env.local }
npm ci
编辑 frontend/.env.local,将租户和店铺 UUID 替换为账户文件中的实际值:
API_TARGET=http://127.0.0.1:28000
VITE_TENANT_ID=替换为实际租户UUID
VITE_STORE_ID=替换为实际店铺UUID
npm run dev
开发服务器端口为 18762,浏览器打开 http://127.0.0.1:18762。页面入口分别为 /#/customer/home、/#/merchant/login、/#/platform/login。修改环境文件后重新启动 Vite。
API_TARGET 只控制 Vite 开发与预览代理;前端业务请求使用同域相对路径。VITE_TENANT_ID 和 VITE_STORE_ID 会进入前端构建产物,只用于默认业务范围,服务端仍独立验证身份与权限。密钥不得使用 VITE_ 前缀。
完整容器部署时,在 ops/prometheus/prometheus.yml 中将平台、向量和 operations 的采集目标分别设置为 api:8000、inference:8200、operations:8300;这些服务通过基础 Compose 网络互相访问。检查 ops/prometheus/replicas/ 中的发现文件,只保留实际运行的采集目标。
从项目根目录执行:
docker compose --profile monitoring up -d prometheus alertmanager grafana
Prometheus、Alertmanager、Grafana 的本机端口分别为 19090、19093、13000。已有 Prometheus 进程在配置修改后需要重启。检查采集目标正常,且 zhifu_workers_alive 包含五类有效工作进程。
开发 Grafana 管理账户为 zhifu,密码为 zhifu_local_only,允许匿名只读访问。生产环境需要独立密码、访问控制和 HTTPS。Alertmanager 默认接收器只在服务内保存告警,外部通知需要配置实际接收渠道。
noeviction。基础 compose.yaml 提供本机开发配置;生产依赖由受控部署配置或托管服务提供。ZHIFU_DEPENDENCY_NETWORK。该网络是 external 网络,启动 runtime Compose 前必须存在。ZHIFU_ENVIRONMENT=production。生产配置校验要求 Redis 使用带认证的 rediss://,RabbitMQ 使用带独立凭据的 amqps://,MySQL 使用独立密码。按部署环境安装受信 CA、配置证书与网络访问控制。ZHIFU_IMAGE 与 ZHIFU_INFERENCE_IMAGE。将完整模型缓存挂载至 ZHIFU_MODEL_PATH,将环境文件绝对路径设置为 ZHIFU_RUNTIME_ENV。ZHIFU_POOL_SIZE、ZHIFU_MAX_OVERFLOW;根据供应商额度配置 AGENT_GLOBAL_CONCURRENCY、AGENT_TENANT_CONCURRENCY、两类预留和租户预算。交互与后台预留之和不得超过全局并发上限。以下 PowerShell 参数需要替换为目标环境的实际值,运行环境文件由部署系统生成和保护:
$env:ZHIFU_IMAGE = 'registry.example.com/zhifu-platform@sha256:替换为镜像摘要'
$env:ZHIFU_INFERENCE_IMAGE = 'registry.example.com/zhifu-inference@sha256:替换为镜像摘要'
$env:ZHIFU_RUNTIME_ENV = (Resolve-Path .work/runtime.production.env).Path
$env:ZHIFU_MODEL_PATH = (Resolve-Path .work/models).Path
$env:ZHIFU_DEPENDENCY_NETWORK = 'zhifu-production'
docker compose -f compose.runtime.yaml config --quiet
docker compose -f compose.runtime.yaml --profile inference --profile workers pull
ZHIFU_RUNTIME_ENV 是 Compose 的注入文件,支持多组服务变量;宿主机配置继续按设置类分别管理。运行镜像只包含应用、依赖和迁移,前端静态文件、模型、开发脚本与密钥独立发布。
首次生产部署在开放入口前执行迁移、知识初始化和服务检查:
docker compose -f compose.runtime.yaml run --rm migrate
docker compose -f compose.runtime.yaml run --rm migrate-oms
docker compose -f compose.runtime.yaml run --rm migrate python -m zhifu.modules.knowledge.vector
docker compose -f compose.runtime.yaml --profile inference up -d --wait api oms operations inference
docker compose -f compose.runtime.yaml run --rm release-check
完成两套数据库迁移后,通过管理命令创建正式租户、店铺和业务账户。密码使用隐藏终端输入,至少 12 个字符:
docker compose -f compose.runtime.yaml run --rm migrate python -m zhifu.manage tenant --name '商家名称'
$tenantId = Read-Host '输入上条命令返回的租户 UUID'
docker compose -f compose.runtime.yaml run --rm migrate python -m zhifu.manage store --tenant $tenantId --name '店铺名称'
$storeId = Read-Host '输入上条命令返回的店铺 UUID'
docker compose -f compose.runtime.yaml run --rm migrate python -m zhifu.manage user --tenant $tenantId --username merchant-admin --kind STAFF
$adminId = Read-Host '输入上条命令返回的员工 UUID'
新增账户没有店铺权限;首位商家管理员由受控数据库管理流程配置 store_grants。使用上面得到的 UUID,在平台 MySQL 执行以下首次初始化 SQL:
SET @tenant_id = UUID_TO_BIN('替换为租户UUID');
SET @store_id = UUID_TO_BIN('替换为店铺UUID');
SET @admin_id = UUID_TO_BIN('替换为员工UUID');
START TRANSACTION;
SELECT p.username, p.kind, p.status, t.name, t.status, s.name, s.status
FROM principals p
JOIN tenants t ON t.id = p.tenant_id
JOIN stores s ON s.tenant_id = t.id
WHERE p.tenant_id = @tenant_id AND p.id = @admin_id AND s.id = @store_id
FOR UPDATE;
确认查询返回唯一目标员工和店铺,员工为启用的 STAFF,租户和店铺均为 ACTIVE 后,在同一事务中执行:
INSERT INTO store_grants (tenant_id, principal_id, store_id, permission) VALUES
(@tenant_id, @admin_id, @store_id, 'orders:read'),
(@tenant_id, @admin_id, @store_id, 'tickets:read'),
(@tenant_id, @admin_id, @store_id, 'stores:manage'),
(@tenant_id, @admin_id, @store_id, 'staff:manage'),
(@tenant_id, @admin_id, @store_id, 'channels:manage'),
(@tenant_id, @admin_id, @store_id, 'rules:write'),
(@tenant_id, @admin_id, @store_id, 'knowledge:write'),
(@tenant_id, @admin_id, @store_id, 'agent:publish');
COMMIT;
SQL 适用于新账户首次初始化;已有授权按当前记录处理,保存操作人、审批依据和授权清单。zhifu.manage grant 可用于其 --help 列出的订单、售后和规则权限。客服、主管、客户和 SERVICE 账户按实际职责分别创建,员工邀请记录需要完成身份接入后才具备登录条件。
平台账户独立保存在 platform_accounts。由受控管理员在交互终端生成 Argon2 密码摘要:
docker compose -f compose.runtime.yaml run --rm migrate python -c "from getpass import getpass; from zhifu.modules.identity.auth import password_hasher; p=getpass('Password: '); assert 12<=len(p)<=256 and p==getpass('Confirm: '), 'Password validation failed'; print(password_hasher.hash(p))"
将输出摘要直接填入 MySQL 客户端中的首次账户登记语句,登记结果保存至受控操作记录:
INSERT INTO platform_accounts (id, username, password_hash, status, permissions, created_at)
VALUES (UUID_TO_BIN(UUID()), 'platform-admin', '替换为完整Argon2摘要',
'ACTIVE', JSON_ARRAY('platform:manage'), UTC_TIMESTAMP(6));
平台页面登记的商家初始为 PENDING,需要在受控接入流程中完成店铺、账户、渠道和权限配置,更新 tenant_registrations 为 COMPLETE 后才能通过平台启用。首次直接使用管理 CLI 创建的租户默认启用,完成配置前保持外部入口关闭。
使用项目自带 OMS 时,为每个租户与店铺准备 32–128 个字符的独立凭据,将对应变量注入运行环境。示例使用 OMS_STORE_TOKEN:
docker compose -f compose.runtime.yaml run --rm migrate-oms python -m zhifu.oms.manage --tenant $tenantId --store $storeId --credential-env OMS_STORE_TOKEN
登记平台连接器时,地址必须能从 API 和工作进程访问。本机容器地址为 http://oms:8100;生产连接器要求 HTTPS,需配置 OMS TLS 入口或使用商家授权的 HTTPS OMS:
$omsBaseUrl = Read-Host '输入应用容器可访问的 OMS 地址'
docker compose -f compose.runtime.yaml run --rm migrate python -m zhifu.modules.integrations.manage --tenant $tenantId --store $storeId --base-url $omsBaseUrl --credential-env OMS_STORE_TOKEN
仓储登记订单与确认履约完成使用单独凭据,通过 zhifu.oms.manage --fulfillment 授予对应能力。平台接入的 SERVICE 账户需要 orders:sync,通过 /internal/v1/orders/{order_id} 同步订单;来源、客户、商品明细和订单标识必须与 OMS 一致。确认与审批要求订单观察时间在最近五分钟内,接入任务应持续更新可信订单。
商家保存渠道名称与公网 HTTPS 回调地址,并确认业务授权范围。新建渠道使用 ZHIFU_CHANNEL_SIGNING_SECRET 作为出站签名凭据变量,需要注入 API 和 channel-delivery。入站签名另行登记密钥标识、协议、凭据变量与有效期;例如将独立密钥注入 API 和管理容器的 CHANNEL_INBOUND_SECRET 后执行:
$channelKeyId = Read-Host '输入入站密钥标识'
$validFrom = Read-Host '输入有效期开始时间,包含时区'
$validUntil = Read-Host '输入有效期结束时间,包含时区'
docker compose -f compose.runtime.yaml run --rm migrate python -m zhifu.operations.channel_keys --tenant $tenantId --store $storeId --key-id $channelKeyId --credential-env CHANNEL_INBOUND_SECRET --protocol zhifu-hmac --valid-from $validFrom --valid-until $validUntil
HMAC 密钥至少 32 个字符;时间使用带时区的 ISO 8601 格式,结束时间晚于开始时间。Standard Webhooks 使用 --protocol standard-webhooks,密钥为 whsec_ 加标准 Base64,解码后为 24–64 字节,每个绑定和密钥标识使用独立密钥。
配置完成后启用渠道,由客户与具有店铺 identities:verify 权限的 SERVICE 账户完成身份关联,再验证签名消息入站和结果回调。该 SERVICE 权限通过受控 store_grants 授权流程登记。接收端验证签名、时间戳和事件标识,按持久事件编号去重;渠道工作进程每组最多尝试三次,失败后通过平台查询并按需重试。
商家管理员发布换货规则、知识资料和 Agent 配置。知识发布依赖可用的 BGE 与 Milvus;Agent 发布检查模型配置、凭据和店铺配置。商品目录、订单来源及售后规则需要使用正式业务数据。
通过平台配置租户并发及 token 额度。启用金额预算时,使用 zhifu.operations.billing_access grant 为不同员工分配 billing:read、billing:request、billing:approve 中所需权限,命令要求 --tenant、--principal、--permission、--operator、--reason。费用页面入口另外需要店铺 store_grants 中的 billing:read。随后依次批准精确模型价格和每日预算,申请人不能审批自己的申请。价格使用核实过的供应商依据,金额以整数微元保存,1000000 微元为 1 元。
保留完整仓库目录,前端构建会引用 docs/design/wireframes 中的已确认样式。在 frontend 目录中为目标店铺设置参数并执行:
$env:VITE_TENANT_ID = $tenantId
$env:VITE_STORE_ID = $storeId
npm ci
npm run build
将 frontend/dist/ 内容部署到静态文件服务器,配置 HTTPS。不同店铺使用对应构建参数;构建后修改服务器环境变量不会改变已生成的静态文件。npm run preview 用于本机检查,默认端口为 18763。
入口代理需要完成以下配置:
/openapi/ 和 /admin/ 原样转发到平台 API。代理位于同一宿主机时,上游使用 127.0.0.1:28000;代理位于容器内时,加入应用网络并使用 api:8000。多副本使用 HAProxy 入口。/channel/,保留完整路径、全部签名请求头和原始请求正文。Authorization、Idempotency-Key、Last-Event-ID 和请求正文,保留服务端状态码及 Retry-After。关闭 API 响应缓存,关闭 SSE 响应缓冲,连接读取超时设置为至少 65 秒。X-Forwarded-For,使登录限流读取正确客户端地址;只信任已授权代理。/internal/ 仅向受信任的业务同步系统开放;数据库、Redis、RabbitMQ、Milvus、推理服务和 /metrics 保持内部访问。使用同一 Linux 宿主机上的 Nginx 时,将构建产物放入 /srv/zhifu/frontend,证书和私钥放入受保护目录。在 Nginx 的 http 配置范围内加入以下配置,替换域名、证书路径及上游端口:
server {
listen 80;
server_name service.example.com;
return 308 https://service.example.com$request_uri;
}
server {
listen 443 ssl;
server_name service.example.com;
ssl_certificate /etc/nginx/certs/zhifu-fullchain.pem;
ssl_certificate_key /etc/nginx/certs/zhifu-key.pem;
root /srv/zhifu/frontend;
index index.html;
location ~ ^/(openapi|admin|channel)/ {
proxy_pass http://127.0.0.1:28000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Connection "";
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 75s;
proxy_send_timeout 75s;
}
location / {
try_files $uri $uri/ =404;
}
}
此示例的 Nginx 直接接收浏览器请求;存在其他代理时,按受信网络配置客户端地址传递。渠道发送方直接使用 HTTPS 地址。通过 FORWARDED_ALLOW_IPS 向 API 容器配置受信代理的实际来源地址。证书、静态目录与配置准备完成后,在目标 Linux 主机检查并加载配置:
sudo nginx -t
sudo systemctl reload nginx
release-check。更新应用时可复用本机部署中的迁移、启动和检查命令。恢复旧应用镜像前,确认其支持当前数据库版本;数据库恢复使用已验证备份和对应恢复流程。
compose.scale.yaml 取消单个 API 的宿主机端口,通过 Docker DNS 将副本加入 HAProxy,入口端口为 28080,指标端口为 28404:
docker compose -f compose.runtime.yaml run --rm migrate python -m zhifu.operations.scale_capacity --replicas 2 --pool-size 8 --max-overflow 2
docker compose -f compose.runtime.yaml -f compose.scale.yaml config --quiet
docker compose -f compose.runtime.yaml -f compose.scale.yaml up -d --wait --scale api=2 api gateway
连接预算检查通过后执行扩容,检查参数与部署中的连接池配置保持一致。前端代理随后使用 127.0.0.1:28080。后续管理这一部署时继续同时传入两个 Compose 文件。每个 API 容器使用一个 Uvicorn 进程,网关最多发现 16 个 API 副本。连接预算要计算全部 API、工作进程、OMS、exporter 与部署任务;增加 API 副本不会自动增加供应商模型额度或 BGE 处理能力。
全部副本保持一致的 SSE 配置。多副本示例的全局 SSE 上限为 3000、每账户上限为 3,每个 API 的基础连接池为 8、额外连接上限为 2,均可通过 Compose 变量调整。Prometheus 应分别采集各个副本,不能只采集负载均衡入口。
需要调试 Python 代码时,基础服务继续使用 compose.yaml,应用进程由宿主机 uv 启动。完成 .env、.env.oms、.env.agent、模型缓存与凭据配置后执行:
uv sync --locked
docker compose up -d --wait
uv run alembic upgrade head
uv run alembic -c oms-alembic.ini upgrade head
uv run python -m zhifu.modules.knowledge.vector
下列常驻命令分别在独立终端执行:
uv run uvicorn zhifu.modules.knowledge.inference:app --host 127.0.0.1 --port 8200
uv run uvicorn zhifu.oms.api:create_app --factory --host 127.0.0.1 --port 8100
uv run uvicorn zhifu.app:create_app --factory --host 127.0.0.1 --port 18000
uv run uvicorn zhifu.monitoring.api:app --host 127.0.0.1 --port 8300
工作进程也分别使用独立终端,API、Agent 和记忆进程需要读取有效模型密钥:
uv run python -m zhifu.modules.agent_runtime.worker
uv run python -m zhifu.modules.memory.worker
uv run python -m zhifu.modules.integrations.worker
uv run python -m zhifu.modules.knowledge.maintenance
uv run python -m zhifu.modules.platform.delivery
Windows 开发使用上述模块入口;渠道投递的持续运行入口与容器工作进程共用 zhifu.operations.worker,维护运行心跳并处理停止信号。这个统一入口在 Windows 支持通过 Ctrl+C 或 Ctrl+Break 正常停止,在 Linux 容器支持 SIGTERM 和 SIGINT;停止时等待业务任务清理连接并删除本进程心跳。前端 API_TARGET 设置为 http://127.0.0.1:18000。同一数据库由选定的宿主机或容器工作进程负责处理,调试时确认实际运行的进程数量。
宿主机完整发布检查可以指定实际地址:
uv run python -m zhifu.operations.release_check --api-url http://127.0.0.1:18000 --oms-url http://127.0.0.1:8100
渠道投递进程的生命周期验收要求当前没有启用渠道和待投递记录,使用真实 MySQL 与 Redis 检查启动、停止和心跳清理。宿主机检查在 Windows 终端中发送 Ctrl+Break,容器检查发送 SIGTERM;两项检查均设置 25 秒启动期限和 10 秒停止期限:
uv run python scripts/verify_host_channel_worker.py
uv run python scripts/verify_channel_worker.py
代码、依赖和接口定义检查:
uv lock --check
uv run ruff check .
uv run ruff format --check .
uv run python scripts/export_openapi.py --check
uv run alembic check
uv run alembic -c oms-alembic.ini check
后端默认测试连接实际服务并创建业务数据,使用独立验收环境执行。停止宿主机与容器中的五类常驻工作进程,完成两套迁移,并保持平台 API 18000、OMS 8100、BGE 8200 和基础依赖运行:
docker compose --profile fault-tests up -d toxiproxy
uv run pytest -q
前端使用开发账户和真实服务执行浏览器功能测试。在 frontend 目录中安装浏览器并运行:
npx playwright install chromium
$env:PLAYWRIGHT_CHROMIUM_EXECUTABLE = node --input-type=module -e "import { chromium } from 'playwright'; console.log(chromium.executablePath())"
$env:FRONTEND_URL = 'http://127.0.0.1:18762'
npm run test:functional
npm run test:responsive
测试前准备开发账户,并更新示例订单观察时间;涉及同一账户或会话的测试顺序执行。生成模型专项、容量测试和会改变进程状态的恢复演练按对应脚本设置数量与时间上限,在独立环境执行。测试结束后恢复工作进程。
FastAPI 在 development 和 test 环境通过平台 /docs 和 /openapi.json 提供接口定义,production 环境关闭这两个入口;业务路径 /openapi/v1 继续可用。仓库同时保存四份 OpenAPI,修改接口后执行 uv run python scripts/export_openapi.py,再运行 --check 验证同步。
docker compose -f compose.runtime.yaml ps
docker compose -f compose.runtime.yaml logs --tail 100 api oms operations
docker compose -f compose.runtime.yaml stop agent memory fulfillment knowledge channel-delivery
docker compose -f compose.runtime.yaml stop api oms operations inference
docker compose stop
容器设置 75 秒停止等待,工作进程正常退出时释放连接、事务资源并删除心跳。业务任务通过租约、版本和原操作标识恢复处理。停止服务保留数据卷,日常停机使用 stop。
平台 MySQL 保存业务事实、权限、费用、会话和 Outbox;OMS MySQL 保存独立订单与履约;持久 Redis 保存记忆与协调状态;Milvus、etcd 和 MinIO 保存知识索引。镜像、模型版本、配置与凭据也需要纳入恢复资料。
仓库提供的 MySQL 与 Redis 备份工具面向本机 compose.yaml,使用宿主机开发环境执行:
uv run python scripts/mysql_recovery.py backup
uv run python scripts/redis_recovery.py backup
$mysqlBackup = Read-Host '输入 MySQL 备份命令返回的目录'
$redisBackup = Read-Host '输入 Redis 备份命令返回的目录'
uv run python scripts/mysql_recovery.py verify --directory $mysqlBackup
uv run python scripts/redis_recovery.py verify --directory $redisBackup
备份分别保存在 .work/backups/ 和 .work/redis-backups/,包含 SHA256 清单。验证使用独立恢复容器,要求保留源镜像;验证完成后删除验证容器。生产数据库使用对应环境的备份、binlog 与恢复工具,并设置加密、独立存储、访问审计和保留期限。
完整业务恢复需要关闭写入和外部调用、停止五类工作进程,选择相容的 MySQL 与 Redis 数据时间,核对授权、记忆引用、Outbox、消费收据和未完成外部操作。每个组件的独立快照只保证其自身范围的一致性。
消息核对使用 zhifu.operations.message_recovery inspect,按租户和事件 UUID 查询收据与发送状态;确认需要重放时使用 replay,保留原事件标识并登记操作人和原因。知识索引使用 zhifu.modules.knowledge.recovery,从当前发布资料重建新的 zhifu_recovery_ 集合,设置文档数、分段数和总运行时间上限,验证成功后配置目标集合并重新启动相关进程。
| 现象 | 检查内容 |
|---|---|
| Compose 提示缺少参数或 external 网络 | 检查 ZHIFU_RUNTIME_ENV、ZHIFU_MODEL_PATH 的绝对路径,以及基础网络是否已创建 |
| 运行容器访问数据库失败 | 检查容器环境文件中的服务地址、凭据和数据库名称;本机 127.0.0.1 地址只适用于宿主机进程 |
| BGE 容器启动失败 | 检查固定 revision 的模型缓存完整性、UID 10001 读取权限和可用内存 |
| 发布检查失败 | 按失败项检查两套迁移、Redis、RabbitMQ、Milvus 集合、BGE、API、OMS 与模型凭据 |
| 登录后没有菜单或查询返回 403 | 检查账户类型、租户/店铺范围和具体权限,平台使用独立账户 |
| 会话持续等待 | 检查 Agent 心跳、队列、并发额度、token/金额预算、模型配置,以及运行是否等待客户或主管操作 |
| 换货审批后无法履约 | 检查 OMS 连接器地址与凭据、订单同步时间、fulfillment 心跳和外部操作状态 |
| 页面请求失败或 SSE 消息延迟 | 检查 API 转发、状态码、SSE 缓冲与超时,以及 Authorization 和 Last-Event-ID 是否被保留 |
| Prometheus 采集失败 | 检查采集地址是否对应容器或宿主机部署方式,并清理已停用服务的发现配置 |