返回顶部
热门问答 更多热门问答
技术文章 更多技术文章

DeepSearch/DeepResearch中最优文本段选择和URL重排

[复制链接]
链载Ai 显示全部楼层 发表于 昨天 17:31 |阅读模式 打印 上一主题 下一主题


  1. 从长网页提取最优文本段:如何利用迟分(late-chunking)算法,从长网页内容中选取最相关的信息小片段。

  2. 对收集到的URL进行重排:如何利用重排器(Reranker) 让 LLM Agent 在几百个URL中聪明地选择爬取哪一个 URL?

可能有人还记得我们上一篇里的结论:“在 DeepSearch 中,Embeddings 模型仅适用于诸如 STS(语义文本相似度)任务之类的查询去重,而 Reranker 甚至不在我们最初的 DeepSearch 编程实现中。”

现在看来,这两类召回模型还是有其价值的,只是用法和我们常规的认知不太一样。我们做搜索一直遵循“80-20”原则,不会为了照顾情绪价值,或为证明自己作为 Embeddings 和 Reranker 提供商的市场存在感而硬上什么模型。我们非常 80-20,非常务实,务实到我们只关心搜索系统的最最本质的需求。

所以,经过数周的反复试验和迭代,我们发现了 Embeddings 和 Reranker 在 DeepSearch/DeepResearch 系统中的一些非常规但非常有效的应用。

从长文本中选取最优文本段

问题是这样的:用 Jina Reader 读取网页内容后,我们需要把它作为一条知识,放到 Agent 的上下文里,供它推理。虽然把全部内容一股脑塞进 LLM 的上下文是最省事的办法,但考虑到 Token 成本和生成速度,这肯定不是最好的选择。在实际应用里,我们需要找出内容中与问题最相关的部分,只把这些部分作为知识添加到 Agent 的上下文里。

? 这里说的是,即使用 Jina Reader 清理成干净 Markdown 后,内容仍然太长的情况。比如 GitHub Issues、Reddit 帖子、论坛讨论和博客文章等长页面中。

基于 LLM 的筛选方法也有同样的成本和延迟问题,所以我们得找找有没有小模型的解决方案:我们需要更小、更便宜,但仍然支持多种语言的模型。这是个关键因素,因为我们没法保证问题或文档永远都是中文的。

我们一边是问题(原始查询或“信息差”问题),另一边是大量的 Markdown 内容,其中大部分内容都是无关紧要的。我们需要选出与问题最相关的片段。这就很像 RAG 社区自 2023 年以来一直在努力解决的分块问题——使用检索器模型只检索相关块,并放到上下文窗口中进行总结。

不过,我们的情况有两个关键区别:

  1. 有限数量文档中的有限数量的文本块。

假设每个块大约有 500 个 Token,那么一个典型的长网页文档大约有 20万 Token(中位数)到 100 万 Token(99 分位)。我们每一步用 Jina Reader 抓取 4-5 个 URL,这样大概会产生几百个文本块。也就是说,几百个向量和几百个余弦相似度。用 JavaScript 在内存里就能轻松处理,根本不需要向量数据库。

  1. 我们需要连续的文本块来形成有效的知识摘要。

我们不能接受像 [1-2, 6-7, 9, 14, 17, ...] 这样由分散的句子组成的摘要。更有用的知识摘要应该是像 [3-15, 17-24, ...] 这样的,更能保持文本的连贯性。这样 LLM 更容易从知识源中复制和引用,也能减少“幻觉”。

剩下的都是开发者们抱怨的那些注意事项:每个文本块不能太长,因为向量模型处理不了太长的上下文;分块会导致上下文丢失,并使得每个文本块的向量都是独立同分布的;以及,到底怎么找到既保持可读性又保持语义的最佳边界?如果你知道我们在说什么,那你很可能在你的 RAG 实现中也被这些问题困扰过。

不过长话短说——使用 jina-embeddings-v3迟分(Late Chunking)完美地解决了这三个问题。“迟分”保留了每个块的上下文信息,对边界不敏感,而且 jina-embeddings-v3 本身在非对称多语言检索任务中也是最先进的。感兴趣的读者可以关注我们的博客文章或论文了解详情,总体的实现是这样的。

☞长文本 Embedding 模型中的“迟分”策略

? https://arxiv.org/pdf/2409.04701

使用迟分的片段选择的流程图

这张图展示了摘要选择算法,它的工作原理类似于一维卷积(Conv1D)。这个过程首先把一个长文档分割成固定长度的块,然后用开启了迟分的 jina-embeddings-v3 向量化这些文本块。计算完每个块和问题之间的相似度分数后,一个滑动窗口会在这些相似度分数上移动,以找到平均值最高的窗口。

以下是示意代码:用迟分和类似“一维卷积”的平均池化,挑出跟问题最相关的段落。

