Aioga
AI资讯 / 技巧观点
返回 AI资讯

LangChain SmithDB 全文搜索:为对象存储设计倒排索引,Agent 追踪中位延迟 400ms

LangChain:Blog(RSS)Aioga 编辑团队2026-07-27T04:06:56.000Z热度 31

LangChain 的 SmithDB 支持对 Agent 追踪数据进行全文搜索和 JSON 过滤,即使底层数据是存储在对象存储中的大型深层嵌套 JSON 文档,其中位(P50...

技巧观点LangChain:Blog(RSS)

今日 AI 情报摘要

LangChain 的 SmithDB 支持对 Agent 追踪数据进行全文搜索和 JSON 过滤,即使底层数据是存储在对象存储中的大型深层嵌套 JSON 文档,其中位(P50)延迟仍可达到 400ms。

该功能通过为对象存储设计的倒排索引实现。

中文正文 · AI 翻译

SmithDB 支持对代理追踪执行全文搜索和 JSON 过滤,P50(中位数)延迟为 400 毫秒,即便底层数据由存储在对象存储中的大型、深层嵌套 JSON 文档组成。

全文搜索是成熟的技术领域。Lucene 已有二十年的历史;Tantivy:https://github.com/quickwit-oss/tantivy 和 Quickwit:https://quickwit.io/blog/quickwit-101 已经将搜索和索引移到了对象存储上。然而,在将文本搜索集成到 SmithDB 时,我们决定从基本原理出发处理问题,因为为搜索工作负载索引代理追踪具有独特挑战。

每个 LangSmith 事件将字段 inputs 和 outputs 编码为其总字节的绝大多数。输入和输出的 payload 大小超过 1 MB 很常见,其中一些未压缩的数据可达数百兆字节。这些内容列在数量级上远超身份、时间戳及其他元数据列。

此外,如原 SmithDB 博客文章所述:https://www.langchain.com/blog/introducing-smithdb#agents-present-a-new-data-problem,与代理追踪相关的 payload 随时间持续增大。这是 LLM 上下文窗口变大以及代理运行时间延长的直接结果,导致 LLM 积累了更多上下文。

这些特性颠倒了传统搜索索引的经济学。传统日志引擎索引数十亿个小文档,因此索引相对于每个文档而言很小。我们索引数十亿个庞大文档,其中一个文档可能生成的索引数据比许多小日志行还多。通常:https://aws.amazon.com/blogs/big-data/amazon-opensearch-service-101-how-many-shards-do-i-need/ 日志的源数据:索引比约为 1:1.25。然而对于 LangSmith 中的代理追踪,我们观察到平均比率更接近 1:1.9。由此得出三点结论:

倒排索引阻止了内容查询执行全量 payload 扫描,并且它必须承载重负载、偏斜的半结构化 payload。

SmithDB 将所有持久数据保存在对象存储中,因此计算相对无状态,系统通过增加节点进行扩展,而无需管理本地磁盘。

查询的成本大致与(对对象存储发出的请求次数)×(每个请求读取的字节数)成正比。在对象存储上:

SmithDB 的倒排索引的每一个方面,从存储布局到查询执行,都是在考虑这些限制的情况下设计的。

在深入了解倒排索引的存储布局之前,让我们先回顾索引需要处理的主要查询模式。SmithDB 的查询范围归结为三类谓词,它们在匹配对象和允许的模式语法上有所不同。

每一节后文都会引用此表:当我们说“仅路径查询”时,我们指 json_key,“键值查询”指 json_key_search,而“全文搜索”指 search。

倒排索引是驱动每个搜索库的数据结构,从 Lucene:https://lucene.apache.org/ 到 Tantivy:https://github.com/quickwit-oss/tantivy。它就像教科书后面的索引:查找一个术语然后直接跳到提到它的页面,而不必阅读每一页。SmithDB 基于这个理念,并为其在对象存储中存储的大型 agent-trace 数据专门优化了存储布局。

倒排索引结构基于三个概念:

拿五条按文本建立索引的 trace 举例:

索引为每个术语保留一个条目,指向包含该术语的文档:

每个术语对应一个字典条目:查找该值,读取它的 posting list,你就能准确知道要获取哪些文档。像 search("deep agents") 这样的查询会取 deep ([1, 2, 3, 4]) 和 agents ([0, 1, 2, 3]) 的 posting list 的交集得到 [1, 2, 3],无需扫描数据内容。

positions 列记录每个文档中该术语出现的 token 偏移,例如 1:[0] 表示文档 1 的位置 0。这就是短语搜索成为可能的原因:search("langsmith engine") 能匹配文档 1,因为 langsmith 在偏移 0 处而 engine 在偏移 1(0 + 1 == 1),但不能匹配文档 4,因为 powers 和 the 居中之间(langsmith 在 1,engine 在 4)。

Tantivy:https://github.com/quickwit-oss/tantivy 是一个出色的搜索索引库,也是 Rust 中 Lucene 风格搜索的显而易见的参考点。我们一开始问自己是否可以直接采用它。我们最终设计的方案深受 Tantivy 的启发,但一些限制使它直接用于我们的用例变得不太合适:

Vortex:https://vortex.dev/ 是 SmithDB 用于对象存储的可扩展列式文件格式。与 Parquet 等固定格式不同,Vortex 允许可插拔的编码和自定义文件布局,这使我们能够根据工作负载调整压缩和 I/O 访问模式,而无需分叉文件格式。

每次读取都会使用统计信息裁剪整个行组,将生存的行过滤为一个掩码,并只投影查询实际需要的列。

Vortex:https://docs.vortex.dev/developer-guide/internals/io 文件中的 I/O 单位是一个段:一个连续的物理字节范围。在对象存储上往返大约需要 100 毫秒,因此查询延迟的主要杠杆是最小化请求次数。Vortex 的 I/O 调度程序会将相邻的段读取合并为一个请求,将 1 MB 间隙内的读取合并成一个请求,最多可达 16 MB 的窗口,因此索引中的顺序访问模式对应非常少的对象存储 GET 操作。

第一个版本几乎是教科书倒排索引的直译。两个列(term_key 用于路径,term_value 用于令牌)使得一个布局可以服务于三种查询形式:路径存在读取 term_key,键控搜索在两列之间交叉 postings,全文搜索只在 term_value 上交叉。Postings 存储为 List cells,位置存储为 List >。

我们依赖 Vortex 的默认设置:term 列使用 FSST 编码,postings 和 positions 使用 bitpacked 编码,以及允许查询时裁剪的分区存储布局。仅位置(用于短语搜索)就比其他每一列大一个数量级,因此我们将索引保存在与核心运行数据分开的文件中。这让我们能够将索引构建和合并与核心写路径解耦。Vortex 的 API 基于行索引和掩码,因此将索引过滤委托给兄弟文件是一种自然的组合方式。

我们的v2布局通过将组织单元从“每行组N个术语”改为基于字节预算的行组,并通过管理每列的字节布局而不是直接依赖Vortex默认值,解决了所有v1问题。本节的其余部分将讲解新的组织单元、其内部内容以及获得字节预算的编码选择。

由于行组是修剪和I/O的单位,我们使用固定的独立字节预算而不是固定行数来确定行组大小。

按字节而不是按术语计数进行大小调整,这解决了v1的第三个问题。术语偏斜使得术语计数成为I/O大小的糟糕代理,因为v1行组中的一个高频术语可能会将其压缩后推到甚至超过500MB。字节预算为每个行组提供了从对象存储获取字节或执行查询时的内存占用的上限。

通过术语列上的分区存储布局,每行组的最小/最大/计数信息允许查询计划器在访问FST之前跳过整个行组。对于针对特定前缀的路径查询,这是最大节省:大多数行组在谓词范围内根本没有内容。

每个行组包含四列(其中三列用于term_key,跳过位置列):

一次查找包括一次字典遍历、一次偏移表读取和一次字节范围获取。FST将术语解析为序数。序数索引到term_info,term_info给出postings的偏移量,以及(对于短语查询)positions的偏移量。查询直接读取这些字节范围。无需载荷扫描,无需嵌套列表解码,并且由于每列都是自有的分块布局,非短语查询只获取term + term_info + postings,从不打开positions列。

我们在术语字典中使用FST。我们在一个具有2.79M术语出现的代表性行组上,将FST与明显的替代方案(Vortex默认的FSST字符串编码、前缀共享的keep_add和普通zstd)进行比较。优势的大小取决于基数:

在 term_key 上,当几百个 JSON 路径在数百万行中重复时,FST 将整个字典压缩到 3.8 KiB:比原始字节小四个数量级,比 zstd 小约 4 倍。在高基数的 term_value 列上,FST 大约比 zstd 大 1.5 倍,但仍然优于 FSST。关键点在于 zstd 是不透明的:每次查找都需要解压块。而 FST 本身就是索引——精确查找、前缀和范围扫描,以及自动机遍历(LIKE、模糊、正则)都直接在压缩字节上运行,成本为 O(|term|),无需哈希。

我们还将键控搜索和全文查询形态折叠到每个行组的单个 FST 中,通过将 term_value 条目存储为 {token}\0{flattened_path}。键控搜索变为精确的 FST 查找;全文搜索变为 token\0 的前缀扫描,遍历该 token 出现的每条路径。

我们对每个 term 使用块位打包增量。索引和位置都使用相同的 Tantivy/Lucene 风格的两级编码。编码的形状使每个 term 的控制成为可能,也使合并变得廉价。

每个 term 列表分成固定的 128 元素块,加上一个剩余元素的尾块:

在一个块内,我们存储连续文档 ID 之间的增量,而不是 ID 本身,并将块按最小宽度位打包以适应其最大增量。一条密集、规则的 ID 序列每个 ID 只需几位。尾部的部分块(对于高频 term 定义上较少,对于低频 term 则是整个 posting 列表)回退到 VInt,每个小增量约 1 字节,在长尾条件下渐进降级。

它产生了两个 v1 列表编码所没有的属性:

Tantivy 也利用 FST,但为每个段构建一个 FST 并进行分片分区。我们为每个行组构建一个 FST。行组大小的 FST 足够小,写入器可以流式处理,而无需在内存中持有段级 FST,且区域级修剪在查询时进行任何 FST 工作之前就会跳过大多数行组。权衡在于一次查找可能会触及每个文件的多个 FST,但修剪在实践中使这种成本很少;存活的 FST 足够小,使得遍历成本低。

在第二部分中,我们将探讨如何实现倒排索引的构建与合并,以及如何在读取路径中利用该索引。在这里阅读第二部分:https://www.langchain.com/blog/full-text-search-in-smithdb-constructing-and-querying-our-inverted-index-pt-2

我们正在构建 SmithDB,以解决与代理可观测性相关的系统问题。如果这种基础设施工作听起来有趣,我们正在招聘:https://www.langchain.com/careers#explore-jobs。

LangSmith,我们的代理工程平台,帮助开发者调试每一个代理决策、评估更改,并一键部署。

情报判断

Aioga 编辑摘要

Aioga 编辑摘要:LangChain 的 SmithDB 支持对 Agent 追踪数据进行全文搜索和 JSON 过滤,即使底层数据是存储在对象存储中的大型深层嵌套 JSON 文档,其中位(P50)延迟仍可达到 400ms。 Aioga 将其归入「技巧观点」方向,重点关注它对真实使用和行业竞争的影响。

背景分析

背景分析:产品与工具类动态的价值取决于它是否解决明确场景、能否进入工作流,以及交付、价格和数据安全是否可接受。

Aioga 观点

Aioga 判断:这条动态更适合作为行业观察信号,当前信息足以建立线索,但不足以推导长期结论。

影响与后续

影响分析:对相关团队而言,短期应先核对来源、可用范围和实际成本,再判断是否值得接入或跟进。 后续观察:继续观察产品是否开放使用、用户反馈、定价、集成能力和后续版本更新。

来源与版权说明

本页正文由公开来源页面提取并按原有信息整理,同时保留来源、发布时间和原文入口。版权归原作者及来源网站所有,请通过原文链接核验和阅读来源版本。

抓取通道: RSS · 原始域名: langchain.com

来源: LangChain:Blog(RSS)

原文链接: 打开原始来源

Aioga 归档: 查看情报页

Content record: source-page · Updated: 2026-07-27T04:06:56.000Z

API 中转站
API RELAY · DEVELOPER INFRASTRUCTURE

API 中转站

统一接入主流 AI 模型 API,为开发、测试与生产环境提供稳定调用入口。

立即访问 api.w173.com
AIOGA SHARE POSTER

分享这篇 AI 情报

LangChain 的 SmithDB 支持对 Agent 追踪数据进行全文搜索和 JSON 过滤,即使底层数据是存储在对象存储中的大型深层嵌套 JSON 文档,其中位(P50...

LangChain:Blog(RSS)2026-07-27T04:06:56.000Z
扫码打开文章详情扫码直达文章详情

Aioga 自动聚合全球 AI 动态,并保留来源信息用于核验与引用。