Files
border-red-post-nalati/docs/RETRIEVAL_EXPORT_API.md
T

8.0 KiB
Raw Blame History

检索与上下文历史导出

本接口为后续实验保留当时的检索证据与配置,不重新检索、不加载 Embedding 或调用生成模型,也不生成质量分数。四种模式仍保持各自证据粒度,不能把条目与 chunk 混为同一评测样本。

请求与权限

POST /api/retrieval/exports,管理员会话、允许的 Origin 和 X-CSRF-Token 均为必需。普通用户 403,匿名/失效会话 401;错误 Origin 或 CSRF 为 403。继承 认证契约,不会返回用户、会话或凭据字段。

{
  "run_ids": ["00000000-0000-4000-8000-000000000001"],
  "include_contexts": false
}

编号仅为格式示例,实际应先从管理员 GET /api/retrieval/runs 选择已存在的记录。run_ids 必须为 1–100 个不重复 UUID,大小写规范化后仍重复也拒绝;include_contexts 为严格布尔值,默认 false。额外字段、空列表和非法编号为 422。

明确选择避免导出无边界的全库记录。任一检索编号不存在即 404,不生成部分文件。可选上下文是这些检索记录关联的全部已保存准备记录,不含其他检索的上下文。

下载与 JSONL 契约

  • 成功为 200,Content-Type: application/x-ndjson; charset=utf-8,Content-Disposition: attachment; filename="nalati-retrieval-<export UUID>.jsonl"。
  • 响应固定 Cache-Control: no-store 和 X-Content-Type-Options: nosniff;X-Records-SHA256 等于文件首行的 records_sha256。
  • UTF-8 编码,每行一个 JSON 对象,每行(包括末行)以 LF 结束;内容中的换行由 JSON 转义。不是 CSV,也不是一个 JSON 数组。
  • 首行为 record_type=manifest。其余先为检索记录,再为上下文记录,各组按数据库 created_at,id 升序。请求 UUID 列表的顺序不影响记录区顺序。

首行字段:

字段 含义
schema_version 固定 nalati-retrieval-export-v1
export_id、exported_at 本次导出 UUID 与带时区 UTC 时间
selection 排序后的检索 UUID 及是否包含上下文
counts 实际 retrieval_runs 与 rag_contexts 条数,不含首行
records_sha256 首行之后全部原始 UTF-8 字节的 SHA-256,含每条末尾 LF
snapshot_semantics 固定 stored_history_not_current_corpus
generation_measurements status=not_called,usage/cost/currency=null;没有生成调用或费用测量,不能解释为零成本

检索行有 record_type=retrieval_run、id、ranking_unit 和 payload。payload 保留原已保存响应,不重新计算或修改分数、耗时、文本、来源及版本:

payload.mode ranking_unit 保留的配置与证据
keyword knowledge_item 条目 BM25、中文分词/标题权重、片段与来源版本
keyword_chunks chunk 文本发布/切分/语料版本、正文 BM25、chunk 原文出处
vector chunk 文本/向量发布、模型完整 revision、空间/维度与精确余弦配置
hybrid chunk 同一 chunk 粒度、两路完整候选/排名/原始分数/贡献、RRF 与模型空间配置

上下文行有 record_type=rag_context、id 和原保存的 payload;保留准备参数、证据、排除原因、提示词版本、请求体及请求摘要。model_called=false,即使 status=prepared 也不是模型回答。原字段详见 RAG_CONTEXT_API.md。不导出数据库 created_by 或认证表数据。

