Files
zclaw_openfang/docs/superpowers/specs/2026-04-01-knowledge-base-design.md
iven 8898bb399e
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
docs: audit reports + feature docs + skills + admin-v2 + config sync
Update audit tracker, roadmap, architecture docs,
add admin-v2 Roles page + Billing tests,
sync CLAUDE.md, Cargo.toml, docker-compose.yml,
add deep-research / frontend-design / chart-visualization skills

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 19:25:00 +08:00

681 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 行业知识库功能设计
> 日期: 2026-04-01
> 状态: 设计完成,待实施
> 范围: SaaS 管理端 + AI Agent 集成
## 1. 背景与目标
ZCLAW 作为面向中文用户的 AI Agent 桌面端,当前对话能力依赖通用 LLM 知识。行业用户(制造业、医疗、教育、设计)在专业领域提问时,通用模型回答缺乏深度和准确性。
**目标**: 建立行业知识库系统,让 SaaS 管理员配置行业专业知识,通过 RAG + Agent Tool 混合方案提升 AI Agent 的行业回答精准度。
**核心价值**:
- 管理员可系统化管理行业知识(分类、录入、版本控制)
- AI Agent 自动检索并引用相关知识RAG 注入)
- Agent 可主动查询知识库Tool 调用)
- 全生命周期分析看板追踪知识使用效果
## 2. 设计决策
| 维度 | 决策 | 理由 |
|------|------|------|
| 使用者 | SaaS 管理员配置(平台级资源) | 当前无多租户架构,知识库作为平台级共享资源,通过角色权限控制访问 |
| AI 集成 | RAG + Agent Tool 混合 | 覆盖自动注入和主动查询两个场景 |
| 文档格式 | 仅 Markdown | 简化实现Markdown 是知识的自然格式 |
| 审核流程 | 免审核(直接生效) | 小团队高效运作 |
| 分析看板 | 全生命周期分析 | 数据驱动知识库运营 |
| 交付节奏 | 一次性完整实现 | 功能完整交付 |
| 存储架构 | PostgreSQL + pgvector | 复用现有基础设施,零新增运维组件 |
| Admin UI | 标签页表格Ant Design 风格) | 与现有 Admin V2 一致 |
| 主键类型 | TEXT应用生成 UUID 字符串) | 匹配现有所有表的主键约定 |
| 向量索引 | HNSWpgvector >= 0.5.0 | 无最低行数要求,召回率优于 IVFFlat |
| 中文检索 | 依赖向量语义搜索 + keywords 数组匹配 | 中文无空格分词tsvector 不适用;向量搜索天然跨语言 |
## 3. 数据模型
### 3.1 约定
- 所有主键使用 `TEXT` 类型,由 Rust 端 `uuid::Uuid::new_v4().to_string()` 生成,匹配现有 25 张表的约定
- 知识库为平台级资源(无 tenant_id通过角色权限控制访问
- 外键引用 `accounts(id)` 均为 TEXT 类型
### 3.2 新增表5 张)
```sql
-- 启用 pgvector 扩展
CREATE EXTENSION IF NOT EXISTS vector;
-- 行业分类树
CREATE TABLE knowledge_categories (
id TEXT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
description TEXT,
parent_id TEXT REFERENCES knowledge_categories(id),
icon VARCHAR(50),
sort_order INT DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
CHECK (id != parent_id) -- 防止自引用
);
-- 知识条目
CREATE TABLE knowledge_items (
id TEXT PRIMARY KEY,
category_id TEXT NOT NULL REFERENCES knowledge_categories(id),
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
keywords TEXT[] DEFAULT '{}',
related_questions TEXT[] DEFAULT '{}',
priority INT DEFAULT 0,
status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active', 'archived', 'deprecated')),
version INT DEFAULT 1,
source VARCHAR(50) DEFAULT 'manual',
tags TEXT[] DEFAULT '{}',
created_by TEXT NOT NULL REFERENCES accounts(id),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
-- 内容长度约束:单条最大 100KB
CHECK (length(content) <= 100000)
);
-- 知识分块RAG 检索核心)
CREATE TABLE knowledge_chunks (
id TEXT PRIMARY KEY,
item_id TEXT NOT NULL REFERENCES knowledge_items(id) ON DELETE CASCADE,
chunk_index INT NOT NULL,
content TEXT NOT NULL,
embedding vector(1536),
keywords TEXT[] DEFAULT '{}',
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 版本快照
CREATE TABLE knowledge_versions (
id TEXT PRIMARY KEY,
item_id TEXT NOT NULL REFERENCES knowledge_items(id) ON DELETE CASCADE,
version INT NOT NULL,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
keywords TEXT[] DEFAULT '{}',
related_questions TEXT[] DEFAULT '{}',
change_summary TEXT,
created_by TEXT NOT NULL REFERENCES accounts(id),
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 使用追踪
CREATE TABLE knowledge_usage (
id TEXT PRIMARY KEY,
item_id TEXT NOT NULL REFERENCES knowledge_items(id),
chunk_id TEXT REFERENCES knowledge_chunks(id),
session_id VARCHAR(100),
query_text TEXT,
relevance_score FLOAT,
was_injected BOOLEAN DEFAULT FALSE,
agent_feedback VARCHAR(20) CHECK (agent_feedback IN ('positive', 'negative')),
created_at TIMESTAMPTZ DEFAULT NOW()
);
```
### 3.3 索引
```sql
-- 关联索引
CREATE INDEX idx_ki_category ON knowledge_items(category_id);
CREATE INDEX idx_kchunks_item ON knowledge_chunks(item_id);
CREATE INDEX idx_kv_item ON knowledge_versions(item_id);
CREATE INDEX idx_ku_item ON knowledge_usage(item_id);
-- 分类树
CREATE INDEX idx_kc_parent ON knowledge_categories(parent_id);
-- 使用追踪时间范围查询
CREATE INDEX idx_ku_created ON knowledge_usage(created_at);
-- 向量相似度索引HNSW无需预填充数据召回率优于 IVFFlat
CREATE INDEX idx_kchunks_embedding ON knowledge_chunks
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- 关键词数组索引GIN支持 && 重叠操作符)
CREATE INDEX idx_ki_keywords ON knowledge_items USING GIN(keywords);
CREATE INDEX idx_kchunks_keywords ON knowledge_chunks USING GIN(keywords);
```
### 3.4 Embedding 维度说明
`vector(1536)` 对应 OpenAI text-embedding-ada-002。若切换到其他 embedding 提供商:
- Zhipu embedding-3: 2048 维
- Qwen text-embedding-v2: 1536 维
- Doubao: 1024 维
**约束**: 同一知识库内所有条目必须使用相同维度的 embedding 模型。切换模型时需执行 re-embedding见 5.4 节)。维度值存储在 `config_items` 表中category: `knowledge_base`, key: `embedding_dimension`),迁移时据此动态创建列。
## 4. API 设计
### 4.1 核心请求/响应类型
```rust
// === 分类 ===
#[derive(Deserialize)]
pub struct CreateCategoryRequest {
pub name: String,
pub description: Option<String>,
pub parent_id: Option<String>,
pub icon: Option<String>,
}
#[derive(Deserialize)]
pub struct UpdateCategoryRequest {
pub name: Option<String>,
pub description: Option<String>,
pub parent_id: Option<String>,
pub icon: Option<String>,
}
#[derive(Serialize)]
pub struct CategoryResponse {
pub id: String,
pub name: String,
pub description: Option<String>,
pub parent_id: Option<String>,
pub icon: Option<String>,
pub sort_order: i32,
pub item_count: i64, // 该分类下的条目数
pub children: Vec<CategoryResponse>, // 树形嵌套
pub created_at: String,
pub updated_at: String,
}
// === 知识条目 ===
#[derive(Deserialize)]
pub struct CreateItemRequest {
pub category_id: String,
pub title: String,
pub content: String,
pub keywords: Option<Vec<String>>,
pub related_questions: Option<Vec<String>>,
pub priority: Option<i32>,
pub tags: Option<Vec<String>>,
}
#[derive(Deserialize)]
pub struct UpdateItemRequest {
pub category_id: Option<String>,
pub title: Option<String>,
pub content: Option<String>,
pub keywords: Option<Vec<String>>,
pub related_questions: Option<Vec<String>>,
pub priority: Option<i32>,
pub status: Option<String>,
pub tags: Option<Vec<String>>,
pub change_summary: Option<String>,
}
#[derive(Deserialize)]
pub struct ListItemsQuery {
pub page: Option<i64>,
pub page_size: Option<i64>,
pub category_id: Option<String>,
pub status: Option<String>,
pub keyword: Option<String>,
}
#[derive(Serialize)]
pub struct ItemResponse {
pub id: String,
pub category_id: String,
pub category_name: String,
pub title: String,
pub content: String,
pub keywords: Vec<String>,
pub related_questions: Vec<String>,
pub priority: i32,
pub status: String,
pub version: i32,
pub source: String,
pub tags: Vec<String>,
pub created_by: String,
pub reference_count: i64, // 引用次数(从 knowledge_usage 统计)
pub created_at: String,
pub updated_at: String,
}
// === 搜索 ===
#[derive(Deserialize)]
pub struct SearchRequest {
pub query: String,
pub category_id: Option<String>,
pub limit: Option<i64>, // 默认 5, 最大 10
pub min_score: Option<f64>, // 最低相关性阈值,默认 0.5
}
#[derive(Serialize)]
pub struct SearchResult {
pub chunk_id: String,
pub item_id: String,
pub item_title: String,
pub category_name: String,
pub content: String,
pub score: f64,
pub keywords: Vec<String>,
}
// === 分析 ===
#[derive(Serialize)]
pub struct AnalyticsOverview {
pub total_items: i64,
pub active_items: i64,
pub total_categories: i64,
pub weekly_new_items: i64,
pub total_references: i64,
pub avg_reference_per_item: f64,
pub hit_rate: f64, // 命中率
pub injection_rate: f64, // 注入率
pub positive_feedback_rate: f64,
pub stale_items_count: i64, // 90天未引用
}
```
### 4.2 分类管理6 个端点)
| Method | Path | 说明 |
|--------|------|------|
| GET | `/api/v1/knowledge/categories` | 树形列表(含每节点 item_count |
| POST | `/api/v1/knowledge/categories` | 创建分类 |
| PUT | `/api/v1/knowledge/categories/:id` | 更新分类(含父级循环检测) |
| DELETE | `/api/v1/knowledge/categories/:id` | 删除分类(有子分类或条目时拒绝) |
| PATCH | `/api/v1/knowledge/categories/reorder` | 批量更新 sort_order |
| GET | `/api/v1/knowledge/categories/:id/items` | 分类下条目分页列表 |
### 4.3 知识条目 CRUD7 个端点)
| Method | Path | 说明 |
|--------|------|------|
| GET | `/api/v1/knowledge/items` | 分页列表(筛选/搜索) |
| POST | `/api/v1/knowledge/items` | 创建条目(触发异步 embedding |
| GET | `/api/v1/knowledge/items/:id` | 条目详情 |
| PUT | `/api/v1/knowledge/items/:id` | 更新条目(触发异步 re-embedding |
| DELETE | `/api/v1/knowledge/items/:id` | 删除条目(级联删除 chunks + versions |
| POST | `/api/v1/knowledge/items/batch` | 批量创建(单次最多 50 条) |
| POST | `/api/v1/knowledge/items/import` | Markdown 文件导入(单次最多 20 个文件) |
### 4.4 版本控制3 个端点)
| Method | Path | 说明 |
|--------|------|------|
| GET | `/api/v1/knowledge/items/:id/versions` | 版本历史列表 |
| GET | `/api/v1/knowledge/items/:id/versions/:v` | 查看特定版本 |
| POST | `/api/v1/knowledge/items/:id/rollback/:v` | 回滚到指定版本(创建新版本) |
### 4.5 检索2 个端点,内部调用)
| Method | Path | 说明 |
|--------|------|------|
| POST | `/api/v1/knowledge/search` | 语义搜索(向量 + 关键词混合) |
| POST | `/api/v1/knowledge/recommend` | 关联推荐(基于当前条目的关键词重叠) |
### 4.6 分析看板5 个端点)
| Method | Path | 说明 |
|--------|------|------|
| GET | `/api/v1/knowledge/analytics/overview` | 总览统计(含命中率/注入率/反馈率) |
| GET | `/api/v1/knowledge/analytics/trends` | 使用趋势(支持 day/week/month 粒度) |
| GET | `/api/v1/knowledge/analytics/top-items` | 高频引用排行(支持分类筛选) |
| GET | `/api/v1/knowledge/analytics/quality` | 质量指标(按分类分组) |
| GET | `/api/v1/knowledge/analytics/gaps` | 知识缺口检测(低分查询聚类) |
### 4.7 权限模型
| 权限 | 说明 | 授予角色 |
|------|------|----------|
| `knowledge:read` | 查看分类、条目、版本、分析 | admin, super_admin |
| `knowledge:write` | 创建/编辑/导入条目和分类 | admin, super_admin |
| `knowledge:admin` | 删除、回滚 | super_admin |
| `knowledge:search` | 内部检索Agent/中间件) | 系统内部 |
## 5. RAG 管道
### 5.1 入库管道(写入路径)
```
管理员创建/编辑 Markdown
内容分块Markdown 标题层级 + 500-1000 token 固定切分 + 50 token 重叠)
Worker 异步生成 embedding调用 models 表中 is_embedding=true 的模型)
存入 knowledge_chunkscontent + embedding + keywords
自动创建 knowledge_versions 快照
更新 knowledge_items.version++
```
**分块策略**:
1. 优先按 Markdown 标题(`#`, `##`, `###`)自然分段
2. 超长段落按 500-1000 token 切分
3. 相邻块之间保留 50 token 重叠,避免语义断裂
4. 每个块继承父级标题作为上下文前缀
**Embedding 生成**:
- 复用现有 embedding 提供商配置OpenAI, Zhipu, Doubao, Qwen, DeepSeek, Local/TF-IDF
- 通过 Worker 系统异步处理,不阻塞管理员操作
- 模型选择: 从 `config_items` 读取 `knowledge_base.embedding_model_id`,默认使用第一个 `is_embedding=true` 的模型
### 5.2 检索管道(读取路径)
```
用户提问
relay 层知识注入(在 chat_completions handler 内调用)
1. 生成查询 embedding
2. 混合检索:
a) HNSW 向量余弦相似度(权重 0.7
b) keywords 数组重叠匹配(权重 0.2
c) related_questions 文本包含匹配(权重 0.1
3. 合并排序,取 Top-K默认 5 条)
4. token 预算控制(不超过 context window 的 20%
5. 格式化注入 system prompt
记录到 knowledge_usage检索事件
LLM 生成回答
```
**混合检索公式**:
```
final_score = 0.7 * cosine_similarity + 0.2 * keyword_overlap_count / max_keywords + 0.1 * related_question_match
```
**token 预算控制**:
- 最大注入 token 数 = min(context_window * 0.2, 2000)
- 按相关性排序,截断超出预算的低分块
- 注入格式: `[行业知识 #N] 标题\n内容`
**集成方式**: 在 `relay::handlers::chat_completions` 内部,转发到上游 LLM 之前调用 `knowledge::service::search_and_inject()`。不使用 Axum 中间件层,而是作为 handler 内的业务逻辑步骤,与现有的 stream 处理管道自然集成。
### 5.3 Agent Tool
```
tool: knowledge_search
params:
query: string # 搜索查询
category?: string # 限定分类
limit?: number # 返回数量 (默认 3, 最大 10)
返回:
items: Array<{
title: string
content: string # 匹配的知识片段
category: string
relevance: number # 相关性分数
}>
```
Agent 在判断需要行业专业知识时主动调用此工具。通过 SaaS API 调用 `POST /api/v1/knowledge/search`
### 5.4 Re-embedding 策略
当 embedding 模型切换时(维度或提供商变化):
1. **检测触发**: 管理员在分析看板页点击"重建索引"按钮
2. **执行流程**:
- 创建 re-embedding Worker 任务,按 batch每批 100 条 item分片
- 每个 batch: 删除旧 chunks → 重新分块 → 生成新 embedding → 写入新 chunks
- 通过 `SpawnLimiter` 控制并发,防止连接池耗尽
3. **原子性**: 每个 item 的 re-embedding 在单个事务内完成(删旧 chunk + 写新 chunk
4. **状态追踪**: 在 `config_items` 中记录 `knowledge_base.reindex_status`idle/running/completed/failed
5. **失败处理**: 单条 item 失败不影响其他 item记录到 operation_logs支持重试
## 6. Admin UI 设计
### 6.1 页面结构
在 Admin V2 侧边栏新增"知识库"菜单组,包含 3 个子页面:
**页面 1: 知识条目(默认页)**
- 顶部 Tab: 知识条目 | 批量导入
- 条目列表 Tab: Ant Design Table
- 列: 标题、分类、关键词Tag、引用次数、状态StatusTag、更新时间、操作
- 筛选: 分类下拉、状态筛选、关键词搜索输入框
- 操作: 新增Modal、编辑Modal、删除Popconfirm、查看版本历史Drawer
- 批量导入 Tab:
- Markdown 文件上传Ant Design Upload支持多文件单次最多 20 个)
- 分类选择(下拉选择导入到哪个分类下)
- 导入预览(文件列表 + 标题预览)+ 确认按钮
**页面 2: 分类管理**
- 树形组件Ant Design Tree
- 拖拽排序
- 内联编辑(新增/重命名/删除)
- 每个节点显示条目数量
- 删除前检查是否有子分类或关联条目
**页面 3: 分析看板**
- 总览卡片: 条目总数、本周新增、活跃率、平均引用次数
- 使用趋势图: 折线图(检索/命中/注入三条线,日/周/月粒度切换)
- 高频引用排行: 表格(支持按分类筛选)
- 质量指标: 命中率、注入率、正向反馈率、过期知识标记90天未引用
- 知识缺口: 缺失主题、查询频率、建议分类
### 6.2 新增文件
```
admin-v2/src/
├── pages/
│ ├── KnowledgeItems.tsx # 知识条目页
│ ├── KnowledgeCategories.tsx # 分类管理页
│ └── KnowledgeAnalytics.tsx # 分析看板页
├── services/
│ └── knowledgeService.ts # API 调用封装
├── types/
│ └── knowledge.d.ts # 类型定义
└── components/
└── knowledge/
├── ItemForm.tsx # 条目编辑表单Modal
├── ItemDetail.tsx # 条目详情抽屉
├── VersionHistory.tsx # 版本历史Drawer
├── ImportPanel.tsx # 批量导入面板
└── AnalyticsCharts.tsx # 分析图表组件
```
### 6.3 路由注册
```typescript
// router/index.tsx 新增(使用现有 lazy 加载模式)
{ path: 'knowledge/items', lazy: () => import('@/pages/KnowledgeItems').then(m => ({ Component: m.default })) },
{ path: 'knowledge/categories', lazy: () => import('@/pages/KnowledgeCategories').then(m => ({ Component: m.default })) },
{ path: 'knowledge/analytics', lazy: () => import('@/pages/KnowledgeAnalytics').then(m => ({ Component: m.default })) },
```
### 6.4 侧边栏导航
```typescript
// AdminLayout.tsx navItems 新增
{
path: '/knowledge/items',
name: '知识库',
icon: BookOutlined,
permission: 'knowledge:read',
group: '资源管理',
},
{
path: '/knowledge/categories',
name: '分类管理',
icon: FolderOutlined,
permission: 'knowledge:read',
group: '资源管理',
},
{
path: '/knowledge/analytics',
name: '知识分析',
icon: BarChartOutlined,
permission: 'knowledge:read',
group: '资源管理',
},
```
## 7. SaaS 后端实现
### 7.1 新增模块
```
crates/zclaw-saas/src/
└── knowledge/
├── mod.rs # 模块注册 + 路由定义pub fn routes() -> Router<AppState>
├── types.rs # 请求/响应/DTO 类型(见 4.1 节)
├── handlers.rs # 23 个 API handler
├── service.rs # 业务逻辑CRUD + 检索 + 分析)
└── chunk.rs # 分块 + embedding 生成 + re-embedding
```
### 7.2 模块注册
```rust
// lib.rs 新增
pub mod knowledge;
// main.rs build_router() 新增
.merge(zclaw_saas::knowledge::routes())
```
### 7.3 新增 Worker
```rust
// workers/generate_embedding.rs
use crate::state::AppState;
use crate::workers::Worker;
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
#[derive(Serialize, Deserialize)]
pub struct GenerateEmbeddingArgs {
pub item_id: String,
}
pub struct GenerateEmbedding;
impl Worker for GenerateEmbedding {
type Args = GenerateEmbeddingArgs;
fn name(&self) -> &str {
"generate_embedding"
}
async fn perform(&self, db: &PgPool, args: Self::Args) -> crate::error::SaasResult<()> {
// 1. 从 knowledge_items 读 content
// 2. 调用 chunk.rs 分块
// 3. 调用 embedding 提供商生成向量
// (通过 relay 模块的 provider 客户端,复用现有 HTTP 客户端)
// 4. 删除旧 chunks写入新 knowledge_chunks
// 5. 更新 knowledge_items.updated_at
Ok(())
}
}
// main.rs Worker 注册新增
state.dispatcher.register::<GenerateEmbedding>();
```
### 7.4 Cargo 依赖
```toml
# zclaw-saas/Cargo.toml 新增
[dependencies]
pgvector = { version = "0.4", features = ["sqlx"] }
```
pgvector crate 提供 `pgvector::Vector` 类型,支持 sqlx 的 `Encode`/`Decode`,可直接用于读写 `vector(N)` 列。
### 7.5 迁移文件
```
crates/zclaw-saas/migrations/20260402000002_knowledge_base.sql
```
包含: pgvector 扩展启用 + 5 张表 + 所有索引(见第 3 节)。
## 8. Docker 变更
将 PostgreSQL 镜像切换为 pgvector 版本:
```yaml
# docker-compose.yml
services:
db:
image: pgvector/pgvector:pg16-alpine # 原 postgres:16-alpine
```
使用 Alpine 变体保持与原有配置一致。
## 9. 权限种子数据
在迁移文件中通过应用层兼容的方式更新权限(`permissions` 列为 TEXT 类型存储 JSON 数组字符串):
```sql
-- 以应用层可解析的格式追加权限
-- super_admin: 追加 knowledge:read, knowledge:write, knowledge:admin, knowledge:search
UPDATE roles
SET permissions = REPLACE(
permissions,
']',
', "knowledge:read", "knowledge:write", "knowledge:admin", "knowledge:search"]'
)
WHERE name = 'super_admin'
AND permissions NOT LIKE '%knowledge:read%';
-- admin: 追加 knowledge:read, knowledge:write, knowledge:search
UPDATE roles
SET permissions = REPLACE(
permissions,
']',
', "knowledge:read", "knowledge:write", "knowledge:search"]'
)
WHERE name = 'admin'
AND permissions NOT LIKE '%knowledge:read%';
```
## 10. 内容限制与防护
| 限制项 | 值 | 实现位置 |
|--------|-----|----------|
| 单条内容最大长度 | 100KB (100,000 字符) | 数据库 CHECK 约束 + API 验证 |
| 批量创建最大条数 | 50 条/次 | API handler 验证 |
| 文件导入最大文件数 | 20 个/次 | API handler 验证 |
| 单文件最大大小 | 5MB | Upload 中间件限制 |
| 搜索结果最大数量 | 10 条 | API 参数上限 |
| 分类树最大深度 | 3 层 | API handler 递归检测 |
| 分类名称最大长度 | 100 字符 | 数据库 VARCHAR 约束 |
| 标题最大长度 | 255 字符 | 数据库 VARCHAR 约束 |
## 11. 验证方案
### 11.1 后端验证
1. **数据库迁移**: 启动 SaaS 服务,确认 pgvector 扩展和 5 张表创建成功
2. **CRUD API**: 用 curl 测试分类和条目的完整 CRUD 流程
3. **分块 + Embedding**: 创建条目后检查 knowledge_chunks 表有正确分块和向量
4. **混合检索**: 调用 `/api/v1/knowledge/search` 验证向量+关键词混合结果
5. **版本控制**: 编辑条目后检查 knowledge_versions 快照正确性,验证回滚
6. **分析 API**: 注入测试数据后验证 5 个分析端点返回正确统计
7. **分类循环检测**: 尝试设置循环父级关系,确认被拒绝
8. **内容限制**: 尝试提交超长内容,确认被 CHECK 约束拒绝
### 11.2 前端验证
1. **分类管理**: 树形 CRUD + 拖拽排序
2. **条目 CRUD**: 创建、编辑、删除、列表筛选
3. **批量导入**: Markdown 文件上传导入
4. **版本历史**: 查看历史版本 + 回滚
5. **分析看板**: 图表渲染 + 数据联动
### 11.3 集成验证
1. **RAG 注入**: 在桌面端对话中提问行业相关问题,验证知识被检索和注入
2. **Agent Tool**: 在对话中触发 Agent 主动查询知识库
3. **使用追踪**: 对话后检查 knowledge_usage 表有检索记录
4. **分析闭环**: 对话后查看分析看板数据更新
5. **Re-embedding**: 切换 embedding 模型后触发重建,验证向量正确更新