# RAG 建筑和内部结构

内 [部分#1](/blog/rag-primer): 获取相关信息@,}然后用它来生成回应 *.* 现在我们深入技术架构

<datetime class="hidden">2025-11-22T09:30</datetime>

<!-- category -- AI, RAG, Machine Learning, Semantic Search, LLM, AI-Article -->
# 一. 导言导言 导言 导言 导言

**📖系列导航** 这是RAG系列的 2Q部分

- [第一部分:起源和基本](/blog/rag-primer) 以及核心概念。
- **建筑和内部** @( @ this article research@)}在技术上深入潜入RAG的操作方式
- [内容:3:](/blog/rag-practical-applications) 建立真正的系统 挑战 和先进技术
- [“4a :ONNX”“& Qdrant 履行”](/blog/semantic-search-with-onnx-and-qdrant) - CPU-友好语义搜索基金会
- [操作中的语义搜索](/blog/semantic-search-in-action) -typeahead,混合搜索@,和UI
- [@ 5:_ 混合搜索@ MS K1\ 自动 @ MASK2 @ Indexing](/blog/rag-hybrid-search-and-indexing) 生产一体化模式
- [6: 图表集](/blog/graphrag-knowledge-graphs-for-rag) - 用于 proposal_- 水平理解的知识图表

如果你读了部分1, 我建议从那里开始去理解"MS K2"

- ARAG是什么以及它为何重要
- 从关键字搜索到语义理解的历史
- RAG 与 fine-调试和其他方法

本篇文章假定你理解这些基本要点,并着重阐述 **技术架构@,实施细节 @,和LLM内部**.

[TOC]

# RAG如何工作 : 完整的图片

从您添加文档到用户得到答案的瞬间, RAG system ,\ \ }

## 阶段=1: 索引_( 准备知识库 200)})

在RAG 取得任何文件前 @, 您需要为您的知识库索引@. 这是 1\ -time process *%(}虽然您可以在稍后添加新文档 @MS K4

```mermaid
flowchart TB
    A[Source Documents] -->|1. Extract Text| B[Text Extraction]
    B -->|2. Split into Chunks| C[Chunking Service]
    C -->|3. Generate Embeddings| D[Embedding Model]
    D -->|4. Store Vectors| E[Vector Database]

    B -.Metadata.-> E

    subgraph "Example: Blog Post"
        F["Understanding Docker: A containerization platform..."]
    end

    subgraph "Chunks"
        G["Chunk 1: Title + Intro"]
        H["Chunk 2: Benefits Section"]
    end

    subgraph "Embeddings"
        I["0.234, 0.891, 0.567, ..."]
        J["0.445, 0.123, 0.789, ..."]
    end

    F --> G
    F --> H
    G --> I
    H --> J

    style D stroke:#f9f,stroke-width:2px
    style E stroke:#bbf,stroke-width:2px
```

### 步骤 @1:

从您的源文档中解开纯文本@ . @ this could be MS K1

- Markdown 文件 @(}就像我的博客poss@)
- 文档的 PDFs @ (}% 1}
- HTML & ( for web scrapping @) @%
- 数据库记录
- 电子邮件@,聊天logs @,等等#.

**我博客“:”的例子**

```csharp
// From MarkdownRenderingService
public string ExtractPlainText(string markdown)
{
    // Remove code blocks
    var withoutCode = Regex.Replace(markdown, @"```[\s\S]*?```", "");

    // Convert markdown to plain text
    var document = Markdown.Parse(withoutCode);
    var plainText = document.ToPlainText();

    return plainText.Trim();
}
```

### 步进2:振

这是大多数 RAG 执行失败的地方 @ . @ 您可以\ '} 您需要语义一致的块@ MS K3 *

**为何要拼凑块?**

- LLMs 有象征性限制@ ( @context window@)
- 更精确的检索@ =}
- 但块块必须包含足够的上下文, 才能有意义

**错误的块块@ : @ {}**

```
Chunk 1: "Docker is a containerization platform. It allows you"
Chunk 2: "to package applications with their dependencies. This"
Chunk 3: "ensures consistency across environments."
```

**不错的粗体块**

```
Chunk 1: "Docker is a containerization platform. It allows you to package applications with their dependencies. This ensures consistency across environments."

Chunk 2: "Benefits of Docker:
- Isolation: Each container runs in its own environment
- Portability: Containers run anywhere Docker is installed
- Efficiency: Lightweight compared to virtual machines"
```

**我的语义搜索执行中的示例@: @ {}**

```csharp
public class TextChunker
{
    private const int TargetChunkSize = 500; // ~500 words
    private const int ChunkOverlap = 50;     // 50 words overlap

    public List<Chunk> ChunkDocument(string text, string sourceId)
    {
        var chunks = new List<Chunk>();

        // Split on section boundaries first (## headers in markdown)
        var sections = SplitOnHeaders(text);

        foreach (var section in sections)
        {
            // If section is small enough, keep it whole
            if (section.WordCount < TargetChunkSize)
            {
                chunks.Add(new Chunk
                {
                    Text = section.Text,
                    SourceId = sourceId,
                    SectionHeader = section.Header
                });
            }
            else
            {
                // Split large sections on sentence boundaries
                var subChunks = SplitOnSentences(section.Text, TargetChunkSize, ChunkOverlap);
                chunks.AddRange(subChunks.Select(c => new Chunk
                {
                    Text = c,
                    SourceId = sourceId,
                    SectionHeader = section.Header
                }));
            }
        }

        return chunks;
    }
}
```

