知识库改进方案

2026-10-08 草案;同日用户确认 9 项决定(见 0.1 节),已按决定更新。实施前不改代码。涉及 aimp-kb(检索、入库、库表)与 aimp-platform packages/ui/src/views/kb/(界面)。行号以 2026-10-08 本地 main 为准。

本文处理知识库从 zhizhan-ai 迁入后遗留的五个问题,按优先级排列:知识应用检索不走索引、入库只有单线程且失败不重试、向量模型没有明确归属、分块策略不能在上传时选择、分类没有在文档页展开。前两个决定知识库能承载多大的数据量,后三个是界面与使用方式。

迁移方案 knowledge-base-convergence.md 已经写过其中三项的要求,交付时没有实现:第 410 行把「KB 默认 embedding 模型 ID/revision;分块/检索策略(保存于 KB 领域配置)」列为业务设置;第 376 行要求「保留线程池、并发上限、失败/重试/取消状态」。cp1–cp3 的验收记录里没有压测或容量测试。本机当前数据是 21 个库、165 个分块向量,本文涉及的容量问题都没有在真实规模下出现过。

#问题现状证据优先级
1知识应用检索每次全量加载向量,在 Python 里逐条计算kb_app_runtime.py:73-85、:88-89P0
2入库全系统单线程、失败不重试、不能多进程,并依赖一个不调用的 rerank 模型kb_pipeline.py:343、389、424、563-583P0
3向量模型由「对接模型」页的排序隐式决定aimp_model_client.py:59-66、services/documents.js:44-46P1
4上传时不能选分块策略;分块器支持的参数大部分没有接出来kb_pipeline.py:412-421、model/document_management.py:70P1
5分类只是工具栏里的一个下拉框DocumentManagement.jsx:198-236P2

0.1 已确认的决定(2026-10-08,用户)

#决定落在哪一节
D1短期不换向量库,继续用 PG + pgvector,把 pgvector 的推荐用法用到位1.3
D2模型调用并发上限缺省 4,可调整,配置放在「平台管理 → 平台设置」2.3
D3更换向量模型期间检索结果不完整,可以接受3.2
D4入库按提交时间先后处理,不按库轮转2.2
D5知识应用跨多个库时,要求这些库使用同一个向量模型3.2
D6不设平台级默认向量模型。向量模型只在知识库页面选择,建库时不预选3.2
D7「对接模型」页不显示模型被几个知识库使用—
D8不使用半精度向量索引1.3
D9语义分块、情境增强做到与 zhizhan-ai 一致4.4、4.5

1. 知识应用检索改走数据库索引

1.1 现状

知识应用(发布后被智能体和工具调用的路径)在 kb_app_runtime.py 的 retrieve() 里按下面的方式检索:

  1. 查出所选库里全部「可检索」文档的全部分块(第 30-43 行),标签和 metadata 过滤在 Python 里做(第 44-49 行)。
  2. 查出这些库的全部分块向量(第 73-75 行),逐条算余弦相似度(第 76-85 行)。
  3. 关键词检索对每个分块做 content.casefold().count(w)(第 88-89 行)。
  4. 混合模式用 RRF 合并两路排名(常数 61,第 104-111 行)。

数据库里已经有能用的索引,但这条路径一个都没用上:

zhizhan-ai 的检索不是这样做的。它的 kb_retrieve_service.py(945 行)在一条 SQL 里带上库、分类、文档、标签、metadata 过滤,向量召回走 pgvector 余弦 TopN,并按召回条数 SET LOCAL hnsw.ef_search(第 396-412 行);关键词召回用 kb_fts.py(68 行):jieba 搜索引擎模式分词,入库写 to_tsvector('simple', …),查询用 websearch_to_tsquery 的 OR 语义加 ts_rank;两路用 RRF(k=60)融合;另有一路章节向量召回,给命中章节的分块加分(权重 0.15,第 64 行),并为没有分块进入召回的章节补最多 2 条(第 66 行)。迁移到 aimp-kb 时,这套实现被换成了上面的 Python 全量计算,jieba 依赖也去掉了。aimp-kb 入库时仍然计算并保存章节向量(kb_pipeline.py:441,表 tb_kb_section_embedding),但知识应用检索不读它。

