smart_rag 0.1.0 → 0.2.1

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 +16 -1
  7. data/ER-diagram.mmd +144 -0
  8. data/Gemfile +50 -0
  9. data/Gemfile.lock +398 -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 的额外增益项,若没有对应特征可直接忽略或留接口。
data/README.en.md CHANGED
@@ -2,21 +2,65 @@
2
2
 
3
3
  [中文 README](README.md)
4
4
 
5
- SmartRAG is a Ruby-based hybrid RAG library that combines vector retrieval, full-text search, and topic/tag organization for document intelligence workflows.
5
+ SmartRAG is a Ruby-based hybrid Retrieval-Augmented Generation (RAG) library that combines vector retrieval, full-text search, LLM-powered Q&A summarization, and topic/tag management covering the full pipeline from document ingestion to intelligent question answering.
6
6
 
7
7
  ## Overview
8
8
 
9
- - Hybrid retrieval: vector + full-text + weighted fusion
10
- - Document ingestion from local files and URLs
11
- - Topic and tag management APIs
12
- - Search logs and system statistics
13
- - Runnable example scripts for quick onboarding
9
+ SmartRAG covers the complete RAG lifecycle:
10
+
11
+ - **Document Processing**: local files and URL import with automatic format conversion (PDF/DOCX/HTML → Markdown)
12
+ - **Smart Chunking**: Markdown heading-based splitting + adaptive size splitting + structure detection
13
+ - **Vector Embedding**: text embeddings via Ollama, stored in PostgreSQL pgvector
14
+ - **Full-Text Indexing**: PostgreSQL tsvector search, Chinese segmented with pg_jieba
15
+ - **Hybrid Retrieval**: vector semantic search + full-text keyword search → RRF fusion → reranking
16
+ - **LLM Q&A**: structured answers from search results (supports EN/ZH/JA/Traditional Chinese)
17
+ - **Topics & Tags**: LLM-generated tags, topic organization and association recommendations
18
+ - **Operations Tooling**: index rebuild, deduplication, backfill, search logs, system statistics
19
+
20
+ ## Architecture
21
+
22
+ ```
23
+ ┌─────────────────────────────────────────────┐
24
+ │ Public API │
25
+ │ SmartRAG::SmartRAG (lib/smart_rag.rb) │
26
+ ├─────────────────────────────────────────────┤
27
+ │ Retrieve Structured Retrieval │
28
+ │ SmartRAG::Retrieve (retrieve.rb) │
29
+ ├──────────────┬──────────────┬────────────────┤
30
+ │ Core Layer │ Services Layer│ Chunking Layer │
31
+ │ │ │ │
32
+ │ Query │ Hybrid │ Markdown │
33
+ │ Processor │ Search Svc │ Chunker │
34
+ │ │ │ │
35
+ │ Document │ Embedding │ Smart │
36
+ │ Processor │ Service │ Chunking │
37
+ │ │ │ │
38
+ │ Embedding │ Fulltext │ │
39
+ │ (Core) │ Search Svc │ │
40
+ │ │ │ │
41
+ │ Fulltext │ Tag │ │
42
+ │ Manager │ Service │ │
43
+ │ │ │ │
44
+ │ │ Summarization │ │
45
+ │ │ Service │ │
46
+ ├──────────────┴──────────────┴────────────────┤
47
+ │ Models Layer (Sequel ORM) │
48
+ │ SourceDocument / SourceSection / Embedding │
49
+ │ Tag / ResearchTopic / SearchLog / SectionFts │
50
+ ├─────────────────────────────────────────────┤
51
+ │ Config Layer (YAML + ERB) │
52
+ │ smart_rag.yml / database.yml / llm_config │
53
+ ├─────────────────────────────────────────────┤
54
+ │ Workers Layer (SmartPrompt) │
55
+ │ get_embedding / analyze_content │
56
+ └─────────────────────────────────────────────┘
57
+ ```
14
58
 
15
59
  ## Default Model Setup
16
60
 
17
61
  Current defaults use local Ollama-compatible endpoints:
18
62
 