**共同的堆积策略 *:***

- **固定的@ - @ size**: 简单但打破语义界限
- **句号@- @% basin**: 尊重语法,但可能太小
- **基于 ' @-" 段落**:自然但可变大小
- **基于 @-**最佳结构化内容 @(_我的偏好#)
- **存在重叠的滑动窗口**: 保证在边界时不会丢失上下文

### 生成嵌入式

嵌入式是使语义搜索成为可能的魔力@.}嵌入器是数字中的矢量 @(arry ),它代表着文字的意思{.}

**密钥概念@: @%** 相似的矢量

```
"Docker container" → [0.234, -0.891, 0.567, ..., 0.123]
"containerization platform" → [0.221, -0.903, 0.534, ..., 0.119]
"apple fruit" → [0.891, 0.234, -0.567, ..., -0.789]
```

前两个矢量将是 载体空间中的 @" @close"}*(#high连带相似 *),}而第三个是遥远的@.{}

**如何生成嵌入@: @%**
现代嵌入模型是接受大规模文本数据集培训的神经网络,以学习语义关系@.大众模式 @:

- **{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2款**@: @ @ 384 @ 维度@ MS K2 fastQ,}好的品质 @ MPK4 @ 我在这个博客上使用什么?
- **文本@ - @ embedding_ MS K1}小** ( OpenAI): MS K2 维度, 非常高品质
- **BGE+-基**: MS K1 维度 I, 状态-of}- NSK5 开放源

**我的 ONNX 嵌入服务中的示例 @:**

```csharp
public async Task<float[]> GenerateEmbeddingAsync(string text)
{
    // Tokenize the input text
    var tokens = Tokenize(text);

    // Create input tensors for ONNX model
    var inputIds = CreateInputTensor(tokens);
    var attentionMask = CreateAttentionMaskTensor(tokens.Length);
    var tokenTypeIds = CreateTokenTypeIdsTensor(tokens.Length);

    // Run ONNX inference
    var inputs = new List<NamedOnnxValue>
    {
        NamedOnnxValue.CreateFromTensor("input_ids", inputIds),
        NamedOnnxValue.CreateFromTensor("attention_mask", attentionMask),
        NamedOnnxValue.CreateFromTensor("token_type_ids", tokenTypeIds)
    };

    using var results = _session.Run(inputs);

    // Extract the output (sentence embedding)
    var output = results.First().AsTensor<float>();
    var embedding = output.ToArray();

    // L2 normalize the vector for cosine similarity
    return NormalizeVector(embedding);
}
```

**为何正常化重要?** 在L2}正常化后..., 共生相似性变成简单的点产物... , 让搜索速度更快

### 向量数据库中的仓库

优化矢量数据库,以储存和搜索高-数向量@.}不同于使用 SQL 查询的传统数据库{,矢量数据基使用相似性搜索MS K3}

**密钥操作@: @%**

- **上层**以元数据添加或更新矢量
- **搜索**\ : 找到 K 最相似的矢量到查询矢量
- **筛选过滤器**: 将矢量搜索与元数据过滤器相结合

**Qdrant 实施示例@: @%**

```csharp
public async Task IndexDocumentAsync(
    string id,
    float[] embedding,
    Dictionary<string, object> metadata)
{
    var point = new PointStruct
    {
        Id = new PointId { Uuid = id },
        Vectors = embedding,
        Payload =
        {
            ["title"] = metadata["title"],
            ["source"] = metadata["source"],
            ["chunk_index"] = metadata["chunk_index"],
            ["created_at"] = DateTime.UtcNow.ToString("O")
        }
    };

    await _client.UpsertAsync(
        collectionName: "blog_posts",
        points: new[] { point }
    );
}
```

**大众矢量数据库:**

- **解冻**支持 @(_MY choice@)
- **pgvictor 变量**: PostgreSQL 扩展 {(} @ msk1 great 如果您已经使用 postgres)}
- **松松**: 管理服务 @( 昂贵但好~)
- **断断**-=YTET -伊甸园字幕组=- 翻译:
- **色谱DB**:Python-聚焦@,轻量级

我们将探讨在即将发表的文章中建立这些数据库。

## 搜索相关信息 )

当用户问一个问题,时,RAG系统需要从知识库中找到最相关的信息\.

```mermaid
flowchart LR
    A["User Query:<br/>'How do I use Docker Compose?'"] --> B[Generate Query Embedding]
    B --> C["Query Vector:<br/>[0.445, -0.123, ...]"]
    C --> D[Vector Search]
    D --> E[Vector Database]
    E --> F[Top K Similar Chunks]
    F --> G["Results:<br/>1. Docker Compose Basics 0.92<br/>2. Multi-Container Setup 0.87<br/>3. Service Configuration 0.83"]

    style B stroke:#f9f,stroke-width:3px
    style D stroke:#bbf,stroke-width:3px
```

