news 2026/5/27 22:07:05

【RAG】【retrievers08】基于Together.ai长上下文嵌入的混合检索

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【RAG】【retrievers08】基于Together.ai长上下文嵌入的混合检索

案例目标

本案例展示如何使用Together.ai的长上下文嵌入模型实现混合检索系统,结合块级别和文档级别的相似度计算,提高RAG系统的检索质量。通过将文档嵌入与块嵌入相结合,利用文档级别的语义信息辅助块级别的检索,从而获得更准确的检索结果。

技术栈与核心依赖

llama-index-embeddings-together

llama-index-llms-openai

llama-index-readers-web

llama-index-readers-file

llama-index-core

BeautifulSoup4

llama-index-vector-stores-chroma

openai

环境配置

# 安装必要的依赖
pip install llama-index-embeddings-together llama-index-llms-openai
pip install llama-index-readers-web llama-index-readers-file
pip install llama-index-core beautifulsoup4
pip install llama-index-vector-stores-chroma openai

# 设置API密钥
import os
os.environ["TOGETHER_API_KEY"] = "your_together_api_key"
os.environ["OPENAI_API_KEY"] = "your_openai_api_key"

案例实现

1. 数据准备

步骤 1

使用BeautifulSoup爬取LlamaIndex文档,获取120个链接的内容:

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin

def get_all_links(url):
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
links = []
for link in soup.find_all('a'):
href = link.get('href')
if href and href.startswith('/') and not href.startswith('//'):
full_url = urljoin(url, href)
links.append(full_url)
return links

步骤 2

使用AsyncHtmlLoader和Html2TextTransformer处理网页内容:

from llama_index.readers.web import AsyncHtmlLoader
from llama_index.core.node_parser import HTML2TextTransformer

loader = AsyncHtmlLoader(urls[:120])
docs = await loader.aload_data()

transformer = HTML2TextTransformer()
transformed_docs = transformer.transform_documents(docs)

2. 混合检索器实现

步骤 3

初始化Together嵌入模型:

from llama_index.embeddings.together import TogetherEmbedding

embed_model = TogetherEmbedding(
model_name="togethercomputer/m2-bert-80M-8k-retrieval",
api_key=os.environ["TOGETHER_API_KEY"]
)

步骤 4

创建自定义混合检索器类:

class HybridRetriever(BaseRetriever):
def __init__(
self,
vector_retriever,
doc_retriever,
alpha=0.5, # 平衡块和文档相似度的权重
):
self.vector_retriever = vector_retriever
self.doc_retriever = doc_retriever
self.alpha = alpha
super().__init__()

def _retrieve(self, query_bundle: QueryBundle):
# 获取块级别的检索结果
vector_nodes = self.vector_retriever.retrieve(query_bundle)

# 获取文档级别的检索结果
doc_nodes = self.doc_retriever.retrieve(query_bundle)

# 创建文档ID到文档节点的映射
doc_id_to_node = {node.node_id: node for node in doc_nodes}

# 计算混合分数
hybrid_nodes = []
for node in vector_nodes:
# 获取节点所属文档的ID
doc_id = node.metadata.get("doc_id")
if doc_id and doc_id in doc_id_to_node:
# 获取文档级别的相似度
doc_node = doc_id_to_node[doc_id]
doc_similarity = doc_node.score

# 计算混合分数
node_score = node.score
hybrid_score = (1 - self.alpha) * node_score + self.alpha * doc_similarity

# 更新节点分数
node.score = hybrid_score

hybrid_nodes.append(node)

# 按混合分数排序
hybrid_nodes.sort(key=lambda x: x.score, reverse=True)

return hybrid_nodes

3. 构建检索系统

步骤 5

创建文档级别的向量存储:

from llama_index.core import Document, VectorStoreIndex, StorageContext
from llama_index.core.node_parser import SentenceSplitter

# 创建文档对象
documents = [Document(text=doc.text, metadata={"doc_id": str(i)}) for i, doc in enumerate(transformed_docs)]

# 创建文档级别的节点解析器(不分割文档)
doc_parser = SentenceSplitter(chunk_size=1000000) # 设置一个很大的值,确保不分割

# 创建文档级别的索引
doc_index = VectorStoreIndex.from_documents(documents, embed_model=embed_model, transformations=[doc_parser])
doc_retriever = doc_index.as_retriever(similarity_top_k=10)

步骤 6

创建块级别的向量存储:

# 创建块级别的节点解析器
chunk_parser = SentenceSplitter(chunk_size=512)

# 创建块级别的索引
chunk_index = VectorStoreIndex.from_documents(documents, embed_model=embed_model, transformations=[chunk_parser])
vector_retriever = chunk_index.as_retriever(similarity_top_k=10)

步骤 7

创建混合检索器:

# 创建混合检索器
hybrid_retriever = HybridRetriever(
vector_retriever=vector_retriever,
doc_retriever=doc_retriever,
alpha=0.5 # 平衡块和文档相似度的权重
)

4. 查询与评估

步骤 8

执行查询并比较结果:

from llama_index.core.query_engine import RetrieverQueryEngine

# 创建查询引擎
query_engine = RetrieverQueryEngine(hybrid_retriever)
base_query_engine = chunk_index.as_query_engine(similarity_top_k=10)