19
- - Embedding model: `qwen3-embedding`
63
+ - Embedding model: `qwen3-embedding` (1024 dimensions)
20
64
  - Text LLM model: `qwen3`
21
65
  - Embedding endpoint: `http://localhost:11434/v1/embeddings`
22
66
  - LLM endpoint: `http://localhost:11434/v1/chat/completions`
@@ -66,49 +110,397 @@ ruby examples/01_quick_start.rb
66
110
  ruby examples/03_search_operations.rb
67
111
  ```
68
112
 
69
- ## Minimal Usage
113
+ ## API Reference
114
+
115
+ ### Initialization
70
116
 
71
117
  ```ruby
72
118
  require "smart_rag"
73
119
 
74
- config = SmartRAG::Config.load("config/smart_rag.yml")
75
- client = SmartRAG::SmartRAG.new(config)
120
+ # From a config file
121
+ client = SmartRAG::SmartRAG.new("config/smart_rag.yml")
122
+
123
+ # Or from a Hash
124
+ client = SmartRAG::SmartRAG.new({
125
+ database: {
126
+ adapter: "postgresql",
127
+ host: "localhost",
128
+ database: "smart_rag_development",
129
+ user: "rag_user",
130
+ password: "your_password"
131
+ }
132
+ })
133
+ ```
134
+
135
+ ### Knowledge Base Management
136
+
137
+ | Method | Description | Returns |
138
+ |---|---|---|
139
+ | `add_document(path, options)` | Import a document (local file or URL) | `{ document_id:, section_count:, status: }` |
140
+ | `remove_document(id)` | Delete a document with all sections/embeddings | `{ success:, deleted_sections:, deleted_embeddings: }` |
141
+ | `get_document(id)` | Get document details | `{ id:, title:, description:, section_count:, metadata: }` |
142
+ | `list_documents(options)` | Paginated listing with title search | `{ documents:, total_count:, page:, per_page:, total_pages: }` |
143
+
144
+ ```ruby
145
+ # Import and auto-generate embeddings
146
+ client.add_document("docs/report.md", generate_embeddings: true)
76
147
 
77
- client.add_document("test/python_basics.md", generate_embeddings: true)
78
- results = client.search("What is machine learning?", search_type: "hybrid", limit: 5)
148
+ # Import from URL
149
+ client.add_document("https://example.com/article.pdf")
79
150
 