### 生成查询嵌入

用户='}%s 问题被转换为矢量 **相同的嵌入模型** 用于索引的 @ . @ 这是关键 {-} 不同的模型产生不兼容矢量.}

```csharp
public async Task<List<SearchResult>> SearchAsync(string query, int limit = 10)
{
    // Same embedding model used for indexing
    var queryEmbedding = await _embeddingService.GenerateEmbeddingAsync(query);

    // Search in vector store
    var results = await _vectorStoreService.SearchAsync(
        queryEmbedding,
        limit
    );

    return results;
}
```

### 步骤 @2: 相似性搜索

矢量数据库计算查询矢量与所有存储的矢量之间的相似性@.通用度量=:

**余心相似性** “(”最受正常向量欢迎

```
similarity = (A · B) / (||A|| × ||B||)
```

范围@: @ @ -1 @ to @1 @ @ @ (_higher#=}更相似的) @

**欧几里地距离** ( 用于未正常化的矢量 @):

```
distance = sqrt(Σ(Ai - Bi)²)
```

范围@: @ @ 0# to @∞ @ @ @ (_lower @=}更相似的@MS K5 @

**点产品** @(}当矢量是预置的 - @% 正式化@):#

```
similarity = A · B
```

范围@: @ @ -1 @ to @1 @ @ @ (_higher#=}更相似的) @

**我的Qdrant 服务中的示例@: @**

```csharp
var searchResults = await _client.SearchAsync(
    collectionName: "blog_posts",
    vector: queryEmbedding,
    limit: (ulong)limit,
    scoreThreshold: 0.7f,  // Only return results with >70% similarity
    payloadSelector: true   // Include all metadata
);

return searchResults.Select(hit => new SearchResult
{
    Text = hit.Payload["text"].StringValue,
    Title = hit.Payload["title"].StringValue,
    Score = hit.Score,
    Source = hit.Payload["source"].StringValue
}).ToList();
```

### 步骤 @3: 重新排序@( 可选但推荐}#)

初始检索速度较快, 但使用更精密的模型来重新定位最高 K 结果@ .

```mermaid
flowchart LR
    A[Vector Search:<br/>Top 50 Results] --> B[Reranking Model]
    B --> C[Reranked:<br/>Top 10 Results]

    style B stroke:#f9f,stroke-width:3px
```

**为何要重新排名帮助我?**

- 优化快速嵌入模型以优化速度@, @ 牺牲某些精度
- 排名模型慢,但更准确
- Two- 阶段办法平衡速度和质量

**重排执行的示例**

```csharp
public async Task<List<SearchResult>> SearchWithRerankAsync(
    string query,
    int initialLimit = 50,
    int finalLimit = 10)
{
    // Stage 1: Fast vector search
    var candidates = await SearchAsync(query, initialLimit);

    // Stage 2: Precise reranking
    var rerankedResults = await _rerankingService.RerankAsync(
        query,
        candidates
    );

    return rerankedResults.Take(finalLimit).ToList();
}
```

## 阶段: 3:_一代_(_创造答案 ―)}

现在我们有了相关信息 , 我们把它和用户的问询一起传送给LLM

```mermaid
flowchart TB
    A[User Query] --> B[Retrieved Context 1]
    A --> C[Retrieved Context 2]
    A --> D[Retrieved Context 3]

    B --> E[Construct Prompt]
    C --> E
    D --> E
    A --> E

    E --> F["System: You are a helpful assistant...\n\nContext:\n1. Docker Compose allows...\n2. Services are defined...\n3. Volumes persist data...\n\nQuestion: How do I use Docker Compose?\n\nAnswer:"]

    F --> G[LLM]
    G --> H[Generated Answer with Citations]

    style E stroke:#f9f,stroke-width:2px
    style G stroke:#bbf,stroke-width:2px
```

### 即时建造

这是RAG 成为艺术的Art. 您需要构造提示, 所以 LLMMS K1

- 用户提供的上下文@(}不是内部知识 @)
- 可能时点选来源
- 当上下文包含一个答案时会承认@' @t
- 保持一致的基调@/}风格

**我的律师GPT系统中的示例提示模板@:**

```csharp
public string BuildRAGPrompt(string query, List<SearchResult> context)
{
    var sb = new StringBuilder();

    sb.AppendLine("You are a technical writing assistant. Your task is to answer the user's question using ONLY the provided context from past blog posts.");
    sb.AppendLine();
    sb.AppendLine("CONTEXT:");
    sb.AppendLine("========");

    for (int i = 0; i < context.Count; i++)
    {
        sb.AppendLine($"[{i + 1}] {context[i].Title}");
        sb.AppendLine($"Source: {context[i].Source}");
        sb.AppendLine($"Content: {context[i].Text}");
        sb.AppendLine($"Relevance: {context[i].Score:P0}");
        sb.AppendLine();
    }

    sb.AppendLine("========");
    sb.AppendLine();
    sb.AppendLine("INSTRUCTIONS:");
    sb.AppendLine("- Answer the question using the provided context");
    sb.AppendLine("- Cite sources using [1], [2], etc.");
    sb.AppendLine("- If the context doesn't contain enough information, say so");
    sb.AppendLine("- Maintain the technical, practical tone of the blog");
    sb.AppendLine();
    sb.AppendLine($"QUESTION: {query}");
    sb.AppendLine();
    sb.AppendLine("ANSWER:");

    return sb.ToString();
}
```

