YeagerZhao
首页博客项目旅程关于
返回

Noodle-Agent:从 PDF 笔记到持续更新的个人知识库

2026 · 09 · 18
目录
从积攒资料,到整理自己的知识一份 PDF 怎样变成笔记架构怎样支持这套流程多份资料怎样形成可更新的知识体系从问题到带引用的回答DSH 怎样把知识服务变成 Agent失败之后,怎样继续处理时间和成本花在哪里当前边界与下一步附录

Noodle-Agent:从 PDF 笔记到持续更新的个人知识库

阅读约 35 分钟。项目:Noodle_Agent。

从积攒资料,到整理自己的知识

学习过程中,我积攒了不少 PDF:课程讲义、教材章节、论文和补充资料。它们能按文件夹保存,里面的知识却很难一起使用。重新学习一个概念时,我经常要先想起它出现在哪份课件里,再翻到对应页面;读到另一本教材的解释,也不容易把两种说法放在一起比较。

我希望做一个围绕这些资料工作的知识库。上传 PDF 后,先把内容整理成能顺着目录阅读的笔记,保留公式、图示和原文页码。以后导入相关资料,系统可以把新内容补充到已有知识点中,让我逐渐形成自己的知识体系。

Noodle-Agent 就是这样一个个人学习项目。它的核心流程是:解析 PDF,生成一组原子笔记,再把它们组装成这份 PDF 的完整笔记;不同资料中相关的原子笔记可以贡献给同一个知识点,知识点再被知识体系引用。来源修改、删除或恢复后,系统重新计算有效贡献,更新受影响的内容与版本。

Noodle-Agent 的资料整理、知识维护与对话入口
Noodle-Agent 的资料整理、知识维护与对话入口

同一组原子笔记可以组成来源笔记,也可以参与跨文档知识归并。右侧的 Agent 提供读取和修改入口。

保留资料,也积累知识

我把整理结果分成两层。来源笔记保留一份 PDF 的学习顺序和原文关系,例如一份神经网络课件依次讲感知机、多层感知机、反向传播和卷积网络。共享知识点则围绕主题组织内容,例如“多层感知机”可以同时吸收课件里的网络图、教材里的解释和另一份资料中的推导。

这两层有不同的用途。复习课程时,我需要跟着老师的章节阅读;围绕一个问题学习时,我希望直接打开对应知识点,看到来自不同资料的有效解释。因此,资料目录和知识体系都需要保留,原始 PDF 也仍然可以打开。

内容能回到原文,是我很在意的一点。模型生成的解释可能省略条件,也可能把图中的箭头读错。笔记里的页码按钮应当帮助我找到相关页面,检查它是否说得准确。跨文档合成后,来源关系也要继续存在,方便比较不同资料的描述。

在工作台里阅读和提问

工作台把资料库、阅读器、原 PDF、知识体系、任务进度和聊天放在同一页面。上传后可以观察后台处理,生成后从目录打开笔记,遇到公式或图示就切到 PDF 核对。问答也可以限制在当前资料范围内,减少其他教材内容对课程问题的干扰。

生成后的神经网络来源笔记
生成后的神经网络来源笔记

来源笔记保留章节目录,正文由多个独立知识单元组成。

在这套生成和维护流程上,我接入了 DeepSeek Harness,下面简称 DSH。它负责会话和工具调用。Agent 可以查询笔记、检索知识、生成引用回答,也能在得到批准后调用编辑工具修改某个正文块。编辑会创建新笔记版本,并触发后续知识维护。

对话是另一种操作方式。用户说“把学习率这一段改得更容易理解”,Agent 仍然需要先找到笔记和目标块,读取当前版本,再提交明确的修改参数。真正决定怎样写入、怎样处理旧版本的,是 Python 领域服务。

目前项目主要面向个人本地使用。工作台、数据库和文件存在本机,真实 PDF 的解析、语言生成、向量计算及部分图像理解通过外部服务完成。离线 fixture 用于验证工程链路,真实资料处理仍需要相应的服务配置。

一份 PDF 怎样变成笔记

以神经网络课件为例,一份文件里既有定义,也有网络结构图、训练过程和推导公式。我希望生成结果能按主题阅读,同时让后续检索和知识归并有明确的处理单位。

上传后,先创建可跟踪的任务

上传接口先检查文件并保存原始 PDF。文件存储按内容哈希组织,数据库记录来源身份、文件版本和处理任务。接口返回任务 ID,前端可以轮询状态,用户不必让上传请求一直等待模型处理结束。

同一份文件重复上传时,系统会检查已有活动来源中的内容哈希。符合去重条件时直接返回原来的版本和任务。用户需要建立新版本时,可以走明确的新版本入口。文件名只帮助识别资料,不能替代内容哈希或版本身份。

上传与生成等待
上传与生成等待

上传先返回任务,后续阶段由 Worker 推进;等待过程中可以查看阶段和调用记录。

Worker 从数据库领取任务,并定期维持租约。解析器可能先返回外部任务标识,Worker 保存它,等到合适时间继续查询结果。等待状态和下一次尝试时间也会落库,便于进程重启后接着处理。

解析结果先变成统一输入