functioncherryPick(question,longContext,options){
if(longContext.length<options.snippetLength*options.numSnippets)
returnlongContext;

constchunks=splitIntoChunks(longContext,options.chunkSize);

constchunkEmbeddings=getEmbeddings(chunks,"retrieval.passage");
constquestionEmbedding=getEmbeddings([question],"retrieval.query")[0];

constsimilarities=chunkEmbeddings.map(embed=>
cosineSimilarity(questionEmbedding,embed));

constchunksPerSnippet=Math.ceil(options.snippetLength/options.chunkSize);
constsnippets=[];
constsimilaritiesCopy=[...similarities];

for(leti=0;i<options.numSnippets;i++){
letbestStartIndex=0;
letbestScore=-Infinity;

for(letj=0;j<=similarities.length-chunksPerSnippet;j++){
constwindowScores=similaritiesCopy.slice(j,j+chunksPerSnippet);
constwindowScore=average(windowScores);

if(windowScore>bestScore){
bestScore=windowScore;
bestStartIndex=j;
}
}

conststartIndex=bestStartIndex*options.chunkSize;
constendIndex=Math.min(startIndex+options.snippetLength,longContext.length);
snippets.push(longContext.substring(startIndex,endIndex));

for(letk=bestStartIndex;k<bestStartIndex+chunksPerSnippet;k++)
similaritiesCopy[k]=-Infinity;
}

returnsnippets.join("\n\n");
}

调用 Jina Embeddings API 的时候,记得把 task 设置成 retrieval,打开 late_chunkingtruncate 也要像下面这样设置:

awaitaxios.post(
'https://api.jina.ai/v1/embeddings',
{
model:"jina-embeddings-v3",
task:"retrieval.passage",
late_chunking:true,
input:chunks,
truncate:true
},
{headers});

如果是要向量化问题,记得把 task 换成 retrieval.query,然后关掉 late_chunking

完整的实现代码可以在 GitHub 上找到:https://github.com/jina-ai/node-DeepResearch/blob/main/src/tools/jina-latechunk.ts

为“下一步阅读”进行 URL 排序

问题如下:在每一次 DeepSearch 漫长过程中,你可能会从搜索引擎结果页(SERP)里收集一堆 URL,每打开一个网页,又能顺藤摸瓜找出不少新链接,就算是去重后,也是轻轻松松几百个网址。同样的,一股脑儿全塞给 LLM 肯定不行,浪费宝贵的上下文长度不说,更要命的是,我们发现 LLM 基本上就是瞎选。所以,得想办法引导 LLM 去挑出那些最有可能包含答案的 URL。

curlhttps://r.jina.ai/https://example.com\
-H"Accept:application/json"\
-H"Content-Type:application/json"\
-H"X-Retain-Images:none"\
-H"X-Md-Link-Style:discarded"\
-H"X-Timeout:20"\
-H"X-With-Links-Summary:all"

这行命令,是在 DeepSearch 里让 Jina Reader 抓取网页的最佳配置。它会把页面上所有链接都单拎出来,放到 links 字段里,同时从 content 字段里把它们删干净。

你可以把这个问题看作“上下文内的 PageRank”,只不过,我们是在一次会话中对数百个 URL 打分。

我们会综合考虑多个因素:最后更新时间、域名出现的频率、网页路径结构,以及最重要的与问题的语义相关性,算出一个综合评分。不过,我们只能使用那些还没点开 URL 就能拿到的信息。

1. 频率信号:如果某个 URL 在不同的信息源中多次出现,它的权重就会更高。另外,如果某个域名在搜索结果中经常出现,来自这个域名的 URL 也会被加分。因为一般来说,热门域名往往包含更权威的内容。

2. 路径结构:我们会分析 URL 的路径结构,来判断哪些内容是聚集在一起的。如果多个网址都属于同一个路径层级,它们的分数会更高;但路径越深,分数加成会逐渐减少。