### 步骤2:LLM推论

建造的加速度将转到LLM, 用于生成“.” 这可以是‘:’

- **AIPI 云尘**@:OpenAI, 人类克劳德MS K2Google PaLM
- **当地模式**@ :_ 使用喇叭 @ .cpp,}ONNX 运行时间@,或火炬沙尔普

**使用本地LLM:}示例**

```csharp
public async Task<string> GenerateResponseAsync(string prompt)
{
    var result = await _llamaSharp.InferAsync(prompt, new InferenceParams
    {
        Temperature = 0.7f,      // Creativity (0 = deterministic, 1 = creative)
        TopP = 0.9f,             // Nucleus sampling
        MaxTokens = 500,         // Response length limit
        StopSequences = new[] { "\n\n", "User:", "Question:" }
    });

    return result.Text.Trim();
}
```

**关键参数解释@: @%**

- **温度**:Q 控制随机性@(0Q @=Q 总是选择最有可能的 @MS K3} @1Q @#=Z 随机抽样_){
- **顶P**:Nucleus 采样 - 只考虑构成顶级P概率质量的符号
- **最大调当量**限制回复长度
- **停止序列**“: 何时停止生产”

### 步骤 @ 3:_ post@ MS K1_ 处理

在LLM 生成响应后 @,}我们经常需要到@:

- 提取引文并将其转换为链接
- 格式化代码块
- 添加元数据@(}来源 @,}信任分数=)
- 记录调试的交互

**@-_process@:}后加示例**

```csharp
public RAGResponse PostProcess(string llmOutput, List<SearchResult> sources)
{
    var response = new RAGResponse
    {
        Answer = llmOutput,
        Sources = new List<Source>()
    };

    // Extract citations like [1], [2]
    var citations = Regex.Matches(llmOutput, @"\[(\d+)\]");

    foreach (Match match in citations)
    {
        int index = int.Parse(match.Groups[1].Value) - 1;
        if (index >= 0 && index < sources.Count)
        {
            var source = sources[index];
            response.Sources.Add(new Source
            {
                Title = source.Title,
                Url = GenerateUrl(source.Source),
                RelevanceScore = source.Score
            });
        }
    }

    // Convert markdown citations to hyperlinks
    response.FormattedAnswer = Regex.Replace(
        llmOutput,
        @"\[(\d+)\]",
        m => {
            int index = int.Parse(m.Groups[1].Value) - 1;
            if (index >= 0 && index < sources.Count)
            {
                var url = GenerateUrl(sources[index].Source);
                return $"[[{m.Groups[1].Value}]]({url})";
            }
            return m.Value;
        }
    );

    return response;
}
```

# 了解 LLM 内部( I) @ : @ Tokens@ MS K1 @ kV Cache},和上下文窗口

在我们转向实际应用之前, 关键在于了解LLMS如何在内部工作@.}这种知识有助于优化RAG系统并避免常见的陷阱_.}

## 什么是Tokens ?

Tokens 是LLMs process *.* text is @'}直接反馈给模型的基本单位 {-\} it'}它们首先细分为符号=%.

**示例符号@: @%**

```
Input:  "Understanding Docker containers"
Tokens: ["Under", "standing", " Docker", " containers"]
```

不同模式使用不同的代谢策略

- **GPT模型**: 使用 Byte-Pair Encoding MS K2BP) 和 @~50K字典
- **克劳德**类似BPE方法
- **Llama 模型**@ :_ 句式Piece 象征性化

**为什么象征性化对RAG:很重要?**

```csharp
public class TokenCounter
{
    // Rough approximation: 1 token ≈ 0.75 words (English)
    public int EstimateTokens(string text)
    {
        var wordCount = text.Split(' ', StringSplitOptions.RemoveEmptyEntries).Length;
        return (int)(wordCount / 0.75);
    }

    public int EstimateTokensAccurate(string text, ITokenizer tokenizer)
    {
        // Use actual tokenizer for precision
        return tokenizer.Encode(text).Count;
    }
}
```

**上下文窗口限制@: @%**