推算:一个 1024 维 float4 向量占 4096 字节。库里有 10 万个分块时,每问一个问题要从 PG 传出约 400MB 向量,再加全部分块正文,然后在单个 Python 进程里做 10 万次 1024 维点积。这个数字是按字节数推算的,没有实测。

另一个后果:测试面板与知识应用是两套检索实现。测试面板只有向量检索、rerank 必选;知识应用支持三种模式、rerank 可选、有阈值。在测试面板上调出来的效果,不代表发布后的效果。

1.2 方案

以 zhizhan-ai 的 kb_retrieve_service.py 与 kb_fts.py 为基础移植,按 aimp-kb 的现状做以下适配:

  1. 向量召回:沿用 zhizhan-ai 的写法,过滤条件全部在 SQL 里,ORDER BY embedding <=> :q LIMIT :n。增加两项 aimp-kb 特有的条件:向量的 embedding_model_id、model_revision 等于库的模型(第 3 节),content_version 等于文档版本。
  2. 带过滤的召回:zhizhan-ai 只调了 ef_search。本方案再加 SET LOCAL hnsw.iterative_scan = relaxed_order,见 1.3 第 2 项。
  3. 关键词召回:照搬 kb_fts.py。aimp-kb 加回依赖 jieba==0.42.1(zhizhan-ai 用的版本)。入库时由 embed_text 生成 content_tokens,与 schema 注释(schema.py:147、179)一致;查询用 websearch_to_tsquery('simple', …) 加 ts_rank。
  4. 章节向量召回:照搬,权重 0.15、每章补 2 条两个常量不变。
  5. 融合:照搬 zhizhan-ai 的 RRF(k=60,单路为空时保留原始分)。aimp-kb 现在用的常数是 61,改为 60。
  6. 检索模式名称:zhizhan-ai 是 hybrid / vector / fulltext,aimp-kb 知识应用配置里已存的是 hybrid / vector / keyword。保留 aimp-kb 的名称,不改已发布应用的配置。
  7. 测试面板与知识应用合并为一个检索函数。测试面板传一份临时配置调用同一个函数。kb_rag_runtime.retrieve 删除。
  8. 存量回填:迁移脚本用 jieba 对现有分块的 embed_text 计算 content_tokens。本机 165 条,脚本可重复执行。

zhizhan-ai 检索里的「LLM 优化」(用对话模型把命中内容精炼成一段上下文)不在本方案范围内:aimp-kb 的知识应用由回答模型直接引用命中分块,两者作用重叠。

1.3 pgvector 用法规范(D1)

依据是 pgvector 0.8 的官方 README(HNSW、Filtering、Iterative Index Scans、Hybrid Search、Performance 各节)。下表每一项写明本方案怎么做,以及本机现在的值。

#项做法本机现状
1查询写法ORDER BY embedding <=> :q LIMIT :k。算子必须与索引的 opclass 对应:vector_cosine_ops 对应 <=>。没有 LIMIT、或按距离的表达式排序,都用不上索引列类型 vector(1024)。实测测试面板写的 embedding::vector(1024) 转换会被规划器消掉,EXPLAIN 显示 Index Scan using idx_tb_kb_emb_hnsw
2带过滤的召回事务内 SET LOCAL hnsw.iterative_scan = relaxed_order、SET LOCAL hnsw.ef_search = max(candidate_k, 100);hnsw.max_scan_tuples 保持缺省 20000,超过后迭代扫描停止,返回已找到的结果两个参数都没设;zhizhan-ai 只设了 ef_search
3小库走精确检索保留 kb_id 上的 btree 索引 ix_tb_kb_emb_kb。库很小时,规划器估算按 kb_id 取行再精确排序更便宜,就会走这条路,结果是精确的。不按库建部分索引:库的数量随用户建库增长,部分索引要动态维护索引已存在
4索引常驻内存HNSW 索引要能放进内存,否则每次查询都读盘。按每个向量约 4–5KB 估算(4096 字节向量加图的邻接信息),10 万个分块约 0.5GB,100 万约 5GB。shared_buffers 取机器内存的 25%,effective_cache_size 取 50%–75%索引 1184kB / 165 行,样本太小,页开销占比高,不能外推;shared_buffers 128MB,是 PG 缺省值
5建索引maintenance_work_mem 要大于索引大小,否则 pgvector 提示「hnsw graph no longer fits into maintenance_work_mem」,构建明显变慢;max_parallel_maintenance_workers 开并行构建。整库导入时先导数据后建索引maintenance_work_mem 64MB,缺省值
6删除与重建后的整理重新向量化是先删后插,HNSW 里被删的节点要等 VACUUM 清理。对 tb_kb_chunk_embedding 调低 autovacuum 阈值;整库更换向量模型之后执行一次 REINDEX INDEX CONCURRENTLY idx_tb_kb_emb_hnsw未设置
7半精度向量不使用(D8)。内存按全精度索引估算,见第 4 项未使用
8混合检索向量与全文检索各取 candidate_k,用 RRF 合并。这是 README「Hybrid Search」一节给的做法,也是 zhizhan-ai 的做法,见 1.2 第 3、5 条见 1.1
9观测启用 pg_stat_statements,按语句看 p95;上线前对检索 SQL 做 EXPLAIN (ANALYZE, BUFFERS),确认走索引、命中缓存未启用