MinerU 返回的文本和图片信息会进入规范化处理,形成页面、内容块、图片资产等内部对象。页码在这个阶段就需要保存:页面的物理位置用于 PDF 定位,显示页码用于正文里的提示,二者可能不同。

如果课件某页同时包含标题、公式和网络图,后续生成不能只拿到一段拼接文本。系统需要知道这些内容各自在哪里,图片对应哪个资产,以及正文中的哪些片段可以作为证据。结构化解析质量会影响后面的规划、图文关联和检索。

解析缓存保存规范化产物,相同输入在满足缓存条件时可以复用。缓存范围主要是解析,新的笔记生成仍然需要按照本次计划执行。调整写作规则后,不能因为解析命中缓存就认为新正文也已经生成。

先规划知识单元,再写正文

生成前会建立资料画像、候选知识、目录和笔记计划。这些计划回答几个实际问题:资料主要讲什么,哪些段落应该形成同一个主题,哪些只是过渡页,图示应该放在哪个知识单元中。

例如“多层感知机的结构”和“反向传播算法”可以分开生成。前者解释层、权重和激活函数,后者解释误差怎样传回和参数怎样更新。把它们拆成独立原子笔记,既方便读者按需要展开,也方便后续把反向传播的补充推导归并到对应 Concept。

原子笔记的粒度来自语义规划,不等同于按固定字数切分文档。一个公式可能需要连同变量定义和适用条件一起保存,一张结构图也可能跨越多个段落。计划需要同时考虑内容边界、上下文和原文覆盖。

从上传到笔记发布的生成流程
从上传到笔记发布的生成流程

阶段产物逐步保存,视觉处理和正文生成在各自阶段内使用有界并发。

规划完成后,系统准备图示理解和正文生成任务。Writer 根据每个笔记计划生成标题、摘要与内容块,并关联论断、证据和图片。输入限定在相应资料窗口及允许引用的内容范围内,避免某个知识单元把整份课件重新总结一遍。

质量检查包含代码校验和模型审核。代码检查结构、引用身份和必要关系;Judge 检查正文是否符合计划、是否遗漏条件,以及是否有需要修改的内容。部分问题可以进入修复,再重新检查。审核没有通过的内容需要记录失败或警告,不能与通过的正文混在一起发布。

组装一份完整的来源笔记

通过检查的原子笔记写入数据库,SourceNote 按目录组装它们。每个目录位置固定到具体 NoteVersion,读者打开的是一次确定的发布结果。原子笔记有自己的身份,完整笔记则保存它们在这份资料里的位置和顺序。

阅读器可以按目录跳转,也可以从正文的证据按钮打开原 PDF。反过来,浏览 PDF 时,导航锚点帮助定位相关笔记。模型生成的说明和原始页面因此能放在一起核对。

MLP 图文笔记与原始页面
MLP 图文笔记与原始页面

生成结果保留图示和解释,原 PDF 用于核对细节。

笔记发布后,系统建立全文和向量索引,并尝试导出 Markdown。开启自动同步时,发布事务还会创建知识同步事件。此时资料已经可以阅读,Concept 的增量维护由后续任务继续执行。

任务完成并不代表每个内容都同样完整。某些资料页可能没有实质知识,某张图也可能理解失败。系统会把这些情况记录为覆盖说明或警告。案例截图展示的是功能和阅读方式,具体耗时、知识单元数量会随资料与模型配置变化。

架构怎样支持这套流程

会话交互和资料长任务分开运行

项目包含 Node/Harness、Python API 和独立 Worker。工作台用 API 上传文件、读取笔记和任务,也通过同源网关连接 Harness 会话。Harness 中的 TypeScript 工具桥接将领域请求转发给 Python 服务。

工作台、Harness、API 与 Worker 的职责
工作台、Harness、API 与 Worker 的职责

会话代理和工具请求有不同路径,后台任务通过数据库协调。

这样拆分主要是因为处理时间和失败方式不同。聊天需要及时返回状态和流式结果;PDF 生成可能等待解析服务,再调用多次模型。Worker 保存任务进度,即使用户关闭页面,已经入队的任务也可以继续执行。

领域服务集中维护业务规则。界面直接编辑和 Agent 调用编辑工具,都使用同一套版本检查与写入逻辑。判断来源是否有效、是否可以发布 Concept,也由领域层负责。会话端不用复制一套知识状态。

代码现在按能力拆分:application/ 放生成、发布、编辑和检索,http/ 放路由及会话网关,storage/ 放模型与迁移,adapters/ 接解析和模型服务,synthesis/ 维护共享知识。公共服务门面负责装配与委托,既有接口可以继续使用。

组件目前共享同一个服务上下文,拆分仍然保留一定耦合。它的直接收益是把不同业务的代码放到可单独阅读的位置;后续若需要独立服务或更严格的依赖边界,还要继续收窄接口。

技术选择和实际代价

TypeScript 用于 Harness 插件、工具 Schema 和 HTTP Provider,Python 用于 PDF 处理、领域规则和持久化。FastAPI 提供内部 API,前端使用原生 JavaScript 模块、HTML 和 CSS。Markdown、公式和 PDF 分别由 Marked、DOMPurify、KaTeX、PDF.js 配合处理。