- GPT-3.5: @ 16K 象征性牌
- GPT-4: 8 K-128K 标牌( 取决于变量MSC4
- Claude @3.5_Sonnet@:} @ 200_K 神令
- Llama @3: @ @ 8} K 标牌@(_ 虽然可以展期 @ I){

在RAG systems\,中, 您必须适配@ :

```
Total tokens = System prompt + Retrieved context + User query + Response buffer
```

如果您的 RAG 在查询和回复前为上下文 {-} 获取“ 10” 文档@ MS K1 标记每个,, k3 * @ 5,000 _ 符号仅用于 profession { msk5\ }\ MSC6\ {

**实际的RAG象征性管理@:**

```csharp
public class ContextWindowManager
{
    private readonly int _maxContextTokens;
    private readonly int _systemPromptTokens;
    private readonly int _responseBufferTokens;

    public ContextWindowManager(
        int totalContextWindow = 4096,
        int systemPromptTokens = 300,
        int responseBufferTokens = 500)
    {
        _maxContextTokens = totalContextWindow;
        _systemPromptTokens = systemPromptTokens;
        _responseBufferTokens = responseBufferTokens;
    }

    public List<SearchResult> FitContextInWindow(
        List<SearchResult> retrievedDocs,
        string query)
    {
        var queryTokens = EstimateTokens(query);

        // Available tokens for retrieved context
        var availableForContext = _maxContextTokens
            - _systemPromptTokens
            - queryTokens
            - _responseBufferTokens;

        var selectedDocs = new List<SearchResult>();
        var currentTokens = 0;

        foreach (var doc in retrievedDocs.OrderByDescending(d => d.Score))
        {
            var docTokens = EstimateTokens(doc.Text);

            if (currentTokens + docTokens <= availableForContext)
            {
                selectedDocs.Add(doc);
                currentTokens += docTokens;
            }
            else
            {
                break; // Context window full
            }
        }

        return selectedDocs;
    }

    private int EstimateTokens(string text)
    {
        // Rule of thumb: 1 token ≈ 4 characters
        return text.Length / 4;
    }
}
```

## KV Cache : LLM='秘密武器

当一个 LLM 生成文本时 ,} 它会从零开始对每个牌子进行全部的重新处理\ I.}它使用 a **密钥@ - @ Value @ MS K1 @ KVQ)} 缓存** 来记住它已经计算了什么\"."

### 变换者如何工作 @ ( @ 简化@ MS K1 @

变换器使用“ " @ avention”\" 机制来理解上下文@ MS K6}

```mermaid
flowchart TB
    subgraph "Generation Step 1: 'Docker'"
        A1[Input: 'Docker'] --> B1[Compute K,V for 'Docker']
        B1 --> C1[Store in KV Cache]
        C1 --> D1[Generate: 'is']
    end

    subgraph "Generation Step 2: 'is'"
        A2[Input: 'is'] --> B2[Compute K,V for 'is']
        B2 --> C2[Store in KV Cache]
        C2 --> E2[Retrieve KV for 'Docker']
        E2 --> F2[Attend: 'is' to 'Docker']
        F2 --> D2[Generate: 'a']
    end

    subgraph "Generation Step 3: 'a'"
        A3[Input: 'a'] --> B3[Compute K,V for 'a']
        B3 --> C3[Store in KV Cache]
        C3 --> E3[Retrieve KV for 'Docker', 'is']
        E3 --> F3[Attend: 'a' to all previous]
        F3 --> D3[Generate: 'container']
    end

    D1 --> A2
    D2 --> A3

    style C1 stroke:#f9f,stroke-width:3px
    style C2 stroke:#f9f,stroke-width:3px
    style C3 stroke:#f9f,stroke-width:3px
```

**没有 KV 缓存@ : @%**

- 步骤“1:”进程 “1”符号“MS K2”O(1)
- 步骤 @2:Q 处理\ 2Q 从头到尾的标记@→Q O(2)}
- 步骤 @3:Q 处理\ 3Q 从头到尾的标记@→Q O(3)}
- + MS K7 NSK8 N @= OQ(N²)

**使用 KV 缓存@ : @**

- 步骤 @ 1: process { 1 matter\ MS K2} 缓存@ ,V @ MPK4 O(1)
- 步骤 @ 2: process *% 1 newmaking* , 再利用缓存 K,V _→ O(1)
- 步骤 @ 3: process *% 1 newmaking* , 再利用缓存 K,V _→ O(1)
- -=YTET -伊甸园字幕组=- 翻译:

这代人 **飞快的更快** -+#10@signals @/_QII和{100>之间的差别

### KV 缓存树结构

KV 缓存组成一个“ "” tree"" , 因为对变压器的注意力是如何起作用的。 “ .” 在模型中的每一层都有自己的 K,+V 矩阵@ MSC4}

```mermaid
graph TB
    A[Input Tokens:<br/>'What is Docker?'] --> B[Layer 1 Attention]
    B --> C[Layer 1 KV Cache]

    B --> D[Layer 2 Attention]
    D --> E[Layer 2 KV Cache]

    D --> F[Layer 3 Attention]
    F --> G[Layer 3 KV Cache]

    F --> H[... up to Layer N]
    H --> I[Output: 'Docker is']

    C -.Key-Value pairs<br/>for all input tokens.-> C
    E -.Key-Value pairs<br/>for all input tokens.-> E
    G -.Key-Value pairs<br/>for all input tokens.-> G

    style C stroke:#bbf,stroke-width:2px
    style E stroke:#bbf,stroke-width:2px
    style G stroke:#bbf,stroke-width:2px
```

**每层商店 :**

