feat: persist reviewed chunks and index publication versions
This commit is contained in:
+10
-1
@@ -37,4 +37,13 @@ FastAPI + Pydantic
|
||||
|
||||
新增 `retrieval_runs` 保存查询、模式、语料指纹和完整结果快照,支持分页读取及按 UUID 复核。零命中如实记录;当前依据修改后失效不会改写历史,但后续检索必须重新检查审核与父记录状态。响应耗时是本次真实读取、分词、排序及片段生成耗时,不含写日志或模型调用。
|
||||
|
||||
当前按知识条目检索,显示片段最长 240 字符;尚无持久化 chunks、倒排索引、Embedding、向量检索、RRF 或 RAG。全语料计算明确限制条目数及总字符数,超限报错,适用于首批小规模资料与后续对照实验准备,不能当作生产检索性能结论。
|
||||
关键词基线仍按知识条目检索,显示片段最长 240 字符;独立的持久化 chunks 和文本索引版本见下方。当前尚无倒排索引、Embedding、向量检索、RRF 或 RAG。全语料计算明确限制条目数及总字符数,超限报错,适用于首批小规模资料与后续对照实验准备,不能当作生产检索性能结论。
|
||||
|
||||
|
||||
## 切分与索引版本(T05)
|
||||
|
||||
`index_versions/chunks` 保存已审核语料的原文切分、出处与版本、参数、内容哈希及语料指纹。构建先保存 ready 快照,不切换当前发布;`index_state` 管理发布指针、代数与目录修订号,发布同一事务更新前后状态并追加 `index_publications`。
|
||||
|
||||
目录写入、构建与发布共用状态行锁,目录写入先于父记录锁获取该锁并递增修订号。发布核对代数、修订号和当前语料指纹;失败回滚,保留旧版本。目录变化后旧指针仍可追溯,但 is_current=false,不可据此绕过正式审核。历史快照不会被改写。接口均限管理员并沿用 Cookie/CSRF,完整边界见 [INDEX_API.md](INDEX_API.md)。
|
||||
|
||||
这只是后续索引的文本版本基础,关键词基线行为不变;没有生成向量或宣称已实现 ANN/混合检索。同步构建和全局写锁面向当前有限语料,后续异步/增量发布须重新设计并验证并发协议。
|
||||
|
||||
@@ -35,3 +35,10 @@
|
||||
状态:Issue #5 分支实现,待审阅。使用 Argon2id 密码哈希、数据库保存摘要的随机 Cookie 会话,以及独立 CSRF 请求头与显式 Origin 白名单;不把角色或会话凭据放入浏览器持久存储。普通注册只能创建 user,管理员仅由本机隐藏密码输入命令创建。知识/来源/文档管理及检索历史限 admin,公开检索继续只使用已核验依据。完整契约与实现依据见 [AUTH_API.md](AUTH_API.md)。
|
||||
|
||||
为改密和会话撤销使用用户行锁与凭据版本,认证预算使用数据库原子计数;不依赖单进程内存限流。现有前端写请求同步 Cookie/CSRF 封装,页面和路由联调仍待前端完成。本分支叠加 PR #6,后续审阅需关注迁移顺序及匿名管理调用变为 401 的行为变化。
|
||||
|
||||
|
||||
## ADR-010 切分快照与显式发布
|
||||
|
||||
状态:T05 分支实现,待审阅。先对当前有效审核语料构建带原文偏移/哈希/出处的 chunks,再以独立的发布请求切换指针。固定 Unicode 字符窗口配置留存在版本中,关键词接口继续按条目运行,防止未经评估就改变实验口径。
|
||||
|
||||
为当前小规模语料选择统一数据库行锁:应用目录写入、构建、发布串行,发布同时校验代数、目录修订和语料指纹;失败回滚全部更新,旧版本保留为历史。任何成功目录写入保守地使旧索引过期,历史不能视作当前有效依据。实现、容量与后续并发扩展边界见 [INDEX_API.md](INDEX_API.md)。
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
# 文本切分与索引版本接口(T05)
|
||||
|
||||
本阶段保存可复核的已审核语料切分及发布指针,为后续检索索引提供版本边界。这里的“索引版本”是文本语料快照,不包含 Embedding、pgvector 向量字段/ANN 索引或 RRF。现有 `POST /api/retrieval` 仍运行原关键词基线,不读取这些 chunks;不能把本阶段称为向量检索已完成。
|
||||
|
||||
## 依赖、迁移与权限
|
||||
|
||||
分支 `feat/backend-chunk-index-versions` 叠加待审 PR #7(认证),并继承 PR #6(关键词)。三项须分别跟踪审阅;本分支不自行合并其他请求。升级时停止旧后端实例,安装依赖、备份并执行 `alembic upgrade head`,再启动新实例。所有实例必须使用当前版本,才能让目录写入遵守同一发布锁。
|
||||
|
||||
新增迁移 `0005_chunk_indexes`,依赖 `0004_auth_sessions`,创建:
|
||||
|
||||
- `index_versions`:切分配置、语料指纹、目录修订号、条目/chunk 数、构建人、构建时间及发布状态。
|
||||
- `chunks`:所属版本、知识 ID、从 0 开始的片序、原文起止偏移、正文、UTF-8 内容 SHA-256 与出处快照。
|
||||
- `index_state`:单例发布指针、发布代数 `generation`、目录修订号 `catalog_revision`。
|
||||
- `index_publications`:每次发布的前后版本、代数、操作人和时间;重复发布当前版本不会新增记录。
|
||||
|
||||
迁移不改写既有知识、审核、用户、会话或检索记录,不创建初始发布版本。所有 `/api/indexes` 接口均要求 `admin`;POST 还必须携带有效 Cookie、明确 Origin 与 `X-CSRF-Token`,与 [认证契约](AUTH_API.md) 相同。
|
||||
|
||||
## 构建与原文切分
|
||||
|
||||
`POST /api/indexes` 创建一个 `ready` 版本,返回 201,不切换当前发布指针。请求可用默认值 `{}` 或:
|
||||
|
||||
```json
|
||||
{"chunk_size": 500, "overlap": 80}
|
||||
```
|
||||
|
||||
`chunk_size` 为 100–2000 个 Python Unicode 字符,默认 500;`overlap` 默认 80,非负且不得超过切分长度一半。自定义较短长度时也须指定兼容的重叠,例如 `{"chunk_size":100,"overlap":20}`。未知字段拒绝,不支持按类别单独发布。
|
||||
|
||||
固定算法 `unicode-window-v1` 从知识条目原正文位置 0 开始(不是关联文档或原网页的偏移),以 `chunk_size-overlap` 前进,末片到正文结束即停止。保留空白、全半角、组合字符和 Emoji,不标准化或截断原文。`start_offset` 包含起点,`end_offset` 不包含终点;每片 `text == 原文[start_offset:end_offset]`。标题放在出处信息中,不拼进正文偏移。客户端若使用 JavaScript 字符串偏移,须注意其 UTF-16 索引与 Python Unicode 字符偏移的区别。
|
||||
|
||||
- 语料条件与关键词基线共用:只读取未删除、审核及采集信息完整的 `verified` 知识,关联来源/文档须有效、归属及来源网址一致;pending/rejected 不进入构建。
|
||||
- 语料指纹与关键词基线使用同一规范 JSON/算法,涵盖实际正文、标题、类别、出处及知识/父记录版本;切分参数独立保存在 `config`。
|
||||
- 出处快照包含 `knowledge_id/knowledge_version`、可空 `document_id/document_version`、可空 `source_id/source_version/source_name`、`source_url/title/category`。以后原资料修改或失效,不改写旧 chunk 内容及出处。
|
||||
- chunk ID 在一个版本内由版本 UUID、知识 ID 与顺序确定;新构建使用新版本 ID。相同资料及参数可重现偏移/正文/内容哈希,但新旧版本的 chunk ID 不相同。
|
||||
- 本阶段同步构建,沿用最多 5000 条及标题/正文总计 200 万字符的语料限制,每版本另限 20000 个 chunks。超限返回 503;事务写入失败也完整回滚,不保留半个版本,不改变旧发布指针。
|
||||
- 可以构建空语料版本,以便所有依据撤回后发布空快照;这不表示存在可用知识。
|
||||
|
||||
## 发布、过期与并发
|
||||
|
||||
先通过 `GET /api/indexes/active` 读取当前代数,再提交:
|
||||
|
||||
```text
|
||||
POST /api/indexes/{version_id}/publish
|
||||
```
|
||||
|
||||
```json
|
||||
{"expected_generation": 0}
|
||||
```
|
||||
|
||||
发布时锁定 `index_state`,检查代数、目录修订号及当前有效语料指纹;资料或审核已变化、代数过期均返回 409,要求重新构建或刷新。成功后同一事务把旧版本设为 `superseded`、新版本设为 `published`、切换指针、增加代数并追加发布记录。校验失败或写入失败保留此前全部发布状态。持有当前代数重复发布当前版本是无变化的 200;仍有效的历史版本可用最新代数重新发布,发布记录保留每次转换。
|
||||
|
||||
知识、来源、文档的应用写入在修改父记录前持有同一状态锁,事务内将 `catalog_revision` 增加一次;失败写入一起回滚修订号。构建、发布和这些写入串行,避免校验到提交之间发生目录修改。为首批小规模资料选择此保守策略,长构建会暂时阻塞管理写入;尚无后台任务或大规模增量索引。
|
||||
|
||||
任一成功目录写入都会使旧快照过期,包括尚未核验的新条目;此规则比只比较有效语料更保守。`GET /active` 同时核对修订号与实际语料指纹,返回:
|
||||
|
||||
```json
|
||||
{"generation": 1, "catalog_revision": 2, "is_current": true, "active_version": {"id": "<版本 UUID>", "status": "published", "config": {"splitter":"unicode-window-v1","chunk_size":500,"overlap":80}, "...":"其余版本字段见 OpenAPI"}}
|
||||
```
|
||||
|
||||
初始无发布时 `active_version=null/is_current=false`。资料变化后指针及历史保留,但 `is_current=false`;`published` 只表示仍是发布指针,不表示资料仍有效。历史 chunks 是当时的依据快照,不能绕过 `is_current` 直接用于后续正式检索。任何结果只描述该事务快照,之后的目录写入仍可让它过期。直接改库不属于支持的维护流程;额外指纹检查可发现绕过修订号的正文/出处变化,不能替代应用写锁。
|
||||
|
||||
## 查询与交接
|
||||
|
||||
| 接口 | 响应 |
|
||||
|---|---|
|
||||
| GET `/api/indexes` | 版本分页,构建时间降序,同时间按 ID |
|
||||
| GET `/api/indexes/active` | 发布代数、目录修订号、当前性与当前版本 |
|
||||
| GET `/api/indexes/publications` | 发布记录分页,代数降序 |
|
||||
| GET `/api/indexes/{version_id}` | 版本元数据 |
|
||||
| GET `/api/indexes/{version_id}/chunks` | chunk 分页;可按 `knowledge_id` 筛选,按知识 ID/片序排列 |
|
||||
|
||||
分页沿用 `{items,total,page,page_size}`,默认 20、最大 100。版本元数据完整字段为 `id/status/config/corpus_fingerprint/catalog_revision/item_count/chunk_count/created_by/created_at/published_at`;`published_at` 是最近一次发布的时间,逐次时间保存在发布记录。版本及发布记录时间统一输出 UTC ISO 8601,避免数据库时区让重读结果出现不同表示。chunk 字段为 `id/index_version_id/knowledge_id/ordinal/start_offset/end_offset/text/text_sha256/provenance`。
|
||||
|
||||
前端 `src/services/indexes.ts` 提供类型和调用封装,写入共用 Cookie/CSRF;未增加页面或假数据。接口新增需由前端按该契约接入、审阅并验收。独立 T05 Issue 因当前缺少 Gitea 写入认证仍待补建,本 PR 和任务板先保留实现与验证记录。
|
||||
|
||||
## 验证及回滚
|
||||
|
||||
验证包含真实 PostgreSQL 的原文重建与哈希、审核筛选、重复构建、过期拒绝、来源/文档更新、失败写入、发布历史、数据库锁竞争、失败构建/发布的真实约束回滚、迁移兼容及真实 HTTP 重启后指针/chunks 持久化。这里只使用占位资料,不是论文实验结果。Docker 和浏览器端验收保持待办。
|
||||
|
||||
备份后配合旧后端执行 `alembic downgrade 0004_auth_sessions`,只撤回这四张表,保留用户、会话、知识及检索记录;索引历史与 chunks 恢复依赖备份。旧应用不可使用新版本数据库混跑。
|
||||
|
||||
并发实现参考 [PostgreSQL 16 行锁说明](https://www.postgresql.org/docs/16/explicit-locking.html) 与 [SQLAlchemy FOR UPDATE](https://docs.sqlalchemy.org/en/20/core/selectable.html#sqlalchemy.sql.expression.Select.with_for_update)。
|
||||
@@ -61,3 +61,12 @@
|
||||
- 默认 Secure/HttpOnly/SameSite Cookie;写操作校验明确 Origin 及当前会话 CSRF。改密使所有旧会话失效,退出持久化撤销;参数错误不回显密码。字段、来源、CSRF 和前端交接见 [认证接口契约](AUTH_API.md)。
|
||||
- 实际验证:`ruff check .`、`ruff format --check .` 通过;`pytest -q` **70 passed**,包含认证、授权、CSRF、输入越权、过期/轮换/撤销、限额、迁移及既有知识/检索回归;真实 HTTP 服务重启验证会话恢复和退出后不再有效。前端 `npm run build` 通过。
|
||||
- 当前仍使用隔离 PostgreSQL 做自动化验证;Docker 容器、前端登录/角色页面及真实浏览器端流程仍待验收。远程 main 的注册原型最低密码提示需要按本契约同步到 15 字符,并接入带 Cookie/CSRF 的调用层。没有宣称已完成前端集成或生产部署。
|
||||
|
||||
## 2026-10-16 T05:持久化 chunks 与索引版本
|
||||
|
||||
- 分支 `feat/backend-chunk-index-versions` 叠加待审 PR #7(`f9827fe`),继承 #6;不等待合并继续后端阶段,同时保留各 PR 的审阅记录。
|
||||
- 新增 `0005_chunk_indexes`:版本、原文切分及出处、发布状态单例、逐次发布记录。构建 ready 快照与发布分开,保留字符偏移、内容哈希、知识/来源/文档版本和语料指纹。
|
||||
- 知识、来源、文档写入与构建/发布共用数据库行锁;目录修订与实际语料指纹一起决定当前性,旧构建/旧代数拒绝发布。构建或发布失败完整回滚,旧发布指针及历史不丢失。
|
||||
- 管理接口统一要求 admin 与写入 CSRF;前端只同步类型和调用层,页面仍待联调。现有关键词基线行为不变,向量、ANN、RRF 与 RAG 未在本阶段实现。
|
||||
- 实际验证:`ruff check .`、`ruff format --check .` 通过;`pytest -q` **91 passed**(隔离 PostgreSQL 16 + pgvector),包含真实锁竞争、失败构建/发布的数据库约束回滚、迁移保留账号/知识/检索记录、原文重建与来源快照、真实 HTTP 重启后的发布指针和 chunks 持久化。修正了发布时间在 UTC 与数据库时区之间表示不一致的问题,索引接口统一 UTC 输出。前端 `npm run build` 通过。
|
||||
- 完整请求/响应、切分/容量、失效策略及回滚说明见 [INDEX_API.md](INDEX_API.md)。本阶段仍是有限语料的同步文本快照;Docker/浏览器验收、独立 T05 Issue 补建及后续 Embedding 方案选择仍有待完成。
|
||||
|
||||
Reference in New Issue
Block a user