快照、容量与失败

  • 检索与可选上下文通过一个 PostgreSQL SQL 语句快照读取,没有跨页读取造成的漂移;执行后新增的上下文留到下一次导出。
  • 已修改、删除或重新发布的知识不会改写历史。导出成功只说明当时记录可读取,不说明它仍是当前有效发布或来源仍受支持。
  • 每次最多 100 条检索、100 条关联上下文,完整 UTF-8 文件(含 manifest)最多 8 MiB。超量为 413,不静默截断;某个检索自身关联超过 100 条准备记录时,本版可先不含上下文导出,不能借此声称已导出全部准备记录。
  • 输出前完成结构、编号/关联、数据库元数据和准备请求摘要校验;未知/缺失字段、非有限数值或关联异常为 409。它是历史格式一致性检查,不是来源真实性或事实正确性证明。
  • 服务端先完整验证并组装文件,再返回下载响应;校验、容量或数据库失败不会先发出部分 JSONL。此接口不写入新的检索/上下文记录,不重建索引。
  • 同一历史选择的记录区字节和摘要可重复;manifest 的导出 UUID/时间每次变化,因此不要比较整个文件的摘要。若新增上下文后再次启用 include_contexts,记录区也会变化。SHA-256 仅供字节完整性核对,不是审阅签名或质量指标。

elapsed_ms 沿用各模式原始计时范围,不是生成模型或完整浏览器交互耗时。模型、语料与参数不一致的记录不能只凭分数直接做实验对比。

调用与核对

已有管理员登录并按认证契约准备 Cookie 文件和当前 CSRF 后,可在仓库根目录调用。Cookie 文件、真实请求、JSONL 和实际日志均留在 Git 元数据目录或仓库外;下面的编号仍需替换成真实已保存的检索编号。

mkdir -p .git/exports
curl --fail-with-body --request POST http://127.0.0.1:8000/api/retrieval/exports \
  --cookie "$COOKIE_JAR" \
  --header 'Origin: http://localhost:5173' \
  --header "X-CSRF-Token: $CSRF_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{"run_ids":["00000000-0000-4000-8000-000000000001"],"include_contexts":true}' \
  --output .git/exports/history.jsonl

仅在 HTTP 200 后按 JSONL 读取文件。核对摘要时不应重新序列化记录:

import hashlib
import json
from pathlib import Path

header, records = Path(".git/exports/history.jsonl").read_bytes().split(b"\n", 1)
manifest = json.loads(header)
assert manifest["schema_version"] == "nalati-retrieval-export-v1"
assert hashlib.sha256(records).hexdigest() == manifest["records_sha256"]
rows = [json.loads(line) for line in records.rstrip(b"\n").split(b"\n")]
assert len(rows) == sum(manifest["counts"].values())

前端调用层 services/exports.ts 的 exportRetrievalHistory 返回 Blob、受限文件名和记录摘要,沿用同一 Cookie/CSRF、401 撤销及错误处理,不放入 localStorage。下载页面已通过 PR #36 合入,可从管理员工作台进入。真实浏览器跨页选择、可选上下文、落盘文件与摘要核对见 导出浏览器验收;调用层模拟网络测试与真实浏览器路径分别记录。

验证与撤回

新增专项覆盖混合模式原始快照、可选准备记录、无命中、软删除后历史、摘要稳定性、权限/CSRF、未知字段/关联损坏拒绝、字节/条数上限、并发新增上下文以及真实 HTTP 后端重启后的同一记录区。坐标 fixture 仅用于导出协议,不构成真实领域模型实验。专项命令 pytest -q backend/tests/test_exports.py:30 passed;完整 pytest -q backend/tests:254 passed, 1 skipped,skip 为显式启用的真实 Embedding 用例,本阶段没有重跑模型。ruff check backend、ruff format --check backend 通过;前端在 frontend/ 执行 npm run test:session:3 passed,npm run build 通过。

数据库不新增迁移,继续为 0007_rag_contexts。撤回导出路由、服务、调用层即可停止新下载;原检索/上下文历史与已保存文件不变,不为回滚删除数据库记录。

Responses 与旧准备快照

新准备记录的 completion.protocol=responses,导出按 Responses 重建请求体并核对哈希;旧记录没有 protocol,继续按原 Chat Completions 配置重建。读取与导出不补写旧字段,不改变旧 payload 或记录字节;同一文件可包含两种协议。该变化仍不代表生成模型已调用,manifest 的生成用量和费用继续为未采集。