- **密钥 @ ( @ K)}**: 用于计算注意分数的表示式
- **数值 @(#V})#**: 基于关注的混合代表

用于使用“:”的模型

- 32 层
- 4096 隐藏的维度
- @32# 关注的负责人
- 8K 上下文窗口

一个序列的 KV 缓存为 @ : @

```
2 (K and V) × 32 layers × 4096 dimensions × 8192 tokens × 2 bytes (FP16)
≈ 4.3 GB of VRAM!
```

这就是为什么长的上下文窗口是内存@- @ tracting .}%

### RAG 系统中的 KV 缓存

RAG 系统可以用聪明的方式利用 KV 缓存优化@:

**即时缓存** “(”得到一些AIP的支持,

```csharp
public class CachedRAGService
{
    // System prompt and retrieved context can be cached!
    public async Task<string> GenerateWithCachedContextAsync(
        string systemPrompt,          // Cached
        List<SearchResult> context,   // Cached
        string userQuery)             // Not cached, changes each time
    {
        var contextText = FormatContext(context);

        // The KV cache for systemPrompt + contextText is reused across queries
        var prompt = $@"
{systemPrompt}

CONTEXT:
{contextText}

QUERY: {userQuery}

ANSWER:";

        return await _llm.GenerateAsync(prompt, useCaching: true);
    }
}
```

**为何如此强大?**

- 首个查詢: 計算系統提示的 KV 快取@ + 上下文 @ (slow @ MPK3}
- 随后以相同上下文查询@: 重新使用缓存的 KV @(10}#x apprepeciate *!)*
- 只有用户查询部分需要新计算

**实例::**

```
Query 1: "How do I use Docker?" → 2 seconds (no cache)
Query 2: "What are Docker benefits?" → 0.2 seconds (cache hit!)
Query 3: "Docker vs VMs?" → 0.2 seconds (cache hit!)
```

所有三个查询都使用相同的已检索上下文@,}因此此背景下的 KV 缓存被重新使用 d. {}

## 火力限制和RAG战略

获取信件和 KV 缓存, 通知您的 RAG 架构决定@: @% 1

### * 1. 振动大小

小块@ = @ 更精确的检索@ I,} 但更多高空@ MPK2

```csharp
// Option A: Small chunks (200 tokens each)
// Retrieve 20 chunks = 4,000 tokens
// Pro: Very precise, only relevant info
// Con: More KV cache entries, slower attention

// Option B: Larger chunks (500 tokens each)
// Retrieve 8 chunks = 4,000 tokens
// Pro: Better context coherence, fewer KV entries
// Con: More noise, less precise

public class AdaptiveChunker
{
    public int DetermineChunkSize(int contextWindowSize)
    {
        if (contextWindowSize <= 4096)
            return 200; // Small chunks for limited windows

        if (contextWindowSize <= 16384)
            return 500; // Medium chunks

        return 1000; // Large chunks for big windows
    }
}
```

### 2.上下文窗口的利用

最多从上下文窗口@- @leave room for singer_:}请勿离开房间

```csharp
public class SafeContextManager
{
    public int GetSafeContextLimit(int totalContextWindow)
    {
        // Use only 75% for input, reserve 25% for output
        return (int)(totalContextWindow * 0.75);
    }

    // Example: 4K model
    // Total: 4096 tokens
    // Safe input: 3072 tokens
    // Reserved for output: 1024 tokens
}
```

### -=YTET -伊甸园字幕组=- 翻译:

在聊天室里 MSKK0 每转一圈,对话历史都会不断增长

```
Turn 1:
System + Context + Query1 = 3000 tokens
Response1 = 300 tokens
Total: 3300 tokens

Turn 2:
System + Context + Query1 + Response1 + Query2 = 3650 tokens
Response2 = 300 tokens
Total: 3950 tokens

Turn 3:
System + Context + Query1 + Response1 + Query2 + Response2 + Query3 = 4250 tokens
ERROR: Context window exceeded!
```

**使用 re @ - retrieval 的解决方案@ :滑落窗口**

```csharp
public class ConversationalRAG
{
    private readonly int _maxHistoryTokens = 1000;

    public async Task<string> ChatAsync(
        List<ConversationTurn> history,
        string newQuery)
    {
        // Re-retrieve context based on current query
        var context = await RetrieveContextAsync(newQuery);

        // Keep only recent conversation history
        var relevantHistory = TrimHistory(history, _maxHistoryTokens);

        var prompt = BuildPrompt(context, relevantHistory, newQuery);

        return await _llm.GenerateAsync(prompt);
    }

    private List<ConversationTurn> TrimHistory(
        List<ConversationTurn> history,
        int maxTokens)
    {
        var trimmed = new List<ConversationTurn>();
        var currentTokens = 0;

        // Keep most recent turns
        foreach (var turn in history.Reverse())
        {
            var turnTokens = EstimateTokens(turn.Query) + EstimateTokens(turn.Response);

            if (currentTokens + turnTokens <= maxTokens)
            {
                trimmed.Insert(0, turn);
                currentTokens += turnTokens;
            }
            else
            {
                break;
            }
        }

        return trimmed;
    }
}
```