第 4、5、6 项是数据库参数,单机安装包的 PG 配置和安装手册要随之更新,按机器内存给出取值。

1.4 被否决的方案

做法否决原因
保留 Python 计算,把向量缓存在进程内存里内存随库大小线性增长;文档更新、删除时要做缓存失效;多进程时每个进程各存一份。
引入独立向量库(Milvus、Elasticsearch 等)D1:短期不换。多一个要部署、备份、升级的组件,离线安装包与安装手册都要跟着改。
关键词检索沿用 aimp-kb 现在的汉字二元组切词(kb_app_runtime.py:13-21),写进 tsvector二元组会产生大量跨词边界的无意义词(「日志不匹配」切出「志不」「不匹」),召回噪声大;zhizhan-ai 原本用的是 jieba,迁移时去掉了,恢复即可。
关键词检索用 pg_trgmpg_trgm 对汉字的切分依赖数据库 locale(本机 lc_ctype = en_US.utf8),行为未验证;排序结果与 zhizhan-ai 不一致。

1.5 取舍

2. 入库:并发、重试、可多进程

2.1 现状

zhizhan-ai 的做法:kb_vectorize_concurrency 缺省 4,线程池并发(vectorization_service.py:265);取任务用 FOR UPDATE SKIP LOCKED(kb_document_service.py:1119)。

2.2 方案

  1. 取任务:
    SELECT … FROM tb_kb_job
     WHERE status = 'queued' AND (next_run_at IS NULL OR next_run_at <= :now)
     ORDER BY create_time
     FOR UPDATE SKIP LOCKED LIMIT 1
    取到后在同一事务里写 status='parsing'、lease_until = now + 10 分钟、worker_id。tb_kb_job 新增 next_run_at、lease_until、worker_id 三列。
  2. 租约:每完成一批向量化续租一次。进程启动时不再重置全部任务,只回收 lease_until 已过期的任务。进程崩溃后,任务最多 10 分钟后被其他进程重新领取。
  3. 并发:处理线程数取平台设置「知识库入库并发」,缺省 2,见 2.3。平台模型调用的并发名额由入库和在线问答共用,缺省 4 个时入库占 2 个,在线问答至少剩 2 个。
  4. 顺序:全局按 create_time 先后处理,不按库轮转(D4)。
  5. 重试,分两层:
    • 批次级:单批向量化收到 429 或 503 时,按 Retry-After 等待后重发这一批,最多 5 次。不重新解析文档。
    • 任务级:批次重试用尽,或调用平台网络失败、docparser 返回 UNAVAILABLE 或 DEADLINE_EXCEEDED 时,任务回到排队,next_run_at 依次为 30 秒、2 分钟、10 分钟后。最多重试 3 次,共执行 4 次;第 4 次失败标为失败(用户确认)。
    • 不重试的错误:解析出空文本、文件损坏、422 参数错误、409 模型版本不符。
    重试是幂等的:写索引前 clean_index() 按 document_id 删除旧分块和向量(kb_pipeline.py:153-155),valid() 按文档版本校验(第 361-385 行),重复执行不会混写。
  6. 独立处理进程:配置项 kb_worker_enabled 已经存在(core/config.py)。新增入口 python -m app.worker,只跑处理线程。接口进程设 KB_WORKER_ENABLED=false。compose 增加一个 kb-worker 服务,用同一个镜像。本机开发保持进程内运行。
  7. 去掉入库对 rerank 的依赖:块长上限改为 min(向量模型 maxInputTokens, 6000)。检索时已经按 rerank 模型的上限截断送入的文本(kb_rag_runtime.py:93-97、kb_app_runtime.py:125),超长分块只把开头部分送去 rerank。
  8. 上传改为流式落盘:现在每个文件整体读进内存再写盘(kb_document_api.py:119,单次最多 20 个、每个 100MB)。改成边读边写、边计数,超过 100MB 时中止并删掉半成品。
  9. 排队可见:文档列表的「等待处理」状态旁显示「前面还有 N 个」。N 按 create_time 早于本任务的排队任务数计算。

