Back to "RAG 实业中RAG+:建筑 Real_-世界应用"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

AI AI-Article LLM Machine Learning RAG Semantic Search

RAG 实业中RAG+:建筑 Real_-世界应用

Saturday, 22 November 2025

内 部分#1 和 部分#2 这篇文章展示了如何建立真正的RAG系统, 并使用最近研究的先进技术 以及运用最新研究成果 .

一. 导言导言 导言 导言 导言

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

如果您读过部分 @ 1 @ 和2,} 我建议从那里开始理解@ MS K3 @

  • RAG是什么,为什么重要? (+Part@1)+#
  • 从关键字搜索到语义理解\ ( Part @1)}历史
  • 完整 RAG 管道: 索引MS K1 recreaking , 生成 *( Part @2)
  • LLM 内存@ : @ massigns @ MS K1} KV 缓存 *, 上下文窗口 @ MPK3
  • 校对:Portnoy

本条假定你理解这些基本要点,并着重阐述 和真实的-世界模式.

校对:Portnoy

这个博客「.」(I')已建立多个RAG-功能特写,

有关员额的建议

使用语义相似性.,

如何运作?

  1. 每个博客文章发表后都会嵌入
  2. 当查看 post @ ,时, 我们从 Qdrant 获取它的嵌入
  3. 查找 & 5 @ 最相似的邮件嵌入
  4. 显示为“ "” 相关员额@"

为什么它比标签更好?

  • 标记需要手工分类
  • 即使没有匹配标签, 语义搜索也发现在概念上与理论相关
  • " @Dockercompropose@"}與"#Container conformation_"(關鍵語言系相關的函數)

代码片断@ : @

public async Task<List<SearchResult>> GetRelatedPostsAsync(
    string currentPostSlug,
    string language,
    int limit = 5)
{
    // Get the current post's embedding
    var currentPost = await _vectorStore.GetByIdAsync(currentPostSlug);

    if (currentPost == null)
        return new List<SearchResult>();

    // Find similar posts
    var similarPosts = await _vectorStore.SearchAsync(
        currentPost.Embedding,
        limit: limit + 1,  // +1 because result includes the current post
        filter: new Filter
        {
            Must =
            {
                new Condition
                {
                    Field = "language",
                    Match = new Match { Keyword = language }
                }
            },
            MustNot =
            {
                new Condition
                {
                    Field = "slug",
                    Match = new Match { Keyword = currentPostSlug }
                }
            }
        }
    );

    return similarPosts.Take(limit).ToList();
}

@2._Semantic博客搜索

此博客的搜索框使用 RAG-stype 语义搜索@(}虽然没有生成部件 {- it's just recredition_).但沒有產生元件 **它MS K3}s justreaccess < msk4}

用户经验@: @%

  • 搜索 @" 正在建立数据库@" @\ → 找到关于 PostgreSQL,}实体框架@MS K4 迁移的文章
  • 搜索 @"}Option@"}#→}找到关于 Docker,}主机@MS K4}(CI}/}CD的站点
  • 不需要精确关键字匹配

实施#: I'Lall在即将到来的关于矢量数据库的文章中写下这个内容

3. MS K1 律师GPT"写作助理

I'm 建立一个完整的RAG系统,

使用大小写@: 当我开始写关于 @ " @ 添加认证到 ASP@ MS K1} nNET Core",}系统=:}

  1. 嵌入我目前的草稿
  2. 搜索相关认证内容的过去文章@, @ASP_.}%NETQ,安全性
  3. 推荐相关代码片断 I'}以前曾使用过
  4. 自动-generate 与相关员额的内部链接
  5. 与我的写作风格保持一致

完整RAG管道:

