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
data/README.md CHANGED
@@ -2,21 +2,65 @@
2
2
 
3
3
  [English README](README.en.md)
4
4
 
5
- SmartRAG 是一个 Ruby 混合检索增强生成(RAG)库,结合向量检索、全文检索与主题/标签管理,用于文档智能检索与问答场景。
5
+ SmartRAG 是一个 Ruby 混合检索增强生成(RAG)库,结合向量检索、全文检索、LLM 总结问答与主题/标签管理,提供从文档导入到智能问答的全链路能力。
6
6
 
7
7
  ## 项目概览
8
8
 
9
- - 混合检索:向量检索 + 全文检索 + 权重融合
10
- - 支持本地文件与 URL 文档导入
11
- - 提供主题与标签管理 API
12
- - 提供搜索日志与系统统计能力
13
- - 内置示例脚本便于快速上手
9
+ SmartRAG 覆盖了 RAG 系统的完整生命周期:
10
+
11
+ - **文档处理**:支持本地文件与 URL 导入,自动格式转换(PDF/DOCX/HTML → Markdown)
12
+ - **智能切块**:基于 Markdown 标题切分 + 自适应大小切分 + 结构检测
13
+ - **向量嵌入**:通过 Ollama 生成文本向量,存储于 PostgreSQL pgvector
14
+ - **全文索引**:PostgreSQL tsvector 全文搜索,中文使用 pg_jieba 分词
15
+ - **混合检索**:向量语义检索 + 全文关键词检索 → RRF 融合 → 重排序
16
+ - **LLM 问答**:基于检索结果生成结构化回答(支持中/英/日/繁体中文)
17
+ - **主题与标签**:LLM 自动生成标签,支持主题组织和关联推荐
18
+ - **运维工具**:索引重建、去重、回填、搜索日志、系统统计
19
+
20
+ ## 架构总览
21
+
22
+ ```
23
+ ┌─────────────────────────────────────────────┐
24
+ │ 用户 API │
25
+ │ SmartRAG::SmartRAG (lib/smart_rag.rb) │
26
+ ├─────────────────────────────────────────────┤
27
+ │ Retrieve 结构化检索 │
28
+ │ SmartRAG::Retrieve (retrieve.rb) │
29
+ ├──────────────┬──────────────┬────────────────┤
30
+ │ Core 层 │ Services 层 │ Chunking 层 │
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 层 (Sequel ORM) │
48
+ │ SourceDocument / SourceSection / Embedding │
49
+ │ Tag / ResearchTopic / SearchLog / SectionFts │
50
+ ├─────────────────────────────────────────────┤
51
+ │ Config 层 (YAML + ERB) │
52
+ │ smart_rag.yml / database.yml / llm_config │
53
+ ├─────────────────────────────────────────────┤
54
+ │ Workers 层 (SmartPrompt) │
55
+ │ get_embedding / analyze_content │
56
+ └─────────────────────────────────────────────┘
57
+ ```
14
58
 
15
59
  ## 默认模型配置
16
60
 
17
61
  当前默认配置为本地 Ollama 兼容端点:
18
62
 
19
- - Embedding 模型:`qwen3-embedding`
63
+ - Embedding 模型:`qwen3-embedding`(4096 维)
20
64
  - 文本 LLM 模型:`qwen3`
21
65
  - Embedding 端点:`http://localhost:11434/v1/embeddings`
22
66
  - LLM 端点:`http://localhost:11434/v1/chat/completions`
@@ -25,109 +69,412 @@ SmartRAG 是一个 Ruby 混合检索增强生成(RAG)库,结合向量检
25
69
 
26
70
  ## 快速开始
27
71
 
28
- ### 1) 安装依赖
72
+ ### 方式 A:安装 gem 使用(推荐)
73
+
74
+ 1) 安装:
29
75
 
30
76
  ```bash
31
- bundle install
77
+ gem install smart_rag
78
+ # 或写入 Gemfile:gem "smart_rag"
32
79
  ```
33
80
 
34
- ### 2) 配置环境变量
81
+ 2) 配置数据库连接(任选其一):
35
82
 
36
- ```bash
37
- cp .env.example .env
38
- ```
83
+ - 复制 `.env.example` 为 `.env` 并填写(库会自动加载 `.env`):
84
+
85
+ ```bash
86
+ cp .env.example .env
87
+ ```
39
88
 
