docs: add architecture, workflow and delivery documents

This commit is contained in:
yi
2026-09-16 19:06:19 +08:00
parent 99f6bd77b0
commit 72fc5b47c7
36 changed files with 8240 additions and 0 deletions
@@ -0,0 +1,48 @@
# DSH 内容生产执行器架构(2026-09-15)
## 1. 职责边界
工作台(FastAPI)保留管理职责:任务创建、导图录入、任务单确认、Agent/知识分类配置、启动/暂停/停止、人工审查、重试/跳过、成稿下载、运行事件与审计展示。
DSH(独立 Worker)负责执行核心内容生产流水线:导图拆解、全量生成、逐段生成、人工打回重做、失败修复重试、最终一致性总检与 docx 组合。
## 2. 后端开关
- 默认 `YAWAN_EXECUTION_BACKEND=inline`:保持原行为,由 API 后台线程执行。
- 设置 `YAWAN_EXECUTION_BACKEND=dsh`:API 只写入 `CampaignRun`/业务状态和 `TaskQueueItem`,不启动内容生产线程。
启动 DSH:
```bash
bash scripts/start_dsh.sh
# 或
cd server && YAWAN_EXECUTION_BACKEND=dsh python -m app.dsh_worker
```
当前版本要求 API 和 DSH 共享同一个 `YAWAN_DATA_DIR`(SQLite、`data/kb`、`data/chroma`、`data/artifacts`、模型缓存)。
## 3. 队列任务
DSH 只领取 `campaign-%` 前缀,避免领取 `training-map:*` 等其他后台任务:
- `campaign-run:{run_id}`:全量/逐段生成,payload 中用 `mode=full|step` 区分。
- `campaign-segment-redo:{segment_id}`:人工打回重做。
- `campaign-segment-fix:{segment_id}`:工作台先应用修复配置,DSH 再执行 pending 段。
- `campaign-parse:{campaign_id}`:导图拆解和任务单生成。
- `campaign-compose:{campaign_id}`:五项跨段一致性总检和六色 docx 成稿。
队列表具备租约、心跳、退避重试、死信和幂等键。DSH 心跳定期续租;崩溃后的过期租约会被重新领取,并把孤儿 `running` 内容段恢复成可执行状态。
## 4. 进度与状态
- DSH 的进度事件写入 `ProgressEvent`,同时保留内存事件通道。
- SSE `/api/events/progress` 和轮询接口统一通过 `progress.snapshot()` 读取内存 + SQLite 事件。
- 前端新增 `composing` 状态,成稿组合期间自动轮询,完成后展示最终文稿或一致性问题。
## 5. 运维注意
1. 生产环境先启动工作台,再启动至少一个 DSH Worker。
2. 不要让 `inline` API 和 DSH 同时执行同一套生产数据;同一环境应统一配置后端模式。
3. DSH 需要与 API 使用相同 Python 依赖、模型密钥、Provider 配置、知识库和数据目录。
4. 死信任务可在工作台运维页面重放;死信会同步补偿 Run/Campaign/Segment 状态并发送通知。
5. 未来跨机器部署时,需要把队列升级为 HTTP Job API,并共享或同步 artifacts/向量索引。
+52
View File
@@ -0,0 +1,52 @@
# Coze Studio 借鉴分析 → 私域Agent 落地清单
分析对象:github.com/coze-dev/coze-studio(字节跳动开源 AI Agent 开发平台,21.5k star,Apache-2.0)
技术栈:Go 后端(DDD 微服务 + Eino 运行时)+ React18/TS 前端(Rush monorepo + FlowGram 画布引擎)
## 一、值得借鉴的 6 个设计(按投入产出排序)
### 1. 工作流画布:节点注册表 + 表单元数据 ⭐ 最值得抄
Coze:每种节点类型一个"注册表"(type 唯一、与后端约定 schema)+ "表单元数据"(FormMeta),
画布上的节点卡只显示关键信息摘要,点击后在**侧边抽屉**里出完整配置表单;支持动态端口
(如意图识别节点按分支数动态生成输出口)。
→ 我们已有 @xyflow/react 画布。落地:
- CanvasPage 抽 `nodeRegistry.ts`:每种 Agent 角色(生产/质检/主控/组合)一份 FormMeta,
节点卡只显示「名称+标签+启停」,配置全部进右侧检查器(对齐已完成的"属性检查器"规划)
- 节点 schema 与后端 canvas_snapshot 字段一一对应(现在已是 {node_id, agent_id, enabled, x, y},加 role 即可)
### 2. 节点/工作流「试运行」(Test Run)
Coze:每个节点支持单节点调试,试运行结果条直接显示在节点卡下方。
→ 我们已有 run-step 逐段生成。落地:画布页加「▶ 试运行此节点」按钮——
选中单个 Agent 节点,用一段测试导图文本走一次该 Agent 的生成,结果展示在节点卡下(复用 SSE 进度)。
### 3. 知识库:分段策略可配置 + 命中测试分 tab
Coze:知识库建库时可选分段方式(自动/自定义分隔符/最大长度),且"命中测试"是一级入口。
→ 我们的 KB 检索测试已在详情页签里 ✓。补:建库弹窗加"分段设置"(当前固定 2200 字聚合,
放开为:自动/自定义长度/按标题切),后端 chunk.chunk_texts 已支持 target 参数,只差暴露。
### 4. 发布流:草稿 ↔ 发布版本分离
Coze:Agent/工作流有"草稿"与"发布"两态,发布时冻结配置快照,回滚=切回历史发布版本。
→ 我们有 canvas_snapshot 和 prompt_template_version 雏形。落地:Agent 加「发布」按钮,
发布时把当前配置写进 agent.runtime_snapshot 冻结;任务生成优先用快照(已有此逻辑),未发布的改动不影响在跑任务。
### 5. Chat SDK / OpenAPI
Coze:提供对话 OpenAPI 和可嵌入的 Chat SDK。
→ 远期:给吴总团队做移动端轻入口或小程序时再考虑;当前 SaaS 页面已够用。
### 6. 功能开关(Feature Flags)
Coze:bot-flags 统一管理功能灰度。
→ 我们的 qc_mode 已是任务级开关。可以再收一个全局开关面板(系统管理→功能开关):
如"允许编辑内置资源""启用跨稿质检""启用总监审核",避免改代码发版。
## 二、不建议照搬的
- Rush monorepo + 30+ packages:我们单应用 147 文件,monorepo 是过度工程
- Go 微服务 + DDD 四层:当前规模 FastAPI 单体+常驻子进程是最优解,拆微服务只会增加运维负担
- i18n:用户全是中文团队,不需要
- 数据库表资源(Coze 的 database 表):我们没有此需求
## 三、建议落地顺序(结合用户此前痛点)
1. 节点注册表+侧抽屉配置(画布体验,1 次迭代)
2. 发布/草稿版本分离(Agent 改配置不再影响在跑任务,解决真问题)
3. 分段策略可配置(KB 清洗质量的延伸)
4. 全局功能开关面板(qc_mode 之类收进去)
5. 单节点试运行(锦上添花)
+61
View File
@@ -0,0 +1,61 @@
# 微信 Bot 接入系统 AI
系统提供 `POST /api/wechat/bot/reply` 作为统一桥接接口。微信侧只负责收发消息,Agent、数字人、技能和已绑定知识库由系统处理。
## 配置
在生产服务器的 `/Users/macclaw/Desktop/yawan-workbench/.env.production` 设置(项目提供了 `.env.production.example` 模板;启动脚本和守护脚本会自动读取):
```bash
YAWAN_WECHAT_ADAPTER_URL=http://127.0.0.1:8765
```
现在使用多账号模式时不需要手动填写 Bot Secret、Agent ID 或用户 ID。创建数字人后系统会自动生成同名 Agent 并绑定;数字人审核生效后,在“数字人 → 微信 Bot 连接”中选择该 Agent 并扫码。系统会为每个账号自动生成独立密钥和凭据目录。一个数字人可以绑定多个 Agent。
接口支持时间戳 HMAC 请求头:
```text
X-WeChat-Bot-Timestamp: 当前 Unix 秒
X-WeChat-Bot-Signature: HMAC-SHA256(secret, timestamp.conversation_id.message_id.text)
```
`message_id` 用于幂等。Bot 重试同一消息时,系统会直接返回上次回复,不重复扣费。旧适配器也可暂时使用 `X-WeChat-Bot-Secret`,但新接入应升级到 HMAC。
## Wechaty 开发验证
`scripts/wechat_bot_adapter.mjs` 是可运行示例:
```bash
cd /Users/macclaw/Desktop/yawan-workbench
npm i wechaty wechaty-puppet-wechat4u
YAWAN_API_URL=https://agent.pducv.cn \
YAWAN_WECHAT_BOT_SECRET="$YAWAN_WECHAT_BOT_SECRET" \
YAWAN_WECHAT_AGENT_ID=3 \
node scripts/wechat_bot_adapter.mjs
```
个人微信的 Web/UOS 协议存在封号和兼容性风险,只建议开发测试。生产建议使用腾讯官方 [openclaw-weixin](https://github.com/Tencent/openclaw-weixin) 的 iLink Bot 通道,或企业微信/公众号官方回调;这些适配器只需把收到的文本按同样 JSON 调用本接口,再将 `reply` 发回微信。
## 官方 iLink 多账号 sidecar
项目还提供 `scripts/wechat_ilink_sidecar.mjs`,使用 CoreSpeed 的官方 iLink SDK 管理多个账号。启动:
```bash
cd /Users/macclaw/Desktop/yawan-workbench
npm i @wechatbot/wechatbot
YAWAN_API_URL=https://agent.pducv.cn \
YAWAN_WECHAT_SIDECAR_PORT=8765 \
/opt/homebrew/opt/node@22/bin/node scripts/wechat_ilink_sidecar.mjs
```
`@wechatbot/wechatbot` 要求 Node.js 22 或更高版本;macOS/Homebrew 环境请使用上面的 Node 22 路径,或将 Node 22 放在 `PATH` 首位。
然后在 API 服务环境设置 `YAWAN_WECHAT_ADAPTER_URL=http://127.0.0.1:8765`。数字人页面点击“微信 Bot 连接”即可生成官方二维码;每个账号使用独立密钥、独立凭证目录和独立会话,只能调用自己绑定且有权限的 Agent。
请求示例:
```json
{"agent_id":3,"conversation_id":"wx-room-or-user-id","message_id":"msg-001","text":"你好,帮我介绍一下课程"}
```
系统会保留会话上下文,并把 Agent 的数字人规则、已挂接技能和知识库相关片段用于本轮回答。知识库检索失败时会记录日志并继续普通对话,避免微信侧卡死。
@@ -0,0 +1,183 @@
# 知识图谱检索升级方案
## 目标
解决训练营导图和内容任务在大知识库下的三个问题:
1. 不把全库原文一次性放进模型上下文;
2. 检索既快又能覆盖概念之间的关系;
3. 图谱、向量库或模型异常时仍能稳定生成并保留原文证据。
目标指标:
- 热态知识检索 P95:250ms 以内;
- 首次冷启动检索:2 秒以内;
- 内容任务最终注入:按 4,000~8,000 token 预算动态决定,不固定条数;
- 训练营标准深度规划:10~30 分钟,超过硬截止时间必须保存阶段性结果;
- 每个结论都能回溯到原始 chunk、文件和版本;
- 图谱服务异常时自动回退到现有向量 + 中文 FTS + RRF + Cross-Encoder 链路。
## 总体架构
```text
上传与索引
├─ 原始文件、chunk、哈希和版本
├─ 向量索引
├─ 中文 FTS 索引
├─ 分层底稿(文件级、分类级、知识库级)
└─ 知识图谱(实体、关系、证据、版本)
用户查询
→ 权限和分类过滤
→ 查询理解(实体、概念、约束、目标)
→ 图谱 1~2 跳关系扩展
→ 图谱证据指向的原文 + 向量/FTS 候选召回
→ 去重与主题覆盖
→ Cross-Encoder 精排
→ 父级上下文扩展
→ token 预算注入模型
→ 生成、质检、引用回溯
```
图谱是“导航和关系路由层”,原始 chunk 是“事实证据层”。任何图谱节点和关系都必须保存来源 chunk,不允许只凭图谱结论生成内容。
## 图谱数据设计
### 实体
实体至少包括:主题、概念、方法、步骤、人物、产品、风险、适用人群、工具、章节和课程天数。每个实体保存:
- `entity_id`、组织和知识库范围;
- 规范名称、别名、类型;
- `canonical_hash`、首次出现和最后更新时间;
- 抽取模型、抽取版本和置信度;
- 对应的来源 chunk 数量。
### 关系
关系采用有向边,例如:先决条件、组成、步骤先后、适用、反例、风险、冲突、相似、引用、属于分类。每条边保存:
- `from_entity_id`、`to_entity_id`、关系类型;
- 权重和置信度;
- `source_chunk_ids`、文件、版本;
- 抽取版本、创建时间和失效时间。
### 版本与权限
图谱实体、关系和证据都必须带组织、知识库、文件版本和分类范围。查询先做权限过滤再做图扩展,不能先查全图再过滤,否则会有越权风险。
## 建图流程
### 上传时增量建图
1. 文件解析、清洗、去重和分块;
2. 根据 `content_hash + chunking_version` 判断是否已有处理结果;
3. 只对新增或发生变化的文件抽取实体和关系;
4. 对别名和同义实体做规范化合并;
5. 写入关系及来源 chunk;
6. 让受影响的分类综述和知识库总览失效;
7. 后台重新生成受影响的摘要和图谱局部;
8. 发布新的图谱版本,旧版本仍可回溯。
图谱建立使用幂等任务、租约、断点游标和阶段性进度。单文件失败不会阻塞整库,也不会把未完成状态标成完成。
### 抽取策略
- 规则抽取:标题、列表、编号、术语表、明显步骤和引用关系优先用本地规则完成;
- 模型抽取:只对规则无法判断的实体和关系做批量 AI 抽取;
- 冲突处理:保留两条关系和各自来源,标记为冲突,交给查询阶段核验;
- 低置信关系:只能用于召回扩展,不能单独作为最终证据;
- 关系重复:按规范化实体、关系类型、来源版本去重。
## 训练营导图检索
### 快速模式
1. 解析主题和用户选择的知识库/分类;
2. 图谱定位相关主题、先决条件、步骤链和冲突点;
3. 以图谱命中的实体和来源 chunk 作为定向查询词;
4. 并行执行向量和中文 FTS 召回;
5. 按知识库、分类和主题做配额,避免大库占满结果;
6. RRF 融合、去重和多样性筛选;
7. Cross-Encoder 对最多 32~64 个候选精排;
8. 回溯代表性原文,按 token 预算交给导图模型。
快速模式不再声称通读全库,返回检索范围、图谱覆盖主题和未覆盖主题。
### 标准/深度模式
1. 先读知识库级和分类级底稿;
2. 从图谱确定相关主题簇、依赖链和冲突区域;
3. 只对相关文件和代表性资料定点回查原文;
4. 对关键缺口和冲突做二次检索;
5. 生成导图和每日递进关系;
6. 保存覆盖范围、引用、未完成主题和可续跑游标。
完整模式不再按 30 万段原文逐批重新交给模型。摘要和图谱按内容哈希增量复用,只有新增、变化或被主题路由命中的区域需要处理。
## 内容任务 Agent 检索
1. 由导图节点、标题、标签、产品和上一段锚点生成查询;
2. 图谱扩展相关概念、步骤、风险和先决条件;
3. 向量 + FTS 初召回 30~60 条;
4. 权限、分类、禁用和消费状态过滤;
5. RRF 融合和近重复去重;
6. Cross-Encoder 精排 16~32 条;
7. 命中 child chunk 后合并同一 parent 的相邻内容;
8. 按 4,000~8,000 token 预算动态注入 6~12 条或更少/更多的来源;
9. 只预留真正注入的片段,生成成功后再标记 consumed;
10. 生成后记录引用、锚点和图谱关系,供下一段承接。
“已读/已摘要”和“已消费”必须保持独立状态。预读不会占用内容任务的消费额度。
## 存储选型
第一阶段保留现有本地向量和 FTS 架构,在业务数据库增加图谱索引或独立的图谱表,先验证质量和延迟。当前不建议为了图谱立即迁移 Qdrant 或 Neo4j,避免在检索质量尚未有评测数据时增加运维单点。
当图谱边和实体规模、并发写入或多租户查询超过本地数据库能力时,再将图谱迁移到 Neo4j/ Memgraph 或 PostgreSQL 图扩展;迁移必须保留 `source_chunk_ids`、版本和权限字段,并提供只读回退。
向量库迁移到 Qdrant只在以下条件满足时进行:现有向量召回 P95 持续超标、索引更新阻塞检索、或需要多副本高并发。迁移前先用同一批标注问题做 Recall@10、MRR、NDCG 和 P95 对比。
## 稳定性和降级
- 图谱不可用:回退向量 + FTS + RRF;
- Cross-Encoder 未加载:回退 RRF;
- FTS 索引预热中:先返回向量召回并标记状态;
- AI 抽取超时:保留原文和已完成图谱,任务可续跑;
- 生成超时:保存阶段结果、游标、费用和未完成主题;
- 所有后台任务采用原子租约、唯一执行键和幂等写入;
- 生产环境不把图谱构建放在 FastAPI 请求线程。
## 验收方法
建立 100~300 条人工标注问题,覆盖主题、步骤、先决条件、冲突和跨文件关系。比较改造前后:
- Recall@10、MRR、NDCG;
- 内容段质检通过率、事实错误率、重复率;
- 来源可追溯率;
- 热态和冷态 P50/P95;
- 图谱不可用时的回退成功率;
- 增量上传后受影响范围是否正确;
- 跨用户、跨组织和分类权限隔离。
## 实施顺序
### P0:观测和基准
保留当前稳定链路,记录候选数量、过滤数量、精排数量、注入 token、引用数量和各阶段耗时,建立标注集。
### P1:图谱增量底座
加入实体、关系、证据、版本和抽取任务;先从标题、术语、步骤和引用关系开始,建立局部图谱和来源回溯。
### P2:图谱路由接入
训练营导图先用图谱定位主题簇和依赖链,再定点回查;内容任务先用图谱补充查询,再走混合召回。
### P3:精排与上下文扩展
启用已部署的本地 Cross-Encoder,接入 parent-child 上下文和 token 预算,做 A/B 评测后调整候选数。
### P4:规模化
只有当指标证明当前本地架构成为瓶颈时,再迁移 Qdrant 或独立图数据库,并保留降级路径。
@@ -0,0 +1,407 @@
# 私域 Agent 内容生产工作台:系统整体架构与功能检查文档
> 文档用途:给产品、运营、测试和维护人员逐项核对当前系统。内容依据 `/server/app`、`/web/src` 和启动脚本整理,描述的是代码已经实现或明确配置的行为;“待确认”项需要在实际环境中验收。本文不包含管理员密码、API 密钥等敏感信息。
>
> 代码位置:`server/app/main.py`(FastAPI 路由)、`server/app/models.py`(SQLModel 数据模型)、`server/app/agents`(Agent Runtime)、`server/app/rag`(知识库检索)、`web/src`(React 前端)。
## 1. 系统边界和运行拓扑
系统是一个单组织、本地持久化、可通过公网隧道访问的内容生产工作台。浏览器只访问 React 单页应用;前端通过 `/api` 调用 FastAPI;FastAPI 使用 SQLite 保存业务状态,知识库源文件和产物保存在数据目录,向量索引由 RAG 子系统维护。微信 iLink 连接由独立 Node sidecar 持有账号凭据,主 API 只保存哈希和引用。
```mermaid
flowchart LR
U[浏览器用户] -->|HTTPS / HashRouter| W[React 工作台]
W -->|/api + 会话令牌| A[FastAPI main.py]
A --> DB[(SQLite workspace.db)]
A --> FS[(data/ kb artifacts ocr models)]
A --> R[RAG pipeline]
R --> V[(向量/全文索引)]
A --> RT[Agent Runtime]
RT --> LLM[Provider / 模型]
A --> Q[持久任务队列]
A --> I[进度 SSE / 轮询]
I --> W
S[wechat_ilink_sidecar.mjs] -->|本机 127.0.0.1:8765| A
S --> WX[官方 iLink 微信协议]
CF[cloudflared / ngrok] --> A
```
### 1.1 进程与端口
| 进程 | 作用 | 默认地址/端口 | 主要数据/日志 |
|---|---|---|---|
| FastAPI + Uvicorn | 认证、业务 API、任务调度和后台线程 | 开发 `8011`;生产 `8010` | `/tmp/yawan-uvicorn.log`;生产 `server/data` |
| React/Vite | 开发预览;生产构建后的静态文件由现有部署方式提供 | 开发通常 `5173` | `web/dist` |
| 微信 iLink sidecar | 多账号扫码、收发微信消息、状态回调 | `127.0.0.1:8765` | `/tmp/yawan-wechat-sidecar.log`;按账号隔离的 storage |
| cloudflared/ngrok | 把生产 API/前端暴露到公网 | 隧道地址 | `/tmp/yawan-cloudflared.log`、`/tmp/yawan-ngrok.log` |
### 1.2 环境与存储
- `YAWAN_ENV=dev` 使用 `server/data-dev`;默认或 `prod` 使用 `server/data`。
- `YAWAN_DATA_DIR` 可指定绝对路径,把 `workspace.db`、`kb/`、`artifacts/`、`ocr/`、`models/`、`chroma/` 等整体迁移到外接硬盘。
- `YAWAN_CORS_ORIGINS` 控制允许的前端来源;生产默认包含 `https://agent.pducv.cn`。
- `DB_PATH`、`KB_DIR`、`ARTIFACTS_DIR`、`OCR_DIR`、`MODELS_DIR` 在 `server/app/config.py` 根据环境动态创建。
- 启动时 `init_db()` 建表、执行兼容迁移、恢复未完成的知识片段预留、对账物理文件与索引,并将空质检报告标记为需复检。
## 2. 用户端功能地图
侧栏由 `web/src/shell.tsx` 的 `navFor()` 根据权限生成;隐藏侧栏只是第一层保护,`AppRouter.tsx` 的 `FeatureGate` 和后端中间件还会再次校验。训练营导图已经作为内容任务入口的兼容路由保留;技能库和记忆库作为 Agent 与技能页签;标签作为知识库页签。
| 功能栏 | 页面/路由 | 主要能力 | 主要权限 |
|---|---|---|---|
| 总览 | `/admin/overview` | 状态、自检、快捷入口、通知 | `read` |
| 内容任务 | `/admin/tasks`、`/admin/tasks/:id` | 建任务、导图拆解、逐段生成、质检、组合和交付 | `feature:tasks`、`tasks:*` |
| 运行记录 | `/admin/runs` | 运行状态、事件、工具审批、失败恢复 | `feature:runs`、`runs:read` |
| 操作日志 | `/admin/audit-logs` | 用户动作审计 | `feature:audit`、`audit:read` |
| Agent 与技能 | `/admin/agents`,`?tab=skills|memories` | Agent、技能、记忆、模型工具、数字人身份配置 | `feature:agents`、`agents:*` |
| 数字人 | `/admin/digital-humans` | 文档蒸馏、测试、反馈、版本、授权、微信 Bot | `feature:digital-humans`、`digital_humans:read` |
| 画布编排 | `/admin/flows` | 节点、边、波次、总监模式、授权 | `feature:flows`、`flows:read` |
| 知识库 | `/admin/knowledge` | 建库、上传、去重、分类、预览、检索、消费记录 | `feature:knowledge`、`kb:*` |
| 模型管理 | `/admin/settings/providers` | Provider、模型目录、默认模型、连接测试 | `feature:models`、`providers:*` |
| 用量分析 | `/admin/settings/usage` | 用量事件、余额、点数发放、配额 | `feature:usage`、`usage:read`、`billing:manage` |
| 系统日志 | `/admin/system-logs` | HTTP/应用/任务错误和 Trace | `feature:system-logs`、`system_logs:read` |
| 访问控制 | `/admin/settings/access` | 成员、角色、资源授权、全局发布、版本审核 | `feature:access`、`roles/users/audit:manage` |
| 功能开关 | `/admin/settings/flags` | 读取和修改应用功能开关 | `feature:flags`、`flags:read` |
| 运营看板 | `/admin/ops` | 指标、告警、备份、死信队列 | `feature:ops`、`ops:*` |
| 操作手册 | `/admin/manual` | 面向普通用户的使用说明 | 登录后可见 |
## 3. 认证、组织和权限模型
### 3.1 登录链路
1. `GET /api/auth/status` 检查是否需要首次初始化。
2. 首次使用 `POST /api/auth/bootstrap` 创建管理员;之后使用 `POST /api/auth/login`。
3. 服务端生成不透明会话令牌,数据库只保存 SHA-256 哈希(`AuthSession`),默认有效期 12 小时。
4. 浏览器把令牌放入 API 请求的 `Authorization` 头;退出调用 `POST /api/auth/logout` 撤销会话。
5. `GET /api/auth/me` 返回当前用户、角色、组织和权限,前端据此渲染页面。
### 3.2 内置角色
- **管理员 admin**:`*` 全部权限,仍受组织边界约束。
- **编辑 editor**:内容任务、Agent/画布、知识库、数字人查看、运行和日志等日常生产权限。
- **审查 reviewer**:查看和审查任务、知识库、记忆,不含配置和生产写入权限。
- **只读 viewer**:只能查看被允许的知识库内容。
角色存储在 `AppUser.role`,可维护的角色集合存储在 `RoleDefinition.permissions`。权限目录按“内容生产、资产与知识、数据与洞察、系统管理”等抽屉分组,仅改变展示方式,不改变已保存 key。
### 3.3 访问判定顺序
1. HTTP 中间件确认 `/api` 请求已认证;微信回调为特例,必须在接口内用账号密钥校验。
2. `required_permission()` 校验方法和路径所需操作权限。
3. `feature_permissions()` 校验功能栏权限。
4. 资源访问函数(`require_kb`、`require_skill`、`require_canvas`、`require_memory` 等)校验组织、所有者、可见性和成员授权。
5. 组织 ID:`0` 表示全局资源;正整数表示租户。数据库迁移会添加索引和触发器,阻止非法组织值落库。
### 3.4 可见性和授权
资源具有 `private/shared/global` 三种可见性。所有者可以管理自己的资源;共享资源通过 `*Grant` 表按 `read/use/manage/export` 授权;全局资源对普通用户只允许查看和使用,不能导出或修改全局本体。普通用户对全局资源的修改/删除写入 `ResourceRevision`,管理员审核后才合并。`ResourceFork` 记录个人副本与全局源的版本基线。
## 4. 数据模型和绑定关系
### 4.1 核心实体
| 实体 | 表 | 关键字段/职责 |
|---|---|---|
| 组织 | `Organization` | 租户名称、slug、启用状态 |
| 用户/角色/会话 | `AppUser`、`RoleDefinition`、`AuthSession` | 本地账号、PBKDF2 密码摘要、RBAC、可撤销登录 |
| Agent | `Agent` | 角色类型、标签、知识库 ID/分类、融合 Agent、模型、工具、规则、数字人、发布快照 |
| 技能 | `AgentSkill`、`AgentSkillBinding`、`AgentSkillGrant` | 技能指令、版本、挂载 Agent、成员授权 |
| 数字人 | `DigitalHuman`、`DigitalHumanGrant` | 十一维人格档案、蒸馏元数据、版本、来源文件和授权 |
| 微信账号 | `WeChatBotAccount` | 所有者、组织、Agent、状态、二维码、凭据哈希/引用 |
| 画布 | `Canvas`、`CanvasGrant` | 节点 Agent、边、总监 Agent/模式、授权 |
| 知识库 | `KnowledgeBase` | 源目录、索引状态、文件/片段计数、分段策略、所有权 |
| 分类/文件 | `KnowledgeCategory`、`KnowledgeFile` | 无限层级分类、AI 推荐分类、文件哈希和 revision |
| 消费记录 | `KnowledgeUsage` | Agent+知识库+片段唯一锁、引用、状态、禁用标记 |
| 任务/内容段 | `Campaign`、`Segment` | 导图原文、画布快照、段级 Agent、状态、锚点、引用、历史版本 |
| 质检/产物 | `QCReport`、`Artifact` | 结构/内容/风格/跨稿质检,组合成稿和下载预览 |
| 运行 | `CampaignRun`、`RunEvent`、`AgentSession`、`TaskQueueItem` | 可恢复执行、进度事件、工具调用会话、租约/重试/死信 |
| AI 用量 | `LLMCall`、`UsageEvent`、`PointAccount`、`PointTransaction`、`UsageQuota` | 调用追踪、不可变计量、余额流水和配额 |
| 日志/通知/记忆 | `AuditLog`、`SystemLog`、`Notification`、`PendingMemory`、`Memory` | 用户动作、系统故障、待读提醒、Agent 长期记忆 |
| 版本提案 | `ResourceRevision`、`ResourceFork` | 全局资源个人修改、删除提案及冲突基线 |
### 4.2 绑定关系(当前代码语义)
```mermaid
erDiagram
APP_USER ||--o{ AGENT : owns
APP_USER ||--o{ KNOWLEDGE_BASE : owns
APP_USER ||--o{ DIGITAL_HUMAN : owns
AGENT }o--o{ AGENT_SKILL : mounts
AGENT }o--o{ KNOWLEDGE_BASE : reads
AGENT }o--o{ AGENT : fusion
AGENT }o--|| DIGITAL_HUMAN : identity
CANVAS }o--o{ AGENT : nodes
CAMPAIGN }o--|| CANVAS : snapshot
CAMPAIGN ||--o{ SEGMENT : contains
SEGMENT }o--|| AGENT : assigned
SEGMENT }o--o{ KNOWLEDGE_BASE : consumes
AGENT ||--o{ MEMORY : accumulates
CAMPAIGN_RUN ||--o{ RUN_EVENT : emits
CAMPAIGN_RUN ||--o{ AGENT_SESSION : resumes
LLM_CALL ||--o| USAGE_EVENT : measured
```
- **Agent→知识库**:`Agent.kb_ids` 和 `kb_category_ids` 保存挂接及分类范围;任务创建时运行快照冻结,生成时不读取后来新增的未授权库。
- **Agent→技能**:`AgentSkillBinding` 多对多;任务快照记录技能指令。
- **Agent→数字人**:`Agent.digital_human_id` 绑定身份;运行时数字人人格优先于 Agent 的 `persona_json`。
- **Agent→记忆**:`Memory.agent_id` 归属 Agent;记忆候选按用户、组织、画布范围过滤并冻结到运行快照。
- **画布→Agent/知识/记忆**:画布节点保存 Agent;画布授权只连带允许依赖资源的读/用,不放大编辑、删除、导出权限。
- **内容任务→画布**:`Campaign.canvas_snapshot` 是创建时快照,之后修改画布不会改变历史任务。
- **知识库消费隔离**:`KnowledgeUsage` 唯一约束为 `(agent_id,kb_id,chunk_id)`,不同 Agent 的消费互不锁定;`banned=true` 的片段永久排除检索。
- **微信账号→Agent**:一个 `WeChatBotAccount.agent_id` 绑定一个 Agent;sidecar 收到消息时把账号 ID、Agent ID、会话 ID 一并回传,后端再次校验所有权和授权。
## 5. Agent 与技能工作区
### 5.1 Agent 配置
可创建、编辑、停用、发布和删除非内置 Agent。职责类型代码为 `production`、`training_map`、`qc`、`service`、`coordinator`、`composer`。生产 Agent 可配置内容标签和融合 Agent;知识库可以限定到分类;模型可跟随全局默认或指定 Provider/目录模型;`allowed_tools` 控制 Runtime 工具。
发布接口 `POST /api/agents/{id}/publish` 调用快照冻结逻辑,将规则、模型、技能、知识边界和记忆候选固化到 `runtime_snapshot`。任务创建又会把该快照复制到 `Segment.runtime_snapshot`,保证生成中途修改配置不会改变本次任务。
### 5.2 技能和记忆
技能支持 Markdown 导入(`POST /api/skills/import`)、版本和 Agent 多选挂载;技能自身可以按成员授权。记忆分为 L1 规则、L2 纠错、L3 偏好、L4 成功等层级,先进入 `PendingMemory`,审批后写入 `Memory`。Runtime 在模型真正调用前记录注入记忆的次数,避免恢复会话重复计量。
### 5.3 删除与绑定检查(现状和验收点)
当前删除接口会先检查引用关系:被画布节点、融合 Agent、历史任务或其他资源引用的 Agent/技能/知识库/记忆/数字人可能被拒绝删除,前端会提示先解绑。产品要求“弹出一键解绑所有后再删除”时,验收应确保:
- 明确列出将解除的绑定(Agent、技能、画布节点、知识库分类、数字人、记忆、微信账号等)。
- 一键操作在同一事务或可恢复事务中完成;失败不得留下半解绑状态。
- 历史任务的快照、日志、质检和账单保留,不因删除配置而丢失。
- 全局资源的普通用户操作仍只能建立个人 `ResourceRevision`,不能直接解绑全局本体。
- 删除微信账号先停止 sidecar 实例、清理二维码和凭据引用,再删除数据库记录。
## 6. 数字人蒸馏和微信 iLink
### 6.1 蒸馏流程
1. `POST /api/digital-humans/distill` 上传或选择文档,服务端抽取代表性样本。
2. `_dh_distill()` 生成 `persona` 与 `persona_meta`,记录来源文件、覆盖范围和不确定性,状态为 `testing` 或 `distilling`。
3. `POST /api/digital-humans/{id}/test-write` 进行人工试写;`/redistill` 根据反馈提升版本号。
4. 补充素材通过 `/redistill` 上传并生成待测试新版本;微信对话不会自动写入数字人人格。
5. 创建数字人时自动生成同名默认 Agent 并绑定;后续可继续创建多个 Agent 绑定同一数字人,运行时把人格档案合并进系统提示。
### 6.2 iLink 账号流程
- 前端数字人页调用 `POST /api/wechat/bot/accounts/connect`,后端生成账号级密钥(只保存哈希)并转发到 `YAWAN_WECHAT_ADAPTER_URL`。
- sidecar 使用 `@wechatbot/wechatbot`、Node 22 和每账号独立 storage 目录;登录回调把 `pending_qr`、`connected`、`error`、`disconnected` 和二维码状态回传 API。
- 微信消息签名为 HMAC-SHA256,后端验证时间戳、账号密钥、账号状态、Agent 绑定、组织和所有者;会话按账号/用户/Agent 隔离。
- 删除调用 `DELETE /api/wechat/bot/accounts/{id}`,sidecar 停止对应 Bot 并回调断开。
- 生产环境需要 `.env.production` 中的 `YAWAN_WECHAT_ADAPTER_URL=http://127.0.0.1:8765`,并由 `守护隧道.sh` 检查 8765 端口自动拉起。
## 7. 知识库、索引和检索
### 7.1 导入链路
支持 `.doc/.docx/.srt/.md/.txt/.json/.jsonl/.pdf` 以及音视频转写后索引。大文件走 `uploads/init`、分片上传、`uploads/{id}/finish`;目录导入走 `import-folder`。文件落盘后计算 `content_hash`,同内容文件跳过,重复片段在索引阶段去重。`KnowledgeFile.revision` 在同名内容变化时递增。
```text
上传/分片 → 文件哈希和去重 → 文本解析或媒体转写 → 分段
→ Embedding → 向量/全文索引 → 后台预热 → ready
```
`index_status`:`empty`、`indexing`、`ready`、`needs_reindex`、`error`。启动对账会比较磁盘文件、文件表和向量计数;不会因为对账自动重建大库。
### 7.2 分类和预览
`KnowledgeCategory` 为无限层级树;文件同时保存人工分类 `category_id` 和 AI 建议 `ai_category_id`、置信度、理由。`POST /api/kbs/{kid}/classify` 批量推荐,`.../classification/confirm` 人工确认。知识库页签提供文件、分类、检索测试、消费记录和设置;文件查看走预览接口,管理员可查看全部消费记录,普通用户只返回自己有权看到的记录。
### 7.3 检索模式
- **full**:选定知识库/分类的全部已索引资料分批阅读/检索,时间和用量较高。
- **quick**:按查询相关性召回,适合快速生成。
- **reuse**:复用已阅读缓存,减少重复解析和模型调用。
RAG 管道包含查询校验、Embedding、召回、去重、消费锁和后处理,并记录阶段耗时和缓存命中率;`/api/kbs/{kid}/search` 和 `/api/kbs/search` 提供检索测试。知识片段消费状态为 `reserved`、`consumed`、`available`,进程启动会归还中断留下的 `reserved`。
## 8. 内容任务和训练营导图
### 8.1 创建和拆解
`POST /api/campaigns` 创建任务并保存导图文本、所选画布快照、知识库范围和 Agent;`POST /api/campaigns/{cid}/parse` 调用 coordinator 将导图拆为 `Segment`。每段包含节点、标题、时间范围、标签、指定 Agent、知识分类限制和运行快照。拆解失败可由 `POST /api/campaigns/{cid}/reparse` 重新拆解。
训练营导图 API 位于 `server/app/training_map.py`,核心输入包括主题、至少一个知识库、可选分类、天数和 Agent。严格模型校验:天数连续、节点标题和叶子内容去重、每个叶子必须有证据来源;导图节点只保留框架短语,详细正文在内容任务生成。导图建议支持整套方案、单天、单日导图和全部导图修改,生成阶段支持进度事件。
全库评估采用分层摘要:原始片段按库分批阅读并递归归并;同一组织、用户、主题、知识库/分类范围及模型签名下,完全相同批次会写入 `training-corpus/summary-cache.sqlite`,后续草稿或重试可增量复用,缓存使用 WAL、忙等待和单批次文件锁避免并发重复调用。通用全文预读仍使用按知识库隔离的 `training-knowledge` 清单;两类缓存均不写入 `KnowledgeUsage` 消费账本。
### 8.2 连续生成和跳过
任务运行使用 `CampaignRun`、`Segment.status` 和锚点卡:上游段产出 `anchor_card`,下游只接收摘要和最后确认段结尾,避免重复全文。跳过段会被记录为 `skipped`,后续段不能假设用户已经学会该前置知识,需要补足最小前提。段状态包括 `pending/running/qc/human_review/approved/rework/failed/skipped`。
逐段操作接口:
- `POST /api/campaigns/{cid}/segments/{sid}`:新增段。
- `PUT /api/campaigns/{cid}/segments/{sid}`:修改 Agent、分类或正文。
- `DELETE /api/campaigns/{cid}/segments/{sid}`:删除段。
- `POST /api/segments/{sid}/review`:通过、打回或跳过。
- `POST /api/segments/{sid}/fix`:提交修改意见并重新生成。
- `POST /api/campaigns/{cid}/run-step`:运行下一步。
- `POST /api/campaigns/{cid}/run`:启动完整流水线;支持暂停、取消、恢复。
### 8.3 质检、组合和交付
质检门包括 `structure`、`content`、`style`、`cross`;报告存放在 `QCReport`,空检查列表在启动迁移时自动标记 FAIL。全部段通过后 `POST /api/campaigns/{cid}/compose` 生成 `Artifact`,支持预览和下载。运行期间每次模型调用都关联 `trace_id`、Agent、段、Provider、模型和用量事件。
## 9. Agent Runtime、工具和 AI 调用
Runtime 的系统工具:`knowledge_search`、`read_upstream_anchors`、`read_agent_memory`、`request_handoff`;联网工具 `web_search`、`web_collect` 默认关闭,启用后需人工审批。每个 `AgentSession` 保存消息、工具状态、轮次、阶段和结果,可从检查点恢复;每个运行共享 240 轮模型预算,耗尽即停止并写入事件。
每次调用的记录路径:
```text
AgentSession → RuntimeContext → LLMCall → UsageEvent → PointTransaction(如结算)
↘ RunEvent / Trace / SystemLog
```
模型选择:Agent 可指定 `model_provider_id/model_catalog_id/model_name`,否则跟随 `/api/settings/model-default`。Provider 通过 `/api/providers` 管理,支持连接测试、发现模型、刷新目录和删除;密钥来自配置或本地密钥存储,错误响应经过脱敏处理。
## 10. 日志、追踪、通知和用量
### 10.1 日志
- **AuditLog 操作日志**:记录用户、动作、资源、结果;不记录请求正文、令牌和密钥。典型动作包括登录、建库、上传、建 Agent、改权限、生成任务等。
- **SystemLog 系统日志**:记录 HTTP 失败、应用错误、任务失败、RAG/队列异常和 Trace;错误处理中间件会把具体 `detail` 写入日志。级别支持 `INFO/WARNING/ERROR`,前端可按来源、状态和时间查看。
- **RunEvent/LLMCall**:运行级工具调用、Agent、模型、重试、耗时和失败原因;用于运行记录和 Trace 详情。
接口:`/api/audit-logs`、`/api/system-logs`、`/api/llm_calls`、`/api/traces`、`/api/traces/{trace_id}`。
### 10.2 通知和进度
`Notification` 记录失败、待审查、记忆待确认等提醒;`GET /api/notifications`、`POST /api/notifications/{id}/read`、`POST /api/notifications/read-all` 支持单条和一键已读。生成进度由 `/api/events/progress`(SSE)和 `/api/events/progress-poll`(轮询)提供,前端 `ProgressToast` 显示 AI 工作阶段。
### 10.3 用量和点数
`UsageEvent` 是追加式计量账本,服务类型包括 `llm/embedding/ocr/storage/export/rerank`,具备幂等键、价格版本、输入输出数量和金额分。`PointAccount` 保存余额,`PointTransaction` 保存充值/扣费/调整流水,`UsageQuota` 保存每日/月度 token、金额、存储和并发限制。用户端 `/api/me/usage`、`/api/points/me` 只返回本人;管理员端 `/api/admin/usage/*` 和 `/api/admin/points/*` 可按用户/组织汇总和发放。
## 11. 任务队列、可靠性和恢复
`TaskQueueItem` 提供幂等 `task_key`、租约、重试退避和死信状态。`CampaignRun` 的 `checkpoint`、`pause_requested`、`cancel_requested` 支持服务重启后恢复。后台线程负责运行任务、索引、预热和告警;进程启动会回收未完成的知识消费预留和历史异常质检。
运营接口包括:
- `GET /api/ops/dashboard`:健康指标。
- `POST /api/ops/alerts/sweep`:扫描告警。
- `POST /api/ops/dead-letter/{task_id}/requeue`:死信重放。
- `GET/POST /api/ops/backup`、`POST /api/ops/backup/drill`:备份和恢复演练。
- `GET /api/system/status`、`GET /api/health`:API、RAG、队列等状态检查。
## 12. 管理员资源发布和版本审核
管理员资源页按 Agent、技能、知识库、画布、数字人、记忆分别查看授权。对应接口提供成员 grant、撤销、发布全局和导出。普通用户编辑全局资源时,后端创建 `ResourceRevision(operation=update/delete)` 和必要的 `ResourceFork`;管理员通过 `/api/admin/resource-revisions/{id}/approve` 或 `reject` 审核。审核批准后才改变全局资源版本,个人删除只隐藏自己的视图,不影响其他用户。
## 13. API 分组速查
### 认证与管理
`/auth/status`、`/auth/bootstrap`、`/auth/login`、`/auth/logout`、`/auth/me`、`/auth/users`、`/auth/roles`;管理员资源授权集中在 `/admin/{agents,skills,knowledge-bases,canvases,digital-humans,memories}`。
### Agent、技能、数字人和画布
`/agents`、`/agents/{id}/publish`、`/agents/{id}/fork`、`/skills`、`/skills/import`、`/skills/{id}/agents`、`/digital-humans/*`、`/canvases`、`/canvases/{id}/fork`。
### 知识库和上传
`/kbs`、`/kbs/{id}`、`/kbs/{id}/categories`、`/kbs/{id}/files/*`、`/kbs/{id}/classify`、`/kbs/{id}/search`、`/kbs/search`、`/uploads/init`、`/uploads/{id}/chunk/{index}`、`/uploads/{id}/finish`、`/kbs/{id}/import`、`/kbs/{id}/rebuild`。
### 任务与运行
`/campaigns`、`/campaigns/{id}/parse`、`/campaigns/{id}/reparse`、`/campaigns/{id}/segments/*`、`/campaigns/{id}/run`、`/runs/{id}`、`/agent-sessions/{id}`、`/segments/{id}/review`、`/segments/{id}/fix`、`/campaigns/{id}/compose`、`/artifacts/{id}/preview`。
### 微信
`/wechat/bot/accounts`(列表、连接、更新、绑定 Agent、删除)、`/wechat/bot/accounts/{id}/callback`(sidecar 状态回调)、`/wechat/bot/reply`(签名消息转发)。
## 14. 从用户角度的标准操作链
1. 登录后在“模型管理”确认可用 Provider 和默认模型。
2. 在“知识库”建库,上传文件/目录,等待索引状态为“就绪”;必要时执行去重、分类和预览。
3. 在“Agent 与技能”创建 Agent,选择职责、挂接知识库/分类、技能、模型和数字人,保存并发布。
4. 在“画布编排”用节点和连线编排 Agent;检查每个节点是否有唯一 Agent 和有效知识范围。
5. 在“内容任务”粘贴训练营导图/框架,选择画布和知识范围,创建任务并拆解;若失败使用“重新拆解”。
6. 查看每个内容段的 Agent、知识引用和锚点;可更换 Agent、修改分类、生成、质检、通过/打回/跳过。
7. 全部段通过后组合成稿,在预览页面复核并下载交付。
8. 需要微信服务时,在“数字人 → 微信 Bot 连接”选择已配置 Agent,生成二维码,扫码后确认状态为“已连接”。
9. 在“运行记录、操作日志、系统日志、用量分析”核对执行、错误、模型调用和余额。
## 15. 逐项验收清单
### 账号与权限
- [ ] 非管理员直接访问无权限路由显示明确中文提示,API 返回 403/404 且不泄露资源存在性。
- [ ] 普通用户看不到未授权 Agent、知识库、技能、数字人、记忆和画布。
- [ ] 全局资源个人修改/删除生成个人版本提案,不影响其他用户。
- [ ] 账号删除是永久删除;停用只改变 `enabled`,两者按钮和审计动作不同。
- [ ] 删除有关联资源时可查看依赖,并验证一键解绑事务、历史快照和日志保留。
### 知识库
- [ ] 首次打开知识库不会显示旧库残留或短暂的“不存在”;详情加载有明确状态。
- [ ] 同内容文件和完全重复片段被跳过,导入结果显示跳过数量。
- [ ] 子分类有文件时父分类计数同步;分类树可展开/收起。
- [ ] 普通用户消费记录只包含自己可用的 Agent/片段;管理员可按用户筛选。
- [ ] 预览按钮返回正确文件标题和正文;大文件不阻塞列表首屏。
- [ ] full/quick/reuse 三种检索模式显示估算耗时、进度和失败原因。
### AI 生成与任务
- [ ] 导图先输出框架文本,确认后才能进入内容任务;节点标题/叶子内容无重复。
- [ ] 导图每天按前置关系递进;跳过内容段后,后续段能看到桥接提示。
- [ ] 内容段显示当前 Agent、模型、知识分类和引用来源。
- [ ] 拆解失败、生成失败、AI 修改、图片/OCR/预读均有进度条、重试入口和日志。
- [ ] 质检四道门均产生可追踪报告;空报告自动判为需复检。
- [ ] 运行暂停、取消、恢复后不会重复扣费或重复消费片段。
### 微信 iLink
- [ ] 选择 Agent 后二维码出现;扫码成功后二维码隐藏且列表显示“已连接”。
- [ ] 已连接账号仍显示删除按钮;删除后 sidecar 实例停止、状态回调断开、刷新不复现。
- [ ] 多账号使用不同 storage 目录和账号密钥;账号 A 无法调用账号 B 的 Agent/会话。
- [ ] 绑定 Agent 变更实时同步 sidecar;失效/过期/错误状态能回传并允许重新扫码。
### 可靠性与部署
- [ ] 生产只使用 `data/`(或明确的 `YAWAN_DATA_DIR`),开发只使用 `data-dev/`。
- [ ] 后端、sidecar、隧道守护进程均可单独重启;502/1033 时日志能定位是 API、隧道还是 sidecar。
- [ ] 启动后未完成运行、片段预留和索引状态能正确恢复或标记。
- [ ] 生产构建通过 `npm run build`,前端动态模块版本与静态资源缓存一致。
## 16. 当前限制和风险边界
- SQLite + NullPool 适合单机/中小规模;多实例横向扩展前需要共享数据库、对象存储和队列,不能直接把本地文件目录挂到多个实例。
- iLink sidecar 依赖 Node.js 22 和 `@wechatbot/wechatbot`;官方适配器不可用时只会显示配置/连接错误,不能在浏览器端直接完成协议登录。
- 本地向量和全文索引路径由 `server/app/rag` 管理;若切换 Qdrant 等外部服务,需要同步配置、迁移和故障回退策略,当前代码仍保留本地存储能力。
- AI 输出受模型可用性、点数余额、Runtime 轮次预算和知识索引状态影响;任何“全库阅读”都可能显著增加时间和用量。
- 日志会对密钥、令牌和请求正文脱敏;若需要排查具体模型错误,应使用 Trace ID、Provider 状态和服务端原始日志,而不是把密钥写入前端提示。
## 16.1 性能基线与运行维护
- SQLite 连接统一启用 WAL、`busy_timeout=30000`、`synchronous=NORMAL` 和外键约束,并建立日志、知识库文件/分类/消费、授权、运行事件、队列等复合索引。
- 知识片段消费预留、确认和释放使用批量查询/`executemany`,减少逐片段 SQL 往返和写锁竞争。
- RAG 检索记录校验、Embedding、召回、后处理和总耗时,并保留缓存命中率;缓存键包含知识库版本、范围、模型和检索参数。
- 管理员可调用 `GET /api/ops/performance` 查看最近 512 次 API 的 P50/P95/P99、慢接口、状态分布及 RAG 阶段指标。该指标为进程内基线,重启后重新采样。
- 启动阶段只做必要初始化;知识库文件对账和全文索引预热由后台维护线程执行,避免大库扫描阻塞首屏和健康检查。
- 生产守护脚本使用单实例锁,避免重复守护进程同时启动后端,降低内存争抢和 SQLite 写锁风险。
- 普通 INFO/DEBUG/WARNING 系统日志与 AI 观测日志进入有界批量队列(最多 1000 条、每批 100 条、最长 1 秒刷盘);ERROR、关键审计、计量账本和任务状态仍同步写入。队列丢弃/失败计数可通过性能指标追踪,进程优雅退出会先刷盘。
- 性能指标现在通过匿名指标信封从 RAG 子进程回传 API 进程,包含 SQL 次数、SQL 耗时、锁错误、RAG 各阶段耗时和错误样本,避免把查询正文、令牌或原始路径写入指标。
- 当前任务队列仍是旁路记录,内容生成/导图/上传依赖进程内线程和内存进度总线;外部 Worker 尚未启用。直接启用会造成重复执行和 SSE 进度丢失,必须先完成原子租约认领、持久化进度游标及唯一执行模式切换。
- 2026-09-13 基线(本机冷启动、37 段产品信息库):首次检索约 3.37 秒,其中 Embedding 约 2.93 秒、召回约 0.41 秒;相同查询命中缓存约 6 毫秒。该样本不能代表 9.8 万段以上大库,需在空闲、内容生成和索引运行中分别采样 P50/P95/P99。
- Worker 审计结论:`TaskQueueItem.lease_next` 当前不是原子认领,且内容任务入队后仍由内存线程直接执行;上传、拆解、导图和 SSE 也依赖进程内状态。因此暂不启用内容生成外部 Worker,下一安全阶段仅考虑可幂等的 FTS 预热;迁移前需先完成原子租约、唯一执行模式、持久化进度游标和幂等验收。
- 2026-09-13 Embedding 诊断已细分为模型加载、Tokenizer、Encode 推理、向量后处理/序列化、进程启动和 IPC 残差,并记录来源、数量、模型版本、维度、PID、缓存命中及 Worker 是否复用。管理员性能接口会聚合这些阶段的 P50/P95;`embedding_count` 可识别 quick 检索误做批量向量化。
- 查询向量 LRU 与检索候选池缓存已分离:向量缓存只依赖规范化 query、模型/版本和策略(模型版本代表向量维度契约);候选池缓存包含知识库/分类文件范围、权限签名、索引版本、检索模式和 top-k。知识库版本变化只影响候选池,避免无关地清空查询向量。
- 2026-09-13 热态未命中采样(单库产品信息,15 条不同 query):首条冷启动约 4.17 秒,其中模型加载约 3.06 秒;模型常驻后总耗时 P50 约 15.93ms、P95 约 25.84ms,Embedding P95 约 16.70ms,Encode P95 约 16.59ms,召回 P95 约 4.30ms,`embedding_count=1` 且 15 条均未命中查询缓存。六库联合采样(约 15 万段)首条冷启动约 7.48 秒,热态未命中约 0.66~0.78 秒,主要耗时在多库召回而非 Embedding。
- 查询缓存复测确认:同 query、同 top-k 第二次命中候选池约 17ms;改变 top-k 后候选池重新计算约 45ms,但查询向量缓存命中、Embedding 耗时约 0ms。缓存键已修复首次维度从未知切换到 512 导致的伪未命中问题。
- 2026-09-13 六库召回稳定性优化:召回线程池改为进程内固定 4 个 Worker,避免每次请求创建线程并限制高并发时的磁盘争用;只读 FTS 索引使用带 inode/版本校验的共享连接、页缓存和 mmap,索引原子替换后自动重连。新增 `fts_connection_reused` 指标,用于区分连接复用与索引自身耗时。
- 2026-09-13 六库热态未命中复测(生产 6 库):Embedding 已常驻后约 14~129ms,召回约 0.64~0.91 秒;瓶颈集中在心法、情欲内容的大型 FTS 索引(约 461MB/862MB)和对应向量 I/O,模型加载不再是稳态瓶颈。后续优先做大库索引体积与查询词规模优化,暂不切换模型或向量数据库。
- 2026-09-13 向量查询进一步优化:移除检索热路径上的 `collection.count()`。该调用在外置盘冷读时,108135 段库约 1.7 秒,而实际向量查询约 20ms;Chroma/Qdrant 对空集合均直接返回空结果,因此无需先 count。检索指标现在只记录 collection、filter、vector 三段真实 I/O。
- 2026-09-13 空闲态 10 条不同 query 只读采样:P50 约 556ms,P95 约 1.25s;首条冷启动约 6.43s,后续 Embedding 约 6~345ms。4 路并发只读采样全部完成,未再出现 `database is locked`;高并发仍受单个常驻 RAG Worker 的队列容量限制,继续保持单 Worker 以控制内存峰值。
- 2026-09-13 稳定性修复:Embedding 用量事件改为独立短事务提交,计量写入失败只记录告警,不再让知识库检索失败;避免内容任务并发时主业务事务与用量写入互相持有 SQLite 写锁。
- 计量短事务设置 500ms 忙等待上限;数据库暂时繁忙时只丢弃本次非关键计量并保留检索结果,避免用户看到 30 秒级假性超时。
## 17. 检查记录模板
| 检查日期 | 环境(dev/prod) | 页面/API | 操作步骤 | 预期 | 实际 | Trace/截图 | 结论 |
|---|---|---|---|---|---|---|---|
| | | | | | | | |
维护此文档时,应以代码中的模型字段、路由和权限 key 为准;新增功能同时补充“功能地图、数据模型、API、权限、验收清单”五个位置。