这个选择减少了前端框架和服务设施的数量,比较适合个人项目。代价是界面状态、局部刷新和组件拆分需要自己维护,阅读器与聊天面板变复杂后,原生模块也不能自动解决所有状态组织问题。

SQLite 同时保存关系、任务和全文索引,向量也保存在数据库中。安装时不需要额外启动消息队列或向量数据库,备份也容易理解。检索规模扩大后,应用层遍历向量会成为需要测量和改造的地方。

模型调用放在适配层,生成、向量和视觉可以分别配置服务。这样便于按任务使用不同模型,也能在测试中替换为 fixture。模型变更仍有成本:输出结构、上下文长度和向量行为都可能变化,需要重新验证任务和已有索引的兼容性。

五类对象,让资料和知识各有位置

对象保存什么一个例子
Source来源身份与可见性,包含上传版本神经网络课件
AtomicNote单个知识单元及其正文版本反向传播算法
SourceNote一份资料的目录与笔记发布快照课件完整笔记
Concept共享知识身份、语义模块与发布版本多层感知机
Synthesis组织 Concept 的目录树和体系版本深度学习知识体系
核心对象与版本引用
核心对象与版本引用

图中展示逻辑关系;数据库还保存内容块、贡献选择、证据、任务和索引等细表。

Source 的新上传版本对应不同的 SourceVersion。AtomicNote 的稳定身份与 NoteVersion 正文分开保存,SourceNoteVersion 固定引用其中的版本。Concept 再通过贡献记录接纳原子笔记,通过模块组织不同侧面的内容。

例如 MLP 的概述、机制推导和变体可以放在不同模块中。发布 ConceptVersion 时固定相应的 ModuleVersion。某个模块发生更新,其他模块仍可保留自己的版本引用,减少无关内容的重写。

这些对象的关系决定了更新范围。修改一篇原子笔记,首先影响它所在的来源笔记;如果它已经贡献给 Concept,还会影响相关模块及引用该 Concept 的知识体系。只有确实使用了这项内容的对象需要协调。

版本和证据分别回答两个问题

版本回答“当时看到的内容是什么”,证据回答“这段内容来自哪里”。项目用活动版本指针定位当前发布,用不可变快照保留历史。创建新版本后推进指针,旧版本继续存在。

证据关系连接正文块、论断、原文片段与页面。合成后的 Concept 也需要保留贡献和证据,读者才能分辨哪份资料支持哪段解释。来源删除时,这些固定引用还能告诉系统哪些模块需要处理。

把历史保存下来也带来维护成本。正文、证据和阶段产物会持续增加;逻辑删除之后,物理文件与历史记录仍可能保留。当前备份和数据维护需要用户了解这些存储位置,项目尚未提供统一的永久清除功能。

数据库结构升级已统一到 Alembic。API、Worker 与 CLI 共用同一入口,旧库需要升级时先保存 SQLite 备份,再执行事务迁移。历史迁移使用冻结结构与明确变更,避免随当前 ORM 变化而改写过去的含义。它处理已知旧结构,遇到不支持的结构会失败并回滚。

图像既需要细节,也需要上下文

课件里的图片包含不同内容:有些是网络结构图,有些是损失曲线,也有装饰图。项目先根据规划和本地信息决定哪些资产需要视觉处理,然后使用裁切图与整页上下文准备输入。

裁切帮助模型读清箭头、图例和符号,整页保留周围标题及解释。对于 MLP 网络图,只看到一组圆圈可能无法判断它在说明结构还是训练算法;页面上的变量定义往往能补充这个区别。

图示处理与失败恢复
图示处理与失败恢复

复用、本地过滤、视觉调用和失败恢复分别处理,未完成的图示会留下记录。

视觉结果包含图意、资产身份和使用建议,代码会校验它是否属于输入范围。批次失败时可以拆小继续尝试,最终无法处理的图记录为警告。正文可以使用已经确认的结果,阅读器仍保留原始图片供核对。

公式展示是另一条链路。结构化公式和 Markdown 中的数学内容由 KaTeX 渲染,符号说明中的下标与转置也需要统一处理。之前遇到过主公式正常、变量列表显示原始 LaTeX 的问题,原因在符号解释的渲染入口。修复需要同时检查正文、变量说明和图注,才能让读者顺畅地阅读同一段推导。

多份资料怎样形成可更新的知识体系

来源笔记生成后,系统已经能回答课件问题。为了长期学习,我还希望同一个主题在不同资料之间有一个稳定的位置。例如,课件介绍 MLP 的层级结构,教材补充通用逼近的条件,另一份笔记讨论激活函数。这些内容可以成为同一个 Concept 的不同模块。

归并的输入是有来源的贡献

原子笔记不会因为标题相似就直接拼接到 Concept。系统先寻找候选知识身份,判断新内容与它的关系,再选择有证据支撑的正文块。贡献记录保存 NoteVersion,选择记录保存实际使用的块,后续更新可以追踪到具体输入。

Concept 的内容按语义模块组织。MLP 的结构说明、推导和变体之间存在联系,也有不同边界。补充一段矩阵推导时,更新对应模块通常比重写整个知识点更容易核对,原来无关的模块可以继续被新发布引用。

跨来源贡献形成共享 MLP 内容
跨来源贡献形成共享 MLP 内容