public async Task<WritingAssistanceResponse> GetSuggestionsAsync(
    string currentDraft,
    string topic)
{
    // 1. Embed the current draft
    var draftEmbedding = await _embeddingService.GenerateEmbeddingAsync(
        currentDraft
    );

    // 2. Retrieve related past content
    var relatedPosts = await _vectorStore.SearchAsync(
        draftEmbedding,
        limit: 5
    );

    // 3. Build context for LLM
    var prompt = BuildWritingAssistancePrompt(
        currentDraft,
        topic,
        relatedPosts
    );

    // 4. Generate suggestions using local LLM
    var suggestions = await _llmService.GenerateAsync(prompt);

    // 5. Extract and format citations
    var response = ExtractCitations(suggestions, relatedPosts);

    return response;
}

这是操作中的 RAG @ -_ 检索@ (ssemantic search MS K2} @ I+{ 增强=(} 添加上下文@ MPK5} @ *+} 新一代 @(LLM 建言).}

RAG 共同挑战和解决方案

建筑生产RAG系统是't polent.这里遇到的挑战,

挑战"震动战略

问题M: 您如何分割文档@ ? @ 过小 @ MS K1 @ 失去上下文 @ I. @ 太大 @ MPK3} 不相干的信息 @ .

解答@: @ 基于文档结构的平衡区块@. @%

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

        // Parse markdown into sections
        var document = Markdown.Parse(markdown);
        var sections = ExtractSections(document);

        foreach (var section in sections)
        {
            var wordCount = CountWords(section.Content);

            if (wordCount < MinChunkSize)
            {
                // Merge small sections
                MergeWithPrevious(chunks, section);
            }
            else if (wordCount > MaxChunkSize)
            {
                // Split large sections
                var subChunks = SplitSection(section);
                chunks.AddRange(subChunks);
            }
            else
            {
                // Just right
                chunks.Add(CreateChunk(section, sourceId));
            }
        }

        return chunks;
    }
}

最佳做法

  • @(_#headers},}段落{)}文档结构
  • 在块中添加重叠@ (50-100 @ words @ MS K1}
  • 保护代码块完整保存
  • 在上下文的每个块块中包含区域标题

包含质量的挑战

问题M: 通用嵌入模型可能无法捕捉域@ - @ 特定语义=.}%

解决方案#:

选项 @ 1: @ pine@ - @ tune 嵌入 -=YTET -伊甸园字幕组=- 翻译:

# Using sentence-transformers in Python
from sentence_transformers import SentenceTransformer, InputExample, losses

model = SentenceTransformer('all-MiniLM-L6-v2')

# Create training examples from your domain
train_examples = [
    InputExample(texts=['Docker Compose', 'container orchestration'], label=0.9),
    InputExample(texts=['Entity Framework', 'ORM database'], label=0.9),
    InputExample(texts=['Docker', 'apple fruit'], label=0.1)
]

# Fine-tune
train_dataloader = DataLoader(train_examples, shuffle=True, batch_size=16)
train_loss = losses.CosineSimilarityLoss(model)
model.fit(train_objectives=[(train_dataloader, train_loss)], epochs=1)

混合嵌入器 @(combine 多重型号@)

public async Task<float[]> GenerateHybridEmbeddingAsync(string text)
{
    var semantic = await _semanticModel.GenerateEmbeddingAsync(text);
    var keyword = await _keywordModel.GenerateEmbeddingAsync(text);

    // Concatenate or weighted average
    return CombineEmbeddings(semantic, keyword);
}

添加元数据过滤器

var results = await _vectorStore.SearchAsync(
    queryEmbedding,
    limit: 10,
    filter: new Filter
    {
        Must =
        {
            new Condition { Field = "category", Match = new Match { Keyword = "ASP.NET" } },
            new Condition { Field = "date", Range = new Range { Gte = "2024-01-01" } }
        }
    }
);

上下文窗口管理

问题M: LLM 具有象征性限制@. 您如何在窗口中匹配查询 <% + 上下文> @+} 在窗口中的提示{?} ?

解答@: @ 动态环境选择和摘要@. @%