# 执行查询
query_str = "What is the LLM interface in LlamaIndex?"
response = query_engine.query(query_str)
base_response = base_query_engine.query(query_str)

# 打印结果
print("混合检索结果:")
print(str(response))
print("\n基础检索结果:")
print(str(base_response))

案例效果

混合检索系统相比仅使用块级别检索的基线系统,在检索质量和答案相关性方面有明显提升。通过结合文档级别的语义信息,混合检索器能够更好地理解查询意图,并返回更相关的文档块。

混合检索器的优势

  • 更准确的排序:文档级别的相似度信息帮助调整块级别的检索结果排序
  • 上下文感知:考虑整个文档的语义,而不仅仅是单个块的局部信息
  • 减少噪声:过滤掉来自不相关文档的高分块
  • 灵活性:通过alpha参数可以灵活调整块级别和文档级别相似度的权重

案例实现思路

本案例的核心思路是通过结合两种不同粒度的检索策略来提高检索质量:

  1. 双粒度索引:同时构建文档级别和块级别的向量索引,分别捕获整体文档语义和局部文本细节
  2. 相似度融合:通过加权平均的方式融合两种粒度的相似度分数,平衡局部和全局信息
  3. 动态权重调整:通过alpha参数可以灵活调整两种相似度的权重,适应不同场景的需求
  4. 长上下文嵌入:利用Together.ai的长上下文嵌入模型,更好地处理长文档的语义表示

这种混合检索方法特别适用于处理长文档集合,其中单个文档包含多个相关但不连续的主题。通过考虑文档级别的语义,可以避免检索到来自不相关文档的高分块,从而提高整体检索质量。

扩展建议

  • 多级混合检索:扩展到更多粒度级别,如段落级别、句子级别等
  • 动态权重调整:根据查询类型或内容动态调整alpha参数
  • 重排序集成:在混合检索结果基础上应用重排序模型进一步优化结果
  • 查询扩展:结合查询扩展技术提高检索覆盖率
  • 多模态混合:扩展到多模态内容,结合文本、图像等多种信息的检索
  • 自适应检索:根据文档特征自动选择最适合的检索策略组合

总结

基于Together.ai长上下文嵌入的混合检索系统通过结合块级别和文档级别的检索策略,有效提高了RAG系统的检索质量。这种方法特别适用于处理长文档集合,能够同时考虑局部文本细节和整体文档语义,从而返回更相关的检索结果。

混合检索的核心优势在于它能够克服单一检索策略的局限性,通过多粒度信息的融合获得更全面的语义理解。随着长上下文嵌入模型的发展,这种混合检索方法将在处理复杂文档集合和多样化查询需求方面发挥越来越重要的作用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/22 3:46:06

PaddleOCR转RKNN并在RK3588上运行

一、Ubuntu20.04(PC端)1.创建环境conda create -n deploy python3.6 conda activate deploy2.安装环境链接: https://pan.baidu.com/s/18KoIYMkCUS5-PNb3DCRTHA?pwd5ix5 提取码: 5ix5pip install rknn_toolkit2-1.4.2b30bdd72ff-cp36-cp36m-linux_x86_6…

作者头像 李华
网站建设 2026/5/22 3:42:53

AGV的“眼睛”是什么?一篇看懂激光雷达核心作用

在智能工厂、仓储物流场景中,AGV小车(自动导引车)是核心“智能搬运工”,而让其实现自主行走的关键,正是被称为“AGV眼睛”的激光雷达。多数人对它的认知停留在自动驾驶领域,殊不知其在AGV领域应用更成熟广泛…

作者头像 李华
网站建设 2026/5/22 3:42:50

远程办公正在重塑技术人的薪资结构:地域差价的终结者

一、远程办公浪潮下,软件测试薪资的地域壁垒正在松动2026年的软件测试行业,远程办公早已不是疫情时期的权宜之计,而是成为了人才市场的结构性常态。对于遍布全国的测试从业者而言,最直观的感受莫过于薪资版图的悄然重构——曾经像…

作者头像 李华
网站建设 2026/5/22 3:42:51

查并集的理解

查并集 1. 找 int find(int x,int pa[]){if(pa[x] ! x){find(pa[x],pa[])}return pa[x]; }通过递归,溯源到x的父节点。 对于int pa[] {0,1,1,1} 下标序列int idx[] {0,1,2,3} 那么序列2,3的父就是1。如果调用find(3,pa),那么就是从而找到了3的父节点 2…

作者头像 李华
网站建设 2026/5/22 3:42:05

【HTML+CSS+JavaScript】02 CSS样式

1. CSS 介绍 CSS(Cascading Style Sheet),层叠样式表, 用于控制页面的样式。 CSS 能够对网页中元素位置的排版进行像素级精确控制,实现美化页面的效果,能够做到页面的样式和 结构分离。 CSS 是在 HTML 文档结构的基础上进行样式定义的。 …

作者头像 李华
网站建设 2026/5/22 3:39:28

终极指南:5分钟掌握iFakeLocation实现iOS虚拟定位的完整方法

终极指南:5分钟掌握iFakeLocation实现iOS虚拟定位的完整方法 【免费下载链接】iFakeLocation Simulate locations on iOS devices on Windows, Mac and Ubuntu. 项目地址: https://gitcode.com/gh_mirrors/if/iFakeLocation 想在iOS设备上轻松模拟任意位置吗…

作者头像 李华