# RAG 分块策略：块大小、重叠、上下文检索与混合搜索

> 分块决定了 RAG 系统能找到什么。先用递归切分器，块大小取几百个 token 并留一些重叠，文档有标题就按标题切，每个块都保留来源元数据。之后一步一步提高检索质量：给每个块补上下文，加入关键词搜索，再做重排序，并且只保留在你自己的问题上有效的步骤。

Mindket 编辑部 · 发布于 2026-11-04 · 更新于 2026-11-05 · https://mindket.com/cn/learn/rag/rag-chunking

## 要点

- 选好块大小和重叠，并清楚每个设置要换掉什么。
- 按标题切分 Markdown，把标题保存为元数据，并处理中文文本。
- 用 Anthropic 的上下文检索提示词给分块补上下文。
- 用倒数排名融合合并向量和关键词的结果，再对最好的候选重排序。

## 开始之前

本课接着第 1 课往下讲，那里的切分器用的是固定大小，还会用到第 2 课里的 `chunks` 表。你需要 Python 3，并执行 `pip install -qU langchain-text-splitters`。

补上下文这一步要用你的密钥调用 Claude API，重排序用第 1 课里的 Voyage AI 密钥，混合查询则运行在装了 pgvector 的 Postgres 上。

## 分块决定了什么