已有案例展示了课程图示和其他来源内容如何进入同一知识点。

维护时需要同时保存贡献和发布正文。贡献告诉系统当前哪些来源可以使用,发布版本告诉读者这一版实际采用了哪些模块。某条贡献加入候选,不等于正文已经成功发布,只有最终版本引用才能说明它进入了活动内容。

资料变更先产生事件

上传后的来源笔记发布、原子笔记编辑、来源删除或恢复,以及单篇原子笔记删除,都有相应的变更事件。Worker 处理这些事件,找出受影响的笔记贡献和模块,再决定如何维护活动知识。

KNOWLEDGE_AUTO_SYNC 控制正常发布和编辑时是否创建增量事件。删除、恢复等维护事件有自己的路径,已经入队的事件也会继续执行。因此关闭这个配置不能当作暂停全部知识维护的方法;如果需要停止后台处理,应管理 Worker 的运行状态。

事件保存身份、处理状态和幂等键。发生同一次变更时,系统可以识别已经入队或处理过的工作,减少重复创建。长任务使用租约和心跳,避免多个执行者无条件提交同一个事件的结果。

资料变更驱动的知识更新
资料变更驱动的知识更新

先确认有效来源,再协调模块;新正文需要质量检查,历史复用走来源与发布一致性检查。

怎样判断值得补充

处理新笔记时,系统收集候选 Concept,包括标题检索、已有贡献和名称匹配得到的身份,再让模型比较内容。结果可以是补充已有模块、增加新模块、创建新 Concept、仅增加证据、没有变化、输入无效或存在冲突。

这个判断需要区分“相关”和“值得更新”。两份课件都讲梯度下降,第二份可能只是重复定义;也可能补充批量与随机更新的区别;还可能给出只适用于某类目标函数的收敛结论。重复内容不必重写,互补内容可以形成贡献,条件不清或矛盾内容需要复核。

模型看到的候选和正文长度都有上限。当前每篇笔记最多输出三个主题决定,候选 Concept 最多八个,较长块和模块正文会截断。系统还检查规范化名称和别名,避免明显的重复身份。这些检查能限制更新范围,但不能证明全库中绝对没有语义等价的知识点。

代码接着验证模型决定。选中的块必须真实存在并具备要求的证据,已有 Concept 必须在候选范围内,模块与预期活动版本也要匹配。模型调用或 JSON 解析失败会留下复核记录,复核状态因此可能来自内容冲突,也可能来自处理异常。

新笔记的有效原子笔记会进入处理范围,但每个正文块不一定都形成更新。已有有效贡献、重复内容和已处理候选可以跳过。保留这种选择过程,能避免一次上传把所有笔记机械地变成一批新 Concept。

按有效来源重建,再决定是否发布

来源有效需要满足可见性与版本要求:Source 和 AtomicNote 仍然有效,贡献引用当前活动笔记版本,并属于来源当前版本。贡献本身也需要处于可以使用的状态。删除的资料和过时笔记不能继续支撑正常发布。

对受影响模块,系统收集全部有效贡献。自动贡献按照选择记录限制输入块,其他兼容的历史贡献使用原有准备逻辑。新生成的候选经过结构、证据、来源和独立 Module Judge 检查,通过后才进入发布事务。

发布前还会再次检查来源快照、模块状态、租约和 Concept 活动版本。模型生成期间如果有人编辑笔记,之前准备的输入可能已经过时;候选即使文字通顺,也不能直接覆盖新的知识发布。

另一个分支是历史复用。系统可以寻找来源版本集合和选中块匹配的历史模块,将它固定到新的 Concept 快照中。当前这条路径不会重新调用 Judge,也没有单独比较提示词或策略版本。它节省重复生成,但将来需要加强对审核规则变化的处理。

候选未通过检查时,系统留下原因。如果旧发布的来源仍然有效,可以保留它供阅读;如果旧发布已经依赖删除或过时的来源,相关模块会保持失效,相应 Concept 暂停普通读取与检索,等待维护完成。

删除、恢复和再次上传有什么区别

用一个简化的 MLP 例子说明。资料 A 贡献基本结构,资料 B 给同一模块补充矩阵表达。B 发布后,模块使用 A、B 的有效输入生成新版本,通过审核后,引用它的知识体系再更新版本。

删除 B 时,B 的原子笔记退出有效检索,相关模块被标记为需要维护。Worker 撤回失效贡献,根据剩余 A 重建。如果已有历史模块正好固定了同一组 A 的 NoteVersion 和选择块,可以复用它。没有有效贡献的模块会退出活动发布;全部模块都无法保留时,Concept 成为撤回状态。

恢复 B 是恢复已有来源身份和符合条件的贡献,再触发协调。再次上传同一个文件则可能建立新的来源和笔记版本。即使文字相同,新的版本 ID 也不能直接当成旧输入,历史复用需要重新满足匹配条件。

这里的回退是在新的知识快照中重新选择有效模块。来源笔记、历史贡献和旧 ConceptVersion 仍用于追踪。系统没有把整个数据库恢复到过去某一时刻,也不会撤销与 B 无关的其他资料更新。

一棵目录树可以引用共享知识

