首页 文章 精选 留言 我的

精选列表

搜索[QClaw脑洞名场面],共4227篇文章
优秀的个人博客,低调大师

当 PDF 不再一股脑丢给 OCR:认识一下 pdf-inspector

很多 PDF 处理流程里,最贵的那一步,往往不是 “读文件”,而是 “看不清就全送去 OCR”。 这件事听上去很自然,做起来也很省心:PDF 来了,扔进 OCR,等结果出来。但问题也很明显 —— 有些 PDF 根本不是扫描件,它本来就带着清清楚楚的文本层;如果还是按同样的重型流程处理,时间和成本都会被悄悄放大。 `pdf-inspector` 想解决的,正是这个环节里的 “误伤”。 项目地址:/firecrawl/pdf-inspector 它是一个用 Rust 编写的 PDF 检查与提取库,核心目标很直接:**先判断 PDF 到底是什么类型,再决定后续该怎么走**。README 对它的描述非常清楚 —— 它可以做 PDF 分类、文本提取,并且能智能识别一个 PDF 是扫描件还是文本型文档,从而帮助上层流程做更聪明的路由决策。 ## **它不是在 “读取 PDF”,它更像是在 “打量 PDF”** 如果把普通 PDF 处理工具比作一位埋头苦干的搬运工,那 `pdf-inspector` 更像是站在门口先看一眼局势的人。 它先问的不是 “怎么提取”,而是: - ・这是文本型 PDF 吗 - ・这是扫描件吗 - ・这是纯图像型文档吗 - ・还是一份混合型 PDF README 里给出的分类结果包括: - • `TextBased` - • `Scanned` - • `ImageBased` - • `Mixed` 而且这个判断不是一句模糊的 “像不像”,它还会返回 **confidence score**,也就是 0.0 到 1.0 的置信度分数;同时还能给出 **按页的 OCR 路由信息**,指出哪些页面缺少文本、需要 OCR 介入。 这就很有意思了。因为现实里的 PDF 从来不是整齐划一的:有的文档前几页是正文,后几页是扫描附录;有的报告主体是文字,但夹着几页图片;有的材料明明能直接提文本,却总被整个送进 OCR。`pdf-inspector` 在这里做的事情,不是粗暴地把整份文档贴上一个标签,而是尽可能把判断拆细,把决策交给真正需要决策的地方。 ## **一个很务实的出发点:不该做 OCR 的,就别做 OCR** README 里对这个项目的定位非常鲜明:它由 Firecrawl 构建,用来在本地处理文本型 PDF,并跳过昂贵的 OCR 服务。 甚至连使用场景都写得很直白 —— 针对大规模 PDF 处理流程,不是把每份 PDF 都送去 OCR,而是先分类: ``` PDF arrives → pdf-inspector classifies it (~20ms) → TextBased + high confidence? YES → extract locally (~150ms), done NO → send to OCR service (2-10s) ``` 这个流程图的价值在于,它没有把工具包装成 “万能 PDF 魔法盒”,而是非常诚实地告诉你:**它特别适合做前置判断与本地提取**。当文档本身已经具备良好的文本结构时,就本地快速完成;当文档缺少可用文本层,再转去 OCR。 README 还提到,之所以这么做,是为了节省大多数本来就是文本型 PDF 所带来的成本与延迟。这一点很朴素,但也很关键。很多工程优化最后都不是更复杂,而是更会分流。 ## **这份 README 的关键词只有两个:快,且知道自己在做什么** `pdf-inspector` 的 “快” 不是一句空泛宣传,README 里把它拆成了多个具体层面。 ### **1. 分类很快** 项目说明中写到,它通过采样内容流来检测 PDF 类型,分类大约在 **10 到 50 毫秒**之间完成。对于 300 页以上的 PDF,也能在毫秒级完成检测。 README 还解释了分类思路: 1. 1. 解析 xref table 和 page tree,而不是完整加载所有对象 1. 2. 根据 `ScanStrategy` 选择页面,默认扫描全部页面并支持提前退出 1. 3. 在内容流里查找 `Tj` / `TJ` 这样的文本操作符,以及 `Do` 这样的图像操作符 1. 4. 根据采样页中的文本操作符情况进行分类 这套思路很像一个经验老到的检查员:不急着把整栋楼拆开重装,而是先看结构、查关键线索,再决定判断。 ### **2. 提取也快** README 里提到,这个库可以在本地 **200ms 以内**处理文本型 PDF。与此同时,它还有一个重要的架构设计:**文档只加载一次**。 也就是说,检测和提取共享同一个已解析文档,不会为了 “先判断、再提取” 而重复做 I / O 和重复解析。这个细节非常工程化,也很能说明作者在意的不是孤立功能点,而是整条处理链的效率。 ## **它提取的不只是 “字”,而是尽量保留 “文档的样子”** 如果一个 PDF 工具只能把文字抠出来,那它离 “可用” 还差一步;真正难的是,把文本顺序、结构层级、列表、表格这些信息尽量保留下来。 `pdf-inspector` 在 README 里把这一块写得相当完整,它支持的并不是单纯文本输出,而是 **带位置感知的提取**,并进一步转换为 **干净的 Markdown**。 ### **文本提取:位置意识很强** 项目支持带有以下信息的文本提取: - ・字体信息 - ・X / Y 坐标 - ・自动多栏阅读顺序 这意味着它不是在 “把字符拼一遍”,而是在尽可能理解页面布局。尤其面对报纸式、多栏式排版时,这一点很重要。很多文档如果只按原始顺序硬拼,最后读起来会像把两条河流拧在了一起;而 `pdf-inspector` 明确支持 **自动检测多栏布局**,并按顺序组织阅读结果。 ### **Markdown 转换:不是简化,而是整理** README 里列出了 Markdown 输出阶段会处理的内容,包括: - ・标题 H1 到 H4,通过字体大小层级识别 - ・粗体和斜体,通过字体名称模式识别 - ・项目符号列表 - ・编号列表 - ・字母列表 - ・代码块,通过等宽字体和关键字检测 - ・表格 - ・财务表格中的数字拆分 - ・图表说明文字 - ・上标和下标 - ・URL 转换为 Markdown 链接 - ・断行连字符恢复 - ・页码过滤 - ・首字下沉合并 - ・目录式点线压缩 看起来像是一长串细节,但这些细节组合起来,其实是在回答同一个问题:**导出的 Markdown 到底能不能直接读、直接用。** 一份好的结构化提取,不是把页面 “打散”,而是把它 “翻译” 成另一种仍然有秩序的表达方式。`pdf-inspector` 做的就是这件事。 ## **表格这件麻烦事,它没有回避** PDF 里的表格,向来是文档处理里的硬骨头。`pdf-inspector` 在 README 中把表格检测单独拿出来写,也说明这部分是它的重要能力之一。 它采用的是 **双模式表格检测**: - ・基于 PDF 绘图操作中的矩形进行检测 - ・基于文本对齐关系进行启发式检测 随后再做: - ・列与行分配 - ・单元格组织 - ・最终格式化为 Markdown 表格 README 还特别提到,它可以处理: - • financial tables - • footnotes - • continuation tables across pages 也就是说,它考虑的不是 “有没有一张最标准的表”,而是现实里那些经常不那么整齐、甚至会跨页延续的表格。 这是一种很实在的设计态度:PDF 不是给解析器准备的,它原本是给人看的,所以所有结构化提取都天然带着一点 “逆向理解” 的意味。表格做得越认真,越说明项目没有停留在 “能跑通” 这个层面。 ## **对字体编码问题,它保持警觉** 不少 PDF 处理问题,看起来像 “提取失败”,实际上根源常常藏在字体编码里。 README 里提到,`pdf-inspector` 支持: - ・ToUnicode CMap 解码 - ・Type0 / Identity-H 字体 - • UTF-16BE - • UTF-8 - ・Latin-1 编码 同时,它还会自动检测 **broken font encodings**,并在发现问题时提示调用方回退到 OCR。 这一点很重要,因为 “错误地提取出一堆乱码” 往往比 “明确告诉你这里不可靠” 更糟糕。一个靠谱的系统,不只是会成功,也知道什么时候该承认自己不该继续硬提。 ## **同一套核心,不只活在 Rust 里** 虽然它的核心是 Rust,但这个项目并没有把自己困在单一语言生态里。README 展示了它在多个环境里的使用方式: - • Python - • Node.js - • Browser WebAssembly - • Rust - • CLI 这不是 “顺手做了几个绑定”,而是让同一个 PDF 能力,在不同上下文里都能被调用。 ### **Python:直接处理文件** ``` import pdf_inspector result = pdf_inspector.process_pdf("document.pdf") print(result.pdf_type) # "text_based", "scanned", "image_based", "mixed" print(result.markdown) # Markdown string or None ``` ### **Node.js:直接读取 Buffer 处理** ``` import { readFileSync } from 'fs'; import { processPdf, classifyPdf } from '@firecrawl/pdf-inspector'; const result = processPdf(readFileSync('document.pdf')); console.log(result.pdfType); // "TextBased", "Scanned", "ImageBased", "Mixed" console.log(result.markdown); // Markdown string or null ``` ### **浏览器 WebAssembly:本地跑,不走服务端** ``` import init, { processPdf } from '@firecrawl/pdf-inspector-wasm'; await init(); const response = await fetch('/document.pdf'); const pdf = new Uint8Array(await response.arrayBuffer()); const result = processPdf(pdf); console.log(result.pdfType); console.log(result.markdown); ``` ### **Rust:最原生的一种方式** ``` use pdf_inspector::process_pdf; let result = process_pdf("document.pdf")?; println!("Type: {:?}", result.pdf_type); if let Some(markdown) = &result.markdown { println!("{}", markdown); } ``` ### **CLI:给命令行工作流留足空间** ``` # Install the CLI tools cargo install pdf-inspector # Convert PDF to Markdown pdf2md document.pdf # JSON output (for piping) pdf2md document.pdf --json # Positioned TextItem JSON, including is_underline metadata pdf2md document.pdf --items-json # Raw markdown only (no headers) pdf2md document.pdf --raw # Token-efficient output (collapses long dot leaders and similar source padding) pdf2md document.pdf --compact # Insert page break markers () pdf2md document.pdf --pages # Process only specific pages pdf2md document.pdf --select-pages 1,3,5-10 # Detection only (no extraction) detect-pdf document.pdf detect-pdf document.pdf --json # Detection + layout analysis (tables, columns) detect-pdf document.pdf --analyze --json ``` 从这些入口能看出来,`pdf-inspector` 的姿态很明确:它不只想成为一个库,也想成为一块可嵌入、可集成、可组合的基础能力。 ## **浏览器侧的 WASM 版本,有一种 “把事情留在本地” 的克制** WASM 版本在 README 里有几个很值得注意的点: - ・解析在本地运行 - ・PDF bytes 不会上传 - ・构建是单线程的 - ・不要求 cross-origin isolation - ・CMaps 已内嵌 - • `init()` 之后提取是同步的 - ・大文档建议放到 Web Worker 里执行 - ・纯图片文档依然需要单独 OCR 这几条信息拼起来,勾勒出了一个很清晰的浏览器侧能力边界:**它能在浏览器里本地做分类和结构化提取,但不会假装自己能替代图像 OCR。** 这种边界感很可贵。很多工具最容易让人失望的地方,是宣传成 “全能型”,实际遇到复杂文档就沉默;而这里的说明方式更像一个稳重的工程组件 —— 能做什么,说清楚;不能替代什么,也说清楚。 ## **Node.js 绑定里,还有一项很实用的能力:区域提取** `napi/README.md` 里提到一个主 README 没有重点展开、但非常实用的能力:**按区域提取文本**。 也就是: ``` extractTextInRegions(buffer: Buffer, pageRegions: PageRegions[]): PageRegionTexts[] ``` 它的设计目标也写得很明白:适用于 **混合 OCR 流程**。先由页面图像上的布局模型识别区域,再由这个函数从 PDF 结构层里提取对应区域的文本。 示例里每个区域结果都带有 `needsOcr` 标记;如果文本不可靠,比如: - ・提取结果为空 - ・字体是 GID 编码 - ・出现垃圾文本 - ・编码异常 那就把这个区域继续送 OCR。 这种能力很像是把 “整份 PDF 是否 OCR” 进一步细化成 “某一页、某一块区域是否 OCR”。对于复杂文档来说,这种粒度显然更灵活。 ## **它的内部结构,读起来很像一条分工明确的流水线** README 给了一张很完整的架构图,从原始 PDF bytes 开始,分成 detector 和 extractor 两条主线。 提取链路里又包括: - • fonts - • content_stream - • xobjects - • links - • layout 然后布局再进入: - • tables - • markdown 最后经过分析、预处理、转换、分类和后处理,产出最终 Markdown。 这种结构感带来的最大好处,是让人一眼看出项目不是 “功能堆在一起”,而是按职责拆开的。README 还列出了源代码目录结构,例如: - • `lib.rs` 负责公共 API、`PdfOptions` builder 和便捷函数 - • `python.rs` 负责 PyO3 Python 绑定 - • `types.rs` 定义共享类型 - • `text_utils.rs` 处理字符与文本辅助逻辑 - • `process_mode.rs` 定义处理模式 - • `detector.rs` 负责快速 PDF 类型检测 - • `glyph_names.rs` 提供 Adobe Glyph List 到 Unicode 的映射 - • `tounicode.rs` 处理 ToUnicode CMap 解析 - • `extractor/` 是文本提取流水线 - • `tables/` 负责表格检测与格式化 - • `markdown/` 负责 Markdown 转换与结构识别 - • `bin/` 放置 CLI 工具 - • `napi/` 是 Node.js / Bun 绑定 - • `wasm/` 是浏览器绑定 如果你喜欢看项目 “骨架”,这一部分会很有阅读价值。它没有试图用很多抽象术语把自己说得高深,反而是把模块划分摆在你面前,让你知道这套能力是怎么层层拼起来的。 ## **扫描策略也不是只有一种** 在分类环节里,README 还给出了 `ScanStrategy` 的几种策略: - • `EarlyExit`:扫描所有页面,遇到第一个非文本页就停止 - • `Full`:扫描所有页面,不提前退出 - • `Sample(n)`:均匀采样若干页 - • `Pages(vec)`:只扫描指定页面 这意味着项目并不是只有一种固定的 “检测姿势”,而是把速度和精度之间的权衡显式交给调用方。 如果你的场景更看重快速路由,可以用更偏速度的策略;如果你需要更准确地区分 `Mixed` 和 `Scanned`,也有对应选择。这样的设计很适合真实系统接入,因为不同业务场景对 “快” 和 “准” 的容忍度并不相同。 ## **从 Benchmark 看,它想证明的不只是能用,而是有竞争力** README 提供了一组基于 `opendataloader-bench` 语料库的 benchmark 结果,测试集包含 200 份 PDF,只展示本地引擎且关闭 OCR。 结果表里,`pdf-inspector` 的成绩是: - • Overall:0.875 - • Reading Order (NID):0.915 - • Tables (TEDS):0.814 - • Headings (MHS):0.788 - • Speed (200 docs):0.470s README 还写到,这组结果在 **2026 年 7 月 31 日**于 **Apple M4 Pro** 上刷新;速度统计是去掉预热后的五次完整跑分中位数。 项目还明确写出一条 “Best fit” 总结:它适合 **native-text PDFs**,尤其是在速度、阅读顺序和表格结构都重要的场景里。在这次对比中,它拿到了更高的整体分、阅读顺序分和表格分,同时也是最快的。 这段 benchmark 信息的价值,不只是 “我更强”,而是它把 “适合什么场景” 说清楚了:**文本型 PDF、重视结构质量、同时在意速度**。这和它前面的整体定位是连贯的。 ## **安装方式很直接,门槛并不高** 如果你想从 README 给出的路径快速上手,不同环境的入口都非常明确。 ### **Python** ``` pip install maturin maturin develop --release ``` ### **Node.js** ``` npm install @firecrawl/pdf-inspector ``` ### **Browser WebAssembly** ``` npm install @firecrawl/pdf-inspector-wasm ``` ### **Rust** ``` cargo add pdf-inspector ``` 或者手动添加依赖: ``` [dependencies] pdf-inspector = "0.1" ``` ### **从源码构建 WASM** ``` cargo install wasm-pack --version 0.15.0 --locked wasm-pack build wasm --target web --scope firecrawl --release ``` Node.js 绑定的 README 里还特别提到,它提供预构建二进制,覆盖 Linux x64 / ARM64、macOS ARM64 和 Windows x64,npm 安装时只会安装与你平台匹配的那个包,而且 **不需要 Rust toolchain**。这对使用者来说非常友好,尤其是在只想集成能力、不想处理本地编译链路的时候。 ## **一个很有 “工程气” 的 PDF 工具** 读完 README 和 description,会很明显地感受到 `pdf-inspector` 的气质:它不是那种试图在文案里包办一切的项目,而是一块边界清楚、能力扎实、特别适合接进处理流水线的基础组件。 它关心的不是 “把 PDF 这件事说得多宏大”,而是几个很具体的问题: - ・这份 PDF 是文本型还是扫描型 - ・哪些页需要 OCR - ・能不能本地快速提取文本 - ・能不能尽量保住阅读顺序和结构 - ・能不能把结果整理成更干净的 Markdown - ・遇到编码问题时,能不能及时识别并让上层回退 这种专注会让一个工具显得很可靠。因为它不是对所有问题都说 “我能”,而是把自己最擅长的那一段路打磨得很深。 如果说 OCR 像重型机械,适合啃最硬的文档;那么 `pdf-inspector` 更像是一位懂分流、会判断、下手快的前场指挥。它先看看眼前这份 PDF 究竟是什么,再决定是轻快地本地处理,还是把真正难啃的部分交给后面的流程。 在 PDF 处理这条链路里,这样的角色,往往比想象中更重要。