80
- puts results[:results].map { |r| r[:section_title] }
151
+ # Paginated listing
152
+ client.list_documents(page: 1, per_page: 10, search: "Python")
81
153
  ```
82
154
 
83
- ## Development Commands
155
+ ### Search (Core)
156
+
157
+ SmartRAG provides three search modes: **hybrid** (default), **vector**, and **fulltext**.
158
+
159
+ ```ruby
160
+ # Unified search entry point
161
+ results = client.search("What is machine learning?",
162
+ search_type: "hybrid", # hybrid | vector | fulltext
163
+ limit: 5,
164
+ language: :en, # :en | :zh_cn | :ja | auto-detect
165
+ alpha: 0.7, # vector weight (0.0-1.0), hybrid only
166
+ include_content: true,
167
+ include_metadata: true,
168
+ generate_tags: false, # use LLM to generate tags from query
169
+ document_ids: [1, 2], # restrict to specific documents
170
+ tags: ["AI", "ML"] # tag filtering/boosting
171
+ )
172
+
173
+ # Individual search modes
174
+ client.vector_search("neural network architectures", limit: 5)
175
+ client.fulltext_search('"deep reinforcement learning"', limit: 5)
176
+ client.hybrid_search("AI applications", language: :en)
177
+ ```
178
+
179
+ #### Hybrid Search Pipeline
180
+
181
+ ```
182
+ User Query
183
+
184
+ ① Language Detection (EN/ZH/JA)
185
+
186
+ ② Optional: LLM query tag generation
187
+
188
+ ③ Query vector embedding
189
+
190
+ ④ Parallel: vector search + full-text search
191
+
192
+ ⑤ RRF Fusion (Reciprocal Rank Fusion, k=60)
193
+
194
+ ⑥ Reranking (rerank_limit=64)
195
+
196
+ ⑦ Domain boosting + category diversity
197
+
198
+ ⑧ Return results
199
+ ```
200
+
201
+ **RRF weights**: vector 0.6 / fulltext 0.4 (adjustable in `config/fulltext_search.yml`).
202
+
203
+ #### Multilingual Support
204
+
205
+ | Language | FTS Configuration | Tokenizer |
206
+ |---|---|---|
207
+ | English | `pg_catalog.english` | stemming |
208
+ | Chinese | `jieba` | pg_jieba segmentation |
209
+ | Japanese | `pg_catalog.simple` | basic |
210
+ | Korean | `pg_catalog.simple` | basic |
211
+
212
+ ### Structured Retrieval (SmartBrain Integration)
213
+
214
+ ```ruby
215
+ plan = {
216
+ queries: [
217
+ { text: "machine learning basics", mode: "semantic", weight: 1.0 },
218
+ { text: "deep neural networks", mode: "keyword", weight: 0.8 }
219
+ ],
220
+ budget: {
221
+ candidate_k: 200,
222
+ per_mode_k: { semantic: 30, keyword: 20 }
223
+ },
224
+ ranking: {
225
+ rerank: { enabled: true }
226
+ }
227
+ }
228
+
229
+ evidence_pack = client.retrieve(plan: plan)
230
+ # Returns EvidencePack: { evidences:, stats:, explain:, warnings: }
231
+ ```
232
+
233
+ ### Tag Management
234
+
235
+ ```ruby
236
+ # LLM auto-generate tags
237
+ result = client.generate_tags("This is a text about deep learning and neural networks...",
238
+ max_tags: 10
239
+ )
240
+ # => { content_tags: ["deep learning", "neural networks"], category_tags: ["AI"] }
241
+
242
+ # Paginated tag listing
243
+ client.list_tags(page: 1, per_page: 20, search: "AI")
244
+ ```
245
+
246
+ ### Topic Management
247
+
248
+ ```ruby
249
+ # Create topic
250
+ client.create_topic("AI Research",
251
+ description: "Artificial intelligence research topics",
252
+ tags: ["AI", "Machine Learning"],
253
+ document_ids: [1, 3]
254
+ )
255
+
256
+ # Query topics
257
+ client.get_topic(1)
258
+ client.list_topics(page: 1, per_page: 20, search: "AI")
259
+
260
+ # Update topic
261
+ client.update_topic(1, title: "Artificial Intelligence Research", tags: ["AI", "DL"])
262
+
263
+ # Delete topic
264
+ client.delete_topic(1)
265
+
266
+ # Document-topic association
267
+ client.add_document_to_topic(topic_id: 1, document_id: 5)
268
+ client.remove_document_from_topic(topic_id: 1, document_id: 5)
269
+
270
+ # Topic recommendations (based on tag co-occurrence)
271
+ client.get_topic_recommendations(1, limit: 5)
272
+ ```
273
+
274
+ ### System Operations
275
+
276
+ | Method | Description |
277
+ |---|---|
278
+ | `statistics` | System stats (documents/sections/topics/tags/embeddings count) |
279
+ | `search_logs(limit:, search_type:)` | Query search history |
280
+ | `rebuild_fts(document_id)` | Rebuild full-text indexes (omit for all) |
281
+ | `rebuild_embeddings(document_id)` | Rebuild vector embeddings (omit for all) |
282
+ | `reindex(document_id)` | Rebuild both FTS + embeddings |
283
+ | `dedupe_by_content_hash` | Deduplicate documents by content hash |
284
+ | `backfill_source_fields(dry_run:)` | Backfill source_uri/source_type/content_hash fields |
285
+ | `prepare_release_indexes(dry_run:)` | Pre-release pipeline: backfill → dedupe → reindex |
84
286
 
85
- - `bundle exec rspec`: run RSpec tests
86
- - `ruby test/test_rag.rb`: run E2E script
87
- - `bundle exec rake db:reset`: recreate database
88
- - `gem build smart_rag.gemspec`: build gem package
287
+ ```ruby
288
+ # System statistics
289
+ stats = client.statistics
290
+ # => { document_count:, section_count:, topic_count:, tag_count:, embedding_count: }
291
+
292
+ # Search logs
293
+ client.search_logs(limit: 50, search_type: "hybrid")
294
+
295
+ # Dry run release prep
296
+ client.prepare_release_indexes(dry_run: true)
297
+
298
+ # Execute release prep
299
+ client.prepare_release_indexes
300
+ ```
301
+
302
+ ## Document Processing Pipeline
303
+
304
+ ```
305
+ URL / file path
306
+
307
+ ① Download (with 301/302 redirect support)
308
+
309
+ ② Extract metadata (size, type, timestamp)
310
+
311
+ ③ Format conversion (Markitdown: PDF/DOCX/HTML → Markdown)
312
+
313
+ ④ Create SourceDocument record
314
+
315
+ ⑤ Smart chunking (heading-based → size-based fallback)
316
+
317
+ ⑥ Store SourceSection records
318
+
319
+ ⑦ Optional: generate Embedding + Tag
320
+
321
+ ⑧ Mark document status as completed
322
+ ```
323
+
324
+ Supported input formats: `.md` / `.txt` / `.pdf` / `.docx` / `.html`
325
+
326
+ ### Chunking Strategies
327
+
328
+ - **MarkdownChunker** (default): split by H1-H3 headings, oversized chunks split further by character count
329
+ - **SmartChunking** (advanced): structure detection + document type awareness (laws/books/papers/manuals), token-based merging
330
+
331
+ Configuration (`config/smart_rag.yml`):
332
+
333
+ ```yaml
334
+ chunking:
335
+ max_chars: 4000 # max characters per chunk
336
+ overlap: 100 # character overlap between chunks
337
+ split_by_headers: true # split by markdown headers first
338
+ min_chunk_size: 100 # discard chunks smaller than this
339
+ ```
340
+
341
+ ## Data Model
342
+
343
+ | Model | Table | Purpose |
344
+ |---|---|---|
345
+ | `SourceDocument` | `source_documents` | Document metadata (title, author, source type, state) |
346
+ | `SourceSection` | `source_sections` | Document sections (title, number, content, language) |
347
+ | `Embedding` | `embeddings` | pgvector vector storage |
348
+ | `Tag` | `tags` | Tags (supports hierarchy via parent_id) |
349
+ | `SectionTag` | `section_tags` | Many-to-many: section ↔ tag |
350
+ | `ResearchTopic` | `research_topics` | Research topics |
351
+ | `ResearchTopicSection` | `research_topic_sections` | Topic ↔ section association |
352
+ | `ResearchTopicTag` | `research_topic_tags` | Topic ↔ tag association |
353
+ | `SearchLog` | `search_logs` | Search records (query, duration, result count) |
354
+ | `SectionFts` | `section_fts` | Full-text search materialized view |
355
+
356
+ ## Dependencies
357
+
358
+ - **Ruby** >= 2.7
359
+ - **PostgreSQL** + `pgvector` extension + `pg_jieba` extension
360
+ - **Sequel** ORM
361
+ - **SmartPrompt** gem (LLM abstraction layer)
362
+ - **Nokogiri** / **Markitdown** (document format conversion)
363
+
364
+ ## Configuration Reference
365
+
366
+ Main configuration files:
367
+
368
+ | File | Purpose |
369
+ |---|---|
370
+ | `config/smart_rag.yml` | Main config (database, embedding, search, chunking, LLM, logging) |
371
+ | `config/database.yml` | Multi-environment database config |
372
+ | `config/llm_config.yml` | LLM adapter config (Ollama / SiliconFlow etc.) |
373
+ | `config/fulltext_search.yml` | Full-text search details (languages, indexes, performance) |
374
+
375
+ Key environment variables:
376
+
377
+ | Variable | Default | Description |
378
+ |---|---|---|
379
+ | `SMARTRAG_DB_NAME` | `smart_rag_development` | Database name |
380
+ | `SMARTRAG_DB_USER` | `rag_user` | Database user |
381
+ | `SMARTRAG_DB_PASSWORD` | - | Database password |
382
+ | `EMBEDDING_MODEL` | `qwen3-embedding` | Embedding model |
383
+ | `EMBEDDING_DIMENSIONS` | `1024` | Vector dimensions |
384
+ | `LLM_MODEL` | `qwen3` | LLM model |
385
+ | `DEFAULT_LANGUAGE` | `en` | Default language |
386
+ | `ENABLE_JIEBA` | `true` | Enable Chinese segmentation |
89
387
 
90
388
  ## Project Structure
91
389
 
92
390
  ```text