### 4. Tokon 成本优化

API=-以百万计的LLMs收费,如果不小心的话,RAG可爆炸成本*:

```csharp
public class CostAwareRAG
{
    // OpenAI GPT-4 pricing (example):
    // Input: $0.03 per 1K tokens
    // Output: $0.06 per 1K tokens

    public decimal EstimateQueryCost(
        int systemPromptTokens,
        int retrievedContextTokens,
        int queryTokens,
        int expectedResponseTokens)
    {
        var inputTokens = systemPromptTokens + retrievedContextTokens + queryTokens;
        var outputTokens = expectedResponseTokens;

        var inputCost = (inputTokens / 1000m) * 0.03m;
        var outputCost = (outputTokens / 1000m) * 0.06m;

        return inputCost + outputCost;
    }

    // Example:
    // System: 300 tokens
    // Context: 3000 tokens (10 retrieved docs)
    // Query: 50 tokens
    // Response: 500 tokens
    //
    // Cost = ((300 + 3000 + 50) / 1000 * 0.03) + (500 / 1000 * 0.06)
    //      = (3350 / 1000 * 0.03) + (500 / 1000 * 0.06)
    //      = $0.1005 + $0.03
    //      = $0.1305 per query
    //
    // At 1000 queries/day = $130/day = $3,900/month!
}
```

**降低成本战略**

1. 获取更少@, @ better}%SK1_已排序的文档
2. 使用便捷的缓存标记@ ( @ Anthropic Claude_ :} < MS K2 价格更便宜 {)}
3. 使用更便宜的模型,在最后一代中再用成本昂贵的模式
4. 使用汇总压缩环境

## 将全RAG与 Toks 一同流动的视觉化

这里的'@ ,KV缓存 @ MS K2和RAG如何匹配\ :

```mermaid
flowchart TB
    A[User Query:<br/>'How does Docker work?'<br/>≈ 12 tokens] --> B[Generate Query Embedding]

    B --> C[Vector Search]
    C --> D[Retrieved Docs:<br/>5 docs × 500 tokens<br/>= 2,500 tokens]

    D --> E[Construct Prompt]
    A --> E

    E --> F["Complete Prompt:<br/>System: 300 tokens<br/>Context: 2,500 tokens<br/>Query: 12 tokens<br/>Total: 2,812 tokens"]

    F --> G[Tokenize Prompt]
    G --> H["Token IDs:<br/>[245, 1034, 8829, ...]<br/>2,812 token IDs"]

    H --> I[LLM Layer 1]
    I --> J[Compute K,V]
    J --> K[KV Cache Layer 1:<br/>2,812 K,V pairs]

    I --> L[LLM Layer 2]
    L --> M[Compute K,V]
    M --> N[KV Cache Layer 2:<br/>2,812 K,V pairs]

    L --> O[... Layers 3-32]
    O --> P[Generate Token 1: 'Docker']

    P --> Q[Add to KV Cache]
    Q --> R[Generate Token 2: 'is']
    R --> S[Add to KV Cache]
    S --> T[... until completion]

    T --> U["Response: 'Docker is a containerization platform...'<br/>≈ 400 tokens"]

    style K stroke:#f9f,stroke-width:2px
    style N stroke:#f9f,stroke-width:2px
    style Q stroke:#bbf,stroke-width:2px
    style S stroke:#bbf,stroke-width:2px
```

**密钥洞见@: @%**

1. **输入符号** @(2,812) 被处理过一次以建立初始 KV 缓存
2. **产生** 重复使用 KV 缓存
3. **每个新标志** 添加到 KV 缓存中, 用于未来待处理的标记
4. **记录和档案管理共计** 需要所有标记的 KV 缓存@ = @ model weights
5. **长期** 最大 KV 缓存@ = @ 更多 VRAM

## 对ARAG的实际影响

获取标识和 KV 缓存会改进RAG 设计@: @

**1. pre- 计算并缓存共同背景@:**

```csharp
// Cache KV for frequently used system prompts + static context
var cachedSystemContext = await _llm.PrecomputeKVCache(systemPrompt + staticContext);

// Reuse for each query (much faster)
foreach (var query in userQueries)
{
    var response = await _llm.GenerateAsync(query, reuseKVCache: cachedSystemContext);
}
```

**优化块边框@: @**

```csharp
// Bad: Arbitrary 500-character chunks
var chunks = text.Chunk(500);

// Good: Chunk on sentence boundaries, measure in tokens
public List<string> ChunkByTokens(string text, int maxTokensPerChunk)
{
    var sentences = SplitIntoSentences(text);
    var chunks = new List<string>();
    var currentChunk = new StringBuilder();
    var currentTokens = 0;

    foreach (var sentence in sentences)
    {
        var sentenceTokens = EstimateTokens(sentence);

        if (currentTokens + sentenceTokens > maxTokensPerChunk && currentTokens > 0)
        {
            chunks.Add(currentChunk.ToString());
            currentChunk.Clear();
            currentTokens = 0;
        }

        currentChunk.Append(sentence).Append(" ");
        currentTokens += sentenceTokens;
    }

    if (currentTokens > 0)
        chunks.Add(currentChunk.ToString());

    return chunks;
}
```