40
- 必填数据库变量:
89
+ - 或直接导出环境变量。必填数据库变量:
41
90
 
42
- - `SMARTRAG_DB_HOST`
43
- - `SMARTRAG_DB_PORT`
44
- - `SMARTRAG_DB_NAME`
45
- - `SMARTRAG_DB_USER`
46
- - `SMARTRAG_DB_PASSWORD`
91
+ - `SMARTRAG_DB_HOST`
92
+ - `SMARTRAG_DB_PORT`
93
+ - `SMARTRAG_DB_NAME`
94
+ - `SMARTRAG_DB_USER`
95
+ - `SMARTRAG_DB_PASSWORD`
47
96
 
48
- ### 3) 初始化数据库
97
+ 3) 初始化数据库(建库、迁移、种子数据):
49
98
 
50
99
  ```bash
51
- bundle exec rake db:create
52
- bundle exec rake db:migrate
53
- bundle exec rake db:seed
100
+ smart-rag-db create
101
+ smart-rag-db migrate
102
+ smart-rag-db seed
103
+ # 或一步到位:smart-rag-db reset
54
104
  ```
55
105
 
56
- ### 4) 导入测试文档(可选)
106
+ 4) 在代码中使用:
57
107
 
58
- ```bash
59
- ruby test/import_doc.rb import
108
+ ```ruby
109
+ require "smart_rag"
110
+
111
+ client = SmartRAG::SmartRAG.new # 读取内置默认配置 + 环境变量
112
+ client.add_document("docs/report.md", generate_embeddings: true)
113
+ results = client.search("机器学习是什么?")
60
114
  ```
61
115
 
62
- ### 5) 运行示例程序
116
+ > 也可显式指定配置:`SmartRAG::SmartRAG.new("config/smart_rag.yml")` 或传入 Hash。完整用法见「API 参考」。
117
+
118
+ ### 方式 B:源码开发
63
119
 
64
120
  ```bash
65
- ruby examples/01_quick_start.rb
66
- ruby examples/03_search_operations.rb
121
+ bundle install
122
+ cp .env.example .env
123
+ bundle exec rake db:create db:migrate db:seed
124
+ ruby test/import_doc.rb import # 可选:导入测试文档
125
+ ruby examples/01_quick_start.rb # 运行示例程序
67
126
  ```
68
127
 
69
- ## 最小调用示例
128
+ 前置依赖见下方「依赖」。
129
+
130
+ ## API 参考
131
+
132
+ ### 初始化
70
133
 
71
134
  ```ruby
72
135
  require "smart_rag"
73
136
 
74
- config = SmartRAG::Config.load("config/smart_rag.yml")
75
- client = SmartRAG::SmartRAG.new(config)
137
+ # 通过配置文件初始化
138
+ client = SmartRAG::SmartRAG.new("config/smart_rag.yml")
139
+
140
+ # 或通过 Hash 配置
141
+ client = SmartRAG::SmartRAG.new({
142
+ database: {
143
+ adapter: "postgresql",
144
+ host: "localhost",
145
+ database: "smart_rag_development",
146
+ user: "rag_user",
147
+ password: "your_password"
148
+ }
149
+ })
150
+ ```
151
+
152
+ ### 知识库管理
153
+
154
+ | 方法 | 说明 | 返回值 |
155
+ |---|---|---|
156
+ | `add_document(path, options)` | 导入文档(本地文件或 URL) | `{ document_id:, section_count:, status: }` |
157
+ | `remove_document(id)` | 删除文档及关联段落/向量 | `{ success:, deleted_sections:, deleted_embeddings: }` |
158
+ | `get_document(id)` | 获取文档详情 | `{ id:, title:, description:, section_count:, metadata: }` |
159
+ | `list_documents(options)` | 分页列表,支持 title 搜索 | `{ documents:, total_count:, page:, per_page:, total_pages: }` |
160
+
161
+ ```ruby
162
+ # 添加文档并自动生成向量
163
+ client.add_document("docs/report.md", generate_embeddings: true)
76
164
 
