[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"public:announcements":3,"footer:categories:zh":4,"public:navigations:zh":132,"post:detail:post-26-RAG检索增强生成:zh":177},[],[5,23,39,55,71,88,103,117],{"id":6,"name":7,"slug":12,"description":13,"icon":18,"color":19,"cover_image":20,"created_at":21,"post_count":22},1,{"en":8,"ja":9,"zh":10,"zh_Hant":11},"Technology","テクノロジー","技术","技術","technology",{"en":14,"ja":15,"zh":16,"zh_Hant":17},"Cutting-edge technology exploration and in-depth analysis covering programming languages, frameworks, and architecture design","プログラミング言語、フレームワーク、アーキテクチャ設計を含む先端技術の探究","前沿技术探索与深度分析，涵盖编程语言、框架、架构设计等核心领域","前沿技術探索與深度分析，涵蓋編程語言、框架、架構設計等核心領域","heroicons:cog-6-tooth","#6366f1",null,"2026-09-30T18:09:53.633610Z",8,{"id":24,"name":25,"slug":29,"description":30,"icon":35,"color":36,"cover_image":20,"created_at":37,"post_count":38},2,{"en":26,"ja":27,"zh":28,"zh_Hant":28},"Tutorial","チュートリアル","教程","tutorial",{"en":31,"ja":32,"zh":33,"zh_Hant":34},"Hands-on tutorials from scratch with clear steps and complete code for developers at all levels","ゼロから始める実践的なチュートリアル。明確な手順と完全なコードで、全てのレベルの開発者に最適","从零开始的实战教程，步骤清晰，代码完整，适合各阶段开发者学习","從零開始的實戰教程，步驟清晰，代碼完整，適合各階段開發者學習","heroicons:academic-cap","#10b981","2026-09-30T18:09:53.641581Z",6,{"id":40,"name":41,"slug":45,"description":46,"icon":51,"color":52,"cover_image":20,"created_at":53,"post_count":54},3,{"en":42,"ja":43,"zh":44,"zh_Hant":44},"Frontend","フロントエンド","前端","frontend",{"en":47,"ja":48,"zh":49,"zh_Hant":50},"Full coverage of web frontend development including Vue, React, new CSS features, and performance optimization","Vue、React、CSSの新機能やパフォーマンス最適化を含むWebフロントエンド開発の全領域","Web前端开发全栈覆盖，包括Vue、React、CSS新特性及性能优化等话题","Web前端開發全棧覆蓋，包括Vue、React、CSS新特性及性能優化等話題","heroicons:computer-desktop","#ec4899","2026-09-30T18:09:53.644838Z",7,{"id":56,"name":57,"slug":62,"description":63,"icon":68,"color":69,"cover_image":20,"created_at":70,"post_count":40},4,{"en":58,"ja":59,"zh":60,"zh_Hant":61},"Backend","バックエンド","后端","後端","backend",{"en":64,"ja":65,"zh":66,"zh_Hant":67},"Server-side development best practices including API design, database optimization, and microservices architecture","API設計、データベース最適化、マイクロサービスアーキテクチャを含むサーバーサイド開発の実践","服务端开发实战经验，API设计、数据库优化、微服务架构等深度内容","服務端開發實戰經驗，API設計、數據庫優化、微服務架構等深度內容","heroicons:server-stack","#f59e0b","2026-09-30T18:09:53.647836Z",{"id":72,"name":73,"slug":78,"description":79,"icon":84,"color":85,"cover_image":20,"created_at":86,"post_count":87},5,{"en":74,"ja":75,"zh":76,"zh_Hant":77},"Fullstack","フルスタック","全栈","全棧","fullstack",{"en":80,"ja":81,"zh":82,"zh_Hant":83},"End-to-end development guides covering the full project lifecycle and technology stack selection","フロントエンドからバックエンドまでの開発プロセス全体をカバーするガイド","从前端到后端的全流程开发指南，覆盖完整项目生命周期与技术选型","從前端到後端的全流程開發指南，覆蓋完整項目生命週期與技術選型","heroicons:swatch","#8b5cf6","2026-09-30T18:09:53.650513Z",0,{"id":38,"name":89,"slug":94,"description":95,"icon":100,"color":101,"cover_image":20,"created_at":102,"post_count":56},{"en":90,"ja":91,"zh":92,"zh_Hant":93},"Essays","エッセイ","随笔","隨筆","essays",{"en":96,"ja":97,"zh":98,"zh_Hant":99},"Technical reflections and development insights recording the programmer's growth journey","プログラマーの成長の軌跡を記録する技術的考察と開発の洞察","技术思考与开发心得分享，记录程序员成长路上的点滴感悟","技術思考與開發心得分享，記錄程序員成長路上的點滴感悟","heroicons:pencil-square","#f43f5e","2026-09-30T18:09:53.653105Z",{"id":54,"name":104,"slug":108,"description":109,"icon":114,"color":115,"cover_image":20,"created_at":116,"post_count":56},{"en":105,"ja":106,"zh":107,"zh_Hant":107},"Tools","ツール","工具","tools",{"en":110,"ja":111,"zh":112,"zh_Hant":113},"Development toolchain and productivity tool recommendations to supercharge your development experience","開発効率を飛躍的に向上させるツールチェーンと生産性ツールの推奨","开发工具链与效率提升利器推荐，让你的开发体验如虎添翼","開發工具鏈與效率提升利器推薦，讓你的開發體驗如虎添翼","heroicons:wrench-screwdriver","#06b6d4","2026-09-30T18:09:53.655605Z",{"id":22,"name":118,"slug":123,"description":124,"icon":129,"color":130,"cover_image":20,"created_at":131,"post_count":87},{"en":119,"ja":120,"zh":121,"zh_Hant":122},"Translation","翻訳","翻译","翻譯","translation",{"en":125,"ja":126,"zh":127,"zh_Hant":128},"Curated translations of high-quality foreign technical articles to keep up with international trends","国際的な技術トレンドを追うための厳選された海外技術記事の翻訳","优质外文技术文章精选翻译，紧跟国际技术前沿动态","優質外文技術文章精選翻譯，緊跟國際技術前沿動態","heroicons:language","#84cc16","2026-09-30T18:09:53.658041Z",[133,144,150,157,164,171],{"id":6,"title":134,"url":139,"icon":20,"parent_id":20,"location":140,"order":6,"is_active":141,"target_blank":142,"created_at":143,"updated_at":20},{"zh":135,"en":136,"ja":137,"zh_TW":138},"首页","Home","ホーム","首頁","\u002F","header",true,false,"2026-09-30T18:09:54.251095Z",{"id":24,"title":145,"url":149,"icon":20,"parent_id":20,"location":140,"order":24,"is_active":141,"target_blank":142,"created_at":143,"updated_at":20},{"zh":146,"en":147,"ja":148,"zh_TW":146},"文章","Posts","記事","\u002Fposts",{"id":40,"title":151,"url":156,"icon":20,"parent_id":20,"location":140,"order":40,"is_active":141,"target_blank":142,"created_at":143,"updated_at":20},{"zh":152,"en":153,"ja":154,"zh_TW":155},"分类","Categories","カテゴリー","分類","\u002Fcategories",{"id":56,"title":158,"url":163,"icon":20,"parent_id":20,"location":140,"order":56,"is_active":141,"target_blank":142,"created_at":143,"updated_at":20},{"zh":159,"en":160,"ja":161,"zh_TW":162},"标签","Tags","タグ","標籤","\u002Ftags",{"id":72,"title":165,"url":170,"icon":20,"parent_id":20,"location":140,"order":72,"is_active":141,"target_blank":142,"created_at":143,"updated_at":20},{"zh":166,"en":167,"ja":168,"zh_TW":169},"关于","About","概要","關於","\u002Fpage\u002Fabout",{"id":38,"title":172,"url":176,"icon":20,"parent_id":20,"location":140,"order":38,"is_active":141,"target_blank":142,"created_at":143,"updated_at":20},{"zh":173,"en":174,"ja":175,"zh_TW":173},"留言板","Guestbook","ゲストブック","\u002Fpage\u002Fguestbook",{"id":178,"title":179,"subtitle":20,"slug":180,"source":181,"source_url":20,"audio":20,"video":20,"video_url":20,"content":182,"excerpt":183,"cover_image":20,"author":184,"category":187,"tags":188,"status":211,"visibility":212,"password":20,"views":213,"likes_count":87,"is_pinned":142,"allow_comments":141,"comments_count":200,"is_password_protected":142,"meta_title":179,"meta_description":183,"meta_keywords":214,"created_at":215,"published_at":215,"updated_at":216,"reading_time":6},26,"RAG 检索增强生成实战：Embedding + Vector DB + ReRank","post-26-RAG检索增强生成","原创","# RAG 检索增强生成实战：Embedding + Vector DB + ReRank\n\n大模型闭卷考试会产生幻觉，RAG（检索增强生成）在生成前先从私有知识库检索最相关 Top-K 段落，再带着上下文答题，是目前让大模型接入企业私有数据最主流、最落地的生产方案。\n\n## 文档分块与向量入库\n\n分块是 RAG 效果的第一道闸门：太小丢上下文，太大污染检索。实际生产通常 200-800 tokens 加 15-20% 重叠窗口；按自然段\u002F标题边界切开比硬切字符效果强很多。用 BGE-M3 \u002F E5-large-v2 这类开源中英双语 Embedding 效果远超 openai-ada-002。\n\n```python\n```python\nfrom __future__ import annotations\nimport json, re\nfrom dataclasses import dataclass\nfrom typing import Iterable\nimport numpy as np\nimport psycopg2.extras\nfrom sentence_transformers import SentenceTransformer, CrossEncoder\n\nCHUNK_SIZE = 512\nCHUNK_OVERLAP = 80\nEMBED_MODEL = \"BAAI\u002Fbge-m3\"\nRERANK_MODEL = \"BAAI\u002Fbge-reranker-v2-m3\"\nTOP_K_RETRIEVAL = 20\nTOP_K_FINAL = 4\n\nembedder = SentenceTransformer(EMBED_MODEL)\nreranker = CrossEncoder(RERANK_MODEL)\n\n@dataclass\nclass Chunk:\n    doc_id: str\n    chunk_idx: int\n    text: str\n    metadata: dict\n\ndef smart_chunk(doc_id: str, text: str, meta: dict | None = None) -> list[Chunk]:\n    paragraphs = re.split(r\"\\n\\s*\\n\", text.strip())\n    chunks: list[Chunk] = []\n    buf, buf_len, idx = [], 0, 0\n    for p in paragraphs:\n        p_len = len(p.split())\n        if buf and buf_len + p_len > CHUNK_SIZE:\n            chunks.append(Chunk(doc_id, idx, \"\\n\\n\".join(buf), meta or {}))\n            idx += 1\n            drop = max(1, len(buf) - (CHUNK_OVERLAP * len(buf) \u002F\u002F max(1, buf_len)))\n            buf, buf_len = buf[drop:], sum(len(b.split()) for b in buf[drop:])\n        buf.append(p); buf_len += p_len\n    if buf: chunks.append(Chunk(doc_id, idx, \"\\n\\n\".join(buf), meta or {}))\n    return chunks\n\ndef pgvector_store(conn, chunks: Iterable[Chunk]) -> None:\n    cur = conn.cursor()\n    cur.execute(\"CREATE EXTENSION IF NOT EXISTS vector\")\n    cur.execute(f\"CREATE TABLE IF NOT EXISTS docs (id BIGSERIAL PRIMARY KEY, doc_id TEXT NOT NULL, chunk_idx INT NOT NULL, content TEXT NOT NULL, metadata JSONB NOT NULL DEFAULT '{{}}'::jsonb, embedding vector(1024) NOT NULL, UNIQUE(doc_id, chunk_idx))\")\n    rows = []\n    for c in chunks:\n        emb = embedder.encode(c.text, normalize_embeddings=True)\n        rows.append((c.doc_id, c.chunk_idx, c.text, json.dumps(c.metadata or {}), psycopg2.extras.Json(emb.tolist())))\n    psycopg2.extras.execute_batch(cur, \"INSERT INTO docs(doc_id, chunk_idx, content, metadata, embedding) VALUES (%s,%s,%s,%s,%s) ON CONFLICT DO NOTHING\", rows)\n    conn.commit()\n\ndef hybrid_search(conn, query: str, top_k: int = TOP_K_RETRIEVAL, category: str | None = None):\n    q_emb = embedder.encode(query, normalize_embeddings=True).tolist()\n    cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)\n    where_sql = \"AND metadata->>'category' = %s\" if category else \"\"\n    params = [q_emb, top_k] + ([category] if category else [])\n    cur.execute(f\"SELECT id, content, metadata, 1 - (embedding \u003C=> %s::vector) AS score FROM docs WHERE true {where_sql} ORDER BY embedding \u003C=> %s::vector LIMIT %s\", params)\n    return [(h[\"content\"], {\"id\": h[\"id\"], \"meta\": dict(h[\"metadata\"]), \"vec_score\": float(h[\"score\"])}) for h in cur.fetchall()]\n\ndef rag_answer(conn, query: str, **filters) -> dict:\n    raw_hits = hybrid_search(conn, query, **filters)\n    if not raw_hits: return {\"answer\": \"抱歉，未找到相关资料。\", \"citations\": []}\n    texts = [h[0] for h in raw_hits]\n    scores = reranker.predict([(query, t) for t in texts], apply_softmax=True)\n    ranked = sorted(zip(scores, raw_hits), reverse=True)[:TOP_K_FINAL]\n    contexts = [f\"[{i+1}] {t[1][0]}\" for i, t in enumerate(ranked)]\n    citations = [{\"id\": t[1][1][\"id\"], \"rerank_score\": float(t[0]), **t[1][1][\"meta\"]} for t in ranked]\n    prompt = f\"基于以下参考资料回答问题，每句结论必须标注引用编号[1]-[{TOP_K_FINAL}]；资料外的内容用'根据所提供资料无法确定'回答。\\n参考资料：\\n{chr(10).join(contexts)}\\n\\n问题：{query}\\n带引用的答案：\"\n    return {\"answer_prompt\": prompt, \"citations\": citations}\n```\n```\n\n## 检索+重排两阶段流水线\n\n向量库 ANN 召回 Top 20-50 保证召回率（不要一开始就取 Top3），再用 CrossEncoder（Reranker）精排到 Top 4 喂给大模型，综合相关性质量提升 20-40%。最终给 Prompt 注入参考资料编号，要求回答强制标注引用编号，可追溯防幻觉。\n\n| 模块 | 朴素方案（Demo） | 生产方案（推荐） | 质量提升 |\n|------|---------------|---------------|---------|\n| 分块 | 硬切 1000 字符 | 自然段边界+512词+15%重叠 | +20-35% |\n| Embedding | openai text-ada-002 | BAAI\u002Fbge-m3 多语言 | +15-25% |\n| 检索 | 向量余弦 Top3 | ANN Top30 + Metadata过滤 | +10-20% |\n| 精修排序 | 不做 | CrossEncoder Reranker | +20-40% |\n| 回答生成 | 直接拼接context | 引用编号强制溯源+拒答兜底 | -40-60%幻觉率 |\n\n## 最佳实践\n\n上线前一定要离线评测：建立 100 条标注问题集（query+期望引用chunk列表），监控 Recall@10\u002FReciprocal Rank\u002FMRR 三个指标。分块策略、模型、Rerank 的每一次改动都要量化对比，不要凭感觉调参。","从零搭建生产级 RAG 系统：文档分块策略（Chunk Size\u002F重叠窗口）、Embedding 模型选型与向量化、向量数据库（PGVector\u002FMilvus）检索过滤、Reranker 重排精修 Top-K，加上引用溯源和 Prompt 压缩优化，附完整可运行代码。",{"id":6,"username":185,"nickname":185,"avatar":20,"cover_image":20,"bio":20,"website":20,"github":20,"avatar_source":20,"resolved_avatar_url":20,"title":20,"created_at":186},"Choyeon","2026-09-30T18:09:53.330367Z",{"id":24,"name":28,"slug":29,"description":33,"icon":35,"color":36,"cover_image":20,"created_at":37,"post_count":87},[189,194,199,205],{"id":6,"name":190,"slug":191,"color":192,"icon":20,"is_active":141,"created_at":193,"post_count":87},"Python","python","#3776ab","2026-09-30T18:09:53.663835Z",{"id":38,"name":195,"slug":196,"color":197,"icon":20,"is_active":141,"created_at":198,"post_count":87},"TypeScript","typescript","#3178c6","2026-09-30T18:09:53.680697Z",{"id":200,"name":201,"slug":202,"color":203,"icon":20,"is_active":141,"created_at":204,"post_count":87},10,"PostgreSQL","postgresql","#336791","2026-09-30T18:09:53.691803Z",{"id":206,"name":207,"slug":208,"color":209,"icon":20,"is_active":141,"created_at":210,"post_count":87},17,"AI","ai","#a855f7","2026-09-30T18:09:53.712868Z","published","public",420,"AI,Python,PostgreSQL,TypeScript","2026-09-22T00:09:53.733462Z","2026-10-01T10:32:42.325973Z"]