public string BuildContextAwarePrompt(
    string query,
    List<SearchResult> retrievedDocs,
    int maxTokens = 4096)
{
    var promptTemplate = GetPromptTemplate();
    var queryTokens = CountTokens(query);
    var templateTokens = CountTokens(promptTemplate);

    // Reserve tokens for: prompt + query + response
    var availableForContext = maxTokens - queryTokens - templateTokens - 500; // 500 for response

    // Add context until we hit limit
    var selectedContext = new List<SearchResult>();
    var currentTokens = 0;

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

        if (currentTokens + docTokens <= availableForContext)
        {
            selectedContext.Add(doc);
            currentTokens += docTokens;
        }
        else
        {
            // Try summarizing the doc if it's important
            if (doc.Score > 0.85)
            {
                var summary = await SummarizeAsync(doc.Text, maxTokens: 200);
                var summaryTokens = CountTokens(summary);

                if (currentTokens + summaryTokens <= availableForContext)
                {
                    selectedContext.Add(new SearchResult
                    {
                        Text = summary,
                        Title = doc.Title,
                        Score = doc.Score
                    });
                    currentTokens += summaryTokens;
                }
            }
        }
    }

    return FormatPrompt(query, selectedContext);
}

尽管有RAG, 却仍挑战着幻觉

问题M: 即便如此,LLMs有时也会忽略它和幻觉

解决方案#:

即时工程

var systemPrompt = @"
You are a technical assistant.

CRITICAL RULES:
1. ONLY use information from the provided CONTEXT sections
2. If the context doesn't contain the answer, say 'I don't have enough information in the provided context to answer that'
3. DO NOT use your training data to supplement answers
4. Always cite the source using [1], [2] notation
5. If you're unsure, say so

CONTEXT:
{context}

QUESTION: {query}

ANSWER (following all rules above):
";

“2. 邮政 - ” 源码验证“:”

public async Task<bool> ValidateResponseAgainstContext(
    string response,
    List<SearchResult> context)
{
    // Check if response contains claims not in context
    var responseSentences = SplitIntoSentences(response);

    foreach (var sentence in responseSentences)
    {
        var isSupported = await IsClaimSupportedByContext(sentence, context);

        if (!isSupported)
        {
            _logger.LogWarning("Hallucination detected: {Sentence}", sentence);
            return false;
        }
    }

    return true;
}

***3. 迭代完善 * : ***

public async Task<string> GenerateWithValidationAsync(
    string query,
    List<SearchResult> context,
    int maxAttempts = 3)
{
    for (int attempt = 0; attempt < maxAttempts; attempt++)
    {
        var response = await _llm.GenerateAsync(
            BuildPrompt(query, context)
        );

        var isValid = await ValidateResponseAgainstContext(response, context);

        if (isValid)
            return response;

        // Refine prompt for next attempt
        query = $"{query}\n\nPrevious attempt hallucinated. Stick strictly to the context.";
    }

    return "I couldn't generate a reliable answer. Please rephrase your question.";
}

“5: 保持指数上扬”“-to @-Date”

问题M: 当您添加新的文档\ , 矢量数据库需要保持当前@ MS K1\ {

解答@: @ 自动索引化管道.

public class BlogIndexingBackgroundService : BackgroundService
{
    private readonly IVectorStoreService _vectorStore;
    private readonly IMarkdownService _markdownService;
    private readonly ILogger<BlogIndexingBackgroundService> _logger;

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                await IndexNewPostsAsync(stoppingToken);

                // Check for updates every hour
                await Task.Delay(TimeSpan.FromHours(1), stoppingToken);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error in indexing service");
            }
        }
    }

    private async Task IndexNewPostsAsync(CancellationToken ct)
    {
        var allPosts = await _markdownService.GetAllPostsAsync();

        foreach (var post in allPosts)
        {
            var existingDoc = await _vectorStore.GetByIdAsync(post.Slug);

            // Check if content changed
            var currentHash = ComputeHash(post.Content);

            if (existingDoc == null || existingDoc.ContentHash != currentHash)
            {
                _logger.LogInformation("Indexing updated post: {Title}", post.Title);

                var chunks = _chunker.ChunkDocument(post.Content, post.Slug);

                foreach (var chunk in chunks)
                {
                    var embedding = await _embeddingService.GenerateEmbeddingAsync(chunk.Text);

                    await _vectorStore.UpsertAsync(
                        id: $"{post.Slug}_{chunk.Index}",
                        embedding: embedding,
                        metadata: new Dictionary<string, object>
                        {
                            ["slug"] = post.Slug,
                            ["title"] = post.Title,
                            ["chunk_index"] = chunk.Index,
                            ["content_hash"] = currentHash
                        },
                        ct: ct
                    );
                }
            }
        }
    }
}