每个知识体系是一棵树,节点可以是目录分组,也可以引用 Concept。Concept 的身份独立于树的位置,因此 MLP 可以同时出现于机器学习和深度学习体系。两个目录节点使用同一个知识身份,各自发布时固定具体 ConceptVersion。

两个知识体系引用同一个 Concept
两个知识体系引用同一个 Concept

树内保存目录关系,多棵树通过共享 Concept 形成逻辑图;Concept 模块是内容结构,不是目录分组。

已有 Concept 更新后,系统刷新引用它的体系快照,保留原有树形编排。新 Concept 通过审核后可以进入全局知识库,再根据可用位置加入现有体系的分组。当前自动编排不会凭空创建新的体系或分组,手工编排体系也不会自动插入原本没有的 Concept。

如果暂时找不到合适位置,新 Concept 可以独立发布,不需要强行塞进某棵树。先修关系、复杂重组和知识点拆分仍需要更完善的规则。共享身份减少了内容重复,目录组织则还需要学习目标和人的判断。

从问题到带引用的回答

先确定问题在什么范围内回答

阅读一份课件时,页面上下文可以提供来源版本、当前笔记或选择内容。问答服务据此判断是否限定来源。指定 SourceVersion 时,只检索该资料的 AtomicNote;全局问题才同时检索原子笔记和 Concept。

这个区分对学习很有用。询问“这份课件中的误差项怎样定义”时,需要保留课程里的符号习惯;询问“反向传播与梯度下降有什么关系”时,可以使用跨资料归纳的解释,再给出相应来源。

页面只传递有界的定位信息和选择摘要。完整正文通过工具读取,避免每次提问都把整个阅读器内容塞进会话。范围本身也不等于证据,真正用于回答的片段仍由检索服务返回。

两类知识各自召回和排序

笔记发布后,全文索引保存标题、摘要、正文和标签,向量索引保存生成向量所用的模型信息与版本。问答时,全文检索、标题摘要匹配和向量相似度一起参与相关性计算。

全文检索可以找到名称、术语和符号,向量检索处理表达不同但语义相关的问题。标题和摘要的字符匹配还帮助覆盖中文分词或模型切换期间的部分情况。未配置真实向量服务时使用 HashEmbedding,它适合验证流程,不代表真实语义检索效果。

问题、混合检索与引用回答
问题、混合检索与引用回答

来源范围先过滤;全局问题才融合 Concept 和原子笔记,回答后还有一次有效性检查。

AtomicNote 当前使用余弦相似度与词法分数组合。Concept 的向量分支直接计算点积,再结合词法分数;它对向量归一化程度有依赖。两类分数没有统一校准,不能解释成回答正确的概率。

全局查询中,系统分别排序和过滤,再按名额交错选择 Concept 与 AtomicNote。这样可以同时保留跨来源解释和页码证据。当前排序由应用代码完成,没有独立 cross-encoder 或 LLM 重排模型,也没有 ANN 向量索引。

检索工具和回答工具怎样衔接

Agent 可以先用搜索工具查看候选,再调用回答工具生成解释。回答工具根据问题和范围重新执行领域检索,当前并不直接消费上一条搜索工具返回的命中列表。前一次搜索帮助 Agent 判断是否找到相关知识,最终回答使用自己的检索结果。

检索结果包含实体类型、版本、正文、来源证据和可用资产。回答模型使用这些信息组织说明,并返回使用的笔记引用。领域服务负责整理引用结果;模型生成的文本仍需要内容评测,引用存在不自动证明每句话都被原文充分支持。

例如询问神经网络课件中的反向传播,可以先解释输出层与隐藏层怎样计算误差,再说明参数更新,并给出课件页码。用户点击引用回到原文,可以检查公式符号与课程定义是否一致。

反向传播问题与引用回答
反向传播问题与引用回答

当前界面展示已有课程问答记录,引用帮助读者回到来源核对。

模型回答期间,资料可能被修改或删除。生成结束后,领域服务重新确认命中的原子笔记仍然有效、Concept 没有被阻断且活动版本未变化。如果发现陈旧来源,会返回 SOURCE_CHANGED 提示并清除命中列表,让用户在同步后重新提问。

这种检查解决的是发布一致性,无法替代科学内容判断。某个术语检索到了相关课件,仍可能缺少回答所需的前提;模型也可能把不同条件下的结论混合。检索召回、引用准确性和未知问题的处理需要分别评测。

DSH 怎样把知识服务变成 Agent

复用会话能力,保留业务边界

项目需要一个能管理多轮对话、调用工具、返回流式内容并请求写入批准的运行时。我选择 DSH,希望复用这些会话能力,把自己的实现集中在资料、证据和知识维护上。

Harness 负责模型与工具之间的交互,工具桥接负责把明确的请求传给领域 API。PDF 生成和自动知识维护仍是 Worker 执行的业务流程,里面可以使用多个模型角色,但不会因此变成几个独立自主 Agent。

这个边界也方便检查故障。对话选错了工具,需要检查提示与工具说明;参数传错了,需要检查 Schema 或桥接;版本没有更新,需要看领域服务及后台事件。几个层次各自有明确的检查位置。

目前项目固定使用一组 DSH 包版本,启动时将 Noodle 插件挂入工作区。会话运行时和知识模型的配置也需要分别核对。固定版本减少环境变化,同时意味着上游升级不能只修改包号,还要验证插件与原生模块兼容性。