77
- client.add_document("test/python_basics.md", generate_embeddings: true)
78
- results = client.search("机器学习是什么?", search_type: "hybrid", limit: 5)
165
+ # URL 导入
166
+ client.add_document("https://example.com/article.pdf")
79
167
 
80
- puts results[:results].map { |r| r[:section_title] }
168
+ # 分页查询
169
+ client.list_documents(page: 1, per_page: 10, search: "Python")
81
170
  ```
82
171
 
83
- ## 开发常用命令
172
+ ### 搜索(核心)
84
173
 
85
- - `bundle exec rspec`:运行 RSpec 测试
86
- - `ruby test/test_rag.rb`:运行端到端测试脚本
87
- - `bundle exec rake db:reset`:重建数据库
88
- - `gem build smart_rag.gemspec`:构建 gem 包
174
+ SmartRAG 提供三种搜索模式:**hybrid**(混合,默认)、**vector**(向量)、**fulltext**(全文)。
175
+
176
+ ```ruby
177
+ # 统一搜索入口
178
+ results = client.search("机器学习是什么?",
179
+ search_type: "hybrid", # hybrid | vector | fulltext
180
+ limit: 5,
181
+ language: :zh_cn, # :zh_cn | :en | :ja | 自动检测
182
+ alpha: 0.7, # 向量权重 (0.0-1.0),仅 hybrid 有效
183
+ include_content: true,
184
+ include_metadata: true,
185
+ generate_tags: false, # 是否用 LLM 从查询中生成标签
186
+ document_ids: [1, 2], # 限定文档范围
187
+ tags: ["AI", "机器学习"] # 标签过滤/加权
188
+ )
189
+
190
+ # 单独使用各搜索模式
191
+ client.vector_search("神经网络架构", limit: 5)
192
+ client.fulltext_search('"deep reinforcement learning"', limit: 5)
193
+ client.hybrid_search("AI应用", language: :zh_cn)
194
+ ```
89
195
 
90
- ## 运维命令(发布前)
196
+ #### 混合搜索流程
91
197
 
92
- 标准发布前步骤(推荐):
198
+ ```
199
+ 用户查询
200
+
201
+ ① 语言检测(中/日/英)
202
+
203
+ ② 可选:LLM 生成查询标签
204
+
205
+ ③ 生成查询向量
206
+
207
+ ④ 并行:向量搜索 + 全文搜索
208
+
209
+ ⑤ RRF 融合(Reciprocal Rank Fusion, k=60)
210
+
211
+ ⑥ 重排序(rerank_limit=64)
212
+
213
+ ⑦ 领域加权 + 类别多样性优化
214
+
215
+ ⑧ 返回结果
216
+ ```
93
217
 
94
- 1. 迁移数据库
218
+ **RRF 融合权重**:向量 0.6 / 全文 0.4(可在 `config/fulltext_search.yml` 调整)。
95
219
 
96
- ```bash
97
- bundle exec rake db:migrate
220
+ #### 多语言支持
221
+
222
+ | 语言 | 全文搜索配置 | 分词方式 |
223
+ |---|---|---|
224
+ | 英文 | `pg_catalog.english` | stemming |
225
+ | 中文 | `jieba` | pg_jieba 分词 |
226
+ | 日文 | `pg_catalog.simple` | 基础分词 |
227
+ | 韩文 | `pg_catalog.simple` | 基础分词 |
228
+
229
+ ### 结构化检索(SmartBrain 集成)
230
+
231
+ ```ruby
232
+ plan = {
233
+ queries: [
234
+ { text: "machine learning basics", mode: "semantic", weight: 1.0 },
235
+ { text: "deep neural networks", mode: "keyword", weight: 0.8 }
236
+ ],
237
+ budget: {
238
+ candidate_k: 200,
239
+ per_mode_k: { semantic: 30, keyword: 20 }
240
+ },
241
+ ranking: {
242
+ rerank: { enabled: true }
243
+ }
244
+ }
245
+
246
+ evidence_pack = client.retrieve(plan: plan)
247
+ # 返回 EvidencePack 格式:{ evidences:, stats:, explain:, warnings: }
98
248
  ```
99
249
 
100
- 2. 回填历史数据字段(`source_type/source_uri/content_hash`)
250
+ ### 标签管理
101
251
 