2.3 并发配置放进平台设置(D2)

「平台管理 → 平台设置」已有可扩展的设置项机制:键在服务端白名单里(services/platform-setting/index.ts:46 的 TEXT_SETTING_KEYS),读取顺序是数据库 > 环境变量 > 缺省值,保存即生效。现成的同类先例是 RESOURCE_KEY_MAX_RESOURCES(按文本存、按整数 1–200 解释、缺省 50,同文件第 48-57 行)。新增两项,照同样方式实现:

键界面名称类型缺省取值越界或为空谁读、何时生效
MODEL_RUNTIME_MAX_CONCURRENCY模型调用并发上限整数4(环境变量 AIMP_MODEL_MAX_CONCURRENCY 有值时取它)1–64保存时 400;库里的值非法时按缺省值处理平台 model-runtime,每次调用前读,带 30 秒缓存。改小后已在执行的调用不中断,新调用按新上限
KB_INGEST_CONCURRENCY知识库入库并发整数21–16,且不大于模型调用并发上限保存时 400,并提示当前的模型调用并发上限kb 处理进程每 30 秒拉取一次,增减处理线程;减少时等正在处理的文档完成后再退出线程

kb 通过新接口 GET /api/v1/model-runtime/limits 读取这两项,用现有的服务凭据鉴权,返回 {maxConcurrency, kbIngestConcurrency}。平台不可达时 kb 沿用上一次取到的值,启动时取不到就用 1。

平台设置页上「知识库入库并发」旁边写明:入库与在线问答共用模型调用并发名额,入库并发等于上限时,入库高峰期的问答会收到 429 并等待重试。

2.4 被否决的方案

做法否决原因
Celery + Redis 任务队列kb 多一个依赖和一个部署组件。PG 的 SKIP LOCKED 能满足多进程取任务,任务状态本来就在 PG 里,不用两边对账。
同一文档内的多个向量化批次并发平台并发名额只有 4。文档之间并发已经能用满名额,文档内再并发只会更快触发 429。
uvicorn 开多个 worker,每个都带处理线程处理线程数随 worker 数翻倍,不可控;接口进程仍然受处理线程的 GIL 影响。
并发上限按模型分别配置(放在「对接模型」的公共能力字段里)平台的并发上限是保护平台自身的总闸,按模型配要把计数器拆成按模型计数,界面多一个字段。供应商各自的限流已经通过 429 和重试处理。出现某个供应商需要比总闸更低的上限时,再按模型加。
只用环境变量配置改值要重启平台和 kb;D2 要求在平台管理里改。

2.5 取舍

3. 向量模型归属到知识库

3.1 现状