块是系统做嵌入、做检索、再交给模型的基本单位。切得太大，一个向量就要代表好几个主题。切得太小，块里就缺了说明它讲什么的词。[LlamaIndex](https://developers.llamaindex.ai/python/framework/optimizing/basic_strategies/basic_strategies/) 直接说明了这个取舍：块越小，嵌入越精确；块越大，嵌入越概括，可能漏掉细节。Anthropic 的文章把块描述为通常不超过几百个 token。

改块大小还有第二个影响。LlamaIndex 建议缩小块的时候同时调高 `similarity_top_k`，它的示例把块大小减半后，把这个值从 2 加倍到 4。

> **我们对第一个设置的看法**
>
> 我们会从下表里 OpenAI 文件搜索的默认值开始，再各试一个更小和更大的尺寸，用第 4 课的指标在你自己的问题上比较检索效果。这些文档都没有给出一个在所有语料上都最好的尺寸。

| 来源 | 块大小 | 重叠 | 计量单位 |
| --- | --- | --- | --- |
| LangChain 教程，RecursiveCharacterTextSplitter | 1000 | 200 | 字符 |
| LlamaIndex 默认值 | 1024 | 20 | 页面未说明 |
| OpenAI 文件搜索默认值 | 800 | 400 | token |

## 先按结构切，再按大小切

[LangChain](https://docs.langchain.com/oss/python/integrations/splitters) 说，大多数情况先用 `RecursiveCharacterTextSplitter`。它按顺序尝试一组分隔符，默认是 `["\n\n", "\n", " ", ""]`，所以会尽量让段落完整，其次是句子，最后才是单词。

自带结构的文档可以做得更好。Markdown 文件是按标题组织的，`MarkdownHeaderTextSplitter` 会按你指定的标题切分，并把标题文字写进每个块的元数据。LangChain 还列出了 HTML、JSON 和代码的切分器，[LlamaIndex](https://developers.llamaindex.ai/python/framework/module_guides/loading/node_parsers/modules/) 对这些格式也有对应的节点解析器。

````python
from langchain_text_splitters import MarkdownHeaderTextSplitter, RecursiveCharacterTextSplitter

with open("refund-policy.md", encoding="utf-8") as f:
    markdown_document = f.read()

# 1. Split on headings. The heading text lands in each section's metadata.
headers_to_split_on = [
    ("#", "Header 1"),
    ("##", "Header 2"),
    ("###", "Header 3"),
]
markdown_splitter = MarkdownHeaderTextSplitter(headers_to_split_on, strip_headers=False)
sections = markdown_splitter.split_text(markdown_document)

# 2. Cut the sections that are still too long. split_documents keeps the metadata.
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
chunks = text_splitter.split_documents(sections)

for chunk in chunks:
    print(chunk.metadata, chunk.page_content[:60])
````

- 对切出来的各个部分调用 `split_documents`，不要用 `split_text`，这样每个块才会保留标题元数据。
- 只有单个部分超过 `chunk_size` 时才会出现重叠，而且重叠不会跨越两个部分的边界。
- `strip_headers` 默认开启，所以标题行会从块文本里去掉，只留在元数据里。如果某个标题单独成了一个很小的块，就把它重新打开。
- 默认的切分器会去掉空白和换行。需要保留原始格式时，LangChain 推荐用 `ExperimentalMarkdownSyntaxTextSplitter`。
- 在 `separators` 末尾保留空字符串 `""`，这样没有换行和空格的文本也能被切开。

## 中文、日文和泰文

这些文字没有词的边界。LangChain 提醒说，用默认分隔符时，一个词可能被切到两个块里。它的办法是在列表里补上这些文字的标点：句号、逗号和零宽空格。

块大小仍然按字符计量，因为递归切分器是按字符数来衡量块大小的。

````python
from langchain_text_splitters import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(
    separators=[
        "\n\n",
        "\n",
        " ",
        ".",
        ",",
        "​",  # Zero-width space
        "，",  # Fullwidth comma
        "、",  # Ideographic comma
        "．",  # Fullwidth full stop
        "。",  # Ideographic full stop
        "",
    ],
    chunk_size=1000,
    chunk_overlap=200,
)
````

## 每个块都要保留元数据

在 LangChain 里，`Document` 包含文本和一个 `metadata` 字典，里面可以记录它的来源，以及它与其他文档的关系。设置 `add_start_index=True`，会再加上每个块开头的字符偏移量。这些元数据之后会派上真正的用场：

- 引用。第 1 课把每个块的 `source` 和 `title` 交给 Claude 的 `search_result` 块，答案就能指回对应的段落。
- 过滤。LlamaIndex 指出，元数据可以在 top-k 相似度搜索之前先过滤数据。OpenAI 文件搜索用 `attributes` 做同样的事，最多 16 个键，每个 256 个字符。
- 隔离。LlamaIndex 的多租户说明里写道，元数据过滤能让每个用户只搜索自己索引的文档。在 pgvector 的近似索引上，过滤发生在扫描之后，第 2 课讲过这一点。

## 给每个块补上下文

Anthropic 的[上下文检索文章](https://www.anthropic.com/research/contextual-retrieval)从这样一个块说起：“The company's revenue grew by 3% over the previous quarter.”（公司收入比上一季度增长了 3%。）单看这句话，既没有公司名也没有时间，所以检索没法把它和“ACME 公司 2023 年第二季度”的问题对上。办法是在嵌入之前，给每个块前面加一段简短说明，文章称之为上下文嵌入（Contextual Embeddings），在建立 BM25 索引之前也同样处理，称之为上下文 BM25（Contextual BM25）。

说明由模型来写。Anthropic 的提示词把整篇文档和这个块交给模型，要求它给出一段简短的上下文，把这个块放回整篇文档里，便于搜索。结果通常是 50 到 100 个 token。文章用的是 Claude 3 Haiku，并配合提示词缓存，这样文档只需加载进缓存一次，不必每个块都加载一遍。

````python
import anthropic

claude = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY

CONTEXT_PROMPT = """<document>
{whole_document}
</document>
Here is the chunk we want to situate within the whole document
<chunk>
{chunk_content}
</chunk>
Please give a short succinct context to situate this chunk within the overall document for the purposes of improving search retrieval of the chunk. Answer only with the succinct context and nothing else."""


def contextualize(whole_document: str, chunk_content: str) -> str:
    response = claude.messages.create(
        model="claude-haiku-5-5",
        max_tokens=200,
        messages=[
            {
                "role": "user",
                "content": CONTEXT_PROMPT.format(
                    whole_document=whole_document, chunk_content=chunk_content
                ),
            }
        ],
    )
    return next(block.text for block in response.content if block.type == "text")


for chunk in chunks:
    context = contextualize(document_text, chunk.page_content)  # document_text: the full text this chunk came from
    chunk.metadata["context"] = context
    text_to_index = f"{context}\n\n{chunk.page_content}"  # embed this, and build the BM25 index from it
````

1. 像之前一样把文档切成块。
2. 对每个块，把整篇文档和这个块连同上面的提示词一起发给模型。
3. 把返回的上下文存在块旁边，并加到块文本前面。
4. 嵌入补过上下文的文本，并用同样的文本建立 BM25 索引。
5. 生成答案时，把补过上下文的块交给模型，并标明哪部分是上下文、哪部分是块本身。文章说这样可以改善回答。

## 上下文带来什么，以及要检查什么

Anthropic 用 1 减去 recall@20 来衡量检索失败，也就是相关文档没有出现在前二十个块里的比例。图中是它在代码库、小说、ArXiv 论文和科学论文上的平均值，嵌入用的是 Gemini Text 004。加了重排序的那一组用的是 Cohere 重排序模型。

同样的实验里，另外两种做法收效不大。给块加通用的文档摘要，提升非常有限；假设文档嵌入和基于摘要的索引，表现则很差。

- 块的边界仍然重要。块大小、边界和重叠都会影响检索。
- 嵌入模型很重要。测试的每个模型都有提升，Anthropic 发现 Gemini 和 Voyage 的嵌入特别有效。
- 针对你的领域写的提示词可能效果更好，比如附上一份只在其他文档里定义过的术语表。
- Voyage AI 提供了一条捷径：`voyage-context-4` 返回的块向量能捕捉完整的文档上下文，不需要手动补充。[Voyage 的页面](https://www.mongodb.com/docs/voyageai/models/contextualized-chunk-embeddings)称它检索准确率更高，对分块策略也更不敏感。Anthropic 的文章没有测试过它。
- 一定要跑评估。第 4 课会讲怎么做。

**前 20 个块里的检索失败率** 越低越好。Anthropic 把失败率定义为 1 减去 recall@20。

- 仅用嵌入: 5.7%
- 上下文嵌入: 3.7%
- 上下文嵌入加 BM25: 2.9%
- 再加重排序: **1.9%**

来源：[Anthropic: Contextual Retrieval](https://www.anthropic.com/research/contextual-retrieval) (2026-11-04 查阅)

## 用排名融合做混合搜索

嵌入抓的是含义，可能漏掉精确的字符串。文章举的例子，是在技术支持库里查“Error code TS-999”。嵌入模型也许会找出讲错误码的一般性内容，却漏掉那条精确匹配，而 BM25 找的正是这个字符串。BM25 是建立在 TF-IDF 之上的词汇排序函数，它加入了文档长度，并对词频做饱和处理，不让常见词占据主导。

Anthropic 的做法是分别用两种方法取出靠前的块，再用排名融合合并并去重。倒数排名融合（Reciprocal Rank Fusion）给每个块的得分，是它在各个列表里 1 / (k + 排名) 之和。下面 pgvector-python 的示例取 k = 60，一个列表来自向量搜索，另一个来自 Postgres 全文搜索，[pgvector README](https://github.com/pgvector/pgvector) 把这种组合称为混合搜索。

和文章有一点不同：Postgres 用 `ts_rank_cd` 排序，它和 BM25 是不同的函数，示例用的也是 `english` 文本搜索配置。信任关键词这一半之前，先确认你的语言是怎么分词的。另一条路是用自带混合搜索的向量数据库，[LlamaIndex](https://developers.llamaindex.ai/python/framework/optimizing/basic_strategies/basic_strategies/) 也列出了这一条，OpenAI 文件搜索则通过 `ranking_options.hybrid_search` 提供 `embedding_weight` 和 `text_weight`，来调整同样的融合。

````sql
-- the index that serves the keyword half
CREATE INDEX ON chunks USING GIN (to_tsvector('english', content));

-- %(embedding)s is the query vector, %(query)s the question text and %(k)s the constant (60 in the example)
WITH semantic_search AS (
    SELECT id, RANK () OVER (ORDER BY embedding <=> %(embedding)s) AS rank
    FROM chunks
    ORDER BY embedding <=> %(embedding)s
    LIMIT 20
),
keyword_search AS (
    SELECT id, RANK () OVER (ORDER BY ts_rank_cd(to_tsvector('english', content), query) DESC) AS rank
    FROM chunks, plainto_tsquery('english', %(query)s) query
    WHERE to_tsvector('english', content) @@ query
    ORDER BY ts_rank_cd(to_tsvector('english', content), query) DESC
    LIMIT 20
)
SELECT
    COALESCE(semantic_search.id, keyword_search.id) AS id,
    COALESCE(1.0 / (%(k)s + semantic_search.rank), 0.0) +
    COALESCE(1.0 / (%(k)s + keyword_search.rank), 0.0) AS score
FROM semantic_search
FULL OUTER JOIN keyword_search ON semantic_search.id = keyword_search.id
ORDER BY score DESC
LIMIT 5
````

**向量、关键词，还是两者结合**

| | 嵌入 | BM25 | 两者融合 (我们的选择) |
| --- | --- | --- | --- |
| 能找到问题的同义表述 | ✓ 是 | ◐ 部分 | ✓ 是 |
| 能找到精确的标识符，比如 TS-999 | ◐ 部分 | ✓ 是 | ✓ 是 |
| 只需要一种索引 | ✓ 是 | ✓ 是 | ✗ 否 |

**我们的选择：两者融合。** Anthropic 的实验发现，嵌入加 BM25 比单用嵌入更好，代价是多一个索引和一个融合步骤。

来源：[Anthropic: Contextual Retrieval](https://www.anthropic.com/research/contextual-retrieval) (2026-11-04 查阅)；[LlamaIndex: Basic strategies](https://developers.llamaindex.ai/python/framework/optimizing/basic_strategies/basic_strategies/) (2026-11-04 查阅)

## 给候选重新排序

混合搜索返回的块，质量仍然参差不齐。重排序器会重新给它们打分。Voyage AI 把自己的重排序器描述为交叉编码器：嵌入模型是把查询和每份文档分开编码，重排序器则把一对查询和文档放在一起处理，所以能更准确地预测相关度。你把它用在嵌入搜索或 BM25 这类词汇搜索得到的靠前候选上。

Anthropic 的流程是：从第一阶段取前 150 个块，重排序后保留最好的二十个放进提示词。重排序在运行时多了一步，所以会增加一点延迟，文章建议你根据成本和速度来调整重排序多少个块。[Voyage 的页面](https://www.mongodb.com/docs/voyageai/models/rerankers)把 `rerank-3` 列为大多数应用准确率最高的模型，`rerank-3-lite` 则面向对延迟敏感的场景，两者的上下文都是 32,000 个 token。

````python
import voyageai

vo = voyageai.Client()  # reads VOYAGE_API_KEY

# candidates: the text of each chunk the hybrid query returned (Anthropic's post started from 150)
reranked = vo.rerank(query, candidates, model="rerank-3", top_k=20)

for result in reranked.results:
    print(f"{result.relevance_score:.4f}", result.document[:60])

context_chunks = [result.document for result in reranked.results]  # these go into the prompt
````

- LlamaIndex 称重排序是杠杆最高的调节项之一。它的做法是把 `similarity_top_k=10` 和本地交叉编码器 `cross-encoder/ms-marco-MiniLM-L6-v2` 搭配，再设 `top_n=3`。
- 同一页还说，在延迟不是关键的时候，基于 LLM 的重排序器可能比交叉编码器更好，代价是多几次 LLM 调用。
- Anthropic 测试的是 Cohere 的重排序器，文章说没来得及测试 Voyage 的。

## Jo Bergum 谈嵌入检索的极限，LlamaIndex 谈上下文的成本

Jo Kristian Bergum 的 X 简介写着，他经营 Hornet.dev，一个为智能体打造的检索引擎。2025 年 8 月，他[在 X 上](https://x.com/jobergum/status/1961663599195144642)说有人叫他“BM25 那个人”，并分享了 Google DeepMind 和约翰斯·霍普金斯大学研究者的[一篇论文](https://arxiv.org/abs/2508.21038)。

论文证明，嵌入向量的维度，限制了它能返回多少种不同的前 k 个结果组合。在论文刻意设计得很简单的 LIMIT 测试上，BM25 在前一百个结果里找回了 93.6% 的相关文档，最好的单向量模型只有 18.9%。

这篇论文 2026 年 3 月修订过，也测了反过来的情况。把每个条目都换成同义词后，BM25 的分数掉了将近 90%，落到大多数嵌入模型后面。所以融合查询的两半都要留着。测试问题里，要有照搬文档原词的，也要有换个说法的。

LlamaIndex 的 X 简介说，它是一家做文档解析和抽取的 AI 研究实验室。2024 年 10 月，它[在 X 上](https://x.com/llama_index/status/1841210062167294287)点出了上下文检索的成本：每个块都要调用一次模型，每次调用都带着整篇文档作为前缀。

上面的 `contextualize()` 循环正是这样。它的提示词以文档开头，每次调用只有块在变，这正是提示词缓存需要的。把同一篇文档的块接连发出去，不要把几篇文档混在一起发。

> 这需要调用 N 次大模型，每次都把整篇文档塞进去作为前缀，所以要降低 token 成本，很大程度上得靠提示词缓存。
>
> LlamaIndex, 按其 X 简介，做文档解析和抽取的 AI 研究实验室，引文为译文, [X](https://x.com/llama_index/status/1841210062167294287) (2026-11-05 查阅)

[![Jo Kristian Bergum（@jobergum）2025 年 8 月 30 日在 X 上说，有人叫他“BM25 那个人”，这次送上一篇《BM25 的不合理有效性》，其实论文的标题是《On the Theoretical Limitations of Embedding-Based Retrieval》](https://mindket.com/blog/shots/x-jobergum-bm25-embedding-limits.webp?v=6c609111b737)](https://x.com/jobergum/status/1961663599195144642)

Jo Kristian Bergum 在 X 上，2025 年 8 月 30 日

[![LlamaIndex（@llama_index）2024 年 10 月 1 日在 X 上谈实现上下文检索 RAG：这是 Anthropic 的一个 RAG 技巧，能明显改善检索，借提示词缓存控制成本，做法是给每个块加上它在整篇文档中位置的说明](https://mindket.com/blog/shots/x-llamaindex-contextual-retrieval-caching.webp?v=30e8a73369dc)](https://x.com/llama_index/status/1841210062167294287)

LlamaIndex 在 X 上，2024 年 10 月 1 日

[The 5 Levels Of Text Splitting For Retrieval](https://www.youtube.com/watch?v=8OJC21T2SL4)

Greg Kamradt 的 YouTube 视频：标题说明，它讲检索用的五个文本切分层级。GitHub 上同名的笔记本列出了这五级，从按字符切分到智能体式切分。

> X 官方嵌入卡片的截图，拍摄于 2026-11-05，时间为协调世界时（UTC）。LlamaIndex 那条帖子被 X 用“Show more”截断了。点击截图可到 X 上打开原帖。

## 常见错误

- 混用单位。LangChain 按字符计，OpenAI 按 token 计，用一个单位写的限制，换到另一个单位就不对了。
- 改了块大小，却不动检索块的数量。LlamaIndex 缩小块的时候会同时调高 `similarity_top_k`。
- 把 OpenAI 的重叠设得超过块大小的一半。文档说它不应超过 `max_chunk_size_tokens / 2`。
- 对中文文本使用英文的默认分隔符，这样会把词切成两半。
- 索引的是补过上下文的块，却只把裸块交给模型。把上下文也一起交过去，并加上标注。
- 照搬别人语料上得出的数字。块的数量、大小或重叠，在 Anthropic 或 OpenAI 那里有效，并不能说明你的文档。

## 自己试一试

- 用两种切分器各切一个你自己的 Markdown 文件，打印每个块和它的元数据，看看哪些标题保留了下来。
- 用三种块大小各跑同样的十个问题，记下每次正确答案来自哪个块。
- 用 Anthropic 的提示词给五个块写上下文并读一读：只看新文本，你能找到每个块吗？
- 拿你文档里的一个精确标识符，先只用向量搜索，再用融合后的查询搜索。

## 下一课

[第 4 课](https://mindket.com/cn/learn/rag/evaluate-rag)讲怎样衡量检索和答案，让上面每个选择都能由你自己问题上的数字来支撑。要给索引提供文件、数据库或网页内容，可以看 Mindket 上的 [MCP 服务器](https://mindket.com/cn/mcp-servers)，它们能把智能体连到这些来源。

## 自测一下

1. 你先按标题切分了一个 Markdown 文件，再把过长的部分切小。哪个调用能让每个块保留所属部分的标题元数据？

   A. RecursiveCharacterTextSplitter.split_text(sections)
   B. 设置了 strip_headers=True 的 MarkdownHeaderTextSplitter
   C. RecursiveCharacterTextSplitter.split_documents(sections)
   D. 把 chunk_overlap 设为 0

   答案：C。 LangChain 说，按标题切分之后要用 split_documents 而不是 split_text，这样各部分的元数据才不会丢。

2. 你的中文文档在词的中间被切开了，LangChain 建议怎么做？

   A. 把表意文字的句号和逗号加进分隔符列表
   B. 把 chunk_overlap 设为 0
   C. 改成按 token 计数
   D. 切分之前删掉所有标点

   答案：A。 默认分隔符假定文字用空格分词。对没有词边界的文字，LangChain 的办法是在列表里补上句号、逗号和零宽空格。

3. 在 Anthropic 的上下文检索里，嵌入和建立 BM25 索引之前，每个块前面会加上什么？

   A. 整篇文档的摘要
   B. 这个块的嵌入向量
   C. 用户的问题
   D. 由模型写的、把这个块放回其所在文档的简短说明

   答案：D。 提示词要求给出一段把这个块放进整篇文档里的简短上下文。同样的实验里，通用的文档摘要提升非常有限。

4. 在混合搜索里，排名融合这一步做什么？

   A. 用交叉编码器给每个块重新打分
   B. 按排名把向量和关键词两个结果列表合并成一个
   C. 在句子边界处切分块
   D. 把向量缩短成更少的维度

   答案：B。 倒数排名融合会为块出现的每个列表加上 1 / (k + 排名)，再按总分排序。

## 常见问题

### RAG 的块大小取多少最好？

没有哪份资料给出唯一的最佳值。默认值各不相同：OpenAI 文件搜索是 800 个 token，LlamaIndex 是 1024，LangChain 教程是 1000 个字符。先选一个，再用你自己的问题比较检索效果，因为块越小，嵌入越精确，块越大，越可能漏掉细节。

### 块之间该留多少重叠？

把它当作要调的设置。LangChain 说，上下文被切到两个块里时，重叠能减轻信息的损失。OpenAI 默认的重叠正好是块大小的一半，这也是它允许的上限，LlamaIndex 的默认重叠则小得多。

### 语义分块值得用吗？

先测量。LlamaIndex 的语义切分器靠嵌入相似度，在句子之间挑选断点，让每个块里都是相关的句子。它的页面提醒说，句子正则主要适用于英文，你可能还要调整断点百分位阈值。我们读到的页面里，没有哪份报告它相比递归切分器的收益。

### 中文或日文文本怎么分块？

照 LangChain 指南的做法，给 RecursiveCharacterTextSplitter 的分隔符列表补上表意文字句号、全角句号、逗号和零宽空格。

### 什么是上下文检索，值得用吗？

它在建立索引之前，给每个块加上一段由模型写的简短说明。在 Anthropic 的实验里，只用嵌入时检索失败减少了 35%，加上 BM25 后减少了 49%，代价是每个块要调用一次模型，提示词缓存可以降低这笔开销。

### 混合搜索比单用向量搜索更好吗？

Anthropic 发现嵌入加 BM25 比单用嵌入更好。LlamaIndex 说嵌入可能返回不了关键词匹配的块，并把混合搜索列为常见的解决办法。代价是多一个索引和一个融合步骤。

### 该把多少个块交给模型？

Anthropic 试了三种数量，发现其中最多的二十个块表现最好，同时提醒多余的信息可能分散模型的注意力。先多取一些，重排序后再保留，然后测试你自己的数量。

## 资料来源

- [LangChain Docs: Text splitter integrations](https://docs.langchain.com/oss/python/integrations/splitters) (2026-11-04 查阅)
- [LangChain Docs: Splitting recursively](https://docs.langchain.com/oss/python/integrations/splitters/recursive_text_splitter) (2026-11-05 查阅)
- [LangChain Docs: Split markdown](https://docs.langchain.com/oss/python/integrations/splitters/markdown_header_metadata_splitter) (2026-11-04 查阅)
- [LlamaIndex Docs: Basic strategies](https://developers.llamaindex.ai/python/framework/optimizing/basic_strategies/basic_strategies/) (2026-11-05 查阅)
- [LlamaIndex Docs: Node parser modules](https://developers.llamaindex.ai/python/framework/module_guides/loading/node_parsers/modules/) (2026-11-04 查阅)
- [OpenAI Docs: Retrieval](https://developers.openai.com/api/docs/guides/retrieval) (2026-11-05 查阅)
- [Anthropic: Contextual Retrieval](https://www.anthropic.com/research/contextual-retrieval) (2026-11-04 查阅)
- [Voyage AI Docs: Rerankers](https://www.mongodb.com/docs/voyageai/models/rerankers) (2026-11-05 查阅)
- [Voyage AI Docs: Contextualized Chunk Embeddings](https://www.mongodb.com/docs/voyageai/models/contextualized-chunk-embeddings) (2026-11-05 查阅)
- [Voyage AI Docs: Quickstart](https://www.mongodb.com/docs/voyageai/quickstart) (2026-11-04 查阅)
- [pgvector README](https://github.com/pgvector/pgvector) (2026-11-04 查阅)
- [pgvector-python: hybrid search example](https://github.com/pgvector/pgvector-python) (2026-11-04 查阅)
- [Jo Kristian Bergum on X: On the Theoretical Limitations of Embedding-Based Retrieval](https://x.com/jobergum/status/1961663599195144642) (2026-11-05 查阅)
- [arXiv: On the Theoretical Limitations of Embedding-Based Retrieval (v2, March 2026)](https://arxiv.org/abs/2508.21038) (2026-11-05 查阅)
- [LlamaIndex on X: Implementing Contextual Retrieval RAG](https://x.com/llama_index/status/1841210062167294287) (2026-11-05 查阅)
- [Greg Kamradt on YouTube: The 5 Levels Of Text Splitting For Retrieval](https://www.youtube.com/watch?v=8OJC21T2SL4) (2026-11-05 查阅)
- [GitHub: 5 Levels Of Text Splitting notebook](https://github.com/FullStackRetrieval-com/RetrievalTutorials/blob/main/tutorials/LevelsOfTextSplitting/5_Levels_Of_Text_Splitting.ipynb) (2026-11-05 查阅)

[浏览 MCP 服务器](https://mindket.com/cn/mcp-servers)