RAG 先进技术

让我们探索最近研究的尖端RAG技术 .

1.伪假文件嵌入 * @(HyDE)*

问题M: 用户查询通常很短,且格式不完善@. @% 文件块详细,而且非常精细: -}{profried.此不匹配会伤害检索}.

解答@: @ 生成一个假想的理想文档, 以解答查询“ ,” 嵌入内容: “ MS K1” 然后搜索“ MPK2” 。

public async Task<List<SearchResult>> HyDESearchAsync(string query)
{
    // Generate hypothetical answer (even if hallucinated)
    var hypotheticalAnswer = await _llm.GenerateAsync($@"
        Write a detailed, technical paragraph that would perfectly answer this question:

        Question: {query}

        Paragraph:"
    );

    // Embed the hypothetical answer
    var embedding = await _embeddingService.GenerateEmbeddingAsync(
        hypotheticalAnswer
    );

    // Search using this embedding
    return await _vectorStore.SearchAsync(embedding);
}

为什么它的工作原理": 假设答案使用与实际文件相似的语言和结构,

{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}自 己...

问题M: 用户查询往往将语义搜索与元数据过滤器混合起来@. @%

例如:: "_Rest 有关Docker}" @= semantitic#("#Docker") @{+过滤器♫(date ∮>2024-01-01)

解答@: @ 使用 LLM 将查询解析为语义 {+} 元数据过滤@.

public async Task<SearchQuery> ParseSelfQueryAsync(string naturalLanguageQuery)
{
    var parsingPrompt = $@"
        Parse this search query into:
        1. Semantic search query (what the user is looking for)
        2. Metadata filters (category, date range, etc.)

        User Query: {naturalLanguageQuery}

        Output JSON:
        {{
            ""semantic_query"": ""the core concept"",
            ""filters"": {{
                ""category"": ""...",
                ""date_after"": ""..."",
                ""date_before"": ""...""
            }}
        }}
    ";

    var jsonResponse = await _llm.GenerateAsync(parsingPrompt);
    var parsed = JsonSerializer.Deserialize<SearchQuery>(jsonResponse);

    return parsed;
}

// Use parsed query
var parsedQuery = await ParseSelfQueryAsync("Recent ASP.NET posts about authentication");
// semantic_query: "authentication"
// filters: { category: "ASP.NET", date_after: "2024-01-01" }

var results = await _vectorStore.SearchAsync(
    embedding: await _embeddingService.GenerateEmbeddingAsync(parsedQuery.SemanticQuery),
    filter: BuildFilter(parsedQuery.Filters)
);

3. 多-出局RAG

问题M: 单一个查询可能会因语句的表达而错过相关文档@. @%

解答@: @ 生成查询,搜索的多种变异, 并使用所有 ,}合并结果MS K2

