基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
AIHT
内容
精选全部 AI 动态热点榜AI 日报收藏
分类
模型行业编程产品技术观点开源
更多
Agent 接入
返回首页开发者导航
AIHT
精选 / 资讯详情
8.0
热点
AI SCORE
技术实践2026-10-23 23:39

用 C# 串起生产级 RAG 的关键环节

dev.to · AI#RAG#点NET#检索优化
Editor brief · 编辑速览

教程覆盖 .NET RAG 从文档解析、OCR、分块到混合检索、重排序、上下文压缩、缓存与评测的完整链路。为各项技术提供 C# 示例,并讨论 GraphRAG、纠错式 RAG 等方案何时值得投入。

文章思维导图
Knowledge map
拖拽缩放
AI deep read

AI 深度解读

RAG 做到「切块、生成向量、检索、交给模型回答」之后,为什么还是会答错?作者把问题拆到了更靠前的位置:文档有没有解析对,索引有没有及时更新,权限有没有跟着变化。高级 RAG 的起点,是查清失败发生在哪一层。

原文列出了混合检索、重排、GraphRAG 等完整路线,但提供的内容在 HTML 解析代码开头截断。这里能展开判断的,是文档摄取与解析;后续技术只有路线说明,没有足够实现和评测证据。

先修哪一层,要由失败样本决定

基础 RAG 的流程很短:提取文本、切块、生成 embedding、做 top-k 向量检索,再把结果放进提示词并验证回答。面对干净文档和简单问题,它已经可能够用。

问题出在真实资料上。扫描 PDF 没有文本层,表格的含义依赖行列关系,网页混着导航和广告,用户的问题又可能模糊、多段、依赖对话历史。此时换一个生成模型,未必能修好证据缺失。

作者给出的扩展路线包含查询改写与扩展、关键词加向量的混合检索、Reciprocal Rank Fusion(RRF)、cross-encoder 重排、父子块检索、上下文压缩,以及证据不足时的纠正与重试。每项技术都对应某类故障,也会增加延迟、token、摄取费用或维护复杂度。

先诊断,再增加技术,是这篇最有价值的原则。

原文把第 19 节 benchmarking 放在决策中心:先建基线,测出失败,再加一种技术并重测。不过,当前材料没有给出评测集、对照结果或收益数字。它是一份工程方法指南,不能据此认定某种组合效果最好。

知识库入库,为什么需要一条数据流水线

作者把摄取流程拆成来源检测、原始文件暂存、解析、清洗与补充元数据、切块、生成向量、写入索引和登记状态。重点是让知识库能够持续维护。

例如,同一文件反复提交,索引状态应该一致;文件内容没变,就不该再次消耗 OCR 和 embedding 费用;源文档删除后,旧块也必须删除,否则系统还会引用已经下线的资料。

为此,登记表需要记录内容 hash、解析器版本、切块器版本、embedding 模型、状态和错误。原始文件与中间结果也应保留,便于重新切块时复用,避免重复下载和 OCR。

示例通过统一数据模型隔离文件格式,让下游切块只依赖 ParsedDocument:

public enum ElementType { Title, Heading, Paragraph, ListItem, Table, Code, Image, Header, Footer }

public record DocumentElement(
    ElementType Type, string Text, int Level = 0, int? Page = null,
    IReadOnlyDictionary<string, string>? Attributes = null);

public record ParsedDocument(
    string DocId, string Source, string Title, string Language,
    IReadOnlyList<DocumentElement> Elements, IReadOnlyDictionary<string, string> Metadata);

public record DocumentContext(string DocId, string Source, string FileName, string ContentType, int TenantId, IReadOnlyList<string> AclGroups);

public interface IDocumentParser
{
    bool CanParse(string contentType, string fileName);
    Task<ParsedDocument> ParseAsync(Stream content, DocumentContext context, CancellationToken ct);
}

public record Chunk(
    string Id, string DocId, int Index, string Text, string SectionPath, int? Page,
    string? ParentId = null, string? PrevId = null, string? NextId = null);

public interface IChunker { IReadOnlyList<Chunk> Chunk(ParsedDocument document); }

关键看 IChunker 的入参:它接收统一文档,而不是 PDF 或 Word 文件流。新增格式主要改解析器,调整切块策略也不用重写文件读取逻辑。页码、章节路径、父子关系和相邻块关系,则为引用定位及后续扩展上下文留了位置。

编排示例使用 Microsoft.Extensions.AI 的 IEmbeddingGenerator,模型为 text-embedding-3-small,流水线版本为 parse-3/chunk-5,每批 BatchSize = 64。它把 SectionPath 和正文一起送入 GenerateAsync,让短段落获得章节语境。这些都是示例配置,没有证据表明适合所有语料。

