完整流水线
复制来源、格式解析、MinerU、图片抽取、视觉描述。
识别实体、概念、主张、矛盾和现有 Wiki 关系。
输出来源页与领域页,附 frontmatter、sources 与 wikilink。
解析、清洗、合并、修复、索引、日志、审核、缓存和向量。
入口 autoIngest(projectPath, sourcePath, llmConfig, ...) 先以“项目 + 来源”加锁,
允许不同来源的准备和模型生成并行,但把会改变 Wiki 的部分放进项目级提交边界。这样既争取吞吐,也避免多个来源同时覆盖聚合页。
来源进入系统
复制、路径与身份
显式导入会把文件复制到 raw/sources/;文件夹导入保留相对目录结构,并把诸如“papers > energy”这样的文件夹上下文交给模型辅助分类。
同名文件通过唯一目标路径处理,来源身份优先使用项目相对路径,避免不同子目录中同名文件互相污染。
格式解析
| 输入 | 实现策略 | 输出 |
|---|---|---|
| 可选 MinerU;失败回退内置 PDFium。文本与图片均可缓存。 | Markdown + wiki/media 图片 | |
| DOC/DOCX/PPT/PPTX | AnyDoc、docx-rs 或 ZIP/XML 结构提取,保留标题、列表、表格语义。 | 结构化 Markdown |
| XLS/XLSX/ODS | calamine / AnyDoc,按工作表转成 Markdown 表格。 | 表格文本 |
| EPUB/MOBI/Org | 专用电子书解析与 Org 文本提取。 | 章节化文本 |
| 网页 | Chrome Clipper 用 Readability 清洗,再由 Turndown 转 Markdown。 | 带 URL 的来源文件 |
解析结果保存在来源旁的 .cache/<filename>.txt;缓存只有在不早于原文件时才有效,结构化文档还带解析器格式标记以拒绝旧缓存。
多模态不是装饰
PDF、PPTX 和 DOCX 的内嵌图片先被提取到 wiki/media/<source-slug>/。只有图片路径没有语义时,文本模型常会在摘要中丢掉它;
因此流水线调用视觉模型生成事实性 alt 文本,再让后续知识页保留图文关系。
- Rust 从文档中抽取图片并统一保存。
- TypeScript 只对当前来源所属媒体目录中的图片生成描述。
- 图片内容以 SHA-256 缓存,相同 Logo 或图表模板不会重复付费。
- 即使模型漏写图片,程序也会向来源摘要页注入“Embedded Images”安全网。
- 注入新描述后重新向量化来源摘要,使图像语义可搜索。
关闭多模态时,代码不仅停止视觉调用,还会从发给生成模型的源文本中移除 Wiki 媒体引用,并跳过安全网注入,保证“关闭”不会通过另一条路径泄漏图片知识。
增量与长文策略
内容哈希缓存
checkIngestCache() 以来源内容和身份判断是否变化。命中时跳过昂贵的两次 LLM 调用,但仍允许图片管线补齐旧版本缺失的媒体或描述。
只有完整写入成功后才保存缓存;部分失败不会被当成已摄入。
当前摄入缓存核心是来源内容 SHA-256 和写入结果,并未形成包含解析器版本、Schema、Purpose、Prompt、模型、参数和代码版本的完整派生指纹。因此源文件不变时,规则或模型升级可能仍被判定为无需重建。
长文档检查点
当来源超过稳定上下文预算,系统按语义边界切成约 12K–60K 字符的块,逐块分析,并维护全局 digest 和检查点。 最终把分块分析汇总成一个“Consolidated Long-Document Analysis”,再进入统一生成阶段。中断后可以从检查点恢复,避免从头消耗模型。
生成 Token 上限随 128K / 256K / 512K 上下文逐级扩大
两阶段 LLM:先理解,再写文件
Stage 1 · Analysis
温度设为 0.1、关闭额外 reasoning,以稳定格式提取:关键实体、概念、论点、与现有 Wiki 的连接、矛盾和建议页面结构。它不直接写磁盘。
Stage 2 · Generation
把第一阶段分析标为“只作上下文,不得复述”,要求响应第一字符就是 ---FILE:,以协议块输出文件:
---FILE: wiki/concepts/knowledge-compilation.md---
---
type: concept
title: Knowledge Compilation
sources:
- raw/sources/example.pdf
---
# Knowledge Compilation
...
---END FILE---
生成 Prompt 同时传入 Schema、Purpose、当前索引、Overview、来源身份和来源全文。它明确禁止输出应用管理的
wiki/index.md 与 wiki/overview.md,并要求来源页链接回原始证据。
可选 Stage 3 · Review Suggestions
当资料规模或生成信号足够时,单独调用模型产生高价值 REVIEW 块。审核与文件生成分开,减少主输出被建议性文字污染。
把概率输出变成可靠文件
writeFileBlocks() 是模型世界与文件系统之间的重要校验层,但“有校验”不等于“有事务”。
协议解析
容忍围栏与少量格式偏差,但拒绝未闭合块、空内容和不安全路径。
内容清洗
规范 frontmatter、来源数组和日期,阻止模型写入应用管理路径。
创建或合并
新页面直接写入;已有页面通过专门合并 Prompt 保留旧信息、来源与人工编辑。
截断修复
若流在 FILE 中途结束,只请求模型重新生成缺失的完整文件块,并过滤越界输出。
写入后,程序确定性更新 Index;模型未生成 Log 时,程序追加标准格式日志;来源摘要缺失时,用 Stage 1 分析生成兜底页。 如果存在硬写入失败或未修复截断,任务抛错并保留已写文件,让重试可以在此基础上合并,而不是把半成品标成成功。 这是诚实的失败语义,却仍会把部分状态暴露给读者、索引器和后续重试;LLM 合并又具有非确定性,因此不能称为真正事务。
从单文件原子写到知识库提交
- 先生成不可变写入计划:目标路径、旧哈希、新哈希、来源与派生指纹。
- 全部内容写入 staging 目录,并完成 frontmatter、引用、链接和安全规则校验。
- 在提交日志中记录 intent,再以 manifest 指针或可恢复的重命名序列一次发布。
- 索引、向量和图谱只消费已提交版本;失败时忽略 staging,启动时扫描未完成 intent。
- 重试使用 operation_id 与预期旧版本做幂等和乐观并发检查,而不是盲目再次让模型合并。
队列与并发控制
- 队列状态持久化到磁盘,应用重启后恢复待处理任务。
- 解析并发可配置为 1–8;模型 worker 数量有独立上限。
- 同一来源用源级互斥避免重复摄入,同一项目提交用项目锁序列化。
- 失败最多自动重试 3 次;使用额度错误可等待约 15 分钟后自动恢复。
- 用户可以暂停、恢复、移动、取消、批量重试或清除已完成任务。
- 取消通过 AbortSignal 贯穿模型流、图片描述、写入前检查和活动状态。
“准备与推理可并行,最终提交按项目串行”是合理起点,但进程内 Mutex 只约束单实例。CLI、编辑器、同步进程或第二个应用实例仍需要跨进程锁与乐观版本检查。
提交之后
- 解析 FILE/REVIEW 块,把待人工判断项写入 Review Store。
- 保存来源内容哈希、此次写入路径和长文检查点状态。
- 如果 Embedding 开启,跳过 index/log/overview,为新领域页建立分块向量。
- 刷新项目文件树并递增 dataVersion,使图谱与检索缓存失效。
- 活动面板记录成功、跳过、警告或失败;完整警告进入
.llm-wiki/ingest-warnings.log。
模型输出不直接等于成功;协议、路径、文件完整性、索引与缓存都有程序校验。这个方向正确,但目前的成功边界仍主要是“工程写入完成”,还没有覆盖跨文件原子性和知识语义正确性。
生产级写入的五个验收门槛
| 门槛 | 必须回答 | 建议指标 |
|---|---|---|
| 幂等 | 同一操作重放会不会重复、漂移或覆盖人工修改? | 重复执行零非预期 diff |
| 事务 | 任一步崩溃后,读者会看见什么版本? | 故障注入后仅旧版或新版可见 |
| 血缘 | 每个主张能否回到具体来源版本和文本跨度? | 引用可定位率、失效传播完整率 |
| 质量 | 摘要是否忠实、合并是否丢信息、矛盾是否保留? | 支持率、遗漏率、冲突保留率 |
| 运行成本 | 失败、重试、长文和多模态的预算是否可控? | 每文档成本、P95 延迟、重试率 |
Prompt 只负责提出候选内容;Schema 校验、证据绑定、事务发布、质量评测和成本预算共同决定它是否能进入长期知识库。
src/lib/ingest.ts、ingest-cache.ts、ingest-queue.ts、source-preprocess.ts、image-caption-pipeline.ts、src-tauri/src/commands/fs.rs。派生指纹、staging/manifest 提交和五项验收门槛是本次审计提出的改进方案。