public async Task<List<SearchResult>> MultiQuerySearchAsync(string query)
{
    // Generate query variations
    var variations = await _llm.GenerateAsync($@"
        Generate 3 different ways to phrase this search query:

        Original: {query}

        Variations (one per line):
    ");

    var queries = variations.Split('\n', StringSplitOptions.RemoveEmptyEntries)
        .Prepend(query) // Include original
        .ToList();

    // Search with all variations
    var allResults = new List<SearchResult>();

    foreach (var q in queries)
    {
        var embedding = await _embeddingService.GenerateEmbeddingAsync(q);
        var results = await _vectorStore.SearchAsync(embedding, limit: 10);
        allResults.AddRange(results);
    }

    // Deduplicate and merge scores
    var merged = allResults
        .GroupBy(r => r.Id)
        .Select(g => new SearchResult
        {
            Id = g.Key,
            Text = g.First().Text,
            Title = g.First().Title,
            Score = g.Max(r => r.Score) // Take best score
        })
        .OrderByDescending(r => r.Score)
        .ToList();

    return merged;
}

4. 上下文压缩

问题M: 回收的块含有不相干的信息@. 发送所有废品标牌 @.

解答@: @ 使用较小的 LLM 压缩仅相关部分的已获取上下文@.

public async Task<string> CompressContextAsync(
    string query,
    List<SearchResult> retrievedDocs)
{
    var compressed = new List<string>();

    foreach (var doc in retrievedDocs)
    {
        var compressionPrompt = $@"
            Extract only the sentences from this document that are relevant to answering the question.

            Question: {query}

            Document:
            {doc.Text}

            Relevant excerpts (maintain original wording):
        ";

        var relevantExcerpt = await _smallLLM.GenerateAsync(compressionPrompt);

        if (!string.IsNullOrWhiteSpace(relevantExcerpt))
        {
            compressed.Add($"From '{doc.Title}':\n{relevantExcerpt}");
        }
    }

    return string.Join("\n\n", compressed);
}

5. 临时检索 multi MS K2Hop RAG

问题M: 复杂问题需要多个来源的信息,

例如@: @ @ "}博客使用什么样的数据库?

  • 寻找使用什么数据库@ ( @ postgreSQL)}
  • Hop 2: 找出语义搜索如何使用该数据库

解答@: @ 迭代检索和合成@.

public async Task<string> MultiHopRAGAsync(string complexQuery, int maxHops = 3)
{
    var currentQuery = complexQuery;
    var allContext = new List<SearchResult>();

    for (int hop = 0; hop < maxHops; hop++)
    {
        // Retrieve for current query
        var results = await SearchAsync(currentQuery, limit: 5);
        allContext.AddRange(results);

        // Check if we have enough information
        var synthesisPrompt = $@"
            Original question: {complexQuery}

            Context so far:
            {FormatContext(allContext)}

            Can you answer the original question with this context?
            If yes, provide the answer.
            If no, what additional information do you need? (be specific)
        ";

        var synthesis = await _llm.GenerateAsync(synthesisPrompt);

        if (synthesis.Contains("yes", StringComparison.OrdinalIgnoreCase))
        {
            // We have enough information
            return ExtractAnswer(synthesis);
        }

        // Extract what we need for next hop
        currentQuery = ExtractNextQuery(synthesis);
    }

    // Final synthesis with all gathered context
    return await GenerateFinalAnswerAsync(complexQuery, allContext);
}

6.Long-用RAG+总结的定期背景内存

问题M: 如何建立能记住几个月或几年前对话的人工智能系统?

解答@: @ 将 RAG 与累进总和合并,以创建可搜索的内存@.

这就是在 DISE ( dirreced 合成进化\ ) 使用 RAG=-}基上下文内存来保持共享的谈话历史@.

实例假想

User (Today): "Remember George's specs?"
AI: "Yes, you discussed George's prescription requirements in our conversation
     from 5 years ago (2019-03-15). He needed progressive lenses with..."

如何运作?