优秀的个人博客,低调大师

agno v2.8.4 发布:实体记忆全面改造,四工具驱动第二大脑能力升级

![在这里插入图片描述](https://developer.qcloudimg.com/http-save/yehe-7620466/7656a645af3953673c333592a0be17c8.png) ![在这里插入图片描述](https://developer.qcloudimg.com/http-save/yehe-7620466/62072e30c3bcdfbc0835f6ce7d5ae838.png) ![在这里插入图片描述](https://developer.qcloudimg.com/http-save/yehe-7620466/6fb56a56496d77365305531ac4939562.png) 2026年7月27日,agno 正式发布 v2.8.4 最新版本。本次版本共包含 5 个提交、92 个文件变更,并由 9 位贡献者参与。整体代码变更规模达到 9,675 行新增、3,736 行删除。 从本次更新内容来看,v2.8.4 的核心重点并不只是常规修复,而是围绕学习系统中的实体记忆能力进行了一次明显的架构调整。原有实体记忆的自动提取模式被收敛,新的设计将实体记忆明确调整为仅支持 AGENTIC 工作方式,也就是由智能体主动通过工具调用完成实体信息的记录、关联、检索和遗忘。 与此同时,本次版本还修复了嵌套执行器需求序列化问题、Skill 脚本与引用工具处理空路径参数的问题,并新增 TrustedRouter 作为 OpenAILike 模型类。 --- **一、本次 v2.8.4 更新概览** v2.8.4 于 2026 年 7 月 27 日发布,更新内容包括以下五项: - • 修复嵌套执行器需求无法正确序列化的问题 - • 修复 Skill 脚本工具和引用工具无法接受空路径参数的问题 - • 新增 TrustedRouter,使其作为 OpenAILike 模型类接入 - • 重构第二大脑中的实体记忆能力 - • 完成 v2.8.4 正式版本发布流程 从提交时间看,前三项修复与新增功能在 2026 年 7 月 26 日完成,实体记忆改造以及版本发布提交则在 2026 年 7 月 27 日完成。 本次变更涉及 92 个文件,说明实体记忆改造并非单点功能更新,而是牵动了示例、学习模块、团队学习示例、测试日志以及实体记忆专题示例等多个部分。 --- **二、修复嵌套执行器需求序列化问题** 本次版本首先修复了嵌套执行器需求的序列化问题。 对于具备多层执行结构的场景,执行器之间可能存在嵌套的依赖需求。当这些需求需要被保存、传递或重新构建时,若序列化过程无法正确处理嵌套层级,就可能导致配置丢失、结构异常或执行行为不一致。 v2.8.4 对这一问题进行了修复,使嵌套执行器需求能够被正确序列化。 虽然本次提供的内容没有展示该修复的具体实现代码,但提交说明已经明确指出,该问题属于嵌套执行器 requirements 的序列化修复。这意味着新版在处理复杂执行器配置时,将更好地保留原始需求结构。 --- **三、Skill 脚本与引用工具支持空路径参数** 第二项修复涉及 Skill 系统中的脚本工具与引用工具。 此前,当路径参数为空值时,相关工具可能无法正确接受或处理该参数。本次 v2.8.4 更新后,Skill 脚本工具和引用工具均支持接收空路径参数。 这一修复的目标非常明确:让工具调用在路径信息缺失或显式传入空值的情况下,仍然能够按照预期完成参数处理,而不是直接因为空路径导致失败。 本次提交说明中使用的是“accept null path args”,即接受空路径参数。该更新属于工具调用参数兼容性修复,有助于减少调用链路中的参数异常。 --- **四、新增 TrustedRouter 作为 OpenAILike 模型类** v2.8.4 新增了 TrustedRouter,并将其纳入 OpenAILike 模型类体系。 这项更新意味着 TrustedRouter 可以按照 OpenAILike 模型类的方式进行使用和集成。对于项目中已经采用 OpenAILike 模型接口或模型抽象方式的场景而言,TrustedRouter 的加入使其能够进入统一的模型使用结构。 本次提供的更新内容没有给出 TrustedRouter 的具体初始化方式、参数结构或调用示例,因此可以确认的信息是: - • TrustedRouter 已被新增 - • TrustedRouter 被定义为 OpenAILike 模型类 - • 该功能已作为 v2.8.4 的正式更新内容发布 --- **五、实体记忆迎来核心改造:从自动提取转向四工具驱动** 本次 v2.8.4 最值得关注的变化,是第二大脑中的实体记忆重构。 实体记忆用于保存智能体对外部世界的知识。它关注的不是用户本身,而是用户周围的人、项目、公司、系统以及其他外部实体。 可以将两类记忆区分为: - • 用户记忆:关于用户自己的信息 - • 实体记忆:关于用户所在世界中的人、项目、公司、系统等信息 在 v2.8.4 之前,实体记忆示例中存在 ALWAYS 模式和 AGENTIC 模式两种方式。而本次更新后,实体记忆被明确调整为仅支持 AGENTIC 模式。 也就是说,实体记忆不再通过自动提取流程进行维护,而是由智能体借助四个工具主动记录、关联、搜索和遗忘实体信息。 新的实体记忆能力围绕以下四个工具构建: - • remember_about - • link_entities - • search_entities - • forget 这四个工具共同构成实体记忆的新操作界面。 --- **六、四个实体记忆工具分别解决什么问题** v2.8.4 中,实体记忆被定义为智能体关于世界的知识库。智能体围绕实体信息执行记录、关系建立、检索和清理操作。 **1. remember_about:记录或更新实体信息** remember_about 用于根据名称新增或更新实体。 它可以记录的信息包括: - • 实体事实 - • 实体事件 - • 实体描述 - • 笔记指针 在这个过程中,实体名称的解析和统一由存储层负责。实体标识会根据名称进行 slug 化处理,因此即使名称存在大小写差异,也可以被识别为同一个实体。 例如,某个名称以不同大小写形式出现时,存储层会将它们解析到同一个人或同一个实体上,而不会因为输入形式不同创建多个重复记录。 这项机制的重点在于:智能体负责表达要记录什么,存储层负责处理实体标识、名称规范化和实体归并。 **2. link_entities:建立实体之间的关系** link_entities 用于记录实体之间的关系。 例如,一个项目与某位负责人之间可以形成关系;一个公司与其负责人、产品、系统之间也可以形成关系。 本次更新特别说明,关系边会保存在两个实体上。也就是说,当两个实体被建立关联后,这条关系不是只保存在单侧,而是会同时体现在双方实体记录中。 这种设计使实体关系能够从不同方向被访问和检索。 **3. search_entities:搜索实体或按最近使用情况列出实体** search_entities 用于查找实体。 它支持两种核心使用方式: - • 根据查询条件搜索相关实体 - • 不传入查询条件时,按照最近使用情况列出实体 这意味着 search_entities 不只承担关键词搜索职责,也可以用于查看近期实体目录。 在实体记忆中,实体目录和相关性召回共同参与上下文构建。即使是新的会话,只要系统能够根据当前问题找到相关实体,之前记录的信息仍然可以被注入到当前对话上下文中。 **4. forget:遗忘事实或归档整个实体** forget 用于处理过时、不再需要或应当归档的记忆。 它支持两类操作: - • 退役某一条事实 - • 归档整个实体 这里的“退役事实”并不等于物理删除。实体记忆强调的是事实的演进过程。对于出现修正的信息,系统不会简单粗暴地覆盖旧内容,而是将旧事实标记为失效或退役,让新事实成为当前有效信息。 --- **七、事实修正机制:新事实会自动取代旧事实** v2.8.4 的实体记忆改造中,一个非常关键的能力是事实 supersession,也就是事实替代或事实继任机制。 当新的事实与旧的事实发生冲突时,新的信息会使旧信息退役。 例如,一个项目此前处于“因审核受阻”的状态,之后又明确说明该项目已经完成上线。此时,“受阻”这一旧状态不会继续作为当前有效事实存在,而会被新的“已上线”事实替代。 本次更新明确说明: - • 修正信息本身就是新事实 - • 新事实会自动使旧事实退役 - • 被替代的旧事实不会被直接删除 - • 事实展示时会携带截至日期信息 - • 较新的事实优先于较旧的事实 这种方式保证了实体记忆不只是保存一个静态结果,还能够表达信息的时间演变。 因此,实体记忆中的“已退役”事实仍然保留历史价值,但在当前知识表达中,最新事实拥有更高优先级。 --- **八、基础示例合并:5_entity_memory.py 成为新的实体记忆入口** 在基础学习示例目录中,v2.8.4 新增了: `cookbook/08_learning/01_basics/5_entity_memory.py` 这个文件将原来的两个实体记忆示例统一为一个新的示例入口。 原先的两个文件被删除: - • `cookbook/08_learning/01_basics/5a_entity_memory_always.py` - • `cookbook/08_learning/01_basics/5b_entity_memory_agentic.py` 新的文件标题为“Entity Memory: The Four Tools”,即实体记忆:四个工具。 示例文件开头对实体记忆的定义非常明确: - • 实体记忆是智能体关于世界的知识 - • 它关注用户周围的人、项目、公司和系统 - • 它不同于用户记忆 - • 用户记忆关注用户自身 - • 实体记忆仅支持 AGENTIC 方式 - • 智能体通过四个工具进行记录 - • 存储层负责处理名称、标识和事实替代 该示例使用 PostgreSQL 作为数据库: ``` db = PostgresDb(db_url="postgresql+psycopg://ai:ai@localhost:5532/ai") ``` 同时,为了保证每次运行演示时都拥有独立的干净空间,示例通过随机字符串生成命名空间: ``` NAMESPACE = f"basics_{uuid4().hex[:6]}" ``` 这种写法的目的,是让每次演示运行从一个新的命名空间开始,避免历史演示数据互相干扰。 智能体初始化时配置了实体记忆: ``` learning=LearningMachine( entity_memory=EntityMemoryConfig(namespace=NAMESPACE), ) ``` 这里不再配置实体记忆的 ALWAYS 模式,而是直接配置带命名空间的 EntityMemoryConfig。 示例中的智能体定位为销售助手,并要求对笔记进行简短确认。 首次对话中,用户提供了一家公司、公司规模、所在地以及技术负责人等信息。智能体在第一个会话中记录这些实体信息。 随后,示例切换到一个新的会话,并询问“我们知道这家公司什么信息”。 这里要验证的核心能力是: - • 会话已经变化 - • 实体目录仍然存在 - • 相关性召回仍然能够带回相关知识 - • 回答问题时不必再执行工具调用 - • 已记录的实体信息可以直接通过注入上下文被用于回答 这也说明实体记忆的价值不局限于单一会话,而在于跨会话的世界知识延续。 --- **九、团队学习示例同步调整** 在团队学习示例中,文件: `cookbook/03_teams/12_learning/03_team_entity_memory.py` 也进行了调整。 原先的配置中,实体记忆使用了 ALWAYS 模式: ``` entity_memory=EntityMemoryConfig( mode=LearningMode.ALWAYS, ), ``` 在 v2.8.4 中,这段配置被替换为: ``` entity_memory=EntityMemoryConfig(), ``` 并附带说明: ``` # AGENTIC-only: the agent records through its four tools ``` 这句说明直接点明了 v2.8.4 的设计变化:实体记忆仅支持 AGENTIC,智能体通过四个工具完成记录。 该团队示例中,用户档案仍然保持 ALWAYS 模式: ``` user_profile=UserProfileConfig( mode=LearningMode.ALWAYS, ), ``` 这进一步体现了用户档案与实体记忆的区别。 用户档案可以继续采用 ALWAYS 模式;实体记忆则不再采用自动提取模式。 --- **十、团队 Agentic Learning 示例修正导入** 文件: `cookbook/03_teams/12_learning/10_team_agentic_learning.py` 中还包含一个导入调整。 更新前后出现的变化是 LearningMode 的导入来源调整。原先存在从一个位置导入 LearningMode 的写法,更新后使用了: ``` from agno.learn.mode import LearningMode ``` 本次提供的差异信息显示,旧导入被删除,并保留了新的导入方式。 这项改动属于示例代码导入路径的整理,与实体记忆重构同步出现。 --- **十一、提取限制示例移除实体记忆相关内容** 文件: `cookbook/08_learning/01_basics/6_extraction_limits.py` 在 v2.8.4 中删除了实体记忆相关配置和展示逻辑。 原先该示例中包含: ``` EntityMemoryConfig ``` 并且在 LearningMachine 配置中设置了实体记忆的 ALWAYS 模式及独立限制: ``` entity_memory=EntityMemoryConfig( mode=LearningMode.ALWAYS, max_updates_per_run=15 ), ``` 原有注释说明了不同存储的更新上限关系: - • LearningMachine 全局 `max_updates_per_run=5` - • user_profile 继承全局上限 5 - • user_memory 显式覆盖为 3 - • entity_memory 显式覆盖为 15 更新后,实体记忆相关导入被删除,实体记忆配置也被删除。 保留下来的限制逻辑聚焦于: - • 用户档案 - • 用户记忆 其中,用户档案使用 ALWAYS 模式,用户记忆使用 ALWAYS 模式并指定每次运行最多更新 3 次。 原先用于打印实体记忆搜索结果的代码也被删除,包括: ``` entities = lm.entity_memory_store.search(query="techcorp", limit=20) ``` 以及打印实体记忆结果的逻辑。 原因已经在测试日志和 README 说明中明确:实体记忆已经没有自动提取流程,因此不再适用于 extraction limits,也就不存在提取过程中的更新次数限制问题。 换句话说,`max_updates_per_run` 示例现在只用于用户档案和用户记忆,而不再覆盖实体记忆。 --- **十二、基础学习 README 更新** 文件: `cookbook/08_learning/01_basics/README.md` 同步更新了实体记忆示例列表。 旧版本中包含两个实体记忆示例: - • `5a_entity_memory_always.py`:ALWAYS 模式下的实体记忆提取 - • `5b_entity_memory_agentic.py`:AGENTIC 模式下的实体记忆管理 v2.8.4 中,这两个条目被删除,替换为: - • `5_entity_memory.py`:四个实体工具,且在 2.8.4 中仅支持 AGENTIC README 的变化准确反映了本次实体记忆能力的迁移结果: - • 两个模式示例合并为一个示例 - • ALWAYS 模式实体记忆示例不再保留 - • 四工具成为实体记忆的统一操作方式 - • 实体记忆仅保留 AGENTIC 模式 --- **十三、测试日志记录了实体记忆改造的验证结果** 文件: `cookbook/08_learning/01_basics/TEST_LOG.md` 也同步记录了这次实体记忆重构的测试情况。 测试日志新增说明指出: - • 原来的 5a 和 5b 示例已被 `5_entity_memory.py` 替代 - • 实体记忆在四工具表面下仅支持 AGENTIC - • 新示例已经使用 gpt-5.5 实际运行验证 - • 在第一个会话中,公司实体被成功记录 - • 公司属性和技术负责人关系被成功记录 - • 在第二个会话中,系统能够基于注入的信息回答问题 - • 第二个会话的回答没有调用工具 - • `6_extraction_limits.py` 不再包含实体记忆 - • 原因是实体记忆没有提取流程,因此不存在需要限制的提取次数 测试日志中,新的 `5_entity_memory.py` 状态为 PASS。 其验证描述是: - • 通过四个实体工具完成记录 - • 在一个会话中完成信息捕获 - • 在全新的会话中完成信息召回 测试结果说明,实体记忆已经能够在首个会话中保存实体与关系,并在后续新会话中借助上下文注入完成回答。 与此同时,`6_extraction_limits.py` 的说明调整为: - • `max_updates_per_run` 只限制 user_profile 和 user_memory - • 实体记忆已从该示例中移除 - • 原因是实体记忆不存在需要限制的提取过程 --- **十四、实体记忆专题示例重构** 在实体记忆专题目录中,原文件: `cookbook/08_learning/04_entity_memory/01_facts_and_events.py` 已被删除。 新的文件为: `cookbook/08_learning/04_entity_memory/01_the_four_tools.py` 该文件新增 86 行内容,完整展示了实体记忆的四工具工作方式,以及事实替代机制。 示例同样使用 PostgreSQL 数据库: ``` db = PostgresDb(db_url="postgresql+psycopg://ai:ai@localhost:5532/ai") ``` 并生成每次运行独立的命名空间: ``` NAMESPACE = f"four_tools_{uuid4().hex[:6]}" ``` 示例特别指出: - • 演示环境中使用新的命名空间,以便每次运行都从干净状态开始 - • 真实部署环境中应固定一个命名空间 - • 持久化本身正是实体记忆存在的意义 智能体初始化配置如下: ``` learning=LearningMachine( entity_memory=EntityMemoryConfig(namespace=NAMESPACE), ) ``` 智能体的角色是项目跟踪助手,要求在接收到信息后简短记录。 --- **十五、专题示例演示了三轮实体记忆交互** 新的 `01_the_four_tools.py` 示例包含三轮关键交互。 **第一轮:记录项目与人员关系** 第一轮中,用户要求追踪一个项目,并说明: - • 该项目当前被安全审核阻塞 - • 某位人员是该项目的设计负责人 这一轮的目标是让智能体通过实体记忆工具记录: - • 项目实体 - • 项目当前状态 - • 人员实体 - • 人员与项目之间的关系 这正对应 remember_about 和 link_entities 的使用方向。 **第二轮:提交修正信息,触发事实替代** 第二轮中,用户提供新的状态信息: - • 项目第一版已经在当天上线到生产环境 这条信息与第一轮中的“项目被审核阻塞”形成了状态演变。 示例明确指出,此时事实替代机制会让旧的“受阻”事实退役,而不是删除。 随后,示例会打印该项目当前有效的事实: ``` store.print(entity_id="radar", entity_type="project", namespace=NAMESPACE) ``` 打印时关注的是“仍然有效的事实”。 旧的受阻信息虽然没有被物理删除,但已经退役,因此当前展示的重点是新的上线状态。 **第三轮:在新的会话中完成召回** 第三轮中,示例再次切换到一个新的会话,并询问项目相关信息。 此时要验证的是: - • 会话已经是全新的 - • 实体目录仍然可用 - • 相关性召回能够识别当前问题涉及的实体 - • 系统能够将相关实体信息注入当前上下文 - • 智能体可以回答关于该项目的问题 示例注释明确指出,实体目录加上相关性召回会注入当前轮次所关注的信息。 这与基础示例中跨会话召回公司的信息形成了呼应:实体记忆并不依赖原始会话持续存在,而是通过持久化实体信息和相关性召回,为新会话提供知识支持。 --- **十六、v2.8.4 中实体记忆的最终使用方式** 综合本次全部示例和代码变化,可以清晰看到 v2.8.4 对实体记忆的最终定位。 实体记忆不再使用 ALWAYS 自动提取模式。 实体记忆的操作方式收敛为四个工具: - • remember_about:记录或更新实体事实、事件、描述与笔记指针 - • link_entities:建立实体关系,并在双方实体上保存关系边 - • search_entities:按条件检索实体,或在没有查询条件时按最近使用情况列出实体 - • forget:退役事实或归档实体 实体解析由存储层完成,包括: - • 名称 slug 化 - • 大小写归一 - • 同名实体合并 - • 实体标识处理 事实演进由 supersession 机制处理,包括: - • 新事实自动替代旧事实 - • 旧事实退役而非删除 - • 事实附带截至日期 - • 新事实优先级高于旧事实 实体记忆支持通过命名空间隔离不同的数据空间。 在示例中,随机命名空间用于保证演示环境的干净状态;在实际部署中,固定命名空间用于获得长期持久化的实体知识。 --- **十七、总结:v2.8.4 的关键变化** 代码地址:github.com/agno-agi/agno agno v2.8.4 的更新重点可以总结为以下几个方面: - • 修复嵌套执行器需求序列化问题 - • 修复 Skill 脚本与引用工具的空路径参数兼容问题 - • 新增 TrustedRouter 作为 OpenAILike 模型类 - • 全面重构第二大脑中的实体记忆 - • 删除实体记忆 ALWAYS 模式示例 - • 删除实体记忆自动提取限制相关配置 - • 将实体记忆统一收敛为 AGENTIC 四工具模式 - • 新增统一基础示例 `5_entity_memory.py` - • 新增实体记忆专题示例 `01_the_four_tools.py` - • 使用事实替代机制处理状态修正和知识演进 - • 支持跨会话的实体目录与相关性召回 - • 在测试日志中确认新实体记忆示例已通过实际运行验证 对于 v2.8.4 而言,实体记忆的变化不仅是 API 或示例文件名称的调整,更是学习机制使用方式的明确收敛。 用户档案和用户记忆仍然可以按照自动学习方式进行更新,而实体记忆则被定位为由智能体主动管理的世界知识库。通过记住实体、关联实体、搜索实体和遗忘实体,智能体能够持续构建关于项目、公司、人员和系统的结构化认知,并在新的会话中重新召回与当前问题最相关的信息。 --- > 我们相信人工智能为普通人提供了一种“增强工具”,并致力于分享全方位的AI知识。在这里,您可以找到最新的AI科普文章、工具评测、提升效率的秘籍以及行业洞察。

优秀的个人博客,低调大师

我建了个「第二大脑」:把散落的文章 PDF 变成会对话的知识库

## 痛点:收藏了 800 篇,要用的时候一篇都找不到 我的收藏夹是个黑洞。 微信收藏、浏览器书签、Notion 剪藏、下载文件夹里的 PDF、截图、公众号文章……粗略统计超过 800 条。每次心血来潮整理,结果都是把 A 文件夹的东西挪到 B 文件夹,标签从「待看」改成「重要待看」,然后再也没打开过。 真正让我崩溃的是上个月做竞品调研。我明明记得三个月前存过一份对手的产品白皮书,翻遍了三个网盘、两个笔记软件、微信收藏,花了四十分钟,最后是在一个叫「新建文件夹(2)」的目录里找到的——文件名叫 `未命名扫描件_20260411.pdf`。 那一刻我意识到问题不在"整理",而在**检索方式**:我一直在用文件名和记忆去找东西,但人对资料的记忆本来就是模糊的,只记得"大概讲过某个观点",记不住它存在哪、叫什么名字。 所以我把思路换了一下:**别整理了,让资料能被"问"出来。** ## 三种现成方案,先说清楚各自适合谁 在动手自建之前,我把市面上主流的三种方案都认真用了一遍,各有各的适用边界。 **NotebookLM** —— 上手最快,体验最好。丢进去十几份 PDF,直接生成播客式对话、思维导图、FAQ。缺点是资料必须上传到 Google,中文长文档的切片质量一般,而且它是个封闭系统,你没法把检索结果接到自己的工作流里。适合:快速吃透一份陌生资料,用完即走。 **Claude 长上下文** —— 最省心。开个对话,把 PDF 全部贴进去,直接问。200K 上下文大概能塞下一本中等厚度的书,准确率很高。缺点是每次新对话都要重新传一遍,成本按 token 算,资料一多就肉疼,而且没有"出处回溯",它给你答案但你不知道来自哪一页。适合:一次性深度阅读几十份文档的场合。 **Perplexity** —— 擅长联网检索,不擅长你的私有资料。它的 Spaces 能上传文件,但检索粒度粗,中文 PDF 表现不稳定。适合:公开信息调研,不适合做私人知识库。 三个方案都有个共同的硬伤:**你的资料躺在别人的服务器上,且检索结果接不回你的日常工具链**。我想要的是一个本地的、能长期增量更新的、能被其他自动化脚本调用的"顾问"。 ## 自建方案:三个模块拼起来 架构其实很简单,就三件事: ```javascript 文档入库 → 语义检索 → AI 回答并附出处 ``` **模块一:文档入库(把 PDF/Markdown/网页变成纯文本块)** 关键不是转格式,而是**分块策略**。我最早按固定 1000 字切,结果经常把一段完整论述拦腰截断,检索出来的片段读不通。后来改成按语义段落切,每块 300~600 字,相邻块之间保留 80 字重叠——这样即使命中在边界上,上下文也还是完整的。 一份 40 页的 PDF 大概切成 60~80 块,每块带上元信息:来源文件名、页码、章节标题。 **模块二:语义检索(不用关键词,用向量)** 关键词检索解决不了"我记得它讲过用 OCR 处理扫描件"这种模糊描述——因为原文里可能根本没出现"OCR"三个字,写的是"图像识别后提取文字"。语义检索把每块文本转成向量,查询时也把问题转成向量,比的是"意思接不近",不是"字一不一样"。 本地跑的话,嵌入模型用开源的小尺寸模型就够(几百 MB,CPU 能跑),向量库存 SQLite 或者专门的向量库都行,几千块文本的规模完全没压力。 **模块三:AI 回答并附出处(这一步是灵魂)** 检索出 Top-5 相关块之后,把它们连同问题一起丢给大模型,用下面这个 Prompt 约束输出: ```javascript 你是我的个人知识库助手。下面是从我的资料库中检索到的 5 个片段, 每个片段带有 [来源: 文件名 P页码] 标记。 请只基于这些片段回答我的问题,遵守以下规则: 1. 每个结论后面必须紧跟 [来源: 文件名 P页码] 2. 片段中没有的信息,直接说"资料里没有提到",不许用你自己的知识补充 3. 如果片段之间有冲突,把冲突原样列出,不要替我调和 4. 回答用中文,口语化,不超过 300 字 问题:{question} 片段: {chunks} ``` 第 2 条和第 3 条是我踩坑后加的。早期版本没有这两句,模型会非常贴心地"补全"我没存过的东西,看起来很专业,实际上是编的——知识库最怕的就是这个,你分不清哪句是你的资料、哪句是它自己编的。 **要求它必须标出处,还有一个附加好处**:你能一眼看出它到底检索准不准。如果附的来源牛头不对马嘴,说明是分块或嵌入的问题,而不是模型的问题,排查方向就很清楚。 ## 具体怎么搭(可复制的最小实现) 不想一上来就搞个大工程的话,最小可用版本只需要三步: **1. 建一个资料目录,统一丢文件** ```javascript knowledge/ ├── raw/ # 原始 PDF、Markdown、网页导出 ├── chunks.jsonl # 切块后的文本 └── vectors.db # 向量库 ``` **2. 一条命令完成入库** ```javascript # 遍历 raw/ 下所有文件,切块 + 生成向量 + 写库 node ingest.js ./knowledge/raw ``` 脚本做的事:识别文件类型 → 提取文本 → 按语义段落切块 → 逐块生成嵌入 → 写入向量库 → 记录 `已处理文件清单`(下次只处理新增的,增量更新)。 **3. 一个命令提问** ```javascript node ask.js "对手的定价策略是怎么分层的?" # → 输出答案 + [来源: 竞品白皮书.pdf P23] [来源: 行业报告2026Q2.md] ``` 整个链路跑通之后,我把它挂成了定时任务:每天凌晨扫一遍 `raw/` 目录,新文件自动入库。也就是说,**我唯一需要做的就是把文件丢进文件夹,剩下的全自动**。 ## 踩坑:扫描版 PDF 必须先 OCR 这是最容易被忽略、也最容易让人误以为"方案不行"的一个坑。 很多 PDF 尤其是扫描件、截图转的 PDF,用常规解析库提取出来是**空字符串**——因为它本质是一张图片,里面根本没有文本层。我第一次入库 200 份资料,有 30 多份解析出来是空的,而且脚本不报错,静悄悄地就跳过去了。等到检索的时候才发现"明明存了就是搜不到"。 解决办法很简单,入库前加一道检测:**提取文本后看长度,低于阈值(比如每页 50 字)就判定为扫描件,先走 OCR 再入库**。OCR 用开源引擎本地跑就行,一页几百毫秒,批量处理完全可以接受。 另外两个小坑顺手提一下: - **表格会被切碎**。PDF 里的表格提取出来经常变成一堆错位的数字,语义检索几乎搜不到。我的处理是把表格单独标记,检索时降权,宁可搜不到也别搜出乱码。 - **同一份资料别重复入库**。增量清单要用文件哈希而不是文件名,我吃过亏——同一份文件改名叫 `白皮书_最终版.pdf` 和 `白皮书_最终版2.pdf`,入库两次,检索时 Top-5 里有三块是重复的,答案质量直线下降。 ## 效果实测 现在我的库里有 620 份资料、约 3.8 万个文本块。 之前那次竞品调研,同样的需求,我从四十分钟翻找变成了**一句话提问、8 秒出答案**,而且答案后面跟着三个来源标注,点开就能核对原文。 更意外的是"意外发现"的价值。有一次我问"我们的产品在处理大文件时有什么已知问题",它给出的答案里引用了一份半年前的会议纪要和一个完全被我遗忘的技术博客——这两份资料如果靠人去翻,一辈子都想不起来要打开它们。资料之间产生了关联,这是文件夹式整理永远做不到的。 代价也要说清楚:入库 620 份资料花了一次性约 6 小时(主要是 OCR),之后每天增量更新不到 1 分钟;检索加回答的响应在 5~10 秒,比不上搜索引擎,但比翻文件夹快两个数量级。 ## 一句话总结 让资料从"仓库"变成"顾问"——**能回答问题的资料才叫知识,否则只是一堆占空间的字节**。 本文是「WorkBuddy 实战笔记」系列之一,记录每天一个真实跑通的自动化场景。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册