smart_rag 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +252 -0
  3. data/.rspec +2 -0
  4. data/AGENTS.md +33 -0
  5. data/API_DOCUMENTATION.md +828 -0
  6. data/CHANGELOG.md +11 -1
  7. data/ER-diagram.mmd +144 -0
  8. data/Gemfile +50 -0
  9. data/Gemfile.lock +381 -0
  10. data/Hybrid_Reranking.md +171 -0
  11. data/README.en.md +420 -28
  12. data/README.md +534 -63
  13. data/Rakefile +268 -0
  14. data/SETUP_GUIDE.md +650 -0
  15. data/SmartChunking.md +180 -0
  16. data/USAGE_EXAMPLES.md +1002 -0
  17. data/config/llm_config.yml +4 -2
  18. data/config/smart_rag.yml +45 -1
  19. data/config.ru +15 -0
  20. data/db/migrations/006_create_text_search_configs.rb +3 -2
  21. data/db/migrations/008_create_embeddings.rb +5 -4
  22. data/db/migrations/012_add_metadata_to_source_sections.rb +11 -0
  23. data/db/migrations/013_create_media_jobs.rb +25 -0
  24. data/db/migrations/014_add_media_job_operations_indexes.rb +11 -0
  25. data/db/migrations/015_add_media_leases_and_objects.rb +80 -0
  26. data/db/migrations/016_add_document_principals_and_staging_references.rb +38 -0
  27. data/db/migrations/017_add_media_job_request_fingerprint.rb +48 -0
  28. data/db/seeds/text_search_configs.sql +3 -3
  29. data/design.md +1057 -0
  30. data/docs/API_DOCUMENTATION.md +838 -0
  31. data/docs/DOCUMENTATION_INDEX.en.md +60 -0
  32. data/docs/DOCUMENTATION_INDEX.md +65 -0
  33. data/docs/FIX_SUMMARY.md +256 -0
  34. data/docs/FIX_SUMMARY_COMPLETE.md +273 -0
  35. data/docs/Hybrid_Reranking.md +171 -0
  36. data/docs/MIGRATION_GUIDE.md +151 -0
  37. data/docs/PERFORMANCE_GUIDE.md +58 -0
  38. data/docs/SETUP_GUIDE.md +659 -0
  39. data/docs/SmartChunking.md +180 -0
  40. data/docs/USAGE_EXAMPLES.md +1008 -0
  41. data/docs/design.md +1057 -0
  42. data/docs/evidence_pack.md +211 -0
  43. data/docs/requirements.md +376 -0
  44. data/docs/retrieval_plan.md +251 -0
  45. data/docs/smartrag_improvement_plan.md +201 -0
  46. data/docs/smartrag_refactor.md +216 -0
  47. data/docs/todo.md +931 -0
  48. data/examples/common.rb +1 -1
  49. data/exe/smart-rag-db +163 -0
  50. data/exe/smart-rag-media-worker +34 -0
  51. data/lib/smart_rag/config.rb +12 -0
  52. data/lib/smart_rag/core/document_processor.rb +80 -16
  53. data/lib/smart_rag/core/local_content_store.rb +51 -0
  54. data/lib/smart_rag/core/media_extractors.rb +140 -0
  55. data/lib/smart_rag/core/media_job_queue.rb +353 -0
  56. data/lib/smart_rag/core/media_metadata_extractor.rb +188 -0
  57. data/lib/smart_rag/core/media_object_registry.rb +79 -0
  58. data/lib/smart_rag/core/media_processor.rb +228 -0
  59. data/lib/smart_rag/core/media_safety_policy.rb +61 -0
  60. data/lib/smart_rag/core/s3_content_store.rb +78 -0
  61. data/lib/smart_rag/core/transcript_normalizer.rb +44 -0
  62. data/lib/smart_rag/core/video_semantic_extractor.rb +130 -0
  63. data/lib/smart_rag/http_access_policy.rb +86 -0
  64. data/lib/smart_rag/http_app.rb +188 -0
  65. data/lib/smart_rag/models/embedding.rb +1 -1
  66. data/lib/smart_rag/models/research_topic.rb +1 -1
  67. data/lib/smart_rag/models/research_topic_section.rb +5 -0
  68. data/lib/smart_rag/models/research_topic_tag.rb +5 -0
  69. data/lib/smart_rag/models/search_log.rb +1 -1
  70. data/lib/smart_rag/models/section_fts.rb +5 -0
  71. data/lib/smart_rag/models/section_tag.rb +5 -0
  72. data/lib/smart_rag/models/source_document.rb +1 -1
  73. data/lib/smart_rag/models/source_section.rb +1 -1
  74. data/lib/smart_rag/models/tag.rb +1 -1
  75. data/lib/smart_rag/models/text_search_config.rb +5 -0
  76. data/lib/smart_rag/retrieve.rb +72 -1
  77. data/lib/smart_rag/services/embedding_service.rb +1 -1
  78. data/lib/smart_rag/services/fulltext_search_service.rb +11 -13
  79. data/lib/smart_rag/services/hybrid_search_service.rb +15 -11
  80. data/lib/smart_rag/services/summarization_service.rb +1 -1
  81. data/lib/smart_rag/services/tag_service.rb +1 -1
  82. data/lib/smart_rag/version.rb +1 -1
  83. data/lib/smart_rag.rb +264 -30
  84. data/patch_language.rb +27 -0
  85. data/requirements.md +376 -0
  86. data/source_documents_export.json +11072 -0
  87. data/todo.md +931 -0
  88. data/workers/analyze_content.rb +6 -2
  89. data/workers/get_embedding.rb +1 -1
  90. metadata +151 -38