flowchart TB
    A[User Message] --> B[Store in RAG Memory]
    B --> C[Extract Key Entities & Topics]
    C --> D[Link to Past Conversations]

    E[Periodic Summarization] --> F[Summarize Old Conversations]
    F --> G[Store Summary with High-Level Tags]
    G --> H[Keep Original for Retrieval]

    I[Future Query: 'George's specs'] --> J[Semantic Search in RAG]
    J --> K[Find: 2019 conversation]
    K --> L[Retrieve Original Context]
    L --> M[LLM generates response with 5-year-old context!]

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

B. 实施方针

public class LongTermConversationalMemory
{
    private readonly IVectorStoreService _vectorStore;
    private readonly IEmbeddingService _embeddingService;

    public async Task StoreConversationAsync(
        string conversationId,
        string userId,
        List<ConversationTurn> turns,
        DateTime timestamp)
    {
        // Extract key entities and topics
        var entities = await ExtractEntitiesAsync(turns);
        var topics = await ExtractTopicsAsync(turns);

        // Create searchable representation
        var conversationText = string.Join("\n", turns.Select(t =>
            $"{t.Speaker}: {t.Message}"));

        // Generate embedding
        var embedding = await _embeddingService.GenerateEmbeddingAsync(
            conversationText);

        // Store in RAG with rich metadata
        await _vectorStore.IndexDocumentAsync(
            id: $"conv_{conversationId}",
            embedding: embedding,
            metadata: new Dictionary<string, object>
            {
                ["user_id"] = userId,
                ["timestamp"] = timestamp.ToString("O"),
                ["entities"] = entities,  // ["George", "specs", "prescription"]
                ["topics"] = topics,      // ["healthcare", "eyewear"]
                ["full_text"] = conversationText,
                ["turn_count"] = turns.Count
            }
        );
    }

    public async Task<List<PastContext>> RetrieveRelevantPastAsync(
        string currentQuery,
        string userId,
        int limit = 5)
    {
        // Embed the current query
        var queryEmbedding = await _embeddingService.GenerateEmbeddingAsync(
            currentQuery);

        // Search past conversations
        var results = await _vectorStore.SearchAsync(
            queryEmbedding,
            limit: limit,
            filter: new Filter
            {
                Must =
                {
                    new Condition { Field = "user_id", Match = new Match { Keyword = userId } }
                }
            }
        );

        return results.Select(r => new PastContext
        {
            ConversationId = r.Id,
            Timestamp = DateTime.Parse(r.Metadata["timestamp"].ToString()),
            Entities = (List<string>)r.Metadata["entities"],
            FullText = r.Metadata["full_text"].ToString(),
            Relevance = r.Score
        }).ToList();
    }

    // Periodic summarization to keep memory manageable
    public async Task SummarizeOldConversationsAsync(DateTime olderThan)
    {
        var oldConversations = await _vectorStore.FindByDateRangeAsync(
            endDate: olderThan);

        foreach (var conv in oldConversations)
        {
            // Generate summary using LLM
            var summary = await _llm.GenerateAsync($@"
                Summarize this conversation, preserving key facts and entities:

                {conv.FullText}

                Summary:");

            // Update document with summary while keeping original
            await _vectorStore.UpdateAsync(
                id: conv.Id,
                additionalMetadata: new Dictionary<string, object>
                {
                    ["summary"] = summary,
                    ["summarized_at"] = DateTime.UtcNow.ToString("O")
                }
            );
        }
    }
}

为何如此强大?

  1. 无限内存范围 @-#多年前的谈话与昨天一样畅通。
  2. 语义搜索 @-@ " @George @'_sspeces @MS K3}即使以"#Geoge@'}处方眼罩要求"保存,
  3. 实体连接 所有提及 " @George@"}的谈话都连接到
  4. 隐私@- @ preserve @- 能够执行 per-用户记忆隔离
  5. 成本:- --Summarization在保持可搜索性的同时防止储存爆炸

Dise:中真实的 --world 例子

DISE 使用此方法来提醒@ : @

  • 工具引用 从几个月前开始, @(}What works {,} 什么是失败的_)
  • 代码模式 在以往项目中取得成功的项目
  • 用户首喜欢 在先前对话中确立
  • 域知识 随时间累积的累计