**3. 监控在生产中的象征性使用@:**

```csharp
public class RAGTelemetry
{
    public void LogRAGQuery(
        string query,
        List<SearchResult> retrievedDocs,
        string response)
    {
        var queryTokens = EstimateTokens(query);
        var contextTokens = retrievedDocs.Sum(d => EstimateTokens(d.Text));
        var responseTokens = EstimateTokens(response);
        var totalTokens = queryTokens + contextTokens + responseTokens;

        _logger.LogInformation(
            "RAG Query: {Query} | Context: {ContextTokens} tokens from {DocCount} docs | " +
            "Response: {ResponseTokens} tokens | Total: {TotalTokens} tokens",
            query, contextTokens, retrievedDocs.Count, responseTokens, totalTokens
        );

        // Alert if approaching context limit
        if (totalTokens > _maxTokens * 0.9)
        {
            _logger.LogWarning("Approaching token limit: {TotalTokens}/{MaxTokens}",
                totalTokens, _maxTokens);
        }
    }
}
```

# 结论:- 建筑精准

我们覆盖了RAG系统的完整技术架构 :

**阶段1: 索引化**

- 从各种来源提取的文本
- 整顿策略 @(_section-}基于#,}句子@-_based{,}与重迭)}
- 嵌入式生成 (ONNXMS K1 API 服务)
- 矢量存储 @ (drant, pgvectorMS K2pineconone})

**阶段 *2:检索**

- 查询是否以索引方式嵌入 @( @same 模式@ !)
- 近似性搜索 @(cosine,eccilidean_,doproduction@)
- 提高精确度的可选重新排序
- 改进结果的元数据过滤

**生产阶段**

- 即时构造 @ (_ context {+} 指令@ MS K2} 查询)}
- 最大代号@)
- 后 - programme {(}\ 引用提取,} 格式@)

**LLM 内部**

- Tokens: 基本单位 @ (not字符@!)
- KV Cache:# 为什么下一代速度很快 @ ( @ linear @ I,} 不是二次曲线@ MSC3 @
- 上下文窗口@: 管理 RAG 的批号限制
- 成本优化@: @ caching,}压缩 @ ,# 智能检索

**关键技术见解*:**

1. **相同的嵌入模型** 用于索引和检索@( @jectric_!)}(% 1)
2. **比你想的要重要得多** 保持语义一致性
3. **排级提高精确度** 以延时费用计算
4. **名声管理至关重要** 查询前的 - @ {} 估计
5. **KV 缓存使RAG变得可行** -再利用快速计算
6. **上下文窗口快速填充** - @10 @ docs #×500#标语@=5#K象征性

# 继续运行到 & 3: @ RAG 在实际操作中的部件

你现在明白了 **RAG是如何工作的** 在技术层面 .}但理论只能让你到现在为止... ...你如何实际建立这些系统?

内 **[内容:3:](/blog/rag-practical-applications)**@,#我们从建筑到实施#:

**真实的-#世界应用程序 @:}**

- 这个博客上的相关文章建议
- 语义博客搜索
- GPT " 写作助理

**共同的挑战和解决办法**

- 保持环境的启动战略
- 改进您域域的嵌入质量
- 动态管理环境窗口
- 尽管有背景,但防止幻觉
- 正在不断更新您的索引@- @to @-_date

**先进技术**

- 假想文档嵌入@ (_ HyDE})
- 使用 LLM - paraceed 过滤器自定义
- 用于取得全面成果的多-Qquery RAG
- 用于减少象征性使用的上下文压缩
- 用于复杂查询的多端-Hop RAG
- LongM- 定期对话记忆

**开始:**

- 周计划执行计划
- 实用守则实例
- 优化战略
- 不使用 RAG 时

**[继续执行“3:”和“RAG”部分](/blog/rag-practical-applications)**

## 资源资源资源 资源和资源资源资源

**基础文件**

- [重新获取@ - @ 启动生成知识 < NLP 强化NLP任务 >](https://arxiv.org/abs/2005.11401) 原始的RAG文件
- [用于 OpenQ- @Domay 问答的高级通道检索器](https://arxiv.org/abs/2004.04906) -DPR基金会
- [你们需要的注意力](https://arxiv.org/abs/1706.03762) - 变形器

**工具与框架@: @%**

- [解冻](https://qdrant.tech/) -矢量数据库
- [NONX 运行时间](https://onnxruntime.ai/) -当地嵌入
- [拉马沙尔普](https://github.com/SciSharp/LLamaSharp) -当地LLM推论
- [句子变换器](https://www.sbert.net/) *-嵌入模型

**继续读取@: @%**

- [人类学:}上下文检索](https://www.anthropic.com/index/contextual-retrieval) *- 先进技术

**系列导航:**

- [第一部分:起源和基本](/blog/rag-primer) 历史和动机
- **建筑和内部** @( @ this article resident develop (技术深潜)
- [内容:3:](/blog/rag-practical-applications) 建立真正的系统

**[继续到 & M3 @ →](/blog/rag-practical-applications)**