后端前端人工智能RAG知识图谱知识管理搜索引擎【免费下载链接】utopiaWorlds first open-source enterprise world model.项目地址https://gitcode.com/gh_mirrors/ont/utopia点击查看免费下载本文基于 Utopia 仓库中的设计决策记录 docs/decisions/0039-a-chunk-is-what-extraction-sees.md讲解该记录的核心主张一个 chunk 就是抽取模型一次调用所看见的全部内容因此 chunk 边界本身就是抽取契约的一部分。文章从旧 29 行字符分块器在真实召回评测中暴露的三个失败模式出发逐条还原块模型blocks.rs与打包器chunker.rs的九项设计决策并用源码、迁移与测试作为证据。读完本文你将理解 Utopia 为什么用 300 token 的预算而不是 1200 字符、表如何带着说明句与表头跨块续写、被分页符劈开的表如何被接回以及如何用UTOPIA_CHUNK_TOKENS环境变量把预算变成可测量的旋钮从而在自己的知识库工程中复现同样的取舍。问题的起点29 行的字符分块器在决策 0039 落地之前Utopia 的分块器只有二十九行代码字符预算 1200重叠 150边界由只认识段落和句子的通用文本切分器选择它不知道什么是表格行、什么是表头、什么是表格的说明句caption。以召回基准recall benchscripts/bench/recall.mjs的语料为例——四份 SEC 文件、由人从原文读出的 52 条真值表truth/nvda-public-docs.json——旧分块器产出的 chunk 中出现了三种可复现的失败形态它们分别对应一种“信息被边界切掉”的方式1. 表的续块丢了表头。财报的 35 个 chunk 里有 13 个从表格中间开始。装 non-GAAP EPS 的那个 chunk 开头是| | Non-GAAP* | | $ | 2.22 | | | $ | 1.87 | …——五个美元数字没有列名。模型只能猜 $2.22 属于哪个季度猜对了就是命中猜错了就是漏。这正是同一份代码在两轮评测中得分在 43 与 45 之间漂移的原因同一行数据在不同 chunk 里被读到的上下文不同抽取结果就不稳定。2. 表丢了它的说明句。“The results of the voting were as follows:” 这一句落在一个 chunk 的末尾它引出的投票数字却从下一个 chunk 开始。解释“这些数字是什么”的句子不在装着数字的 chunk 里。3. 分页符劈开了一张表切分器把分页符当成边界。8-K 的 HTML 在纸张翻页处有一个hr恰好落在 Stephen C. Neal 投票表的中间。转换器把hr渲染成主题分隔thematic break切分器又偏爱在主题分隔处切分于是表的后半截——弃权票abstentions和券商非投票broker non-votes——变成了一张没有名字的孤表。根因是预算本身。旧代码写的是 1200 字符旁边注释写着“约 1000 token”。这对中文成立英文在 1200 字符里只有约 300 token宽表永远放不进一块。同一份文档中文拿到四倍于英文的上下文。从源码看这个问题在 crates/utopia-ingest/src/chunker.rs 的模块注释里被完整记录了下来作为新实现的设计动机。被否掉的四条路死胡同也是决策的一部分决策记录用一节专门写下“不走的路”因为它们说明了为什么最终方案长这样更聪明的切分器text-splitter的MarkdownSplitter。它确实把标题排在段落、句子之上但它把一行表格行与整张表排在同一个层级——超预算的表仍然在行之间被切开且没有任何机制重复表头。它还保留“主题分隔优先作为边界”的行为正是 Neal 失败的重演。这一轮只采纳它的两样东西标题跟随heading attachment与按 token 计尺寸作为单个超长段落的退路而不是作为分块器本身。重叠overlap作为上下文。旧方案用 150 字符重叠来跨边界携带上下文。对散文它携带句子的尾巴对表格它携带上一行的尾巴——这正是错误的信息。上下文应当是表头与说明句它们是被选出来的而不是从上一块恰好结束的地方抄来的。现在引入外部文档解析器Docling、Unstructured。它们把文档解析成结构化元素并且续块会重复表头。但对 HTML、Markdown、DOCX 和电子表格Utopia 自己的解析器已经产出结构为了一个五十行就能写的规则给 Rust 流水线加一个 Python 服务毫无收益。它们的价值在 PDF 版式与扫描页——那是 cut 2位于同一套块模型之后因此换解析器时打包器完全不用动。只把解析器输出切块而不做“接回”。把 Markdown 读成块解决了表头和说明句但解决不了 Neal解析器已经把那张表产出为两张表第二张在数据行下带着一条分隔行块读取器如实报告了两张表。“接回”是另一条独立的规则而且刻意做窄见决策 6。九项决策块模型与打包器如何把“不拆”变成代码1. chunk 就是抽取看到的全部边界是抽取契约的一部分模型只拿到一个 chunk没有别的被边界切掉的内容提示词救不回来。因此打包器的规则从抽取器这一侧书写永不拆表格行永不把表头与表体分开永不把说明句与它的表分开永不把标题与其下第一个块分开。这不是排版偏好——每一项被违反时都在基准里对应一个具体的漏检miss。2. 解析器的文本被读成块打包器在块上工作crates/utopia-ingest/src/blocks.rs 用pulldown-cmark把解析器的 Markdown 读成顶层块序列——标题、段落、表表头行与体行分开为独立范围、分隔线、其他——每块带着它在原文里的字节范围。块的种类在Kind枚举中定义Heading(u8)、Paragraph、Table { head, rows }、Rule、Other列表、代码块、引用、原样 HTML 整块作为一个单元。crates/utopia-ingest/src/chunker.rs 在块之上打包。两层分离正是 cut 2 便宜的原因外部解析器只要产出块打包器既不知道也不关心。关键实现细节是块文本由原文的逐字切片拼接而成一个字不改——模型回引的引文仍能通过span_in_quotecrates/utopia-server/src/extraction.rs比较时忽略大小写与空白在 chunk 里找到。3. 表带着它的说明句和表头走续块重复两者一张表紧前面的一段短段落——至多 200 字节或以冒号结尾——被认作表的说明句随表移动放得下的表整张进入一个 chunk放不下的表在行之间切开每一片都是说明句 → 表头行 → 尽量多的行一行永不拆分说明句 表头 一行仍然超预算时照发——没有更好的切法。这就是直接修复“13 个无表头 chunk”的那一刀。源码里的常量是CAPTION_MAX_BYTES 200、CAPTION_RUN_MAX 5表前最多连续五段短说明一起算——财报里“NVIDIA CORPORATION”“CONDENSED CONSOLIDATED STATEMENTS OF INCOME”“(In millions)”“(Unaudited)”就是四段各算一段的说明句见 chunker.rs 的units()。chunker.rs的测试a_wide_table_is_split_by_rows_and_every_piece_carries_its_header_and_caption断言每一片都同时包含表头、分隔行、说明句和章节面包屑且 40 行中每一行在全文中恰好出现一次。2026-09-13 的修订针对充值后 300 token 轮次暴露的两个缺口一句说明引出的是它后面的一整串表不只第一张。“Stockholders approved the election of each of our ten director nominees. The results of the voting were as follows:”后面跟着十张表旧行为让说明句只跟着 Tench Coxe 那张走Jen-Hsun Huang 的表落在另一块里四个票数全对却没有一句话说明这是在投什么——“elected director”这条边就此丢失。现在说明句附着到其后每一张表直到出现表格或分隔线以外的东西为止在同一块内只渲染一次十张表挤进一块时“结果如下”不会念十遍。说明句与其表之间的分隔线不拆散它们。第 5 项议案的“results were as follows:”和它的表在 HTML 里隔了一页旧的向前看逻辑看到分隔线就停说明句留在了上一块。现在在寻找说明句的表时跳过分隔线。两条都是关于文档结构的规则与 SEC 的措辞无关——代码注释明确写明了这一点chunker.rs。4. 预算是 token 而不是字符——并且是 300因为 1000 被量过、输了计数用tiktoken的 cl100k内嵌于 crate无需联网。它并非抽取模型DeepSeek自己的分词器但同为 BPE、比率相近且预算是上限而非账本。最初这节选择了 1000 以尊重旧注释基准第一轮就把它推翻1000 token 时得分 36/52此前 43、45收购 8-K 从九块变成两块模型面对 4700 字符只写了七条事实——地址、电话、“published in the SEC”——收购本身一条没有。抽取器单次调用的产出不随输入变长而变多喂得越多它越挑容易的几条写。默认改为300这正是旧字符预算在英文上的实际大小也是 43/45 两轮被测量的条件。中文拿到的上下文比从前少这一点尚未被测量、保持开放。预算是一个旋钮UTOPIA_CHUNK_TOKENS环境变量定义在 crates/utopia-core/src/config.rs 的AppConfig.chunk_tokens默认300见Default实现经UTOPIA_前缀环境变量注入由 pipeline.rs 在读取文档时传入reading.chunk(state.chunk_tokens)。这样下一次测量不必重新编译。预算大小本身是一个带权衡的旋钮——更少、更大的调用对单次回复更多事实——本 cut 内未单独测量基准比较因此同时比较结构与大小单独测预算留作开放问题。5. 标题是面包屑写进 chunk 文本也写进chunks.heading一个 chunk 所在的标题路径被前置到它的文本中——作为标题行本身——并作为纯文本存入chunks.heading列。这一列自 ingest 迁移起就存在migrations/0002_ingest.sql 的CREATE TABLE chunks中heading TEXT从未被写过直到本决策第一次填它。当 chunk 正文已以该标题开头时前缀被跳过。标题永不独自结束一个 chunk它附着到其后内容。测试a_chunk_opens_with_the_headings_it_lives_under验证了面包屑文本如Report › Part B › B.1与heading列的一致。6. 主题分隔不是边界被它劈开的表被接回旧切分器偏爱在水平线处切。本语料里水平线是分页符而分页符正是表最可能被拦腰截断的地方。因此分隔线从块序列中被丢弃不参与打包units()对Kind::Rule直接跳过。另外在 blocks.rs 的join_continuations中序列表、分隔线、表若两张表列数相同且第二张的“表头”行首格与第一张某个体行的首格共享开头两个词——Number of shares Abstaining接在Number of shares For之后——则合并为一张表第二张的“表头行”变成第一张的体行其分隔行被丢弃。规则刻意窄只比对行首标签不看数字。“同宽且表头含数字”的宽规则会把两张表头是年份2025 | 2024的财务表错误接成一张。测试同时守住两种形状a_headerless_table_after_a_rule_continues_the_one_before与two_tables_with_numeric_headers_stay_two_tables。7. 不重叠块是语义单元。上下文来自面包屑、说明句和表头——按它们是什么来选择而不是把上一块的尾巴抄过来。此外重叠让抽取器在重叠跨度上被要求产出两遍事实台账会去重但调用费用是实付的。8.char_start/char_end命名正文不含前缀这两列指向 chunk 正文在解析文本中的逐字跨度前缀面包屑、重复的说明句、重复的表头从别处复制不属于该跨度。目前除一个测试夹具外无人读取这两列记录在此是为了让第一个读者知道他们拿到的是什么。chunker.rs的flush()中char_start取正文各片span().start的最小值char_end取最大span().endspan_in_quote与正文切片共同保证了“原文逐字可回放”。9. 每份文档在下次重新处理时重新分块不做任何提前工作replace_chunkscrates/utopia-store/src/documents.rs按精确文本认领旧块新文本意味着每个块都被取代并重新插入文档被重新抽取。这正是既有的重新处理路径旧块保留其向量与证据链接。没有迁移来为整个部署重新分块——旧块不是“错”只是“更差”它们在下一次各自重新处理时变好。流水线侧由replace_chunks_if_current配合 sha256 快照校验保证并发安全pipeline.rs。基准测量的完整经过2026-09-13决策记录保留了一天的三次测量因为它同时展示了结构变化与预算大小的分离实验轮次条件得分说明基线旧切法两轮43/52、45/52关系边 12/12稳定漏检三条都不在extraction_drops/ontology_misses中——从未被抽出而非抽出后被丢弃实验 1--reprocess全量重分块1000 token36/52关系边 8/12收购 8-K 4/11两个 chunk 里七条事实全是地址电话——推翻了决策 4 的 1000实验 2300 token账户余额耗尽37/52无效测量HTTP 402俄亥俄展品的 3–7 块未发送已完成的三个文档 29/37与基线两轮 29/37、33/37 在一个标准差内重跑300 token账户充值45/52字面值 36/39基线 31、32俄亥俄展品15/15关系边 8/12三个关系漏检是 Vera Rubin 伙伴——图里其实有模型写NVIDIA partner CoreWeave真值以平台为主语两种读法都可辩护集成结合说明句串修订与结构形状检查#63743/52然后 46/52第二次关系边 12/12财报19/19六次漏检全是字面值无一条在extraction_dropsrecall.mjs的注释给出了判定口径52 条真值、九成命中率下 1σ ≈ 2.7 条单轮差一两条不是证据scripts/bench/recall.mjs命令行node scripts/bench/recall.mjs --kb id --reprocess在改动解析器时连分块一起重来。独立于得分在重建后的 chunk 上直接观察到的结果没有 chunk 在表内开头而缺表头此前财报 35 块中有 13 块Neal 投票表重新成为一张表内部没有分隔线装 non-GAAP EPS 的 chunk 带着表头——但那是解析器的版式行而非列名这正是下面的开放问题。开放问题预算单独测量。300 与 1000 在同一个基准上各跑一轮每轮约二十分钟才能把结构变化与尺寸变化分开。指向单元格或区域的证据。事实的证据是一个文本跨度对表它应能命名某行某列对图它应是页面上的一个区域。这是从图像抽取的前提也是“文档、证据、事实”的台账纪律扩展到两种新证据形态——不在本记录内。解析器交出的表头。打包器重复的是解析器标记为表头的行。XBRL 财报里那是| | NVIDIA CORPORATION | | … |——因为没有th一个版式行被提升为表头——而真正命名列的行Three Months Ended | Six Months Ended然后是日期是第一个体行留在第一片里。机制是对的输入是错的选表头行是promote_first_row_headers的职责与已有的head_blank规则同属一处不在本 cut。DOCX 与 PDF 的表。DOCX 解析器把表拍平成段落PDF 解析器没有表。两者到达块读取器时都是散文、按散文处理。电子表格与 CSV 产出的是制表符/管道分隔行而非 Markdown 表同样按段落读取。前两者产出真正的 Markdown 表很便宜是 cut 2后两者也是 cut 2。相关记录与延伸阅读决策 0039 是召回基准的测量对象而基准归属决策 0033提示词预算的另一半由 0006 设定。本决策的上游契约“一个 chunk 说明它的话从哪来”出处与锚点在 0040 中chunker.rs的chunk_segments按出处分段、块不跨段、面包屑跨段照传正是 0040 决定 2 的实现测试a_chunk_holds_one_provenance_and_the_breadcrumb_crosses_it。分块的领域概览见 docs/design/sources.md其中确认默认预算 300、cl100k、UTOPIA_CHUNK_TOKENS决策记录约定见 docs/decisions/README.md。关键源码crates/utopia-ingest/src/blocks.rs块读取与续表接回、crates/utopia-ingest/src/chunker.rs打包器与全部规则、crates/utopia-core/src/config.rsUTOPIA_CHUNK_TOKENS旋钮、crates/utopia-store/src/documents.rsreplace_chunks认领机制、migrations/0002_ingest.sqlchunks.heading列。赞分享后端前端人工智能RAG知识图谱知识管理搜索引擎【免费下载链接】utopiaWorlds first open-source enterprise world model.项目地址https://gitcode.com/gh_mirrors/ont/utopia点击查看免费下载相关推荐utopia 本体规模与抽取提示词从 108k token 整体内联到按字符预算的按块检索utopia 本体规模与抽取提示词从 108k token 整体内联到按字符预算的按块检索 本技术指南围绕 utopia 的一条核心工程决策展开当导入的领域后端前端人工智能RAG知识图谱知识管理搜索引擎BDI 心智状态本体核心模式实战Agent-Skills-for-Context-Engineering 中的 Belief-Desire-Intention 本体工程指南BDI 心智状态本体核心模式实战Agent Skills for Context Engineering 中的 Belief Desire Intention后端前端人工智能RAG知识图谱知识管理搜索引擎Feast Data Types for Java从 Protobuf 到 Java 的数据契约模块全解析Feast Data Types for Java从 Protobuf 到 Java 的数据契约模块全解析 导读 java/datatypes 是 FeastMLOps后端数据工程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