这创造了一个 AI 系统, 从每次互动中真正建立 "learns" 并构建机构记忆@, 而不是从每场会议开始更新_.}

需要考虑的挑战:

  1. 隐私隐私权@: 旧对话必须适当隔离每个用户
  2. 相关性衰减并非所有旧信息都保持相关
  3. 储存费用*: 比额表需要总结战略
  4. 一致性: 保持摘要与原件一致
  5. 检索精度: 平衡最近和历史重要背景

此技术将RAG从 @ " @ 搜索我的文档@ MS K1} 转换为 @ I" @ remember everything we'_ 曾经讨论过的一切...

不使用 RAG 时

RAG is'}不是总能解答的 .}这里*'}当它避免时*: *

普通知识问题

  • 法国首都何为法国首都?
  • RAG 增加延迟和成本,无益

创用CC BY-SA 2.

  • 诗歌 @,#虚构_,}集思广益
  • RAG通过以现有案文为基础限制创造力

@ 3. @ real @ -}时间数据需求

  • 现时运动分数
  • 由API整合服务更好 @,不是RAG

4.数学推理

  • "计算@15%在 @$83.47"上提示
  • LLMs 能够提供计算@; @RAG does'}t help

非常小的知识库

  • 如果您的知识基础符合上下文窗口中的内容 ,}只要包含全部
  • 对于 5 文档来说, RAG 管理费是'}值不值得的 。

当控制LLM '训练时

  • 如果你能从零开始在您的数据上 训练一个模型 , fell-"也许更好些
  • RAG 最好使用您不做 '\ t控制的预@ - @ 训练型号

开始使用RAG:}一个实用指南

想要建立您自己的 RAG system @ ? @ 这里# MS K1 @ 一步_ - @ by @ MPK3} 步进方式@ MSC4 @

“1:”周开始简单

目标#: 获得基本检索功能,无 LLM.

// 1. Choose an embedding service (start with API for simplicity)
var openAI = new OpenAIClient(apiKey);

// 2. Embed a few test documents
var docs = new[]
{
    "Docker is a containerization platform",
    "Kubernetes orchestrates containers",
    "Entity Framework is an ORM for .NET"
};

var embeddings = new List<float[]>();
foreach (var doc in docs)
{
    var response = await openAI.GetEmbeddingsAsync(
        new EmbeddingsOptions("text-embedding-3-small", new[] { doc })
    );
    embeddings.Add(response.Value.Data[0].Embedding.ToArray());
}

// 3. Implement basic search (in-memory for now)
var query = "container orchestration";
var queryEmbedding = await GetEmbeddingAsync(query);

var results = embeddings
    .Select((emb, idx) => new
    {
        Text = docs[idx],
        Score = CosineSimilarity(queryEmbedding, emb)
    })
    .OrderByDescending(r => r.Score)
    .ToList();

// 4. Verify search works
foreach (var result in results)
{
    Console.WriteLine($"{result.Score:F3}: {result.Text}");
}
// Expected: Kubernetes scores highest

添加矢量数据库

目标#: 缩放到真实的文档收藏@ . @

实施下一步措施

  1. 在嵌入器中运行 Qdrant
  2. 您的文档索引
  3. 执行搜索端点

I'Lall在即将发表的关于矢量数据库的文章中详细论述这一点*.

+LLM 生成

目标#: 完成RAG管道.

// 1. Retrieve context
var context = await SearchAsync(query, limit: 3);

// 2. Build prompt
var prompt = $@"
    Answer the question using this context:

    {FormatContext(context)}

    Question: {query}

    Answer:";

// 3. Generate (start with API)
var response = await openAI.GetChatCompletionsAsync(new ChatCompletionsOptions
{
    Messages =
    {
        new ChatMessage(ChatRole.System, "You are a helpful assistant."),
        new ChatMessage(ChatRole.User, prompt)
    },
    Temperature = 0.7f,
    MaxTokens = 500
});