工具是明确的业务接口

当前桥接注册 24 个领域工具,包含 13 个读工具和 11 个写工具。工具描述说明用途,Schema 限制输入与输出,Provider 负责 URL、超时、取消、错误及结果长度。复杂判断继续放在 Python 中。

用户想做的事对应工具示例返回内容
查看笔记noodle_get_atomic_note当前版本与内容块
找相关知识noodle_search_knowledge候选、证据和版本
回答问题noodle_answer_knowledge回答与引用
修改一段笔记noodle_edit_note_block新版本或冲突错误
查看生成进度noodle_get_job_status状态、阶段和警告

工具会带上会话 ID 和调用 ID,帮助把执行记录与领域操作关联起来。对于需要长时间处理的操作,返回 Job 标识,由后台继续执行;读取和正文块编辑等操作可以直接返回结果。接口的同步或异步方式由业务决定。

一次对话编辑的写入顺序

以把一段解释改得更清楚为例,Agent 先读取当前笔记,确认要改的 block_key 和 expected_version_id,准备新的正文,再请求这次写工具执行的批准。批准后调用 Provider,领域服务检查活动版本和目标块。

对话修改经过批准与版本检查
对话修改经过批准与版本检查

图中省略失败分支;若版本已变化,领域服务拒绝这次陈旧写入。

写入会创建新的 NoteVersion,保留未修改块的内容、证据和资产,更新活动指针与索引,再克隆所属 SourceNote 的发布快照。修改后的块标记为人工修订,原来用于证明它的机器 Claim 会解绑,避免把旧原文引用直接当成新措辞的证明。

隔离演示库中的正文修改和版本结果
隔离演示库中的正文修改和版本结果

示例通过实际领域编辑接口执行,使用合成资料,不改动课程笔记。

开启自动同步时,事务同时创建笔记更新事件并标记旧贡献失效。后台再按照有效来源维护 Concept 和知识体系。这意味着基础笔记版本可以立即推进,共享知识发布还要经过后续协调。

人工改写也有一个当前边界:自动贡献要求块具备证据,新修改块解绑旧 Claim 后,不一定马上满足这个条件。编辑会触发维护,但新增措辞不能保证直接进入 Concept。后续需要补充证据确认或人工采纳流程,才能兼顾自主改写和自动归并。

如果新文本与原文相同,接口返回 UNCHANGED,不创建多余版本。若另一处编辑已经推进活动版本,旧请求会得到冲突错误,Agent 需要重新读取后再决定怎样修改。

上下文怎样控制大小

会话中会出现用户问题、页面位置、工具 Schema、读取正文和多轮历史。项目给这些输入设置不同边界:页面上下文保存必要身份和选中摘要,工具正文设置长度上限,长结果由 Harness 的结果管理机制处理,会话接近上下文边界时可以压缩历史。

会话上下文与持久知识的分工
会话上下文与持久知识的分工

会话层保留任务与交互信息,知识库通过工具按需进入当前上下文。

这些机制由不同层执行。Python 网关限制注入的页面上下文,HTTP Provider 限制返回正文,DSH 管理会话记录与压缩。笔记规划使用自己的局部输入,不直接依赖聊天窗口里已经积累的历史。

长期知识存在数据库和文件中,会话摘要帮助模型继续当前任务。项目目前没有完整的个人偏好记忆或跨会话学习机制。保留过往对话,不等于系统已经知道用户长期的学习目标,也不等于它会自动把所有聊天内容纳入知识体系。

失败之后,怎样继续处理

状态说明结果,阶段说明进度

Job 保存状态、当前阶段、进度、错误和下一次尝试时间。创建、执行、外部等待、完成、带警告完成及失败是不同情况。前端展示阶段名称,方便用户知道当前在解析、规划、理解图示还是生成正文。

资料任务的主要状态与恢复路径
资料任务的主要状态与恢复路径

阶段产物帮助继续执行,租约到期帮助重新领取;具体重试仍受任务状态与入口约束。

外部解析还没完成时,任务可以保存等待信息,下次再查询。进程异常退出时,租约到期后任务有机会被重新领取。已经终止的失败任务通过明确恢复或阶段重启入口处理,用户可以保留仍然适用的解析和中间结果。

阶段重启需要清理从所选阶段开始的旧产物。例如改变笔记规划,后续正文和质量结果也可能需要重做;只修复导出问题时,没有必要重新把 PDF 发给解析服务。恢复范围取决于失败位置和输入是否变化。

来源删除同样会影响运行中的任务。系统会取消或阻止不再允许发布的工作,持久化阶段还要检查有效来源。任务拿到了租约,不能据此忽略资料后来已经被删除。

不同错误需要不同处理

超时与限流可以在允许的重试范围内继续;JSON 不符合预期,需要结构检查或修复;图片批次失败,可以拆成更小输入;正文质量未通过,需要保留原因并判断是否重写。把所有异常都重试,可能重复付费,也可能反复生成同一个错误。

项目既有接口客户端重试,也有生成任务级重试,它们的配置和适用范围不同。排查时需要查看实际调用记录,确认一次阶段尝试触发了多少外部请求,避免把重试次数理解为一个全局数字。