102
- ```bash
103
- bundle exec rake db:backfill_source_fields
252
+ ```ruby
253
+ # LLM 自动生成标签
254
+ result = client.generate_tags("这是一段关于深度学习和神经网络的文本...",
255
+ max_tags: 10
256
+ )
257
+ # => { content_tags: ["深度学习", "神经网络"], category_tags: ["AI"] }
258
+
259
+ # 分页查询标签
260
+ client.list_tags(page: 1, per_page: 20, search: "AI")
104
261
  ```
105
262
 
106
- 3. 执行一键检索发布准备(backfill -> dedupe -> reindex)
263
+ ### 主题管理
107
264
 
108
- ```bash
109
- bundle exec rake db:prepare_release
265
+ ```ruby
266
+ # 创建主题
267
+ client.create_topic("AI 研究",
268
+ description: "人工智能相关研究主题",
269
+ tags: ["AI", "机器学习"],
270
+ document_ids: [1, 3]
271
+ )
272
+
273
+ # 查询主题
274
+ client.get_topic(1)
275
+ client.list_topics(page: 1, per_page: 20, search: "AI")
276
+
277
+ # 更新主题
278
+ client.update_topic(1, title: "人工智能研究", tags: ["AI", "深度学习"])
279
+
280
+ # 删除主题
281
+ client.delete_topic(1)
282
+
283
+ # 文档与主题关联
284
+ client.add_document_to_topic(topic_id: 1, document_id: 5)
285
+ client.remove_document_from_topic(topic_id: 1, document_id: 5)
286
+
287
+ # 主题推荐(基于标签共现)
288
+ client.get_topic_recommendations(1, limit: 5)
110
289
  ```
111
290
 
112
- 仅预演(不写入):
291
+ ### 系统运维
113
292
 
