# 《WaLiAPI - 本地 LLM API 网关》第3-3节:知识库数据模型与文档解析

作者:小傅哥
博客:https://bugstack.cn (opens new window)

沉淀、分享、成长,让自己和他人都能有所收获!😄

大家好,我是技术UP主小傅哥。

从这一节开始,我们进入知识库的核心——数据存储和文档解析。知识库不是简单的文本搜索,而是 文档 → 解析 → 分块 → 向量化 → 索引 → 检索 的完整流水线。这一节覆盖前半段:数据模型和文档解析。

# 一、本章诉求

  1. 设计知识库的数据库表结构(4个migration)
  2. 实现 Rust 数据模型(models.rs)
  3. 实现文档解析(parser.rs — 支持 txt/md/pdf/docx/代码文件)
  4. 实现文本分块(splitter.rs — 普通文本 + Markdown按标题分块 + 代码按符号分块)
  5. 实现 tree-sitter 符号感知代码解析(code_parser.rs)
  6. 实现数据库 CRUD(repository.rs)

# 二、数据库表结构设计

# 2.1 Migration 008 — 核心四表

知识库的核心是四张表,形成 知识库 → 文档 → 切片 的层级关系:

kb_knowledge_bases (知识库)
    │  1:N
kb_documents (文档)
    │  1:N
kb_chunks (切片 + 向量)
    
kb_tasks (处理任务)
1
2
3
4
5
6
7

008_knowledge_base.sql

-- 知识库:一个知识库对应一个主题/项目
CREATE TABLE IF NOT EXISTS kb_knowledge_bases (
    id            TEXT PRIMARY KEY,
    name          TEXT NOT NULL,
    description   TEXT,
    status        INTEGER NOT NULL DEFAULT 1,      -- 1=active, 0=disabled
    doc_count     INTEGER NOT NULL DEFAULT 0,
    chunk_count   INTEGER NOT NULL DEFAULT 0,
    total_tokens  INTEGER NOT NULL DEFAULT 0,
    embedding_model  TEXT,                          -- 向量模型名
    embedding_channel_id TEXT,                      -- 向量渠道 ID
    created_at    TEXT NOT NULL,
    updated_at    TEXT NOT NULL
);

-- 文档:上传的每个文件是一条记录
CREATE TABLE IF NOT EXISTS kb_documents (
    id            TEXT PRIMARY KEY,
    kb_id         TEXT NOT NULL,
    filename      TEXT NOT NULL,
    file_path     TEXT,                             -- 本地文件路径(如果是导入)
    file_type     TEXT NOT NULL,                    -- pdf/txt/md/docx/code...
    file_size     INTEGER NOT NULL DEFAULT 0,
    content_hash  TEXT NOT NULL,                    -- SHA256,防止重复上传
    chunk_count   INTEGER NOT NULL DEFAULT 0,
    token_count   INTEGER NOT NULL DEFAULT 0,
    status        TEXT NOT NULL DEFAULT 'pending',  -- pending/processing/ready/failed
    error_message TEXT,
    created_at    TEXT NOT NULL,
    updated_at    TEXT NOT NULL,
    FOREIGN KEY (kb_id) REFERENCES kb_knowledge_bases(id) ON DELETE CASCADE
);

-- 切片:文档被分块后的最小检索单元
CREATE TABLE IF NOT EXISTS kb_chunks (
    id             TEXT PRIMARY KEY,
    doc_id         TEXT NOT NULL,
    kb_id          TEXT NOT NULL,
    chunk_index    INTEGER NOT NULL,                -- 分块序号
    content        TEXT NOT NULL,                   -- 分块文本内容
    token_count    INTEGER NOT NULL DEFAULT 0,
    embedding      BLOB,                            -- 向量数据(二进制)
    embedding_dim  INTEGER NOT NULL DEFAULT 0,      -- 向量维度
    metadata       TEXT NOT NULL DEFAULT '{}',       -- JSON元数据
    created_at     TEXT NOT NULL,
    FOREIGN KEY (doc_id) REFERENCES kb_documents(id) ON DELETE CASCADE,
    FOREIGN KEY (kb_id) REFERENCES kb_knowledge_bases(id) ON DELETE CASCADE
);

-- 处理任务:记录异步处理进度
CREATE TABLE IF NOT EXISTS kb_tasks (
    id            TEXT PRIMARY KEY,
    kb_id         TEXT NOT NULL,
    doc_id        TEXT,
    task_type     TEXT NOT NULL,                    -- embed/index/import
    status        TEXT NOT NULL DEFAULT 'pending',
    progress      INTEGER NOT NULL DEFAULT 0,
    total_items   INTEGER NOT NULL DEFAULT 0,
    done_items    INTEGER NOT NULL DEFAULT 0,
    error_message TEXT,
    created_at    TEXT NOT NULL,
    completed_at  TEXT,
    FOREIGN KEY (kb_id) REFERENCES kb_knowledge_bases(id) ON DELETE CASCADE
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

设计决策

决策点 选择 原因
主键类型 TEXT (UUID) 避免自增ID暴露顺序信息,支持分布式场景
embedding 存储 BLOB 向量是 f32 数组,用 bincode 序列化为二进制,比 JSON 存储节省 50% 空间
外键 CASCADE 删除知识库时自动删除关联文档和切片,避免孤儿数据
content_hash SHA256 防止重复上传同一文档,hash 相同则跳过
status 字段 pending→processing→ready→failed 文档处理是异步的,需要状态追踪