COMPLETED_WITH_WARNINGS 表示可用结果附带覆盖说明,用户仍应查看缺失内容。知识同步还有自己的复核和错误状态,资料 Job 完成与 Concept 发布成功也需要分别观察。

生成成功后,还要确认能否提交

可靠性检查包含输入准备与最终发布两个时间点。模型调用可以花很长时间,期间笔记、贡献和知识版本都有可能变化。因此重建使用来源快照,发布再检查 lease、revision 和预期活动版本。

对话写入通过一次性批准控制操作意图,版本检查控制实际目标,数据库事务保存相互依赖的变更。这些机制解决不同问题:用户批准了修改,也可能使用了已经过时的笔记版本;模型写出了候选,也可能失去了任务租约。

模型调用通常放在发布事务外,避免整个生成过程持续占用数据库写锁。某些同步操作仍需要在事务中准备索引,例如正文编辑时的向量计算,因此长事务和失败恢复还有进一步优化空间。

怎样验证这些路径

工程测试检查上传、持久化、版本、来源有效性、编辑、删除恢复、归并和 API 契约。隔离集成脚本使用合成 PDF 启动真实 API、Worker 与 Harness,执行工具桥接并检查阅读器。它不会访问个人数据库,也不会依赖真实模型作答。

这次维护版本的本地回归有 110 项 Python 测试和 9 项 TypeScript 测试通过,Windows 与 Linux 的统一启停、wheel 安装、浏览器检查及镜像构建也已验证。迁移检查对已知旧库逐表比较非空业务内容,确认升级没有改变已有正文与记录。

这些结果说明相应工程路径可运行。内容评测还需要固定资料和问题,分别检查解析遗漏、笔记条件、图文关联、检索召回和引用正确性。Agent 是否选择了合适工具,也需要真实会话评测,不能由手动调用 ToolRuntime 的集成测试代替。

时间和成本花在哪里

在阶段内并发,控制调用数量

笔记规划、正文生成、审核和视觉处理各自有并发配置。多个独立笔记计划可以同时写作,但视觉输入没有准备好时,相关正文不能直接使用不存在的图示理解。阶段间遵循依赖,阶段内才安排可并行的任务。

阶段内的有界并发
阶段内的有界并发

槽位表示并发上限,实际数量由配置决定;多个任务汇合后再进入下一阶段。

并发增大可以缩短部分等待,也会同时增加外部请求。接口限流、网络、内存和重试都会影响结果,需要按实际日志调节。当前知识同步事件内部的笔记和模块仍主要顺序处理,不能用 Writer 的并发配置推断归并吞吐。

解析缓存和视觉复用减少重复工作,固定计划与版本又帮助判断产物是否还能使用。缓存要保存输入身份和适用范围,否则旧图片解释或旧索引可能被错误带入新任务。

生成适配器支持快模型与较强模型的配置,并按任务调用。模型切换可能改变费用和质量,效果需要在相同资料上比较。项目目前没有自动保证每个任务都选择最优模型的策略。

时间线解释一段等待

系统记录阶段事件、语言模型调用与视觉调用。前端可以显示当前阶段、耗时、调用数量、Token 和警告;失败时也可以沿着任务 ID 找到相关产物及错误。

神经网络课件的一次生成记录
神经网络课件的一次生成记录

这是已有案例的阶段记录,用来说明怎样观察任务;它不作为当前版本的通用性能基准。

墙钟耗时和累计模型耗时有不同含义。两个请求并行各执行十秒,总等待可能接近十秒,累计调用时间却接近二十秒。外部排队、重试和轮询也会影响用户等待,因此单看一个 Token 数或调用时长不能解释全部进度。

对于图示较多的课件,视觉处理值得重点观察。是否逐图请求、批次是否拆分、整页上下文是否重复、失败后是否反复调用,都可能影响时间和成本。原始记录比仅展示“优化后更快”更有用。

性能变化要与质量一起检查

缩小输入、减少图示调用或降低模型规格,都可能缩短等待,但也可能丢失条件和解释。比较方案时,应保持资料和问题一致,同时看笔记覆盖、错误引用、图示理解与实际耗时。

当前已经具备记录调用和阶段的基础,还缺少持续运行的内容评测与成本看板。接下来可以把常用课件和固定问题变成小规模回归集,记录修改前后的质量、耗时和调用情况,再决定是否保留优化。

当前边界与下一步

还需要补足的地方

真实内容质量仍需要人工检查。解析可能丢失复杂版式,Writer 可能简化适用条件,Judge 也可能漏掉科学错误。准备来源证据和独立审核可以限制风险,但还需要明确的错误样例与人工标注来判断实际效果。

自动归并的身份匹配也有限。候选截断、不同名称的同义概念、复合笔记和跨领域术语都可能影响决定。现有名称与别名检查之后,还需要语义重复检查、可解释的冲突处理和更完整的候选复核界面。

对话改写与证据维护之间存在缺口。人工修订块会解绑原 Claim,当前缺少顺畅的重新证据化流程;历史模块复用也没有单独验证策略版本。完善这些规则,比单纯增加生成任务更能改善长期知识维护。