114
- ```bash
115
- DRY_RUN=1 bundle exec rake db:backfill_source_fields
116
- DRY_RUN=1 bundle exec rake db:prepare_release
293
+ | 方法 | 说明 |
294
+ |---|---|
295
+ | `statistics` | 系统统计(文档/段落/主题/标签/向量数量) |
296
+ | `search_logs(limit:, search_type:)` | 查询搜索历史记录 |
297
+ | `rebuild_fts(document_id)` | 重建全文索引(不传参=全量) |
298
+ | `rebuild_embeddings(document_id)` | 重建向量嵌入(不传参=全量) |
299
+ | `reindex(document_id)` | 一键重建 FTS + 向量 |
300
+ | `dedupe_by_content_hash` | 按内容哈希去重重复文档 |
301
+ | `backfill_source_fields(dry_run:)` | 回填 source_uri/source_type/content_hash 字段 |
302
+ | `prepare_release_indexes(dry_run:)` | 发布前准备:backfill → dedupe → reindex |
303
+
304
+ ```ruby
305
+ # 系统统计
306
+ stats = client.statistics
307
+ # => { document_count:, section_count:, topic_count:, tag_count:, embedding_count: }
308
+
309
+ # 搜索日志
310
+ client.search_logs(limit: 50, search_type: "hybrid")
311
+
312
+ # 预演发布准备(不写入)
313
+ client.prepare_release_indexes(dry_run: true)
314
+
315
+ # 执行发布准备
316
+ client.prepare_release_indexes
317
+ ```
318
+
319
+ ## 文档处理管线
320
+
321
+ ```
322
+ URL / 文件路径
323
+
324
+ ① 下载(支持 301/302 重定向)
325
+
326
+ ② 提取元数据(大小、类型、时间)
327
+
328
+ ③ 格式转换(Markitdown: PDF/DOCX/HTML → Markdown)
329
+
330
+ ④ 创建 SourceDocument 记录
331
+
332
+ ⑤ 智能切块(Markdown 标题切分 → 超限大小切分)
333
+
334
+ ⑥ 存储 SourceSection 记录
335
+
336
+ ⑦ 可选:生成 Embedding + Tag
337
+
338
+ ⑧ 标记文档状态为 completed
339
+ ```
340
+
341
+ 支持的输入格式:`.md` / `.txt` / `.pdf` / `.docx` / `.html`
342
+
343
+ ### 切块策略
344
+
345
+ - **MarkdownChunker**(默认):按 H1-H3 标题切分,超限段落再按字符数拆分
346
+ - **SmartChunking**(高级):结构检测 + 文档类型感知(法规/书籍/论文/手册),基于 token 合并
347
+
348
+ 配置项(`config/smart_rag.yml`):
349
+
350
+ ```yaml
351
+ chunking:
352
+ max_chars: 4000 # 最大块字符数
353
+ overlap: 100 # 块间重叠字符数
354
+ split_by_headers: true # 优先按标题切分
355
+ min_chunk_size: 100 # 最小块大小
117
356
  ```
118
357
 
358
+ ## 数据模型
359
+
360
+ | 模型 | 表名 | 用途 |
361
+ |---|---|---|
362
+ | `SourceDocument` | `source_documents` | 文档元数据(标题、作者、来源类型、状态) |
363
+ | `SourceSection` | `source_sections` | 文档分段(标题、序号、内容、语言) |
364
+ | `Embedding` | `embeddings` | pgvector 向量存储 |
365
+ | `Tag` | `tags` | 标签(支持层级 parent_id) |
366
+ | `SectionTag` | `section_tags` | 段落到标签的多对多关联 |
367
+ | `ResearchTopic` | `research_topics` | 研究主题 |
368
+ | `ResearchTopicSection` | `research_topic_sections` | 主题到段落的关联 |
369
+ | `ResearchTopicTag` | `research_topic_tags` | 主题到标签的关联 |
370
+ | `SearchLog` | `search_logs` | 搜索记录(查询、耗时、结果数) |
371
+ | `SectionFts` | `section_fts` | 全文搜索物化视图 |
372
+
373
+ ## 依赖
374
+
375
+ Ruby 运行时依赖由 gem 自动安装(见 `smart_rag.gemspec`),包括 Sequel、pg、SmartPrompt、concurrent-ruby、dotenv、rack、puma、aws-sdk-s3 等。
376
+
377
+ 还需自行准备的外部服务/工具:
378
+
379
+ - **Ruby** >= 2.7
380
+ - **PostgreSQL** + `pgvector` 扩展 + `pg_jieba` 扩展(中文分词,可选;未安装时中文退回 `simple` 分词)
381
+ - **Python 3** + `markitdown`(仅在导入 PDF/DOCX/HTML 等需要格式转换的文档时必需):
382
+
383
+ ```bash
384
+ pip install markitdown
385
+ ```
386
+
387
+ - 向量嵌入与 LLM 端点(默认指向本地 Ollama,见「默认模型配置」)
388
+
389
+ ## 配置参考
390
+
391
+ 主要配置文件:
392
+
393
+ | 文件 | 用途 |
394
+ |---|---|
395
+ | `config/smart_rag.yml` | 主配置(数据库、嵌入、搜索、切块、LLM、日志) |
396
+ | `config/database.yml` | 多环境数据库配置 |
397
+ | `config/llm_config.yml` | LLM 适配器配置(Ollama / SiliconFlow 等) |
398
+ | `config/fulltext_search.yml` | 全文搜索详细配置(语言、索引、性能) |
399
+
400
+ 关键环境变量:
401
+
402
+ | 变量 | 默认值 | 说明 |
403
+ |---|---|---|
404
+ | `SMARTRAG_DB_NAME` | `smart_rag_development` | 数据库名 |
405
+ | `SMARTRAG_DB_USER` | `rag_user` | 数据库用户 |
406
+ | `SMARTRAG_DB_PASSWORD` | - | 数据库密码 |
407
+ | `EMBEDDING_MODEL` | `qwen3-embedding` | 嵌入模型 |
408
+ | `EMBEDDING_DIMENSIONS` | `4096` | 向量维度 |
409
+ | `LLM_MODEL` | `qwen3` | LLM 模型 |
410
+ | `DEFAULT_LANGUAGE` | `en` | 默认语言 |
411
+ | `ENABLE_JIEBA` | `true` | 启用中文分词 |
412
+
119
413
  ## 目录结构
120
414
 
121
415
  ```text
122
416
  lib/