3.2 方案

  1. tb_kb 新增 embedding_model_id、embedding_model_revision。
  2. 建库时必选向量模型,不预选(D6)。下拉框列出已启用的 embedding 模型;维度不是 1024 的置灰,并注明原因。没选时「创建」按钮不可点。
  3. 上传、重新向量化一律使用库的模型。接口参数 embedding_model_id 与库的模型不一致时返回 422,不再静默采用。
  4. 测试面板的 Embedding 改为只读,显示库的模型。
  5. 知识应用的向量模型改为由所选知识库推出,不再单独选择。所选的多个库模型不一致时,保存失败,并列出模型不同的库名(D5)。
  6. 更换向量模型:在库的设置页操作。确认框显示要重建的文档数和分块数。确认后写入新模型,全部可检索文档重新排队向量化(只重新切块和向量化,已解析的 Markdown 不重新解析)。重建期间页面顶部显示「重建中 x / y」,还没重建的文档不参与检索,检索结果不完整(D3)。
  7. 模型版本变化(管理员在「对接模型」页改了模型名、地址、维度等):库的设置页显示「模型配置已变化,需要重建」,提供「按新版本重建」。

3.3 被否决的方案

做法否决原因
沿用 zhizhan-ai 的全局设置,全平台一个向量模型换模型要重建全部库;不同库无法用不同模型。迁移方案第 410 行要求的是按库保存。
更换模型时新旧两套向量并存,重建完成后切换D3 已接受重建期间结果不完整。另外 tb_kb_chunk_embedding 的主键是 chunk_id,一个分块只能存一个向量。并存要改主键并多一倍存储。迁移方案第 421 行已把「无停机索引切换」列为不做。
知识应用跨模型检索:每种模型各生成一次问题向量,结果合并D5 已定不做。不同模型的相似度分数不能直接比较,只能依赖 rerank 合并;每次问答多一次向量调用。

3.4 迁移

迁移脚本按库统计可检索文档的 (embedding_model_id, model_revision):

4. 分块策略:库级默认值,上传时可改

4.1 现状

zhizhan-aiaimp-kb 现在本方案 v1
策略6 种3 种6 种:按结构和句子、按页、启发式、语义、自定义分隔符、整篇不分块
块长、重叠有有有
标题切分层级、父块上限有分块器有,没接出来接出来,放在「高级」里
语义分块有分块器有,没接出来做,与 zhizhan-ai 一致(D9),见 4.4
情境增强有无(文档表留着 contextual_prefix 列,schema.py:101)做,与 zhizhan-ai 一致(D9),见 4.5
向量化范围(正文 / 标题 / 标题+正文)有无不做
跨库「向量化配置」有无不做,由库级默认值 + 批量重新向量化替代
在哪里选向量化对话框、向量化配置上传后「重新向量化」库设置(默认值)、上传对话框(本批覆盖)、重新向量化

4.2 方案

  1. tb_kb 新增 chunk_defaults(JSONB),字段见下表。为空时沿用现在的缺省规则。
  2. 库设置页增加「分块默认值」。
  3. 上传对话框显示「分块:使用知识库默认值(按结构和句子,420 / 40)」,点「本批单独设置」展开表单,只对这一批文件生效,写入每个文档已有的 chunk_method、parser_config、contextual_prefix 字段。
  4. 「重新向量化」使用同一个表单。
  5. 入库流程把 heading_split_level、parent_max_tokens、custom_delimiter 传给 split_by_strategy();接口的 chunk_method 放开到 6 种。

参数约束

字段类型必填取值为空或越界
methodstring是sentence / page / heuristic / semantic / custom / none422
chunk_sizeint是32–6000,且不超过向量模型 maxInputTokens422
chunk_overlapint是0–1000,小于 chunk_size422
heading_split_levelint否0–6,0 表示自动识别缺省 0
parent_max_tokensint否0–8000,0 表示整章作为一个父块缺省 0
custom_delimiterstringmethod=custom 时必填不超过 200 字符method=custom 且为空时 422。分块器本身的行为是回退按标题切分(kb_chunking.py:996),接口层先拦住
contextual_prefixbool否true / false缺省 false
context_model_id、context_model_revisionstringcontextual_prefix=true 时必填公共目录里已启用的 chat 模型contextual_prefix=true 且为空时 422;模型被停用或版本变化时,入库按「情境增强失败」处理(4.5 失败语义),不阻断向量化

4.3 不做的选项

4.4 语义分块(D9)

4.5 情境增强(D9)

移植 zhizhan-ai 的 contextual_prefix_service.py(519 行)。入库时为每个分块生成一句说明前缀,只拼进 embed_text(因此也进入 content_tokens),不改返回给人和回答模型的 content。常量照搬:

常量值含义
MAX_CHUNKS_PER_DOC300单文档超过这个分块数不生成前缀
MIN_CHUNKS_FOR_PREFIX3少于这个分块数整篇跳过
MAX_PREFIX_CHARS300前缀长度上限,超出截断
DOC_HEAD_CHARS6000文档摘要取正文开头的字符数
MAX_LOCAL_CONTEXT_CHARS8000局部窗口(父块或相邻块)字符预算
CONCURRENCY4单文档内并发调用的批数
BATCH_MAX_CHUNKS6每批最多合并的分块数
BATCH_OUTPUT_TOKENS_PER_CHUNK、BATCH_MIN_OUTPUT_TOKENS160、512每批输出预算

四级门控照搬,开启情境增强不等于每块调用一次:

  1. 文档级:分块方式为「按页」「整篇不分块」时整篇跳过。
  2. 短文档:分块数少于 3 时整篇跳过,文档摘要那次调用也省掉。
  3. 块级规则:纯标题块、纯图片块、章节整块跳过;表格块不跳过。
  4. 模型端:提示里给出章节路径,模型判断分块已自足时输出 NONE。

每个文档的调用次数 = 1 次文档摘要 + ⌈通过门控的分块数 ÷ 6⌉ 次批调用。

与 zhizhan-ai 不同的两处:

失败语义照搬:全程不抛错。文档摘要失败时整篇没有前缀;单批失败时这一批没有前缀;向量化照常完成。每个文档记录跳过、NONE、失败三个计数,文档详情里显示;只有「失败」计数大于 0 才标为警告。

设置表单提供「马上测试」:对选中的一个文档,实时生成前 10 个分块的前缀预览,不写库。zhizhan-ai 的向量化配置表单有同样的功能(KbVectorizeConfigFormView.vue:333)。

5. 分类:文档页左侧分类栏

现状:分类只出现在工具栏的「分类筛选」下拉框、「包含子分类」开关,以及每行文档名下的分类名(KnowledgeBaseDocuments.jsx:280)。zhizhan-ai 是左侧栏:点开知识库后列出分类和各自的文档数(zhizhan-ai KbTab.vue:4-50)。分类树接口已经返回每个分类的文档数(service/document_management.py:81),不用改后端。

  1. 「文档」页签分左右两栏。左栏宽 236px:「全部文档」「根分类」,下面是分类树,每项带文档数。
  2. 点父分类时,列表默认包含子分类的文档。「包含子分类」改为列表上方的小开关。
  3. 库的创建人看到每项的「⋯」菜单(新建子分类、重命名、删除)和底部「新建分类」。其他人只能浏览。
  4. 上传的目标分类默认取左栏当前选中的分类。
  5. 工具栏里的「分类筛选」下拉框删除。
  6. 不做拖拽移动。移动文档沿用现有的「移动」批量操作。

5.1 示意图:文档页

画的是内容区,宽 1220px(实际页面左侧还有约 220px 的导航栏)。库名、文档名、格式、分块数、大小取自本机「CP2 全格式验收-2026-09-13」库。分类名是假设的:本机所有库的文档都在根分类,没有可用的真实分类数据。

CP2 全格式验收-2026-09-13
本团队及被授权的团队可查看、下载和检索;管理文档需要所属团队的知识库编辑权限。 向量模型:KB 百炼向量 text-embedding-v4
文档检索和问答测试回答设置设置
分类20 篇
全部文档20
根分类0
▾ Office 文档7⋯
表格3
PDF2
图片5
文本与其他6
+ 新建分类
搜索文档名☑ 包含子分类批量操作 ▾上传文档
文档格式状态分块大小
☐cp2-docx.docx
Office 文档
DOCX可检索236.1 KB
☐cp2-doc.doc
Office 文档
DOC可检索218.0 KB
☐cp2-xls.xls
Office 文档 / 表格
XLS可检索16.0 KB
☐cp2-xlsx.xlsx
Office 文档 / 表格
XLSX可检索14.9 KB
☐cp2-long-table.xlsx
Office 文档 / 表格
XLSX可检索176.9 KB
☐cp2-pptx.pptx
Office 文档
PPTX可检索127.8 KB
☐cp2-ppt.ppt
Office 文档
PPT等待处理 · 前面还有 3 个—593.0 KB