检索方面,目前在 SQLite 中保存向量,由应用计算相似度。Concept 使用点积而原子笔记使用余弦,两类分数还没有统一校准;固定名额融合和缺少独立重排也需要评测。对于个人规模可以先观察,扩大数据量前应测量召回、延迟与索引维护成本。

部署目前适合可信本地环境。内部 API 没有完整的多用户认证和权限隔离,数据删除以逻辑删除为主,部分编辑与编排代码仍较复杂。Python 依赖采用版本范围,macOS 也还没有实机验收。依赖安全审计已经发现需要升级的间接依赖,替换后要继续验证 Harness 与原生模块。

与其他开源项目的侧重点

项目主要侧重点对 Noodle 的启发
Dify知识库与应用工作流组织配置、操作界面和可视化编排
RAGFlow文档解析与知识库 RAG 应用解析、分块与检索体验
LlamaIndex数据接入、索引、检索及 Agent 开发组件可组合的数据与检索接口
Noodle-Agent来源笔记、共享 Concept 和版本维护围绕个人学习维护内容与来源关系

这些项目的范围和成熟度不同,比较时需要选定具体版本和相同任务。Noodle 当前把可阅读笔记、跨来源贡献和来源撤回后的协调放进自己的领域模型,仍然可以借鉴其他项目在解析、检索、配置和评测上的做法。

例如验证另一种解析器时,可以比较同一张网络图及其变量定义是否保留;验证重排时,可以比较正确片段能否进入回答;验证工作流配置时,可以看用户能否理解任务失败并恢复。这样的比较更容易形成可以落实的改进。

把音视频也接入同一套知识维护

下一步希望支持课程视频和音频。音频先转写,视频还要提取关键帧、识别课件和保留时间关系,再把主题段落生成原子笔记。完成后仍然可以组成来源笔记,向已有 Concept 提供贡献。

质量、检索与音视频输入的后续计划
质量、检索与音视频输入的后续计划

虚线部分表示尚未完成的能力,改进顺序不代表承诺发布日期。

音视频接入需要扩展证据位置。PDF 用页码定位,视频和音频需要时间段,读者应该能从笔记跳回相应播放位置。转写错误、说话者和关键帧也会影响证据解释,不能只把字幕文字当成普通 PDF 文本。

因此需要调整解析入口、资产类型和证据模型,让不同媒体保留自己的定位方式。来源版本、笔记版本和 Concept 贡献则可以继续沿用相同的维护思路:媒体内容更新或删除后,重新计算哪些输入仍然有效。

实现顺序会先放在小规模固定资料上完善内容评测、证据和复核,再验证检索与索引,随后接入音视频。新增输入后也要走同样的来源检查与发布流程,让已经积累的知识能继续维护。

附录

安装与运行

需要 Node.js 22.19+ 或 24+、Python 3.12+。从仓库创建环境,安装依赖,并复制配置模板:

git clone https://github.com/JaegerZhao/Noodle_Agent.git
cd Noodle_Agent
npm ci
python -m venv .venv
# Windows PowerShell:.\.venv\Scripts\Activate.ps1
# Linux/macOS:source .venv/bin/activate
python -m pip install -e "./services/noodle[dev]"
# Windows:Copy-Item .env.example .env
# Linux/macOS:cp .env.example .env
npm run dev

工作台默认位于 http://127.0.0.1:8000/app/,内部 API 文档位于 /internal/docs。用 npm stop 停止本项目进程,NOODLE_PYTHON 可指定 Python。已有 .env 不需要覆盖。

配置模板默认使用 fixture,不能解析任意真实 PDF。真实处理需要启用 MinerU 和生成模型,填写相应密钥;向量、视觉和 Harness 会话模型也应按实际用途配置。完整说明见仓库 运行指南。

代码阅读入口

本文对应 0.2.0 的实现,源码链接固定到提交 58099ce,方便与后续更新区分。

关注内容入口
上传、生成、发布、编辑与检索application/
API 与 Harness 网关http/
模型、迁移与备份storage/
自动知识维护与模块发布synthesis/
工具定义与桥接src/

数据和数据库维护

统一启动入口默认把领域数据放在 data/noodle/,Harness 配置与会话放在 .runtime/dsh-home/。数据库、Blob、解析产物和导出需要一起备份,.runtime/ 中的会话也应按需要保存。

npm run db:status
npm run db:upgrade

结构升级前的自动数据库备份不能代替完整业务备份。需要撤销升级时,应停止服务,另存当前数据,恢复匹配旧代码的备份。来源逻辑删除后,历史记录、原文件、导出和备份仍可能存在。

验证入口

npm run typecheck
npm test
npm run lint:python
npm run test:python
npm run test:launcher
python scripts/delivery-check.py --browser

浏览器验证需要已安装的 Chromium,可设置 EDGE_EXECUTABLE。工程测试使用合成资料;真实内容还需要在自己的资料与问题集上抽查。生成与问答结果中的错误,可以连同相关页码、版本和执行记录一起保存,逐渐积累为回归案例。

访问项目
YeagerZhao

AI Developer / Visual Creator / Explorer

构建有价值的产品,记录思考,探索世界

在这些平台找到我
B站小红书CSDNGitHub

© 2026 YeagerZhao · Built with Claude Code and Codex.