运行层面,作者要求限制并发,避免压垮 OCR 和 embedding 服务;单份坏文件单独标记失败;摄取放在后台队列中执行。权限变更则更新已有块的 ACL 字段,无需重新生成向量。

文档能读出来,不代表适合检索

解析质量决定了检索能拿到什么证据。

PDF 的难点在于,它保存的是页面上字形的位置,不天然具备段落语义。PdfPig 能辅助提取文本,但多栏阅读顺序、重复页眉页脚和表格仍需处理。原文建议复杂版式考虑 Azure AI Document Intelligence 的 layout 模型;扫描件则需要 OCR。当前材料没有展开 OCR 实现。

Word 有更明确的结构,DocumentFormat.OpenXml 可以读取标题、段落、列表和表格。但标题样式不能只靠 Heading1 判断,本地化模板和自定义样式可能不同,还需解析样式显示名,并用大纲级别兜底。修订、批注、脚注是否保留,也要先制定规则,尤其要避免把内部批注直接送入知识库。

Excel 需要先判断用途。政策表、目录、价格表适合按记录检索;「按地区汇总收入」属于计算任务,作者建议使用 SQL 或受治理的数据查询工具。

表格进 RAG 时,每行都应带上列名和工作表名。示例使用 ClosedXML,通过 GetFormattedString() 读取显示值,并把一行改写成带字段名的文本。它假定已用区域的首行就是表头,实际还需处理多行表头、合并单元格、隐藏行以及公式缓存。示例中的价格 499、生效日期 2025-01-01,只是说明记录格式,不是业务结论。

HTML 则要优先提取 <main>、<article>,清除导航、页脚、广告等模板内容,同时保留标题层级、代码块和表格。否则每页重复的导航文字也会进入向量,干扰召回。

安全问题贯穿这些格式:白底白字、隐藏工作表、HTML 隐藏元素都可能夹带提示注入。作者要求按文件字节识别格式,限制文件大小、页数和解压体积,并把提取内容视为不可信数据。清理隐藏文字只是其中一步。

我的判断

我赞同作者把重点放在数据质量和索引维护上。对于团队文档问答,权限过期、源文件删除后仍可检索、表格丢失列名,都是具体且可检查的问题,比直接增加一层 agent 更容易确定改动是否有效。

但代码应当作为结构示意。作者也明确说明,示例省略了生产所需的错误处理、重试和遥测,相关库与服务 API 要按安装版本验证。

还有一个实现细节需要补齐:示例用内容 hash 配合 parse-3/chunk-5 判断是否重处理,清理旧块时却只按 keepContentHash 保留当前版本。同一内容只更换切块器时,hash 不变;如果新旧块并存,这个条件不足以识别旧块。实际设计应把流水线版本或索引代次纳入清理规则。

「先写新块,再删旧块」能减少文档短暂搜不到的窗口,但两次独立操作不能保证真正的原子切换。原文提出的蓝绿索引加别名切换,更适合模型或 schema 的整体迁移。

至于自建还是托管,作者给出了 Azure AI Search indexers、integrated vectorization 等替代方案。普通需求可以用托管能力减少运维;需要特殊结构切块、自定义补充信息或多存储索引时,自建才更有理由。原文没有成本和质量对照,这仍是经验判断。

能拿来做什么

  • 为现有文档问答整理一组真实失败问题,逐条检查是解析遗漏、切块断句、检索漏召回,还是生成阶段忽略证据,再决定改哪一层。
  • 在 Node 或 .NET 的摄取服务中保留标题、页码、表头和来源位置,同时记录内容 hash 与处理版本,让资料能够重建、追溯和迁移。
  • 给团队知识库补上删除同步与权限更新机制,并验证旧文档撤回后不能继续被引用,权限变更能够传递到已有索引块。
  • 遇到 Excel 问答时,先区分查记录和做统计;记录检索保留字段名,需要聚合计算的请求交给受控查询工具。
Original source

本文由 AI 通读原文后重新编写,观点部分为站内判断,细节以原文为准,来源 dev.to · AI,原文版权归原作者所有。

阅读原文
上一篇
用 TypeScript 与 MCP 搭建销售分析助手
下一篇
伪造审批如何击穿多 Agent 付款限制

资讯速览

dev.to · AI · 2026-10-23 23:39

AI 评分 8.0 / 10

相关标签

#RAG#点NET#检索优化

继续阅读

  • 购物 Agent 的正确性不能只验支付
  • 用 TypeScript 与 MCP 搭建销售分析助手
  • 伪造审批如何击穿多 Agent 付款限制
  • MCP 连不上?按固定顺序定位故障
  • 用GitLab标签驱动Agent分析与开发