卓安Claw 数据存储与处理架构:先存后处理 v1.0
本页目录
- 0. 结论
- 1. 先把问题拆开:四类数据,四种顺序
- 2. 为什么不能“先处理后存”
- 2.1 法律场景的原件价值
- 2.2 处理本身是不确定的、会变的
- 2.3 工程上的失败模式
- 2.4 合规与数据主权
- 3. 目标架构:原始层 + 派生层
- 3.1 五层数据
- 3.2 原始层的“不可变”具体指什么
- 4. 一次上传的完整时序
- 4.1 同步段(请求内,目标 < 1 秒,不含大文件传输)
- 4.2 异步段(worker)
- 4.3 状态机
- 5. 数据模型(V1 建议)
- 5.1 为什么用 version 而不是覆盖
- 5.2 幂等键
- 6. 处理流水线的工程要求
- 6.1 同步与异步的边界
- 6.2 失败处理
- 7. GitHub 调研:别人怎么做的
- 7.1 直接证据:文档管理系统“原件永不覆盖”
- 7.2 媒体系统:原图与派生图分离
- 7.3 文档 AI 工具:它们是“转换器”,不是“档案库”
日期:2026-11-11
状态:架构对齐稿(待评审)
范围:卓安律所(单所/分所)的案卷、业务记录、Agent 产物、知识沉淀;以及庭立方平台的数据边界
关联:ADR-003-单壳一体化重构.md、卓安Claw-AI原生办案系统-设计需求-v1.0.md、曾鸣智能-卓安对齐-v1.0.md
0. 结论
先存储,后处理。原件是唯一事实源,处理结果是可重建的派生层。
更准确地说,不是“先处理再存”或“先存再处理”二选一,而是:
- 同步落原件:上传/扫描/企微/邮件进来的文件,先做准入检查(类型、大小、病毒),边读边算 SHA-256,写入不可变原始层,并落一条最小清单(manifest)。
- 异步做处理:OCR、版面解析、正文抽取、分页、缩略图、实体/时间线抽取、切块、向量化、索引,全部进任务队列,失败可重试,升级可重跑。
- 派生可重建:文本、Markdown、页码映射、摘要、向量、索引都可以删掉重建;原始件永远不覆盖。
- 业务事实先落,指标后算:线索、案件、节点、财务这些业务记录,先写事实/事件,再异步汇总成经营指标;不要让报表反过来阻塞业务。
- AI 产物先以“提议/草稿”落,律师确认后才写业务表:Agent 不能直接改事实。
一句话给非技术同事:先把原件锁进保险柜,再让机器去读;机器读错了可以重读,保险柜里的东西不能动。
1. 先把问题拆开:四类数据,四种顺序
“数据怎么存”容易混在一起。卓安Claw 至少有四类数据,处理顺序不同:
| 数据类型 | 例子 | 正确顺序 | 事实源 | 能否重建 |
|---|---|---|---|---|
| 案卷文件 | 证据、笔录、起诉书、判决书、会见记录、录音录像 | 先存原件,后解析 | 原始文件 + 哈希 + 清单 | 原件不可重建;解析可重建 |
| 业务记录 | 线索、客户、案件、12 节点、清单、财务、渠道成本 | 先记事实/事件,后算指标 | 业务表 + 事件日志 | 指标可重算;事实不可凭空重建 |
| Agent 产物 | 摘要、检索初稿、文书草稿、风险提示、建议 | 先落草稿,律师确认后写回 | 草稿区 + 确认记录 | 可重生成;已确认版本要留痕 |
| 知识与记忆 | 结案复盘、办案经验、所内知识、个人偏好 | 先结构化复盘/审核,再入知识库 | 审核通过的知识条目 | 可从复盘重建;原始案卷不直接入知识库 |
所以,本文的“先存后处理”主要针对案卷文件;对业务数据,等价原则是“事实先落,派生后算”;对 AI 产物,是“草稿先落,确认后生效”。
2. 为什么不能“先处理后存”
2.1 法律场景的原件价值
刑事案卷不是普通文档。原件承载的不只是文字,还有:
- 文件格式、排版、页码、印章、签名、手写批注、表格结构;
- 文件的创建/修改时间、来源、上传人、传递链路;
- 证据的完整性(哈希)与保管链(谁在什么时候看过、导出过、发给谁);
- 庭审/质证时对“原件与复制件一致”的说明能力。
如果先 OCR/转 Markdown,只存处理结果,等于把“证据”降级成“文本”。一旦 OCR 错一个字、漏一页、表格串行,后面所有检索、摘要、Agent 引用都建立在错误底稿上,而且无法证明错在哪。
2.2 处理本身是不确定的、会变的
- OCR 引擎会升级,识别率会变;
- PDF 解析器对扫描件、双栏、表格、手写件的效果不同;
- 大模型摘要/抽取有随机性,提示词和模型版本会变;
- 同一份文件,今天解析失败,明天换个引擎可能成功。
如果“处理完才存”,每次升级都等于把历史数据重新赌一遍;如果“只存处理结果”,旧版本的错误永远无法追溯。正确做法是:原件只进一次,派生结果带版本,随时可重跑、可对比、可回滚。
2.3 工程上的失败模式
- 上传 1GB 案卷,同步 OCR 要几分钟,请求超时,用户以为没存上,重复上传;
- 处理到一半进程崩溃,原件和数据库都不完整;
- 外部模型调用失败/限流,整个上传失败;
- 同一文件重复上传,存了多份,检索结果重复;
- 处理结果写进业务表后,发现解析错了,无法回退。
“先存原件 + 异步处理”把这些问题拆开:存储要可靠,处理要可重试。两者失败互不拖累。
2.4 合规与数据主权
- C 类案卷要求本地/私有云保存,原件不出所;
- 对外部模型只能送必要的片段,且要脱敏、留痕;
- 如果先处理再存,处理过程本身就可能把全文送出去,违背“案卷不出所”;
- 原件先落本地,后续处理才能按级别选择“本地 OCR / 本地模型 / 脱敏后外部模型”。
3. 目标架构:原始层 + 派生层
flowchart LR
U[上传/扫描/企微/邮件] --> G[准入检查<br/>类型/大小/病毒]
G -->|通过| S[原始层<br/>SHA-256 内容寻址<br/>不可变]
G -->|拒绝| Q[隔离区<br/>保留审计]
S --> M[清单 manifest<br/>+ 事务 outbox]
M --> J[处理队列]
J --> P[解析/OCR/版面/抽取]
P --> A[派生层<br/>文本/页码/实体/摘要]
A --> I[索引层<br/>全文/元数据/向量]
I --> AG[Agent/检索/质控/经营]
A -.流水线升级.-> P
S -.永不修改.-> S
3.1 五层数据
| 层 | 内容 | 是否事实源 | 生命周期 | 存储建议 |
|---|---|---|---|---|
| L0 原始层 | 原始文件、哈希、大小、MIME、来源、上传人、保管链 | 是 | 按案件保留期/法律留痕,不可变 | 本地磁盘/NAS/私有对象存储;内容寻址 |
| L1 解析层 | 逐页文本、Markdown、版面块、表格、OCR 置信度、页码映射 | 否 | 可重建,随流水线版本 | 文件 + 数据库索引 |
| L2 索引层 | 全文索引、元数据索引、向量索引 | 否 | 可重建 | SQLite FTS5 / PostgreSQL / pgvector / Qdrant |
| L3 语义层 | 当事人、机关、日期、金额、罪名、证据清单、时间线、争点、摘要 | 否 | 可重建,需标注模型/提示词版本 | JSON/表 |
| L4 业务/展示层 | 案件、节点、清单、记录、财务、经营指标、Agent 草稿 | 业务事实是;指标否 | 业务事实长期;指标可重算 | SQLite/PostgreSQL |
原则:L1–L3 都可以删了重建;L0 不能。L4 的业务事实不能靠 AI 重写,AI 只能提议。
3.2 原始层的“不可变”具体指什么
- 文件按内容寻址:
sha256作为 blob ID;同一文件重复上传只存一份,多个案件/文书版本引用同一个 blob; - 原文件写入后不原地修改;需要修订时新增版本,旧版本保留;
- 数据库只存相对路径,不存绝对路径;换机器/换盘可迁移;
- 每个 blob 有
size、mime、sha256、created_at、encryption、legal_hold; - 每条案件文书版本有
document_id、blob_id、version、original_name、source、uploaded_by; - 删除是“墓碑 + 审批 + 保留期”,不是直接
rm;派生层先删,原始层最后删; - 备份只承诺“原件 + 元数据”可恢复;派生层丢了就重跑。
4. 一次上传的完整时序
4.1 同步段(请求内,目标 < 1 秒,不含大文件传输)
- 客户端上传到临时文件(流式,不一次性读进内存);
- 准入检查:扩展名/MIME/大小上限/病毒扫描(可异步但未通过前不进案件库);
- 边写边算 SHA-256;
- 原子移动到内容寻址路径(先写临时文件,再
rename,避免半截文件); - 同一事务写:
-
zhuoan_doc_blob(没有则插入); -zhuoan_doc_version(案件文书版本); -zhuoan_ingest_job/ outbox(待处理事件); - 返回
202 Accepted+document_id+job_id+status=stored。
关键:原件落盘和“待处理事件”要在同一个逻辑事务里完成(本地 SQLite 可用同库事务;跨文件系统用 outbox + 对账)。 否则会出现“文件存了、任务没入队”或“任务入队了、文件没存”的双写不一致。
4.2 异步段(worker)
- worker 取任务(
queued→running,带租约/超时); - 识别文件类型:PDF 文本型/扫描型、Word、图片、音频、压缩包;
- 解析/OCR: - 文本型 PDF:直接抽文本 + 版面; - 扫描型 PDF/图片:OCR,保留逐页置信度; - Office:转 PDF/HTML/Markdown(按引擎能力); - 音频/视频:转写 + 分段时间戳;
- 写派生结果(
zhuoan_doc_artifact),带blob_id + artifact_type + pipeline_version唯一键; - 建全文索引;需要时切块、向量化;
- 更新版本状态
ready;失败则failed+ 错误摘要,按退避重试;超过次数进dead,人工处理; - 全过程追加
zhuoan_doc_event(uploaded/parsed/indexed/failed/viewed/exported/model_sent)。
4.3 状态机
received → stored → queued → running → parsed → indexed → ready
↘ failed ↗(重试)
↘ dead(超限,人工)
↘ quarantined(病毒/损坏/哈希不符)
对用户展示的状态可以简化成:
- 原件已存(可下载、可取证、可审计)
- 解析中(OCR/抽取)
- 可检索(全文/语义)
- 需人工处理(失败/加密/损坏)
Agent 的读取门槛:
stored:只能读元数据,不能把内容当事实;parsed:可读文本,但标注“未完成索引/可能有识别误差”;ready:可检索、可引用,引用必须带blob_id + page;failed/dead:Agent 不得引用,提示人工处理。
5. 数据模型(V1 建议)
不直接改上游 document 表的核心字段,避免上游合并冲突;用 zhuoan_* 侧表扩展。
-- 原始件:内容寻址,不可变
CREATE TABLE IF NOT EXISTS zhuoan_doc_blob (
id TEXT PRIMARY KEY,
sha256 TEXT NOT NULL UNIQUE,
size_bytes INTEGER NOT NULL,
mime_type TEXT,
storage_path TEXT NOT NULL, -- 相对路径
encryption TEXT DEFAULT 'none', -- none/bitlocker/envelope
legal_hold INTEGER DEFAULT 0,
created_at TEXT NOT NULL
);
-- 案件文书版本:关联上游 document
CREATE TABLE IF NOT EXISTS zhuoan_doc_version (
id TEXT PRIMARY KEY,
document_id TEXT NOT NULL, -- 上游 document.id
blob_id TEXT NOT NULL,
version INTEGER NOT NULL,
original_name TEXT,
source TEXT, -- upload/scan/wecom/email/agent
uploaded_by TEXT,
uploaded_at TEXT NOT NULL,
status TEXT NOT NULL, -- stored/queued/processing/ready/failed/quarantined
UNIQUE(document_id, version)
);
-- 处理任务:或作为 outbox
CREATE TABLE IF NOT EXISTS zhuoan_ingest_job (
id TEXT PRIMARY KEY,
blob_id TEXT NOT NULL,
pipeline_version TEXT NOT NULL,
stage TEXT NOT NULL, -- parse/ocr/thumbnail/extract/embed/index
status TEXT NOT NULL, -- queued/running/succeeded/failed/dead
priority INTEGER DEFAULT 100,
attempts INTEGER DEFAULT 0,
max_attempts INTEGER DEFAULT 5,
last_error TEXT,
idempotency_key TEXT NOT NULL UNIQUE,
created_at TEXT NOT NULL,
started_at TEXT,
finished_at TEXT
);
-- 派生结果:同一 blob/类型/流水线版本唯一
CREATE TABLE IF NOT EXISTS zhuoan_doc_artifact (
id TEXT PRIMARY KEY,
blob_id TEXT NOT NULL,
artifact_type TEXT NOT NULL, -- text/markdown/pages/thumbnail/entities/summary
pipeline_version TEXT NOT NULL,
engine TEXT, -- docling/mineru/paddleocr/tika...
model TEXT,
prompt_hash TEXT,
content_path TEXT,
content_json TEXT,
page_map TEXT, -- JSON: page -> char range / bbox
confidence REAL,
created_at TEXT NOT NULL,
UNIQUE(blob_id, artifact_type, pipeline_version)
);
-- 只追加事件:审计与保管链
CREATE TABLE IF NOT EXISTS zhuoan_doc_event (
id INTEGER PRIMARY KEY AUTOINCREMENT,
blob_id TEXT,
document_id TEXT,
event_type TEXT NOT NULL, -- uploaded/viewed/parsed/indexed/exported/model_sent/deleted
actor TEXT,
detail TEXT,
created_at TEXT NOT NULL
);
5.1 为什么用 version 而不是覆盖
- 上游
document已有version/replaced_by,可以复用“第几版”的语义; - 但文件内容用
blob_id指向不可变 blob,document.version只是业务版本号; - 同一文书改稿:新增
zhuoan_doc_version行 + 新 blob;旧行保留; - 同一文件重传:SHA-256 命中已有 blob,只新增引用,不重复占空间。
5.2 幂等键
建议:
idempotency_key = sha256(blob.sha256 + ':' + stage + ':' + pipeline_version)
- 同一文件、同一阶段、同一流水线版本,只允许一个成功产物;
- 重跑时先查已有 artifact:成功则直接复用;失败则新建任务;
- 流水线升级 =
pipeline_version变化 = 新产物,不覆盖旧产物。
6. 处理流水线的工程要求
| 要求 | 做法 |
|---|---|
| 可重试 | 任务租约 + 超时 + 指数退避;失败不丢原件 |
| 可恢复 | worker 崩溃后任务回到 queued;用 started_at/租约判断僵尸任务 |
| 可重跑 | 管理端“重新解析”按钮;按 pipeline_version 新生成 artifact |
| 可对比 | 新旧 artifact 并存;可看差异/置信度;不自动替换已确认内容 |
| 可限流 | 按案件/用户/引擎限并发;大文件低优先级;夜间批量 OCR |
| 可观测 | 队列深度、成功率、平均耗时、失败原因、单文件成本 |
| 可隔离 | 病毒/损坏文件进隔离区;不进入案件库,不送模型 |
| 可审计 | 谁上传、谁查看、谁导出、谁送过外部模型、用了哪个模型/提示词 |
6.1 同步与异步的边界
| 动作 | 同步/异步 | 说明 |
|---|---|---|
| 哈希、大小、MIME 检查 | 同步 | 很快,决定是否接收 |
| 病毒扫描 | 同步门槛或快速异步 | 未通过不进案件库;隔离区保留 |
| 写原件 + manifest | 同步 | 必须完成才返回成功 |
| 首页预览/缩略图 | 可同步(小文件) | 只作预览,不当作已解析 |
| 全文 OCR/版面 | 异步 | 大文件、扫描件可能几分钟 |
| 实体/时间线抽取 | 异步 | 依赖全文,LLM 可能慢/不稳定 |
| 切块/向量化 | 异步 | 可批量、可重建 |
| 全文/语义索引 | 异步 | ready 后才对 Agent 开放 |
| 结案复盘/知识蒸馏 | 异步 + 人工审核 | 不能自动把案卷变知识 |
6.2 失败处理
- 哈希不符/文件损坏:
quarantined,通知上传人,保留审计; - 加密 PDF/不支持格式:
failed,提示人工解密/转换,不反复重试; - OCR 质量低:仍可
ready,但标confidence,Agent 引用时提示“识别质量低”; - 外部模型失败:不影响原件和本地解析;重试或降级本地模型;
- 磁盘满:拒绝新上传,告警;不能写半截文件;
- 重复上传:哈希命中,复用 blob,返回已有文档提示。
7. GitHub 调研:别人怎么做的
调研方式:2026-11-11 通过 GitHub REST API 检索 + 读取公开 README/文档;星数为当时快照。只做架构参考,未做代码审计,许可证结论不构成法律意见。
7.1 直接证据:文档管理系统“原件永不覆盖”
paperless-ngx/paperless-ngx(约 48k stars,GPL-3.0)的文档明确写了:
Paperless will always store the original document ... and will never overwrite that document ... Archived versions are stored alongside the original versions.
它的做法:
- 原件保存在
originals/,OCR 后的可搜索版本保存在archive/; - OCR 用 OCRmyPDF,处理是可重跑的;
- 文件有 checksum、archive checksum、原始文件名、归档序号;
- 删除进回收站,原件不是立即物理删除。
这几乎就是卓安Claw 需要的“原件层 + 派生层”原型。注意:GPL-3.0,不能直接把代码嵌入闭源产品;可以借鉴设计,或作为独立服务评估。
7.2 媒体系统:原图与派生图分离
immich-app/immich(约 119k stars,AGPL-3.0)把原始照片/视频与缩略图、转码视频分开存;派生文件可以重新生成,原图不动。这个模式对案卷里的图片、扫描件、录音录像同样适用:原图/原音是证据,缩略图/转写只是浏览辅助。
7.3 文档 AI 工具:它们是“转换器”,不是“档案库”
| 项目 | Stars | 许可证 | 定位 | 对卓安的用法 |
|---|---|---|---|---|
| docling-project/docling | 约 70k | MIT | 文档转结构化,面向 GenAI | 本地解析 PDF/Office,产出 Markdown/JSON |
| Unstructured-IO/unstructured | 约 16k | Apache-2.0 | 文档 ETL,分区/清洗/分块 | 解析流水线的一环 |
| opendatalab/MinerU | 约 84k | Apache-2.0 + 附加条款 | PDF/Office 转 Markdown/JSON,扫描件强 | 本地重解析;商用前看附加条款阈值 |
| apache/tika | 约 4k | Apache-2.0 | 检测/抽取 1000+ 文件类型 | 文件类型识别、元数据抽取 |
共同点:输入是一个已存在的文件,输出是派生结果;它们都不负责“唯一事实源”。 所以正确用法是“先存原件,再调用它们;把输出按版本缓存”,而不是“先调用它们,只存输出”。
7.4 数据湖/表格式:不可变文件 + 快照 + 时间旅行
- apache/iceberg(约 9.4k,Apache-2.0):数据文件不可变,通过快照管理表版本,支持时间旅行;
- delta-io/delta(约 9.1k,Apache-2.0):ACID、时间旅行、可重算。
可借鉴的不是“上大数据平台”,而是三条原则:
- 原始数据只追加,不原地改;
- 派生表/指标可重算;
- 每次处理有版本,可回到某个时间点。
卓安不需要 Iceberg/Delta 的复杂度;用“blob + artifact + pipeline_version”就能表达同样语义。
7.5 工作流引擎:长任务要“可恢复、可重试、可幂等”
- temporalio/temporal(约 24k,MIT):持久化执行、重试、超时、补偿;
- dagster-io/dagster(约 16k,Apache-2.0):以数据资产为中心,支持重新物化(re-materialization)。
卓安 V1 不必引入 Temporal/Dagster;用数据库任务表 + 单机 worker 就够。但要借鉴它们的任务状态机、租约、幂等键、重试上限、死信。等做私有云/多所平台时,再评估 Temporal。
7.6 向量库:索引不是事实源
- pgvector/pgvector(约 23.6k,PostgreSQL License):在 Postgres 里做向量检索;
- qdrant/qdrant(约 35.5k,Apache-2.0):独立向量检索服务。
两者都应该是派生索引:文本和页码映射存在 L1/L2,向量只是加速检索。换 embedding 模型时,重建索引即可;不能把“向量库里的片段”当成唯一案卷副本。
7.7 法务 DMS 集成:DMS 是事实源,AI 通过接口读
protomated/legal-context-ce(约 29 stars,MPL-2.0)是一个 MCP 服务,把律所 Clio 文档管理系统接给 Claude:
- Clio 仍是文档事实源;
- AI 通过 API/MCP 查询,不把整个 DMS 复制进模型;
- 访问受 OAuth/权限控制。
这印证了卓安的方向:案管库/原件库是事实源,Agent 是通过工具访问的“读者”,不是数据的拥有者。
7.8 脱敏:对外部模型之前的派生步骤
data-privacy-stack/presidio(原 microsoft/presidio,约 11.8k,MIT):检测/脱敏姓名、电话、身份证号、地址等 PII。
用法:原件不动;在“送外部模型”前,从 L1 文本生成脱敏副本,记录 model_sent 事件;C 类默认禁止送外部模型。脱敏副本也是派生层,不能替代原件。
7.9 对象存储:S3 兼容 + 版本/对象锁
minio/minio(约 61k,AGPL-3.0):S3 兼容对象存储,支持版本、对象锁(WORM)。适合私有云原始层,但 AGPL-3.0 商用/分发需法务评估;也可以选云厂商 OSS/COS/S3 或本地 NAS + 文件系统。
7.10 调研结论
- 成熟系统没有“先处理后存”的:Paperless、Immich、Iceberg/Delta 都是“原始不可变 + 派生可重建”。
- 文档 AI 工具是转换器:Docling/Unstructured/MinerU/Tika 都假设输入文件已存在;不应让它们承担存储职责。
- 长任务需要工作流语义:Temporal/Dagster 的价值是重试、幂等、可观测;V1 用 DB 队列即可,但状态机不能省。
- 索引/向量是缓存:pgvector/Qdrant 不能当事实源。
- 许可证要提前看:GPL/AGPL(Paperless、Immich、MinIO)不要直接嵌入闭源产品;Apache/MIT 也不是“零义务”,要保留声明、注意专利条款;MinerU 有附加商用条款。
7.11 许可证速查
| 许可证 | 项目 | 对卓安的含义 |
|---|---|---|
| GPL-3.0 | Paperless-ngx | 借鉴设计;嵌入/分发需法务评估,倾向独立服务或重写 |
| AGPL-3.0 | Immich、MinIO | 网络服务也可能触发义务;商用分发前必须评估 |
| Apache-2.0 | Unstructured、Tika、Iceberg、Delta、Dagster、Qdrant | 较宽松;保留 NOTICE/许可证,注意专利条款 |
| MIT | Docling、Temporal、Presidio | 较宽松;保留版权声明 |
| Apache-2.0 + 附加条款 | MinerU | 有商用阈值/附加条件,使用前读 LICENSE |
| PostgreSQL License | pgvector | 宽松,类似 BSD/MIT |
| MPL-2.0 | legal-context-ce | 文件级 copyleft;修改文件需开源该文件 |
8. 存储选型与容量
8.1 分阶段选型
| 阶段 | 场景 | 原始层 | 元数据/业务 | 全文索引 | 向量 |
|---|---|---|---|---|---|
| V1 单机 | 单所/演示/试点 | 本地磁盘/NAS,内容寻址目录 | SQLite WAL | SQLite FTS5 | 可选 sqlite-vec,或暂不做 |
| V2 私有云 | 多律师/多分所 | S3 兼容对象存储或 NAS | PostgreSQL | PostgreSQL FTS | pgvector |
| V3 平台 | 庭立方多租户 | 各律所自持原件;平台不存原件 | 平台元数据仓 | 平台只索引脱敏知识/指标 | 平台知识索引 |
不要做的事:
- 不要把 1GB 文件塞进 SQLite 的 BLOB;
- 不要把“解析后的文本”当唯一副本;
- 不要让向量库成为唯一检索入口;
- 不要跨租户做全局哈希去重(会泄露“某文件在某所存在”);律所内可以去重,平台层禁止。
8.2 容量估算(按用户口径)
- 单案约 1GB,单所约 1,000 案/年 → 每年约 1TB 原始件;
- 7 家分所 → 每年约 7TB;
- 3 年保留 → 约 21TB,加备份约 42TB(未计压缩/去重);
- 扫描件/录音录像可能更大;建议冷热分层:在办热存,结案后转冷/近线,保留索引;
- 去重(同一证据多案引用)、PDF 压缩、视频转码只能优化派生层,不能牺牲原件。
这些是量级估算,不是承诺;实际按试点所的真实案卷测量后再定采购。
8.3 备份与恢复
- 原始层:每日增量 + 定期全量 + 异地/离线副本;至少 3-2-1;
- 元数据:SQLite 定期快照/WAL 备份;PostgreSQL 持续归档;
- 派生层:可不备份,恢复后重跑;但索引重建需要时间,重要案件可保留缓存;
- 恢复演练:每季度抽一个案件,从原件 + 元数据恢复,验证哈希、页码、审计链;
- 加密密钥单独备份;否则备份不可读。
9. 安全、合规与数据边界
9.1 数据分级
| 级别 | 例子 | 存储 | 外部模型 | 平台 |
|---|---|---|---|---|
| A 公开 | 宣传内容、公开案例 | 任意 | 可用 | 可用 |
| B 内部 | 经营指标、脱敏知识、模板 | 所内/私有云 | 脱敏后可用 | 聚合/脱敏后可用 |
| C 案卷秘密 | 案卷、证据、当事人信息、会见记录 | 本机/私有云 | 默认禁止;确需时仅脱敏片段 + 审批 + 留痕 | 不上传原件/全文 |
9.2 技术控制
- 传输 TLS;静态加密(BitLocker/LUKS/对象存储 SSE);
- 案件级 ACL:客服/客户经理/谈案/承办/管理者按权限;C 类文件默认最小可见;
- 每次查看/下载/导出/送模型写
zhuoan_doc_event; - 外部模型网关:按数据级别拦截;C 类直接拒绝;B 类先脱敏;记录 provider/model/prompt_hash;
- 导出:水印、审批、有效期;导出件也记哈希;
- 删除:审批 + 墓碑 + 保留期;派生先删、原件后删;SSD 场景用“加密密钥销毁(crypto-shredding)”而不是承诺物理擦除;
- 法务保留(legal hold):涉及诉讼/调查的案件,禁止删除,直到解除。
9.3 平台(庭立方)边界
- 平台拿:租户/律所、用户/角色、案件状态、节点进度、质量指标、渠道/经营聚合、脱敏后的知识条目;
- 平台不拿:案卷原件、全文、当事人敏感信息、会见记录、证据细节;
- 跨所知识:必须律师审核 + 脱敏 + 授权;保留来源案件 ID(平台侧可用假名);
- 平台报表:小样本阈值(如少于 N 家律所不展示),防止反推单所经营数据;
- 平台不能做跨租户内容哈希去重/比对,避免推断“某文件在某所”。
9.4 与“数据主权”口径一致
对客户/律师的说法:
- “资产存本机 + 模型自选”;
- “原件不出所,平台只拿流程和指标”;
- “AI 处理在本地优先;确需外部模型时,只送必要片段并留痕”;
- 不说“完全本地/无需联网/案卷绝对不出终端”(在线模型、激活/更新仍需联网)。
10. 与当前卓安Claw 的差距
10.1 现状
document表有file_path、file_size、version、mime_type、replaced_by,但没有 SHA-256、没有处理状态、没有派生结果表;db.ocr_file()是同步、按需调用 OCR,不缓存结果,不记录流水线版本;- Agent 的
zhuoan_case工具主要拿案件/节点/清单/文档数量,没有把案卷全文/页码引用接入; - 知识库/记忆是另一套,不能和案卷原件混为一谈;
- 目前没有任务队列/worker,也没有“解析中/可检索”的状态展示。
10.2 V1 最小落地(建议)
- 建侧表:
zhuoan_doc_blob、zhuoan_doc_version、zhuoan_ingest_job、zhuoan_doc_artifact、zhuoan_doc_event; - 上传改造:上传接口先算哈希、写原件、写 manifest + job,返回 202;原
document.file_path保留兼容; - 单机 worker:一个后台线程/进程轮询 job;先支持 PDF 文本抽取 + 扫描件 OCR + 缩略图;
- FTS5 索引:解析完成后写全文索引;Agent 工具只读
ready的文本,引用带页码; - 管理端:显示“原件已存/解析中/可检索/失败”,提供“重新解析”;
- 回填:对现有
document逐条算哈希、建 blob/version、入队;不移动原文件,先建立映射,验证后再迁移; - 审计:上传/查看/导出/送模型四类事件先做;C 类外部模型拦截先做规则。
10.3 暂不做
- 不做完整数据湖/Iceberg/Delta;
- 不做多租户对象存储;
- 不做跨所知识共享;
- 不做自动把案卷全文向量化后送外部 embedding(C 类默认本地);
- 不在 11/27 前重构整个案管文件模型;用侧表渐进。
11. 验收标准
| 场景 | 预期 |
|---|---|
| 上传 1GB PDF | 快速返回“原件已存”,后台解析;页面不阻塞 |
| 解析中杀掉 worker | 原件完整;任务回到队列;重试后成功;不产生重复 blob |
| 同一文件重复上传 | 哈希命中,只存一份;两条案件引用;提示已存在 |
| 升级 OCR/解析版本 | 生成新 artifact;旧 artifact 仍可读;可对比;不自动覆盖已确认内容 |
| 删除索引/向量库 | 可从原件 + artifact 重建;业务不丢 |
| 哈希不符/文件损坏 | 进隔离区;告警;不进入案件库;不送模型 |
| C 类文件送外部模型 | 被拦截;审计记录尝试;界面提示原因 |
| Agent 引用 | 能定位到 blob_id + page;标注解析版本/置信度 |
| 备份恢复 | 原件 + 元数据一致;派生重建;审计链连续 |
| 删除案件 | 审批 + 墓碑 + 保留期;派生先删、原件后删;有审计 |
12. 什么情况下可以“先处理再存”
不是绝对禁止,但必须限定为不承担事实源职责的临时处理:
- 上传前预览:用户选文件后,本地/临时 OCR 首页,确认“是不是这份”;临时文件 TTL 删除,不进入案件库;
- 准入检查:病毒扫描、格式探测、损坏检测;不通过进隔离区,保留审计;
- 客户端脱敏:在律师本机先脱敏,再上传脱敏副本;原件仍在本地保存;
- 即时聊天附件:非案卷的临时附件,可处理后在内存/临时目录使用,明确 TTL,不索引、不训练;
- 离线导入预处理:批量导入前先做清单/去重/格式转换,但转换前的原件必须保留在导入包/隔离区,确认后再入库。
红线:
- 不能只存处理结果、不存原件;
- 不能把 C 类全文先送外部模型再存;
- 不能把临时预览结果当“已解析”给 Agent 引用;
- 不能因为处理失败而丢原件。
13. 11/27 演示口径
可以说:
- “原件先存、处理可重跑;机器读错了可以重读,原件不动。”
- “案卷留在所里/本机,平台只拿流程和经营指标。”
- “Agent 引用能回到原件页码,不是凭空生成。”
- “同一份证据多个案件引用,只存一份,但权限和审计分开。”
不要承诺:
- “全自动解析所有格式”;
- “OCR 100% 准确”;
- “案卷全文上平台”;
- “已经建成数据湖/多租户平台”;
- “AI 可以独立判断证据真伪”。
演示建议(如果时间允许):
- 上传一份 PDF → 状态“原件已存/解析中”;
- 切到案件 → 显示“可检索”,点开引用 → 定位到页码;
- 点“重新解析” → 显示新版本,旧版本仍可查;
- 展示审计:谁上传、谁查看、是否送过外部模型。
14. 待决策
- V1 原始层放哪:单机本地目录,还是直接上 NAS/对象存储?建议试点期本地目录 + 可配置根路径,私有云再切对象存储。
- OCR/解析引擎组合:Docling(MIT)+ Tika(Apache-2.0)+ PaddleOCR/系统 OCR;MinerU 作为扫描件增强,商用前审附加条款。
- 向量化是否默认开启:C 类默认本地 embedding;外部 embedding 需审批。V1 可先只做 FTS5,向量后置。
- 保留期:按案件类型/结案时间定;需要与卓安档案管理制度对齐,本文不替律所定年限。
- 平台指标口径:与经营分析 V2 的 ID/口径统一后再上平台,避免两套数字。
- 是否引入 Temporal:V1 不引入;当出现多机 worker、跨服务补偿、长流程编排时再评估。
15. 参考
- Paperless-ngx:https://github.com/paperless-ngx/paperless-ngx
- 文档:
docs/usage.md(原件永不覆盖、archive 并存) - Immich:https://github.com/immich-app/immich
- Docling:https://github.com/docling-project/docling
- Unstructured:https://github.com/Unstructured-IO/unstructured
- MinerU:https://github.com/opendatalab/MinerU
- Apache Tika:https://github.com/apache/tika
- Apache Iceberg:https://github.com/apache/iceberg
- Delta Lake:https://github.com/delta-io/delta
- Temporal:https://github.com/temporalio/temporal
- Dagster:https://github.com/dagster-io/dagster
- pgvector:https://github.com/pgvector/pgvector
- Qdrant:https://github.com/qdrant/qdrant
- MinIO:https://github.com/minio/minio
- Presidio:https://github.com/data-privacy-stack/presidio
- LegalContext:https://github.com/protomated/legal-context-ce
说明:以上星数/许可证为 2026-11-11 GitHub API 快照;许可证结论不构成法律意见,商用前由法务复核。