最后一行的「等待处理 · 前面还有 3 个」演示第 2 节的排队提示,这个文档在本机的真实状态是「可检索」。「设置」页签是新增的,承载第 3、4 节的库级设置。

5.2 示意图:上传对话框

左:缺省折叠,只显示库的默认值。右:点「本批单独设置」后展开。文件名取自本机库。

上传文档
目标分类
Office 文档
取左栏当前选中的分类
文件
cp2-docx.docx cp2-pptx.pptx
单次最多 20 个,每个不超过 100MB
分块
使用知识库默认值:按结构和句子,块长 420,重叠 40
本批单独设置
向量模型
KB 百炼向量 text-embedding-v4
由知识库决定,在「设置」页签更换
取消上传
上传文档 · 本批分块设置
分块方式
按结构和句子按页启发式语义自定义分隔符整篇不分块
块长
420 32–6000,不超过向量模型的输入上限 8192
重叠
40 小于块长
高级 ▾
标题切分层级 自动 父块上限 整章
情境增强
☑ 开启 模型 Qwen3.8-27B-MTP ▾
每篇 1 次摘要 + 每 6 个分块 1 次调用;少于 3 个分块的文档跳过
恢复知识库默认值
只对本批文件生效,不修改知识库默认值
取消上传

「输入上限 8192」取自本机 text-embedding-v4 的 maxInputTokens。

5.3 示意图:建库对话框与「设置」页签

左:建库对话框,「标识」「名称」「描述」是现有字段(KnowledgeBaseDialog.jsx:50-69),向量模型和分块默认值是新增的;向量模型未选,所以「创建」不可点。右:设置页签,演示管理员在「对接模型」页改过模型配置之后的状态。模型名与维度取自本机「对接模型」。

新建知识库
标识
ops-runbook
名称
运维排查手册
向量模型
请选择向量模型 ▾
可选:KB 百炼向量 text-embedding-v4、Qwen3-Embedding(均为 1024 维)
建库后更换模型需要重建全部文档的向量
分块默认值
按结构和句子,块长 420,重叠 40 修改
取消创建
向量模型更换模型
KB 百炼向量 text-embedding-v4 · 1024 维
20 篇文档、41 个分块使用此模型
分块默认值编辑
按结构和句子,块长 420,重叠 40,标题层级自动,父块整章;情境增强关闭
只影响之后上传或重新向量化的文档

右侧的「41 个分块」是本机该库 20 篇文档 chunks_count 之和。横幅只在模型版本变化时出现,本机当前不处于这个状态。

6. 影响面

位置改动
aimp-kb service/kb_app_runtime.py、kb_rag_runtime.py检索合并为一个函数,改为 SQL 召回;kb_rag_runtime.retrieve 删除
aimp-kb service/kb_pipeline.py取任务、租约、重试、并发线程;用 jieba 写 content_tokens;去掉 rerank 依赖;使用库的模型和分块默认值;语义分块传向量函数
aimp-kb 新增,从 zhizhan-ai 移植kb_retrieve_service.py(检索)、kb_fts.py(jieba 全文检索)、contextual_prefix_service.py(情境增强);依赖加 jieba==0.42.1
aimp-kb api/kb_document_api.py、kb_management_api.py、model/document_management.py上传流式落盘;上传和重新向量化接收分块参数;模型参数不一致返回 422;库的设置接口
aimp-kb alembictb_kb 加 3 列,tb_kb_job 加 3 列;回填库的模型与 content_tokens
aimp-kb 新入口 app/worker.py;meta deploy/kb/compose.yaml、release/compose/docker-compose.yml独立处理进程
aimp-platform packages/ui/src/views/kb/建库对话框、设置页签、文档页左栏、上传对话框、测试面板的 Embedding 只读、知识应用表单的向量模型改为只读推导
aimp-platform server services/platform-setting/、services/model-runtime/、routes/model-runtime/两个平台设置项;并发上限改为读平台设置;新增 GET /model-runtime/limits
aimp-platform ui 平台设置页两个设置项的表单与说明
meta release/:PG 配置、安装手册按 1.3 第 4、5、6 项给出 PG 参数的取值方法