123
- smart_rag.rb # 主 API 入口
124
- smart_rag/core/ # 核心处理逻辑
125
- smart_rag/services/ # 搜索/标签/嵌入服务
126
- config/ # 运行时配置
127
- db/ # 迁移与种子 SQL
128
- examples/ # 示例代码
129
- test/ # 手工/E2E 脚本与样例文档
130
- spec/ # RSpec 测试
417
+ smart_rag.rb # 主 API 入口(SmartRAG::SmartRAG 类)
418
+ smart_rag/config.rb # 配置加载(YAML + ERB)
419
+ smart_rag/version.rb # 版本号
420
+ smart_rag/errors.rb # 自定义异常类
421
+ smart_rag/retrieve.rb # 结构化检索(RetrievalPlan → EvidencePack)
422
+ smart_rag/models.rb # 模型加载和连接管理
423
+ smart_rag/models/ # Sequel ORM 模型(11 张表)
424
+ smart_rag/core/ # 核心处理逻辑
425
+ query_processor.rb # 查询处理器(搜索 + 问答)
426
+ document_processor.rb # 文档处理器(导入 + 切块 + 存储)
427
+ embedding.rb # 向量嵌入底层操作
428
+ fulltext_manager.rb # 全文索引管理
429
+ markitdown_bridge.rb # 文档格式转换桥接
430
+ smart_rag/services/ # 服务层
431
+ embedding_service.rb # 嵌入服务(CRUD + 批量)
432
+ vector_search_service.rb # 向量检索服务
433
+ fulltext_search_service.rb # 全文检索服务
434
+ hybrid_search_service.rb # 混合检索服务(RRF + 重排序)
435
+ summarization_service.rb # LLM 总结问答服务
436
+ tag_service.rb # 标签生成和管理服务
437
+ smart_rag/chunker/ # 切块器
438
+ markdown_chunker.rb # Markdown 标题切分
439
+ smart_rag/smart_chunking/ # 高级智能切块
440
+ pipeline.rb / parser.rb # 结构检测 + 类型感知切块
441
+ merger.rb / tokenizer.rb # Token 合并策略
442
+ smart_rag/parsers/ # 解析器
443
+ query_parser.rb # 查询解析
444
+ config/ # 运行时配置
445
+ db/ # 数据库迁移和种子 SQL
446
+ examples/ # 示例代码(6 个场景)
447
+ test/ # E2E 测试脚本 + 测试文档
448
+ spec/ # RSpec 测试
449
+ workers/ # SmartPrompt worker 定义
450
+ ```
451
+
452
+ ## 开发常用命令
453
+
454
+ ```bash
455
+ # 运行测试
456
+ bundle exec rspec # RSpec 单元/集成测试
457
+ SMARTRAG_LIVE_SPECS=1 bundle exec rspec spec/documentation # 真实模型文档示例
458
+ ruby test/test_rag.rb # E2E 测试脚本
459
+
460
+ # 数据库操作
461
+ bundle exec rake db:create # 创建数据库
462
+ bundle exec rake db:migrate # 运行迁移
463
+ bundle exec rake db:seed # 导入种子数据
464
+ bundle exec rake db:reset # 重建数据库
465
+
466
+ # 运维操作
467
+ bundle exec rake db:backfill_source_fields # 回填字段
468
+ bundle exec rake db:prepare_release # 发布前准备
469
+
470
+ # 构建
471
+ gem build smart_rag.gemspec # 构建 gem 包
472
+
473
+ # 导入测试文档
474
+ ruby test/import_doc.rb import
475
+
476
+ # 重建嵌入
477
+ ruby test/reembed_all.rb
131
478
  ```
132
479
 
133
480
  ## 文档导航
@@ -135,6 +482,18 @@ spec/ # RSpec 测试
135
482
  完整文档清单、阅读顺序和维护建议见 `docs/DOCUMENTATION_INDEX.md`。
136
483
  英文版见 `docs/DOCUMENTATION_INDEX.en.md`。
137
484
 
485
+ 其他重要文档:
486
+
487
+ - `docs/design.md` — 系统设计文档
488
+ - `docs/API_DOCUMENTATION.md` — API 详细文档
489
+ - `docs/SETUP_GUIDE.md` — 环境搭建指南
490
+ - `docs/USAGE_EXAMPLES.md` — 使用示例
491
+ - `docs/Hybrid_Reranking.md` — 混合检索与重排序说明
492
+ - `docs/SmartChunking.md` — 智能切块说明
493
+ - `docs/MIGRATION_GUIDE.md` — 迁移指南
494
+ - `docs/PERFORMANCE_GUIDE.md` — 性能优化指南
495
+ - `ER-diagram.mmd` — ER 图
496
+
138
497
  ## 说明
139
498
 
140
499
  - 部分历史文档仍保留旧默认值(如 OpenAI 示例)。运行时配置以 `config/smart_rag.yml` 为准。
@@ -142,3 +501,115 @@ spec/ # RSpec 测试
142
501
  ## 许可证
143
502
 
144
503
  MIT
504
+ # Media HTTP API
505
+
506
+ SmartRAG exposes a small Rack-compatible app for retrieval and media ingestion:
507
+
508
+ ```ruby
509
+ require 'smart_rag'
510
+ require 'smart_rag/http_app'
511
+
512
+ rag = SmartRAG::SmartRAG.new(config)
513
+ app = SmartRAG::HttpApp.new(
514
+ rag: rag,
515
+ extractors: {
516
+ audio_transcriber: audio_transcriber,
517
+ video_transcriber: video_transcriber,
518
+ image_describer: image_describer,
519
+ frame_describer: frame_describer,
520
+ ocr_extractor: ocr_extractor
521
+ }
522
+ )
523
+ ```
524
+
525
+ Endpoints:
526
+
527
+ - `POST /v1/retrieve`: JSON `{ "plan": { ... } }`
528
+ - `POST /v1/media`: JSON URL import or multipart fields `operation`, `options`, `file`
529
+ - `POST /v1/media` with `options.async=true`: queue the import and return HTTP 202
530
+ - `GET /v1/media/jobs?status=failed&limit=20&offset=0`: list and filter jobs
531
+ - `GET /v1/media/jobs/:id`: inspect queued, processing, completed, partial, or failed state
532
+ - `POST /v1/media/jobs/:id/cancel`: cancel a queued job
533
+ - `POST /v1/media/jobs/:id/retry`: manually retry a failed job
534
+ - `GET /v1/media/jobs/stats`: queue counts, oldest queued age, and stale processing count
535
+ - `GET /healthz`
536
+
537
+ Start the bundled Rack entrypoint with a Rack server such as Puma:
538
+
539
+ ```bash
540
+ SMARTRAG_CONFIG_PATH=config/smart_rag.yml bundle exec puma -p 9393 config.ru
541
+ ```
542
+
543
+ Allowed operations are `add_document`, `add_media`, `add_image`, `add_audio`, and `add_video`. Extractor objects are server-side configuration and are never accepted from HTTP payloads.
544
+
545
+ Run migration `013_create_media_jobs`, then start a worker with:
546
+
547
+ ```bash
548
+ bundle exec smart-rag-media-worker
549
+ # For cron or one-shot processing:
550
+ bundle exec smart-rag-media-worker --once --batch-size 20
551
+ ```
552
+
553
+ The `media` section in `config/smart_rag.yml` configures file/duration limits, URL allowlists, command timeouts, the optional local content-addressed store, OpenAI-compatible vision/transcription, Tesseract OCR, and job retry count. Asynchronous multipart uploads are copied to `SMARTRAG_MEDIA_JOB_UPLOAD_DIR`. Completed/canceled uploads are removed immediately; failed uploads remain available for manual retry until terminal jobs are pruned.
554
+
555
+ On startup the worker requeues `processing` jobs older than `MEDIA_JOB_STALE_AFTER_SECONDS`. Once per hour it removes terminal jobs older than `MEDIA_JOB_RETENTION_SECONDS` (defaults: 15 minutes and 7 days). `/healthz` includes the same queue statistics as the stats endpoint, making backlog and expired worker leases observable without inspecting PostgreSQL directly.
556
+
557
+ ## Media P3 production controls
558
+
559
+ Migration `015_add_media_leases_and_objects` adds worker heartbeat leases, per-principal idempotency, S3/MinIO storage, reference-counted object cleanup, and optional HTTP authentication/quotas.
560
+
561
+ Migration `016_add_document_principals_and_staging_references` is the data-integrity follow-up. It protects retained failed-job staging objects with an explicit foreign key, makes failed synchronous imports discoverable by object GC, and adds principal ownership to documents. Authenticated retrieval, document reads/lists/deletion, and statistics are owner-scoped; direct embedded calls remain global unless a `principal:` is supplied.
562
+
563
+ Run all migrations through `017_add_media_job_request_fingerprint` before deploying the current queue code. Migration 017 backfills a canonical SHA-256 request fingerprint for existing jobs and makes the new column required.
564
+
565
+ Send `Idempotency-Key` with an asynchronous import to make retries safe. Keys are isolated by authenticated principal. Reusing a key with the same operation, source, and canonicalized options returns the original job with `deduplicated: true`; reusing it with a different payload returns HTTP `409` with `code: "idempotency_conflict"`. Nested hash key order and symbol/string keys do not change the fingerprint, while array order remains significant. Workers update `heartbeat_at` while extraction is running, so long videos are not requeued merely because their original `started_at` is old.
566
+
567
+ For S3 or MinIO:
568
+
569
+ ```bash
570
+ MEDIA_CONTENT_STORE_ENABLED=true
571
+ MEDIA_CONTENT_STORE_PROVIDER=s3
572
+ MEDIA_S3_BUCKET=smart-rag-media
573
+ MEDIA_S3_REGION=us-east-1
574
+ MEDIA_S3_ENDPOINT=http://minio:9000 # omit for AWS S3
575
+ MEDIA_S3_FORCE_PATH_STYLE=true # usually required by MinIO
576
+ MEDIA_S3_ACCESS_KEY_ID=...
577
+ MEDIA_S3_SECRET_ACCESS_KEY=...
578
+ ```
579
+
580
+ `aws-sdk-s3` is a runtime dependency and is loaded only when the S3 provider is selected. Stored objects are tracked in `media_objects` and `media_object_references`; deleting a document releases its reference, and the worker removes zero-reference objects during hourly garbage collection. Retained jobs, including failed jobs, protect their staging objects from garbage collection until the job is pruned.
581
+
582
+ Enable Bearer authentication and PostgreSQL-backed quotas with:
583
+
584
+ ```bash
585
+ SMARTRAG_HTTP_AUTH_ENABLED=true
586
+ SMARTRAG_HTTP_PRINCIPAL=production-agent
587
+ SMARTRAG_HTTP_TOKEN=replace-with-a-secret
588
+ SMARTRAG_REQUESTS_PER_MINUTE=120
589
+ SMARTRAG_UPLOAD_BYTES_PER_DAY=10737418240
590
+ ```
591
+
592
+ All endpoints except `/healthz` then require `Authorization: Bearer ...`. Job reads and mutations are scoped to the authenticated principal. Retrieval also injects the authenticated principal, limits backend search to owned document IDs, and rechecks every returned candidate against PostgreSQL, so a backend that ignores `document_ids` cannot leak another principal's evidence. The current YAML/env entrypoint supports one token; embedded applications can pass a `tokens: { principal => token }` map to `HttpAccessPolicy` for multiple callers.
593
+
594
+ ### Real storage and isolation verification
595
+
596
+ The MinIO integration spec is opt-in because it performs real object writes and deletes. Start MinIO, create or allow creation of the configured bucket, load the PostgreSQL test environment, and run:
597
+
598
+ ```bash
599
+ SMARTRAG_MINIO_E2E=1 \
600
+ SMARTRAG_MINIO_ENDPOINT=http://127.0.0.1:19000 \
601
+ SMARTRAG_MINIO_BUCKET=smart-rag-e2e \
602
+ SMARTRAG_MINIO_ACCESS_KEY=smart-rag-e2e \
603
+ SMARTRAG_MINIO_SECRET_KEY=smart-rag-e2e-secret \
604
+ bundle exec rspec spec/integration/minio_content_store_spec.rb
605
+ ```
606
+
607
+ This verifies cross-instance upload/materialization, asynchronous worker consumption of an `s3://` staging URI, reference attachment/detachment, real object deletion, and failed-job GC protection. PostgreSQL-backed tenant and idempotency coverage can be run independently with:
608
+
609
+ ```bash
610
+ bundle exec rspec \
611
+ spec/integration/media_tenant_isolation_spec.rb \
612
+ spec/integration/media_p3_spec.rb
613
+ ```
614
+
615
+ Those specs cover Bearer-token HTTP retrieval isolation, invalid-token `401`, same-payload deduplication, different-payload `409`, and concurrent inserts racing on the same principal/key.