93
391
  lib/
94
- smart_rag.rb # Main API entry
95
- smart_rag/core/ # Core processing logic
96
- smart_rag/services/ # Search/tag/embedding services
97
- config/ # Runtime config files
98
- db/ # Migrations and seed SQL
99
- examples/ # Example programs
100
- test/ # Manual/E2E scripts + sample docs
101
- spec/ # RSpec tests
392
+ smart_rag.rb # Main API entry (SmartRAG::SmartRAG class)
393
+ smart_rag/config.rb # Config loading (YAML + ERB)
394
+ smart_rag/version.rb # Version
395
+ smart_rag/errors.rb # Custom error classes
396
+ smart_rag/retrieve.rb # Structured retrieval (RetrievalPlan → EvidencePack)
397
+ smart_rag/models.rb # Model loading and connection management
398
+ smart_rag/models/ # Sequel ORM models (10 tables)
399
+ smart_rag/core/ # Core processing logic
400
+ query_processor.rb # Query processor (search + Q&A)
401
+ document_processor.rb # Document processor (import + chunk + store)
402
+ embedding.rb # Low-level embedding operations
403
+ fulltext_manager.rb # Full-text index management
404
+ markitdown_bridge.rb # Document format conversion bridge
405
+ smart_rag/services/ # Service layer
406
+ embedding_service.rb # Embedding service (CRUD + batch)
407
+ vector_search_service.rb # Vector search service
408
+ fulltext_search_service.rb # Full-text search service
409
+ hybrid_search_service.rb # Hybrid search service (RRF + reranking)
410
+ summarization_service.rb # LLM Q&A summarization service
411
+ tag_service.rb # Tag generation and management service
412
+ smart_rag/chunker/ # Chunkers
413
+ markdown_chunker.rb # Markdown heading-based chunker
414
+ smart_rag/smart_chunking/ # Advanced smart chunking
415
+ pipeline.rb / parser.rb # Structure detection + type-aware chunking
416
+ merger.rb / tokenizer.rb # Token merging strategies
417
+ smart_rag/parsers/ # Parsers
418
+ query_parser.rb # Query parser
419
+ config/ # Runtime configuration
420
+ db/ # Database migrations and seed SQL
421
+ examples/ # Example scripts (6 scenarios)
422
+ test/ # E2E test scripts + sample documents
423
+ spec/ # RSpec tests
424
+ workers/ # SmartPrompt worker definitions
425
+ ```
426
+
427
+ ## Development Commands
428
+
429
+ ```bash
430
+ # Run tests
431
+ bundle exec rspec # RSpec unit/integration tests
432
+ SMARTRAG_LIVE_SPECS=1 bundle exec rspec spec/documentation # Live-model documentation examples
433
+ ruby test/test_rag.rb # E2E test script
434
+
435
+ # Database operations
436
+ bundle exec rake db:create # Create database
437
+ bundle exec rake db:migrate # Run migrations
438
+ bundle exec rake db:seed # Seed data
439
+ bundle exec rake db:reset # Recreate database
440
+
441
+ # Operations
442
+ bundle exec rake db:backfill_source_fields # Backfill fields
443
+ bundle exec rake db:prepare_release # Pre-release pipeline
444
+
445
+ # Build
446
+ gem build smart_rag.gemspec # Build gem package
447
+
448
+ # Import test documents
449
+ ruby test/import_doc.rb import
450
+
451
+ # Rebuild embeddings
452
+ ruby test/reembed_all.rb
453
+ ```
454
+
455
+ ## Media Storage, Tenant Isolation, and Idempotency
456
+
457
+ Run database migrations through `017_add_media_job_request_fingerprint` before deploying the current asynchronous media queue. Migrations 015 and 016 add leases, object references, authenticated document ownership, and explicit staging-object protection. Migration 017 backfills and requires a canonical SHA-256 fingerprint for every queued request.
458
+
459
+ For asynchronous `POST /v1/media` requests, send `Idempotency-Key`. Repeating the same operation, source, and canonicalized options for the same authenticated principal returns the original job with `deduplicated: true`. Reusing the key with a different payload returns HTTP `409` and `code: "idempotency_conflict"`. Different principals may use the same key independently.
460
+
461
+ Configure AWS S3 or MinIO with the `MEDIA_CONTENT_STORE_*` and `MEDIA_S3_*` variables documented in `.env.example`. MinIO normally requires `MEDIA_S3_FORCE_PATH_STYLE=true`. The `aws-sdk-s3` runtime dependency is loaded only when the S3 provider is selected. Retained queued, processing, and failed jobs protect their staging objects from garbage collection.
462
+
463
+ When HTTP authentication is enabled, every endpoint except `/healthz` requires a Bearer token. Retrieval is scoped by the authenticated principal at both boundaries: owned document IDs are pushed into search, and returned candidates are rechecked against PostgreSQL before evidence is emitted. Job reads and mutations are scoped the same way.
464
+
465
+ The real MinIO suite is opt-in because it writes and deletes actual objects:
466
+
467
+ ```bash
468
+ SMARTRAG_MINIO_E2E=1 \
469
+ SMARTRAG_MINIO_ENDPOINT=http://127.0.0.1:19000 \
470
+ SMARTRAG_MINIO_BUCKET=smart-rag-e2e \
471
+ SMARTRAG_MINIO_ACCESS_KEY=smart-rag-e2e \
472
+ SMARTRAG_MINIO_SECRET_KEY=smart-rag-e2e-secret \
473
+ bundle exec rspec spec/integration/minio_content_store_spec.rb
474
+ ```
475
+
476
+ It verifies cross-instance storage, asynchronous worker materialization, reference lifecycle, real deletion, and failed-job GC protection. Run the real PostgreSQL HTTP isolation and idempotency checks with:
477
+
478
+ ```bash
479
+ bundle exec rspec \
480
+ spec/integration/media_tenant_isolation_spec.rb \
481
+ spec/integration/media_p3_spec.rb
102
482
  ```
103
483
 
104
484
  ## Documentation Map
105
485
 
106
- See `docs/DOCUMENTATION_INDEX.en.md` for a curated map of all docs, reading order, and maintenance notes.
486
+ See `docs/DOCUMENTATION_INDEX.en.md` for a curated map of all docs, reading order, and maintenance notes.
107
487
  Chinese version: `docs/DOCUMENTATION_INDEX.md`.
108
488
 
489
+ Other key documents:
490
+
491
+ - `docs/design.md` — System design
492
+ - `docs/API_DOCUMENTATION.md` — Detailed API docs
493
+ - `docs/SETUP_GUIDE.md` — Environment setup guide
494
+ - `docs/USAGE_EXAMPLES.md` — Usage examples
495
+ - `docs/Hybrid_Reranking.md` — Hybrid search & reranking details
496
+ - `docs/SmartChunking.md` — Smart chunking details
497
+ - `docs/MIGRATION_GUIDE.md` — Migration guide
498
+ - `docs/PERFORMANCE_GUIDE.md` — Performance optimization guide
499
+ - `ER-diagram.mmd` — ER diagram
500
+
109
501
  ## Notes
110
502
 
111
- - Some legacy docs still contain older defaults (for example OpenAI references). Runtime truth is `config/smart_rag.yml`.
503
+ - Some legacy docs still contain older defaults (e.g. OpenAI references). Runtime truth is `config/smart_rag.yml`.
112
504
 
113
505
  ## License
114
506