对使用者可见的行为变化:

7. 验证

项做法期望
检索延迟生成 1 万和 10 万个分块的合成库,同一组问题分别跑旧实现和新实现,记录 p50、p95,以及 EXPLAIN (ANALYZE, BUFFERS)新实现走 idx_tb_kb_emb_hnsw 与 ix_tb_kb_chunk_content_tokens;p95 不随分块数线性增长。没有定容量目标,实测数字写进本文作为基线
检索一致性评测集上对比新旧实现前 10 条的重合率Top10 重合率不低于 80%(用户确认)
带过滤召回在 10 万分块里只选一个 50 分块的库检索,candidate_k=30返回 30 条;关掉 iterative_scan 时少于 30 条(用来证明这项设置生效)
并发入库一次上传 20 个文件同时最多 2 个处于「解析中 / 索引中」,其余显示排队位次,按提交顺序开始;全部完成后 20 个都是「可检索」
并发热调整入库进行中,在平台设置把「知识库入库并发」从 2 改为 330 秒内同时处理的文档变为 3 个;不重启平台和 kb
设置校验把「模型调用并发上限」设为 2,再把「知识库入库并发」设为 3保存失败,提示不能大于模型调用并发上限 2
限流重试在平台设置把「模型调用并发上限」临时设为 1,同时上传 5 个文件,期间在测试面板提问日志里出现 429 后的批次重试,最终全部「可检索」,没有文档被标为失败
进程崩溃入库中途终止处理进程,再启动租约过期后任务被重新领取,文档最终「可检索」,分块数与单独处理一次时相同
模型归属建库选 Qwen3-Embedding,上传 1 个文件;之后在「对接模型」页调整排序,再上传 1 个两个文档的向量都是 Qwen3-Embedding;检索不报 409
语义分块用「语义」方式上传本机 test1 库的「2026美伊战争态势分析报告.md」(按句子分块时 41 块)分块边界与按句子分块不同;任务记录里有句向量调用次数,没有降级警告
情境增强门控开启情境增强,上传「链路详情日志不匹配-现场排查指引.pdf」(按页分块时 4 块),再用「按结构和句子」上传同一文件按页时整篇跳过,没有模型调用;按句子时生成前缀,跳过、NONE、失败三个计数之和等于分块数
情境增强失败不阻断情境增强模型选一个已停用的 chat 模型后上传文档最终「可检索」,失败计数大于 0,文档详情显示警告
与 zhizhan-ai 一致同一文档、同一组参数分别在 zhizhan-ai 和 aimp-kb 入库分块数、分块边界一致;情境增强的跳过与生成数一致(前缀文字因模型不同可以不同)
不依赖 rerank停用全部 rerank 模型后上传入库成功;检索测试提示需要 rerank 模型

8. 迁移与回滚

9. 实施顺序

  1. 第 1 节(检索)。独立,可以先做;先做合成数据压测,拿到旧实现的基线。
  2. 第 2 节(入库),含 2.3 的两个平台设置项。与第 1 节没有依赖,可以并行。
  3. 第 3、4 节一起做:两者都改 tb_kb、库的设置接口和「设置」页签,合并成一次迁移。4.5 情境增强最后做。
  4. 第 5 节(分类栏)。纯前端,随时可做。

10. 未决问题

前两轮的 12 项已由 0.1 节的 9 项决定关闭。容量没有给出具体数字,以第 7 节的实测结果作为基线。上一版列的「情境增强系统提示词的来源」不成立:完整指令在代码的 user 消息里(4.5 节)。剩一项不阻塞开工的核对:

#问题影响谁定,何时必须定
1zhizhan-ai 部署环境里那个「LLM 应用」是否另外配了系统提示词。仓库里看不到应用配置;移植后不设系统提示词如果那边配了额外要求,两边生成的前缀风格会有差别;不影响门控、合批和失败处理【待确认】能访问 zhizhan-ai 部署库的人查看该应用配置;在第 7 节「与 zhizhan-ai 一致」那项验证时对比即可