return response.Value.Choices[0].Message.Content;

最佳和波兰语周@4:

  • 在 API 成本上添加 caching @ ( @ saave@ ) @
  • 改进填布战略
  • 添加元数据过滤
  • 执行混合搜索
  • 添加引证提取

前往本地@ ( @ optional @ MS K1

一旦基本知识发挥作用, , 迁移到本地的推论中 @(I' 将在即将推出的文章中提及此事@):

  • 本地LLM与GPU加速度的推导
  • CPU-用 ONNX 嵌入 运行时间

结论结论

RAG (Retrieval-Auged Generation)是一种强大的技术,可以使LLMs更加准确,}更新@-to}-DMS K6通过以实际文件作为答复依据来令人信服_.而不是仅仅依靠模型='培训数据>,RAG systems

  1. 检索 利用语义搜索从知识库获得的相关信息
  2. 增加额 LLM's 与检索的上下文同步
  3. 生成生成 以有引文的实际来源为依据的答复

RAG:的主要优势

  • 继续更新您的知识库@) @
  • 以源头为基点的“(”减少幻觉 “)”
  • 可解释的 @(_can 引用来源@)
  • 无昂贵的再培训 )
  • 私密性@ - @ preservation @ MS K1 @ can 完全本地运行@ I) @
  • 使用您自己的文档@) @%

何时使用 RAG: @

  • Known - 密集任务
  • 经常更新信息
  • 私有的/ - 专有数据
  • 需要引证和可审计性
  • 成本和简单问题

何时避免RAG:

  • 一般知识问题
  • 创意写作
  • 实时--时间数据 @ (_ 使用 APIs 代替@ MS K2
  • 非常小的知识基础

随着HYDE, multive-query recreactionMS K2和上下文压缩,等先进技术的开发,该字段正在迅速发展,但核心概念仍然简单:使LLMs能够在正确的时间访问正确的信息*.

开始简单@, @ 测量结果@ , @ 和迭代.} RAG 是今天建立可靠的AI系统最实际的方法之一 @ MS K3 @

从理论到生产

您现在完成了 3-部分RAG系列:

第一部分:起源和基本

  • ARAG是什么以及它为何重要
  • 从关键字搜索到语义理解的历史
  • RAG 与 fine @-}调制,}长环_,}和其他方法

建筑和内部

  • 完整 RAG 管道: 索引MS K1 recreating, 生成
  • LLM 内存@ : @ massigns @ MS K1} kV 缓存 *, 上下文窗口
  • 附有C#代码的技术实施细节

本篇文章 )

  • 真实-世界执行@(相关职位 @,语义搜索},写作助理_)
  • 共同的挑战与解决方案 @(_chunking@,}嵌入质量#,}幻觉=)
  • 高级技术 @(HyDE,Self}-ueryMS K3多-_hery,上下文压缩@,Long{-Text memoryMPK8
  • 不使用 RAG 时
  • 获取启动指南

你现在有完整的图片了 : 从了解RAG'的起源到建立具有先进优化度的生产系统

什么是' 下一步 @?

现在,你从理论到实践都了解RAG+,# 即将发表的文章将展示您如何在 C#:}建立完整的RAG系统

很快会到来

  • CPU-友好语义搜索 - 建立语义搜索與 ONNX 嵌入, 在沒有 GPU 要求的 VPS 上运行
  • 自动-主矢量数据库 - 使用 Docker, 包括索引的Qdrant 完整设置指南@, search @,和优化策略
  • 建造一名RAG书写助理 @- 有关创建 AI-+#powered写作助理的完整系列, 该助手使用您现有的内容作为知识库

这些文章将引领你从理论到实践 ,,

执行指南,将RAG知识转化为工作系统=!

资源资源资源 资源和资源资源资源

基础文件

工具与框架@: @%

继续读取@: @%

本RAG系列 :

幸福的建筑

logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.