@@ -0,0 +1,171 @@
1
+ # RAGFlow 多路召回与重排序(Hybrid Search & Reranking)技术介绍
2
+
3
+ 在 RAGFlow 中,多路召回(Multi-path Retrieval)与重排序(Reranking)技术共同构成了其高精度检索的核心架构,旨在解决单一检索方式在复杂查询下容易出现的“搜不准、搜不全”问题。以下是 2026 年初该技术的详细解读:
4
+
5
+ 1. 多路召回技术:确保“广而全”
6
+
7
+ RAGFlow 采用双路混合检索架构,利用不同维度的“筛子”同时在海量文档中筛选候选结果。
8
+ 全文检索(关键词通路):
9
+ 核心算法:通常基于 BM25 算法。
10
+ 优势:擅长精准匹配缩写、产品型号、专业术语或姓名。例如搜索“R1-750”,全文检索能精准锁定包含该特定编号的文档。
11
+ 向量检索(语义通路):
12
+ 核心算法:利用 Embedding 模型(如 BGE 或 OpenAI 兼容模型)将文本转化为高维向量。
13
+ 优势:理解用户意图,即使问题中没有原词,也能找到意思相近的内容。例如用户问“如何理财”,系统能检索到包含“资产配置”或“储蓄方案”的片段。
14
+ 混合融合(RRF):
15
+ 系统使用 倒数排名融合(Reciprocal Rank Fusion, RRF) 等算法将两路结果合并,初步平衡关键词匹配和语义相关性的得分。
16
+
17
+ 2. 重排序技术:确保“精而准”
18
+
19
+ 多路召回虽然覆盖面广,但往往会混入不相关的噪音。RAGFlow 引入重排序(Reranking)阶段,对初步选出的 Top-K 候选片断进行“二次打分”。
20
+ 级联式重排序策略:
21
+ 交叉编码器(Cross-Encoder):这是重排序的核心模型(如 bge-reranker-v2-m3)。与简单的向量相似度不同,它会将查询(Query)和文档(Document)同时输入模型,捕捉更细微的语义匹配关系。
22
+ 上下文长度优势:截至 2026 年,其主流重排序模型已支持最高 8192 tokens 的上下文,能够处理更长的文档片段而不会丢失关键信息。
23
+ 多模型集成:
24
+ RAGFlow 支持集成多种顶级重排序器,包括 Cohere Rerank、Jina Reranker 以及开源的 BGE 系列。2026 年甚至支持通过 vLLM 托管这些重排序模型以获得更高的推理效率。
25
+
26
+ 3. 技术核心优势
27
+
28
+ 首条命中率提升:通过先“广搜”再“精排”,显著提高了首个召回片段的相关性,这对于 LLM 减少幻觉至关重要。
29
+ 结构化数据亲和:针对 CSV/JSON 等缺乏自然语言语义的结构化数据,多路召回中的关键词通路能补足传统向量检索的短板。
30
+ 可追溯性:重排序后的高分片段会与原文位置绑定,在 UI 界面上直接展示为高亮引用,保证了 AI 回答的“有据可查”。
31
+ 通过这种双引擎驱动 + 深度精排的模式,RAGFlow 能够将检索准确率从初级 RAG 的约 60% 提升至 90% 以上。
32
+
33
+ # 多路召回与重排序设计方案
34
+
35
+ 1) Hybrid Search:多路召回 + 融合
36
+
37
+ - 入口:rag\nlp\search.py 的 Dealer.search()
38
+ - 文本召回:FulltextQueryer.question() 生成 MatchTextExpr(BM25/查询字符串)并扩展同义词与细粒度 token。
39
+ - 参考:rag\nlp\query.py
40
+ - 向量召回:get_vector() 生成 MatchDenseExpr,向量字段命名 q_{dim}_vec。
41
+ - 参考:rag\nlp\search.py
42
+ - 融合:FusionExpr("weighted_sum", {"weights":"0.05,0.95"}),文本/向量权重融合。
43
+ - 参考:rag\nlp\search.py
44
+ - 数据库层执行:
45
+ - OpenSearch:使用 query_string + knn,并用 FusionExpr 的权重调整 boost。
46
+ - 参考:rag\utils\opensearch_conn.py
47
+ - OB/Infinity 等:由连接器实现融合查询与归一化,Infinity 会归一化两路得分,后续无需再 rerank。
48
+ - 参考:rag\nlp\search.py 中 settings.DOC_ENGINE_INFINITY 分支
49
+
50
+ 2) Rerank:两种路径
51
+
52
+ - 内置 rerank(无外部模型):
53
+ - Dealer.rerank() 调用 FulltextQueryer.hybrid_similarity()
54
+ - 得分 = token_similarity * tkweight + vector_similarity * vtweight + rank_feature
55
+ - token_similarity 对内容 tokens + 标题/重要关键词加权(title2,important5,question*6)。
56
+ - 参考:rag\nlp\search.py, rag\nlp\query.py
57
+ - 外部 rerank 模型:
58
+ - Dealer.rerank_by_model() 使用 reranker 输出向量得分,混合 token 相似度。
59
+ - rerank 模型适配统一接口:similarity(query, texts)。
60
+ - 参考:rag\nlp\search.py, rag\llm\rerank_model.py
61
+
62
+ 3) 排序增强:rank_feature(Pagerank / 标签)
63
+
64
+ - rank_feature 引入 pagerank 与标签相关性加权。
65
+ - _rank_feature_scores() 对标签向量与 query 标签做相似度,叠加 pagerank。
66
+ - 参考:rag\nlp\search.py, rag\utils\opensearch_conn.py
67
+
68
+ 4) 流程细节
69
+
70
+ - 再排序池大小:RERANK_LIMIT 固定到 64 的倍数分页,以扩大 rerank 范围。
71
+ - 参考:rag\nlp\search.py
72
+ - 失败回退:如果融合查询结果为空,降低 min_match、提高 similarity threshold 再试。
73
+ - 参考:rag\nlp\search.py
74
+
75
+ Ruby 复刻设计方案(详细)
76
+
77
+ A. 模块划分
78
+
79
+ - HybridSearch::QueryBuilder
80
+ - 构造全文检索查询 + 同义词扩展 + token 权重。
81
+ - 接口:build_text_query(question, min_match) → MatchTextExpr + keywords。
82
+ - 参考:rag\nlp\query.py
83
+ - HybridSearch::Embedding
84
+ - encode_queries(text) → vector
85
+ - 统一向量字段名:q_#{dim}_vec。
86
+ - HybridSearch::Fusion
87
+ - 表示融合策略:weighted_sum,保存权重。
88
+ - 参考:common\doc_store\doc_store_base.py
89
+ - HybridSearch::DocStoreAdapter
90
+ - search(select_fields, filters, match_exprs, order_by, limit, offset, rank_feature)
91
+ - 提供 OpenSearch/PG/OB/自研引擎适配。
92
+ - HybridSearch::Reranker
93
+ - rerank_by_model:外部模型返回相似度。
94
+ - rerank_by_hybrid:token+vector 混合。
95
+ - HybridSearch::Retriever
96
+ - orchestrator:负责 recall → rerank → filtering → pagination。
97
+
98
+ B. 核心数据结构
99
+
100
+ - MatchTextExpr, MatchDenseExpr, FusionExpr(对齐 common\doc_store\doc_store_base.py)
101
+ - SearchResult:total, ids, fields, query_vector, highlight, aggs
102
+
103
+ C. 召回策略(Hybrid Search)
104
+
105
+ 1. 构建全文查询:
106
+ - 英文:词权重 + 词邻近短语(bigram boost)。
107
+ - 中文:分词 + 同义词 + fine-grained token。
108
+ 2. 构建向量查询:q_{dim}_vec + topk + similarity_threshold
109
+ 3. 组装 FusionExpr:默认 "0.05,0.95"(文本/向量)
110
+ 4. 交给 DocStoreAdapter 执行。
111
+
112
+ D. Rerank 策略
113
+
114
+ - 如果配置 rerank_model:
115
+ - score = tkweight * token_similarity + vtweight * model_score + rank_feature
116
+ - 否则:
117
+ - score = tkweight * token_similarity + vtweight * vector_similarity + rank_feature
118
+ - tkweight = 1 - vector_similarity_weight(配置默认 0.3)
119
+ - rank_feature 依赖 pagerank / tag_vector(若存在)。
120
+
121
+ E. 评分细节复刻
122
+
123
+ - token_similarity:
124
+ - 使用 term-weight 计算 query tokens 与 doc tokens 的重合度。
125
+ - doc tokens= content_ltks + title_tks*2 + important_kwd*5 + question_tks*6
126
+ - vector_similarity:
127
+ - cosine similarity of query_vector vs doc_vector。
128
+ - rank_feature:
129
+ - pagerank + 标签向量相似度(可按需求保留)。
130
+
131
+ F. 分页与 rerank pool
132
+
133
+ - 先取大范围 RERANK_LIMIT(推荐 64 的倍数)
134
+ - rerank 后再分页
135
+ - 避免直接分页导致 rerank “局部最优”。
136
+
137
+ G. Ruby 伪代码
138
+
139
+ def retrieve(question, page, page_size, topk:, similarity:, vec_weight:, rerank_model: nil)
140
+ text_expr, keywords = QueryBuilder.build_text_query(question, min_match: 0.3)
141
+ dense_expr = Embedding.match_dense(question, topk: topk, similarity: similarity)
142
+
143
+ fusion = FusionExpr.new("weighted_sum", topk, weights: "0.05,0.95")
144
+ match_exprs = [text_expr, dense_expr, fusion]
145
+
146
+ pool = docstore.search(fields, filters, match_exprs, limit: rerank_limit, offset: page_offset)
147
+
148
+ scores = if rerank_model
149
+ Reranker.rerank_by_model(rerank_model, pool, question, tkweight: 1-vec_weight, vtweight: vec_weight)
150
+ else
151
+ Reranker.rerank_by_hybrid(pool, question, tkweight: 1-vec_weight, vtweight: vec_weight)
152
+ end
153
+
154
+ ranked = pool.sort_by { |doc| -scores[doc.id] }
155
+ paginate(ranked, page, page_size)
156
+ end
157
+
158
+ H. 配置参数建议
159
+
160
+ - vector_similarity_weight(默认 0.3)
161
+ - topk(召回池大小)
162
+ - similarity_threshold(向量召回阈值)
163
+ - rerank_model_id(可选)
164
+ - rank_feature(pagerank/tag_fea 权重)
165
+
166
+ 复刻重点与注意事项
167
+
168
+ - 若底层引擎能做融合归一化(类似 Infinity),可跳过自定义 rerank。
169
+ - 参考:rag\nlp\search.py 对 Infinity 的分支判断。
170
+ - 不同引擎的融合实现差异较大(OpenSearch 用 knn + query_string + boost),建议先实现一个“逻辑融合 + 本地 rerank”的通用路径,再做引擎级融合优化。
171
+ - rank_feature(pagerank/tag_fea)是 RAGFlow 的额外增益项,若没有对应特征可直接忽略或留接口。
@@ -0,0 +1,151 @@
1
+ # Migration Guide
2
+
3
+ ## Version Matrix
4
+
5
+ | SmartRAG Version | Notes |
6
+ | --- | --- |
7
+ | 1.0.x | Initial stable APIs |
8
+ | 1.1.x | Return-shape updates |
9
+ | 1.2.x | Search option rename |
10
+ | 1.3.x | Runtime/platform updates |
11
+
12
+ ## Breaking Changes
13
+
14
+ ### 1.1.x
15
+
16
+ - search() method now returns a Hash
17
+ - add_document() return value structure changed
18
+
19
+ ### 1.2.x
20
+
21
+ - alpha parameter renamed to vector_weight
22
+
23
+ ### 1.3.x
24
+
25
+ - Minimum Ruby version increased to 3.3.0
26
+ - PostgreSQL 16+ required
27
+
28
+ ## SQL Migration Examples
29
+
30
+ ```sql
31
+ ALTER TABLE search_logs ADD COLUMN IF NOT EXISTS metadata jsonb;
32
+ ```
33
+
34
+ ```sql
35
+ CREATE INDEX IF NOT EXISTS idx_search_logs_created_at
36
+ ON search_logs (created_at);
37
+ ```
38
+
39
+ ## Coverage
40
+
41
+ - Migration steps for Document Management
42
+ - Migration steps for Search Operations
43
+ - Migration steps for Research Topics
44
+ - Migration steps for Tag Management
45
+ - Migration steps for Hybrid Search
46
+ - Migration steps for Vector Search
47
+ - Migration steps for Full-Text Search
48
+ - Migration steps for Error Handling
49
+ - Migration steps for Performance Optimization
50
+
51
+ ## Retrieval Refactor Migration (2026-02)
52
+
53
+ ### Scope
54
+
55
+ - `retrieve(plan) -> EvidencePack` contract rollout
56
+ - `source_documents` new columns: `source_type/source_uri/content_hash`
57
+ - index governance pipeline: backfill, dedupe, reindex
58
+
59
+ ### Recommended Steps
60
+
61
+ 1. Backup database.
62
+ 2. Run migrations:
63
+
64
+ ```bash
65
+ bundle exec rake db:migrate
66
+ ```
67
+
68
+ 3. Backfill historical documents:
69
+
70
+ ```bash
71
+ bundle exec rake db:backfill_source_fields
72
+ ```
73
+
74
+ Optional dry run:
75
+
76
+ ```bash
77
+ DRY_RUN=1 bundle exec rake db:backfill_source_fields
78
+ ```
79
+
80
+ 4. Run release preparation pipeline:
81
+
82
+ ```bash
83
+ bundle exec rake db:prepare_release
84
+ ```
85
+
86
+ Optional dry run:
87
+
88
+ ```bash
89
+ DRY_RUN=1 bundle exec rake db:prepare_release
90
+ ```
91
+
92
+ 5. Verify:
93
+ - `source_documents.source_type/source_uri/content_hash` populated
94
+ - `retrieve(plan)` returns `explain.filters_applied`
95
+ - `search_logs.filters` contains `plan/stats/explain`
96
+
97
+ ### Rollback Notes
98
+
99
+ - Schema rollback:
100
+
101
+ ```bash
102
+ bundle exec rake db:rollback[1]
103
+ ```
104
+
105
+ - If backfill/dedupe/reindex already ran, restore from database backup for full rollback.
106
+
107
+ ## Media Queue Integrity Migration (015-017, 2026-08)
108
+
109
+ ### Scope
110
+
111
+ - `015_add_media_leases_and_objects`: heartbeat leases, per-principal idempotency keys, object references, and API quota counters.
112
+ - `016_add_document_principals_and_staging_references`: document ownership and an explicit foreign key from retained jobs to staging media objects.
113
+ - `017_add_media_job_request_fingerprint`: canonical request fingerprints used to distinguish a retry from conflicting reuse of an idempotency key.
114
+
115
+ ### Deployment Order
116
+
117
+ 1. Stop media workers and pause asynchronous ingestion. Existing synchronous retrieval may remain online.
118
+ 2. Back up PostgreSQL.
119
+ 3. Run migrations through 017 before deploying the current queue code:
120
+
121
+ ```bash
122
+ bundle exec rake db:migrate
123
+ ```
124
+
125
+ 4. Verify the schema version and required column:
126
+
127
+ ```sql
128
+ SELECT * FROM schema_info;
129
+
130
+ SELECT column_name, is_nullable
131
+ FROM information_schema.columns
132
+ WHERE table_schema = 'public'
133
+ AND table_name = 'media_jobs'
134
+ AND column_name = 'request_fingerprint';
135
+ ```
136
+
137
+ The expected migration version is `17`, and `request_fingerprint.is_nullable` must be `NO`. Migration 017 backfills existing jobs before adding the `NOT NULL` constraint.
138
+
139
+ 5. Deploy the application and worker together, then resume asynchronous ingestion.
140
+ 6. Verify that an identical principal/key/payload returns the original job, while the same principal/key with a different source or options returns HTTP 409 with `code: "idempotency_conflict"`.
141
+
142
+ ### Operational Notes
143
+
144
+ - The fingerprint includes operation, logical source, and recursively canonicalized serializable options. Hash key order and symbol/string keys are normalized; array order is preserved.
145
+ - Different principals may reuse the same idempotency key.
146
+ - Tools that insert directly into `media_jobs` must now supply `request_fingerprint`; normal application code must use `MediaJobQueue#enqueue`.
147
+ - Retained jobs, including failed jobs, protect `staging_media_object_id` from object garbage collection. Pruning the job releases that protection.
148
+
149
+ ### Rollback Notes
150
+
151
+ Rollback across migration 017 requires stopping application and worker processes first. Older code does not write `request_fingerprint`, while current code expects it to exist. Rolling back 016 can also remove staging-object protection and document ownership, so restore the matching application version at the same time. Prefer a forward fix after production jobs have been created under the new schema.
@@ -0,0 +1,58 @@
1
+ # Performance Guide
2
+
3
+ ## Performance Optimization
4
+
5
+ Target latency:
6
+ - P50 < 150ms
7
+ - P95 < 250ms
8
+ - P99 < 500ms
9
+
10
+ ## PostgreSQL Tuning
11
+
12
+ Recommended baseline:
13
+
14
+ ```conf
15
+ shared_buffers = 2GB
16
+ work_mem = 64MB
17
+ maintenance_work_mem = 512MB
18
+ max_connections = 200
19
+ ```
20
+
21
+ Notes:
22
+ - `shared_buffers` can be tuned around 25% of total RAM.
23
+ - OS page cache and related settings can use the remaining 75% of total RAM.
24
+
25
+ ## Indexing Strategies
26
+
27
+ Vector index (IVFFLAT):
28
+
29
+ ```sql
30
+ CREATE INDEX CONCURRENTLY idx_embeddings_ivfflat
31
+ ON embeddings USING ivfflat (vector vector_cosine_ops)
32
+ WITH (lists = 100);
33
+ ```
34
+
35
+ Vector index (HNSW):
36
+
37
+ ```sql
38
+ CREATE INDEX CONCURRENTLY idx_embeddings_hnsw
39
+ ON embeddings USING hnsw (vector vector_cosine_ops);
40
+ ```
41
+
42
+ Full-text index:
43
+
44
+ ```sql
45
+ CREATE INDEX CONCURRENTLY idx_section_fts_content
46
+ ON section_fts USING gin (fts_combined);
47
+ ```
48
+
49
+ ## Related Features
50
+
51
+ - Document Management
52
+ - Search Operations
53
+ - Research Topics
54
+ - Tag Management
55
+ - Hybrid Search
56
+ - Vector Search
57
+ - Full-Text Search
58
+ - Error Handling