3. 语义相关性:我们用 jina-reranker-v2-base-multilingual 来评估问题和每个 URL 的文本信息(例如标题和摘要)的语义相关性,这是一个典型的重排序问题。每个 URL 的文本信息来自以下几个地方:

  • 搜索引擎结果页(SERP)API 返回的标题和摘要(https://s.jina.ai/ 这个接口,加上 'X-Respond-With': 'no-content',就可以只返回标题和摘要,不返回具体内容)。

  • 页面上 URL 的锚文本(用 https://r.jina.ai 接口,设置 'X-With-Links-Summary': 'all',可以返回页面内所有链接的摘要信息,也就是锚文本)。

4. 最后更新时间:DeepSearch 的有些查询对时效性要求很高,所以一般来说,越新的 URL 价值越高。但是在不具备像 Google 这样的大规模索引能力的前提下,很难准确判断网页的最后更新时间。我们这里用的是一套组合拳,综合考虑以下信号,最终给出一个带有置信度评分的时间戳,以便在需要时优先展示最新的内容:

  • SERP API 提供的筛选功能(比如 s.jina.ai 的 tbs 参数,可以按时间过滤)。

  • HTTP Header 信息分析(比如 Last-Modified 和 ETag 字段)。

  • 元数据提取(比如 meta 标签和 Schema.org 时间戳)。

  • 内容模式识别(识别 HTML 里可见的日期)。

  • 针对特定 CMS 平台的指标 (比如 WordPress, Drupal, Ghost 这些平台)

5. 受限内容:某些社交媒体平台的内容是受限的,或者需要付费才能访问。不登录的话,没办法合法地获取这些内容。因此,我们会积极维护一份黑名单,把这些有问题的 URL 和域名都记录下来,降低它们的排名,避免在这些无法访问的内容上浪费计算资源。

6. 域名多样性:有时候,权重最高的几个网址都来自同一个域名,这会让 DeepSearch 陷入“局部最优”,影响最终结果的质量。就像前面提到的,排名靠前的 URL 全都来自 StackOverflow。为了提高结果的多样性,我们可以用一种“探索-利用”的策略:从每个域名下选择排名 Top K 的 URL。

URL 排序的完整代码实现,可以在我们的 Github 上找到:https://github.com/jina-ai/node-DeepResearch/blob/main/src/utils/url-tools.ts#L192

<action-visit>
-CrawlandreadfullcontentfromURLs,youcangetthefulltext,lastupdateddatetimeetcofanyURL.
-MustcheckURLsmentionedin<question>ifany
-ChooseandvisitrelevantURLsbelowformoreknowledge.higherweightsuggestsmorerelevant:
<url-list>
+weight:0.20"https://huggingface.co/docs/datasets/en/loading":"Load-HuggingFaceThissavestimebecauseinsteadofwaitingfortheDatasetbuilderdownloadtotimeout,Datasetswilllookdirectlyinthecache.Settheenvironment...SomedatasetsmayhavemorethanoneversionbasedonGittags,branches,orcommits.Usetherevisionparametertospecifythedatasetversionyouwanttoload..."
+weight:0.20"https://huggingface.co/docs/datasets/en/index":"Datasets-HuggingFace?DatasetsisalibraryforeasilyaccessingandsharingdatasetsforAudio,ComputerVision,andNaturalLanguageProcessing(NLP)tasks.Loadadatasetina..."
+weight:0.17"https://github.com/huggingface/datasets/issues/7175":"[FSTimeoutError]load_dataset·Issue#7175·huggingface/datasetsWhenusingload_datasettoloadHuggingFaceM4/VQAv2,IamgettingFSTimeoutError.ErrorTimeoutError:Theaboveexceptionwasthedirectcauseofthefollowing..."
+weight:0.15"https://github.com/huggingface/datasets/issues/6465":"`load_dataset`usesout-of-datecacheinsteadofre-downloadinga...Whenadatasetisupdatedonthehub,usingload_datasetwillloadthelocallycacheddatasetinsteadofre-downloadingtheupdateddataset."
+weight:0.12"https://stackoverflow.com/questions/76923802/hugging-face-http-request-on-data-from-parquet-format-when-the-only-way-to-get-i":"HuggingfaceHTTPrequestondatafromparquetformatwhenthe...I'vehadtogetthedatafromtheirdataviewerusingtheparquetoption.ButwhenItrytorunit,thereissomesortofHTTPerror.I'vetrieddownloading..."
</url-list>
</action-visit>

总结

自 2025 年 2 月 2 日我们的 DeepSearch 开源以来,我们发现了两个能大幅提高质量的工程细节。有意思的是,这两个细节都以一种“上下文窗口内”的方式利用了多语言 Embedding 和 Reranker 模型。跟这些模型通常需要的大规模预计算索引相比,简直是小巫见大巫。

这可能预示着,未来的搜索技术会朝着两极分化的方向发展。我们可以借用卡尼曼(Kahneman)的双过程理论来理解这个趋势:

  • 快思考Fast-think (grep、BM25、SQL):快速、基于规则的模式匹配,计算量很小。

  • 慢思考Slow-think (LLM):全面推理,具有深层次的上下文理解能力,但计算量很大。

  • 中间地Mid-think (Embedding,Reranker 等召回模型): 具备一定的语义理解能力,优于简单的模式匹配,但推理能力远不及 LLM。

有一种可能就是:两级分化的搜索架构变得越来越流行:轻量级、高效的 SQL/BM25 负责检索的输入,然后直接把结果喂给 LLM 进行检索输出。那么,中间层模型的剩余价值就转移到了特定的上下文窗口内的任务上:比如过滤、去重、排序等等。在这些场景下,如果用 LLM 做完整推理反而效率不高。

但无论如何,挑选关键片段URL 排序 仍然是仍然是直接影响 DeepSearch/DeepResearch 系统质量的根本环节。希望我们的发现能帮助你改进自己的系统。

查询扩展(Query expansion)是另一个决定质量的关键因素。我们正在积极评估各种方法,从简单的基于 Prompt 的重写,到小模型,再到基于推理的方法。请期待我们后续在这个方向上的研究成果!

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

链载AI是专业的生成式人工智能教程平台。提供Stable Diffusion、Midjourney AI绘画教程,Suno AI音乐生成指南,以及Runway、Pika等AI视频制作与动画生成实战案例。从提示词编写到参数调整,手把手助您从入门到精通。
  • 官方手机版

  • 微信公众号

  • 商务合作

  • Powered by Discuz! X3.5 | Copyright © 2025-2025. | 链载Ai
  • 桂ICP备2024021734号 | 营业执照 | |广西笔趣文化传媒有限公司|| QQ