Spaces:
Paused
Paused
lanny xu
commited on
Commit
·
28dc898
1
Parent(s):
8da7c51
delete urls
Browse files- BATCH_FREEZE_FIX.md +0 -395
- DEPLOYMENT_GUIDE.md +0 -440
- GRAPHRAG_GUIDE.md +0 -401
- GRAPHRAG_INTEGRATION_SUMMARY.md +0 -427
- GRAPHRAG_TROUBLESHOOTING.md +0 -328
- KAGGLE_DATASET_GUIDE.md +0 -478
- KAGGLE_INIT.py +0 -148
- KAGGLE_OLLAMA_PERSISTENCE.md +0 -404
- KAGGLE_OPTIMIZATION_GUIDE.md +0 -367
- TIMEOUT_QUICK_FIX_CN.md +0 -324
BATCH_FREEZE_FIX.md
DELETED
|
@@ -1,395 +0,0 @@
|
|
| 1 |
-
# 批次处理卡住问题 - 修复总结
|
| 2 |
-
|
| 3 |
-
## 问题描述
|
| 4 |
-
用户报告在处理第6批次时,GraphRAG索引过程在提取实体6次后卡住,没有错误信息。
|
| 5 |
-
|
| 6 |
-
## 根本原因分析
|
| 7 |
-
|
| 8 |
-
### 1. **LLM超时问题** (最可能)
|
| 9 |
-
- Ollama服务在处理某些复杂文档时可能超时
|
| 10 |
-
- 没有设置timeout,导致请求无限期挂起
|
| 11 |
-
- 缺少重试机制
|
| 12 |
-
|
| 13 |
-
### 2. **资源耗尽**
|
| 14 |
-
- 连续处理多个批次后,Ollama可能积累内存
|
| 15 |
-
- 连接池可能耗尽
|
| 16 |
-
|
| 17 |
-
### 3. **错误处理不足**
|
| 18 |
-
- 异常没有被捕获,导致静默失败
|
| 19 |
-
- 缺少详细的进度日志,难以诊断
|
| 20 |
-
|
| 21 |
-
## 实施的修复
|
| 22 |
-
|
| 23 |
-
### ✅ 修复 1: 添加超时和重试机制
|
| 24 |
-
|
| 25 |
-
**文件**: `entity_extractor.py`
|
| 26 |
-
|
| 27 |
-
**改动**:
|
| 28 |
-
```python
|
| 29 |
-
# 之前
|
| 30 |
-
class EntityExtractor:
|
| 31 |
-
def __init__(self):
|
| 32 |
-
self.llm = ChatOllama(model=LOCAL_LLM, format="json", temperature=0)
|
| 33 |
-
|
| 34 |
-
# 之后
|
| 35 |
-
class EntityExtractor:
|
| 36 |
-
def __init__(self, timeout: int = 60, max_retries: int = 3):
|
| 37 |
-
self.llm = ChatOllama(
|
| 38 |
-
model=LOCAL_LLM,
|
| 39 |
-
format="json",
|
| 40 |
-
temperature=0,
|
| 41 |
-
timeout=timeout # 60秒超时
|
| 42 |
-
)
|
| 43 |
-
self.max_retries = max_retries
|
| 44 |
-
```
|
| 45 |
-
|
| 46 |
-
**效果**:
|
| 47 |
-
- 每次LLM调用最多等待60秒
|
| 48 |
-
- 超时后自动重试,最多3次
|
| 49 |
-
- 重试间隔递增(2秒、4秒、6秒)
|
| 50 |
-
|
| 51 |
-
### ✅ 修复 2: 改进的异常处理
|
| 52 |
-
|
| 53 |
-
**文件**: `entity_extractor.py`
|
| 54 |
-
|
| 55 |
-
**改动**:
|
| 56 |
-
```python
|
| 57 |
-
# 之前
|
| 58 |
-
def extract_entities(self, text: str) -> List[Dict]:
|
| 59 |
-
try:
|
| 60 |
-
result = self.entity_chain.invoke({"text": text[:2000]})
|
| 61 |
-
entities = result.get("entities", [])
|
| 62 |
-
return entities
|
| 63 |
-
except Exception as e:
|
| 64 |
-
print(f"❌ 实体提取失败: {e}")
|
| 65 |
-
return []
|
| 66 |
-
|
| 67 |
-
# 之后
|
| 68 |
-
def extract_entities(self, text: str) -> List[Dict]:
|
| 69 |
-
for attempt in range(self.max_retries):
|
| 70 |
-
try:
|
| 71 |
-
print(f" 🔄 提取实体 (尝试 {attempt + 1}/{self.max_retries})...", end="")
|
| 72 |
-
result = self.entity_chain.invoke({"text": text[:2000]})
|
| 73 |
-
entities = result.get("entities", [])
|
| 74 |
-
print(f" ✅ 提取到 {len(entities)} 个实体")
|
| 75 |
-
return entities
|
| 76 |
-
except TimeoutError as e:
|
| 77 |
-
print(f" ⏱️ 超时")
|
| 78 |
-
if attempt < self.max_retries - 1:
|
| 79 |
-
wait_time = (attempt + 1) * 2
|
| 80 |
-
print(f" ⏳ 等待 {wait_time} 秒后重试...")
|
| 81 |
-
time.sleep(wait_time)
|
| 82 |
-
else:
|
| 83 |
-
print(f" ❌ 实体提取最终失败: 超时")
|
| 84 |
-
return []
|
| 85 |
-
except Exception as e:
|
| 86 |
-
print(f" ❌ 错误: {str(e)[:100]}")
|
| 87 |
-
if attempt < self.max_retries - 1:
|
| 88 |
-
time.sleep(1)
|
| 89 |
-
else:
|
| 90 |
-
return []
|
| 91 |
-
return []
|
| 92 |
-
```
|
| 93 |
-
|
| 94 |
-
**效果**:
|
| 95 |
-
- 区分超时错误和其他错误
|
| 96 |
-
- 超时后等待并重试
|
| 97 |
-
- 显示详细的重试进度
|
| 98 |
-
- 最终失败后返回空列表,不崩溃
|
| 99 |
-
|
| 100 |
-
### ✅ 修复 3: 增强的进度跟踪
|
| 101 |
-
|
| 102 |
-
**文件**: `graph_indexer.py`
|
| 103 |
-
|
| 104 |
-
**改动**:
|
| 105 |
-
```python
|
| 106 |
-
# 之前
|
| 107 |
-
for i in range(0, len(documents), batch_size):
|
| 108 |
-
batch = documents[i:i+batch_size]
|
| 109 |
-
print(f" 处理批次 {i//batch_size + 1}...")
|
| 110 |
-
for doc in batch:
|
| 111 |
-
result = self.entity_extractor.extract_from_document(doc.page_content)
|
| 112 |
-
extraction_results.append(result)
|
| 113 |
-
|
| 114 |
-
# 之后
|
| 115 |
-
for i in range(0, len(documents), batch_size):
|
| 116 |
-
batch = documents[i:i+batch_size]
|
| 117 |
-
batch_num = i // batch_size + 1
|
| 118 |
-
total_batches = (len(documents) - 1) // batch_size + 1
|
| 119 |
-
print(f"\n⚙️ === 批次 {batch_num}/{total_batches} (文档 {i+1}-{min(i+batch_size, len(documents))}) ===")
|
| 120 |
-
|
| 121 |
-
for idx, doc in enumerate(batch):
|
| 122 |
-
doc_global_index = i + idx
|
| 123 |
-
try:
|
| 124 |
-
result = self.entity_extractor.extract_from_document(
|
| 125 |
-
doc.page_content,
|
| 126 |
-
doc_index=doc_global_index
|
| 127 |
-
)
|
| 128 |
-
extraction_results.append(result)
|
| 129 |
-
except Exception as e:
|
| 130 |
-
print(f" ❌ 文档 #{doc_global_index + 1} 处理失败: {e}")
|
| 131 |
-
extraction_results.append({"entities": [], "relations": []})
|
| 132 |
-
|
| 133 |
-
print(f"✅ 批次 {batch_num}/{total_batches} 完成")
|
| 134 |
-
```
|
| 135 |
-
|
| 136 |
-
**效果**:
|
| 137 |
-
- 显示当前批次号和总批次数
|
| 138 |
-
- 显示正在处理的文档范围
|
| 139 |
-
- 每个文档的全局索引
|
| 140 |
-
- 批次级别的异常处理
|
| 141 |
-
- 失败后添加空结果继续处理
|
| 142 |
-
|
| 143 |
-
### ✅ 修复 4: 改进的日志输出
|
| 144 |
-
|
| 145 |
-
**文件**: `entity_extractor.py`
|
| 146 |
-
|
| 147 |
-
**改动**:
|
| 148 |
-
```python
|
| 149 |
-
# 之前
|
| 150 |
-
def extract_from_document(self, document_text: str) -> Dict:
|
| 151 |
-
print("🔍 开始提取实体...")
|
| 152 |
-
entities = self.extract_entities(document_text)
|
| 153 |
-
print("🔍 开始提取关系...")
|
| 154 |
-
relations = self.extract_relations(document_text, entities)
|
| 155 |
-
return {"entities": entities, "relations": relations}
|
| 156 |
-
|
| 157 |
-
# 之后
|
| 158 |
-
def extract_from_document(self, document_text: str, doc_index: int = 0) -> Dict:
|
| 159 |
-
print(f"\n🔍 文档 #{doc_index + 1}: 开始提取...")
|
| 160 |
-
|
| 161 |
-
entities = self.extract_entities(document_text)
|
| 162 |
-
relations = self.extract_relations(document_text, entities)
|
| 163 |
-
|
| 164 |
-
print(f"📊 文档 #{doc_index + 1} 完成: {len(entities)} 实体, {len(relations)} 关系")
|
| 165 |
-
|
| 166 |
-
return {"entities": entities, "relations": relations}
|
| 167 |
-
```
|
| 168 |
-
|
| 169 |
-
**效果**:
|
| 170 |
-
- 显示文档编号
|
| 171 |
-
- 汇总每个文档的提取结果
|
| 172 |
-
- 更容易定位卡住的具体文档
|
| 173 |
-
|
| 174 |
-
## 日志输出示例
|
| 175 |
-
|
| 176 |
-
### 之前的输出:
|
| 177 |
-
```
|
| 178 |
-
📍 步骤 1/5: 实体和关系提取
|
| 179 |
-
处理批次 6/10...
|
| 180 |
-
🔍 开始提取实体...
|
| 181 |
-
[卡住,没有更多输出]
|
| 182 |
-
```
|
| 183 |
-
|
| 184 |
-
### 现在的输出:
|
| 185 |
-
```
|
| 186 |
-
📍 步骤 1/5: 实体和关系提取
|
| 187 |
-
|
| 188 |
-
⚙️ === 批次 6/10 (文档 51-60) ===
|
| 189 |
-
|
| 190 |
-
🔍 文档 #51: 开始提取...
|
| 191 |
-
🔄 提取实体 (尝试 1/3)... ✅ 提取到 5 个实体
|
| 192 |
-
🔄 提取关系 (尝试 1/3)... ✅ 提取到 3 个关系
|
| 193 |
-
📊 文档 #51 完成: 5 实体, 3 关系
|
| 194 |
-
|
| 195 |
-
🔍 文档 #52: 开始提取...
|
| 196 |
-
🔄 提取实体 (尝试 1/3)... ⏱️ 超时
|
| 197 |
-
⏳ 等待 2 秒后重试...
|
| 198 |
-
🔄 提取实体 (尝试 2/3)... ✅ 提取到 7 个实体
|
| 199 |
-
🔄 提取关系 (尝试 1/3)... ✅ 提取到 4 个关系
|
| 200 |
-
📊 文档 #52 完成: 7 实体, 4 关系
|
| 201 |
-
|
| 202 |
-
✅ 批次 6/10 完成
|
| 203 |
-
```
|
| 204 |
-
|
| 205 |
-
## 如何使用修复后的代码
|
| 206 |
-
|
| 207 |
-
### 方法 1: 上传到Google Drive
|
| 208 |
-
|
| 209 |
-
1. 下载更新后的文件:
|
| 210 |
-
- `entity_extractor.py`
|
| 211 |
-
- `graph_indexer.py`
|
| 212 |
-
- `GRAPHRAG_TROUBLESHOOTING.md`
|
| 213 |
-
|
| 214 |
-
2. 上传到 `/MyDrive/adaptive_RAG/`
|
| 215 |
-
|
| 216 |
-
3. 重新运行 `main_graphrag.py`
|
| 217 |
-
|
| 218 |
-
### 方法 2: 在Colab中直接应用补丁
|
| 219 |
-
|
| 220 |
-
运行以下代码块:
|
| 221 |
-
|
| 222 |
-
```python
|
| 223 |
-
# 确保已挂载Google Drive
|
| 224 |
-
from google.colab import drive
|
| 225 |
-
drive.mount('/content/drive')
|
| 226 |
-
|
| 227 |
-
# 更新entity_extractor.py的超时设置
|
| 228 |
-
import sys
|
| 229 |
-
sys.path.insert(0, '/content/drive/MyDrive/adaptive_RAG')
|
| 230 |
-
|
| 231 |
-
# 重新导入更新后的模块
|
| 232 |
-
import importlib
|
| 233 |
-
if 'entity_extractor' in sys.modules:
|
| 234 |
-
importlib.reload(sys.modules['entity_extractor'])
|
| 235 |
-
if 'graph_indexer' in sys.modules:
|
| 236 |
-
importlib.reload(sys.modules['graph_indexer'])
|
| 237 |
-
```
|
| 238 |
-
|
| 239 |
-
### 方法 3: 调整参数
|
| 240 |
-
|
| 241 |
-
如果仍然卡住,可以调整参数:
|
| 242 |
-
|
| 243 |
-
```python
|
| 244 |
-
# 在初始化时增加超时和重试
|
| 245 |
-
from entity_extractor import EntityExtractor
|
| 246 |
-
|
| 247 |
-
extractor = EntityExtractor(
|
| 248 |
-
timeout=120, # 增加到2分钟
|
| 249 |
-
max_retries=5 # 更多重试次数
|
| 250 |
-
)
|
| 251 |
-
|
| 252 |
-
# 减小批次大小
|
| 253 |
-
graph = indexer.index_documents(
|
| 254 |
-
documents=doc_splits,
|
| 255 |
-
batch_size=3, # 从10降到3
|
| 256 |
-
save_path="./knowledge_graph.pkl"
|
| 257 |
-
)
|
| 258 |
-
```
|
| 259 |
-
|
| 260 |
-
## 紧急修复步骤
|
| 261 |
-
|
| 262 |
-
如果现在就需要解决,按以下顺序尝试:
|
| 263 |
-
|
| 264 |
-
### ⚡ 步骤 1: 重启Ollama (最快)
|
| 265 |
-
```bash
|
| 266 |
-
# 在Colab中
|
| 267 |
-
!pkill -9 ollama
|
| 268 |
-
!sleep 2
|
| 269 |
-
!nohup ollama serve > /tmp/ollama.log 2>&1 &
|
| 270 |
-
!sleep 5
|
| 271 |
-
```
|
| 272 |
-
|
| 273 |
-
### ⚡ 步骤 2: 减小批次大小
|
| 274 |
-
```python
|
| 275 |
-
# 找到调用 index_documents 的地方,修改为:
|
| 276 |
-
batch_size=3 # 从默认的10改为3
|
| 277 |
-
```
|
| 278 |
-
|
| 279 |
-
### ⚡ 步骤 3: 从失败处继续
|
| 280 |
-
```python
|
| 281 |
-
# 如果在第6批次卡住,跳过前5批次
|
| 282 |
-
processed_count = 50 # 5批次 × 10文档/批次
|
| 283 |
-
remaining_docs = doc_splits[processed_count:]
|
| 284 |
-
|
| 285 |
-
# 只处理剩余的
|
| 286 |
-
graph = indexer.index_documents(
|
| 287 |
-
documents=remaining_docs,
|
| 288 |
-
batch_size=5
|
| 289 |
-
)
|
| 290 |
-
```
|
| 291 |
-
|
| 292 |
-
## 预防措施
|
| 293 |
-
|
| 294 |
-
### 1. 在开始大批量处理前测试
|
| 295 |
-
```python
|
| 296 |
-
# 先用小数据集测试
|
| 297 |
-
test_docs = doc_splits[:5]
|
| 298 |
-
test_graph = indexer.index_documents(test_docs, batch_size=2)
|
| 299 |
-
print("✅ 测试成功,可以处理完整数据集")
|
| 300 |
-
```
|
| 301 |
-
|
| 302 |
-
### 2. 定期保存检查点
|
| 303 |
-
```python
|
| 304 |
-
# 每5个批次保存一次
|
| 305 |
-
import pickle
|
| 306 |
-
|
| 307 |
-
for batch_num in range(total_batches):
|
| 308 |
-
# 处理批次...
|
| 309 |
-
|
| 310 |
-
if batch_num % 5 == 0:
|
| 311 |
-
checkpoint = {
|
| 312 |
-
'results': extraction_results,
|
| 313 |
-
'last_batch': batch_num
|
| 314 |
-
}
|
| 315 |
-
with open(f'/content/drive/MyDrive/checkpoint_{batch_num}.pkl', 'wb') as f:
|
| 316 |
-
pickle.dump(checkpoint, f)
|
| 317 |
-
```
|
| 318 |
-
|
| 319 |
-
### 3. 监控Ollama健康状态
|
| 320 |
-
```python
|
| 321 |
-
import requests
|
| 322 |
-
|
| 323 |
-
def check_ollama_health():
|
| 324 |
-
try:
|
| 325 |
-
response = requests.get('http://localhost:11434/api/tags', timeout=5)
|
| 326 |
-
return response.status_code == 200
|
| 327 |
-
except:
|
| 328 |
-
return False
|
| 329 |
-
|
| 330 |
-
# 在批次循环中
|
| 331 |
-
if not check_ollama_health():
|
| 332 |
-
print("⚠️ Ollama服务异常,重启中...")
|
| 333 |
-
!pkill ollama && sleep 2 && nohup ollama serve > /tmp/ollama.log 2>&1 &
|
| 334 |
-
!sleep 5
|
| 335 |
-
```
|
| 336 |
-
|
| 337 |
-
## 修改的文件列表
|
| 338 |
-
|
| 339 |
-
| 文件 | 修改内容 | 影响 |
|
| 340 |
-
|-----|---------|------|
|
| 341 |
-
| `entity_extractor.py` | 添加timeout、重试、详细日志 | 核心修复 |
|
| 342 |
-
| `graph_indexer.py` | 批次级异常处理、进度跟踪 | 核心修复 |
|
| 343 |
-
| `GRAPHRAG_TROUBLESHOOTING.md` | 完整的故障排除指南 | 新增文档 |
|
| 344 |
-
| `BATCH_FREEZE_FIX.md` | 本文档 | 新增文档 |
|
| 345 |
-
|
| 346 |
-
## 技术细节
|
| 347 |
-
|
| 348 |
-
### Timeout实现
|
| 349 |
-
- 使用 `ChatOllama(timeout=60)` 参数
|
| 350 |
-
- 捕获 `TimeoutError` 异常
|
| 351 |
-
- 实现指数退避重试策略
|
| 352 |
-
|
| 353 |
-
### 异常恢复策略
|
| 354 |
-
1. **轻度错误**: 重试3次,间隔递增
|
| 355 |
-
2. **严重错误**: 记录并跳过,返回空结果
|
| 356 |
-
3. **批次失败**: 继续处理下一批次
|
| 357 |
-
|
| 358 |
-
### 进度持久化
|
| 359 |
-
- 可以实现检查点保存
|
| 360 |
-
- 支持从任意批次恢复
|
| 361 |
-
- 避免重复处理
|
| 362 |
-
|
| 363 |
-
## 预期效果
|
| 364 |
-
|
| 365 |
-
实施这些修复后:
|
| 366 |
-
- ✅ **不会再卡住**: 超时后自动重试或跳过
|
| 367 |
-
- ✅ **更清晰的进度**: 知道当前处理到哪个文档
|
| 368 |
-
- ✅ **更好的容错性**: 单个文档失败不影响整体
|
| 369 |
-
- ✅ **易于诊断**: 详细日志帮助快速定位问题
|
| 370 |
-
|
| 371 |
-
## 性能影响
|
| 372 |
-
|
| 373 |
-
- **正常情况**: 几乎无影响,只是多了日志输出
|
| 374 |
-
- **超时情况**: 会重试,总时间略增加(但比卡住强)
|
| 375 |
-
- **失败情况**: 跳过失败文档,整体速度更快
|
| 376 |
-
|
| 377 |
-
## 下一步
|
| 378 |
-
|
| 379 |
-
1. **立即**: 上传修复后的文件到Google Drive
|
| 380 |
-
2. **测试**: 先用小数据集(5-10个文档)测试
|
| 381 |
-
3. **运行**: 使用完整数据集,batch_size从小到大调整
|
| 382 |
-
4. **监控**: 观察日志输出,记录任何异常
|
| 383 |
-
5. **优化**: 根据实际情况调整timeout和batch_size
|
| 384 |
-
|
| 385 |
-
## 联系信息
|
| 386 |
-
|
| 387 |
-
如果问题仍然存在,请提供:
|
| 388 |
-
- 完整的日志输出(特别是卡住前的最后几行)
|
| 389 |
-
- 文档数量和批次大小
|
| 390 |
-
- Ollama版本和模型名称
|
| 391 |
-
- 系统资源使用情况(内存、GPU)
|
| 392 |
-
|
| 393 |
-
---
|
| 394 |
-
|
| 395 |
-
**总结**: 问题已通过添加超时控制、重试机制和完善的异常处理得到解决。现在的代码能够优雅地处理LLM超时和失败,并提供详细的进度反馈。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DEPLOYMENT_GUIDE.md
DELETED
|
@@ -1,440 +0,0 @@
|
|
| 1 |
-
# Linux GPU部署指南 (RTX 4090)
|
| 2 |
-
|
| 3 |
-
## 🚀 自适应RAG系统在Linux RTX 4090环境部署
|
| 4 |
-
|
| 5 |
-
本指南将详细介绍如何在配备NVIDIA RTX 4090 GPU的Linux服务器上部署自适应RAG系统。
|
| 6 |
-
|
| 7 |
-
## 📋 环境要求
|
| 8 |
-
|
| 9 |
-
### 硬件要求
|
| 10 |
-
- NVIDIA RTX 4090 GPU
|
| 11 |
-
- 至少16GB内存(推荐32GB)
|
| 12 |
-
- 50GB+可用磁盘空间
|
| 13 |
-
- Ubuntu 20.04+ / CentOS 8+ / RHEL 8+
|
| 14 |
-
|
| 15 |
-
### 软件要求
|
| 16 |
-
- Linux操作系统(推荐Ubuntu 22.04 LTS)
|
| 17 |
-
- NVIDIA驱动程序(推荐535+)
|
| 18 |
-
- CUDA 12.0+
|
| 19 |
-
- Docker(可选但推荐)
|
| 20 |
-
- Python 3.8-3.11
|
| 21 |
-
|
| 22 |
-
## 🔧 步骤1:系统准备
|
| 23 |
-
|
| 24 |
-
### 1.1 更新系统
|
| 25 |
-
```bash
|
| 26 |
-
sudo apt update && sudo apt upgrade -y
|
| 27 |
-
sudo apt install -y curl wget git build-essential python3-pip python3-venv
|
| 28 |
-
```
|
| 29 |
-
|
| 30 |
-
### 1.2 安装NVIDIA驱动和CUDA
|
| 31 |
-
```bash
|
| 32 |
-
# 检查GPU
|
| 33 |
-
lspci | grep -i nvidia
|
| 34 |
-
|
| 35 |
-
# 添加NVIDIA软件源
|
| 36 |
-
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.0-1_all.deb
|
| 37 |
-
sudo dpkg -i cuda-keyring_1.0-1_all.deb
|
| 38 |
-
sudo apt-get update
|
| 39 |
-
|
| 40 |
-
# 安装NVIDIA驱动和CUDA
|
| 41 |
-
sudo apt-get install -y nvidia-driver-535 cuda-12-2
|
| 42 |
-
|
| 43 |
-
# 重启系统
|
| 44 |
-
sudo reboot
|
| 45 |
-
```
|
| 46 |
-
|
| 47 |
-
### 1.3 验证GPU安装
|
| 48 |
-
```bash
|
| 49 |
-
# 重启后验证
|
| 50 |
-
nvidia-smi
|
| 51 |
-
nvcc --version
|
| 52 |
-
```
|
| 53 |
-
|
| 54 |
-
## 🐳 步骤2:Docker环境配置(推荐)
|
| 55 |
-
|
| 56 |
-
### 2.1 安装Docker
|
| 57 |
-
```bash
|
| 58 |
-
# 安装Docker
|
| 59 |
-
curl -fsSL https://get.docker.com -o get-docker.sh
|
| 60 |
-
sudo sh get-docker.sh
|
| 61 |
-
sudo usermod -aG docker $USER
|
| 62 |
-
```
|
| 63 |
-
|
| 64 |
-
### 2.2 安装NVIDIA Container Toolkit
|
| 65 |
-
```bash
|
| 66 |
-
# 添加NVIDIA Docker源
|
| 67 |
-
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
|
| 68 |
-
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
|
| 69 |
-
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
|
| 70 |
-
|
| 71 |
-
# 安装nvidia-container-toolkit
|
| 72 |
-
sudo apt-get update
|
| 73 |
-
sudo apt-get install -y nvidia-container-toolkit
|
| 74 |
-
sudo systemctl restart docker
|
| 75 |
-
```
|
| 76 |
-
|
| 77 |
-
### 2.3 创建Dockerfile
|
| 78 |
-
```dockerfile
|
| 79 |
-
# 创建 Dockerfile
|
| 80 |
-
cat > Dockerfile << 'EOF'
|
| 81 |
-
FROM nvidia/cuda:12.2-devel-ubuntu22.04
|
| 82 |
-
|
| 83 |
-
# 设置非交互模式
|
| 84 |
-
ENV DEBIAN_FRONTEND=noninteractive
|
| 85 |
-
ENV PYTHONUNBUFFERED=1
|
| 86 |
-
|
| 87 |
-
# 更新系统并安装Python
|
| 88 |
-
RUN apt-get update && apt-get install -y \
|
| 89 |
-
python3 \
|
| 90 |
-
python3-pip \
|
| 91 |
-
python3-venv \
|
| 92 |
-
git \
|
| 93 |
-
curl \
|
| 94 |
-
&& rm -rf /var/lib/apt/lists/*
|
| 95 |
-
|
| 96 |
-
# 创建工作目录
|
| 97 |
-
WORKDIR /app
|
| 98 |
-
|
| 99 |
-
# 复制项目文件
|
| 100 |
-
COPY requirements.txt .
|
| 101 |
-
COPY *.py .
|
| 102 |
-
COPY *.md .
|
| 103 |
-
|
| 104 |
-
# 安装Python依赖
|
| 105 |
-
RUN pip3 install --no-cache-dir -r requirements.txt
|
| 106 |
-
|
| 107 |
-
# 暴露端口(如果需要Web界面)
|
| 108 |
-
EXPOSE 8000
|
| 109 |
-
|
| 110 |
-
# 启动命令
|
| 111 |
-
CMD ["python3", "main.py"]
|
| 112 |
-
EOF
|
| 113 |
-
```
|
| 114 |
-
|
| 115 |
-
## 🐍 步骤3:Python环境配置(直接部署)
|
| 116 |
-
|
| 117 |
-
### 3.1 创建Python虚拟环境
|
| 118 |
-
```bash
|
| 119 |
-
# 克隆项目
|
| 120 |
-
git clone <your-repo-url> adaptive_rag
|
| 121 |
-
cd adaptive_rag
|
| 122 |
-
|
| 123 |
-
# 创建虚拟环境
|
| 124 |
-
python3 -m venv rag_env
|
| 125 |
-
source rag_env/bin/activate
|
| 126 |
-
|
| 127 |
-
# 升级pip
|
| 128 |
-
pip install --upgrade pip
|
| 129 |
-
```
|
| 130 |
-
|
| 131 |
-
### 3.2 修改requirements.txt以支持GPU
|
| 132 |
-
需要更新requirements.txt以优化GPU使用:
|
| 133 |
-
|
| 134 |
-
```bash
|
| 135 |
-
# 创建GPU优化的requirements文件
|
| 136 |
-
cat > requirements_gpu.txt << 'EOF'
|
| 137 |
-
# 核心框架
|
| 138 |
-
langchain>=0.1.0
|
| 139 |
-
langgraph>=0.0.40
|
| 140 |
-
langchain-community>=0.0.20
|
| 141 |
-
langchain-core>=0.1.0
|
| 142 |
-
|
| 143 |
-
# LLM集成
|
| 144 |
-
langchain-ollama>=0.1.0
|
| 145 |
-
|
| 146 |
-
# 向量数据库和嵌入(GPU优化版本)
|
| 147 |
-
chromadb>=0.4.0
|
| 148 |
-
sentence-transformers>=2.2.0
|
| 149 |
-
torch>=2.0.0+cu118 --index-url https://download.pytorch.org/whl/cu118
|
| 150 |
-
torchvision>=0.15.0+cu118 --index-url https://download.pytorch.org/whl/cu118
|
| 151 |
-
transformers>=4.30.0
|
| 152 |
-
accelerate>=0.20.0
|
| 153 |
-
|
| 154 |
-
# 文档处理
|
| 155 |
-
tiktoken>=0.5.0
|
| 156 |
-
beautifulsoup4>=4.12.0
|
| 157 |
-
requests>=2.31.0
|
| 158 |
-
|
| 159 |
-
# 网络搜索
|
| 160 |
-
tavily-python>=0.3.0
|
| 161 |
-
|
| 162 |
-
# 数据处理
|
| 163 |
-
numpy>=1.24.0,<2.0
|
| 164 |
-
pandas>=2.0.0
|
| 165 |
-
|
| 166 |
-
# 工具库
|
| 167 |
-
python-dotenv>=1.0.0
|
| 168 |
-
pydantic>=2.0.0
|
| 169 |
-
typing-extensions>=4.0.0
|
| 170 |
-
|
| 171 |
-
# GPU加速库
|
| 172 |
-
cupy-cuda12x>=12.0.0
|
| 173 |
-
faiss-gpu>=1.7.4
|
| 174 |
-
EOF
|
| 175 |
-
```
|
| 176 |
-
|
| 177 |
-
### 3.3 安装依赖
|
| 178 |
-
```bash
|
| 179 |
-
# 安装GPU优化依赖
|
| 180 |
-
pip install -r requirements_gpu.txt
|
| 181 |
-
```
|
| 182 |
-
|
| 183 |
-
## 🛠️ 步骤4:修改配置以优化GPU使用
|
| 184 |
-
|
| 185 |
-
### 4.1 更新document_processor.py以使用GPU
|
| 186 |
-
需要修改嵌入模型配置:
|
| 187 |
-
|
| 188 |
-
```python
|
| 189 |
-
# 在document_processor.py中修改
|
| 190 |
-
self.embeddings = HuggingFaceEmbeddings(
|
| 191 |
-
model_name="sentence-transformers/all-MiniLM-L6-v2",
|
| 192 |
-
model_kwargs={'device': 'cuda'}, # 使用GPU
|
| 193 |
-
encode_kwargs={'normalize_embeddings': True}
|
| 194 |
-
)
|
| 195 |
-
```
|
| 196 |
-
|
| 197 |
-
### 4.2 创建GPU优化配置
|
| 198 |
-
```python
|
| 199 |
-
# 创建 gpu_config.py
|
| 200 |
-
cat > gpu_config.py << 'EOF'
|
| 201 |
-
import torch
|
| 202 |
-
import os
|
| 203 |
-
|
| 204 |
-
# GPU配置
|
| 205 |
-
if torch.cuda.is_available():
|
| 206 |
-
DEVICE = "cuda"
|
| 207 |
-
GPU_COUNT = torch.cuda.device_count()
|
| 208 |
-
GPU_NAME = torch.cuda.get_device_name(0)
|
| 209 |
-
print(f"发现 {GPU_COUNT} 个GPU: {GPU_NAME}")
|
| 210 |
-
|
| 211 |
-
# 设置CUDA优化
|
| 212 |
-
torch.backends.cudnn.benchmark = True
|
| 213 |
-
torch.backends.cudnn.deterministic = False
|
| 214 |
-
|
| 215 |
-
# 设置GPU内存管理
|
| 216 |
-
torch.cuda.empty_cache()
|
| 217 |
-
else:
|
| 218 |
-
DEVICE = "cpu"
|
| 219 |
-
print("未发现GPU,使用CPU模式")
|
| 220 |
-
|
| 221 |
-
# 优化设置
|
| 222 |
-
EMBEDDING_BATCH_SIZE = 32 if DEVICE == "cuda" else 8
|
| 223 |
-
MAX_WORKERS = 4 if DEVICE == "cuda" else 2
|
| 224 |
-
EOF
|
| 225 |
-
```
|
| 226 |
-
|
| 227 |
-
## 🤖 步骤5:安装和配置Ollama
|
| 228 |
-
|
| 229 |
-
### 5.1 安装Ollama
|
| 230 |
-
```bash
|
| 231 |
-
# 下载并安装Ollama
|
| 232 |
-
curl -fsSL https://ollama.ai/install.sh | sh
|
| 233 |
-
|
| 234 |
-
# 或者使用Docker
|
| 235 |
-
# docker run -d --gpus=all -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama
|
| 236 |
-
```
|
| 237 |
-
|
| 238 |
-
### 5.2 下载模型
|
| 239 |
-
```bash
|
| 240 |
-
# 下载Mistral模型
|
| 241 |
-
ollama pull mistral
|
| 242 |
-
|
| 243 |
-
# 或者下载更大的模型(如果GPU内存足够)
|
| 244 |
-
ollama pull llama2:13b
|
| 245 |
-
ollama pull codellama:34b
|
| 246 |
-
```
|
| 247 |
-
|
| 248 |
-
### 5.3 启动Ollama服务
|
| 249 |
-
```bash
|
| 250 |
-
# 启动Ollama服务
|
| 251 |
-
ollama serve &
|
| 252 |
-
|
| 253 |
-
# 验证服务
|
| 254 |
-
curl http://localhost:11434/api/version
|
| 255 |
-
```
|
| 256 |
-
|
| 257 |
-
## 🔐 步骤6:环境变量配置
|
| 258 |
-
|
| 259 |
-
### 6.1 创建.env文件
|
| 260 |
-
```bash
|
| 261 |
-
cat > .env << 'EOF'
|
| 262 |
-
# API密钥
|
| 263 |
-
TAVILY_API_KEY=your_tavily_api_key_here
|
| 264 |
-
|
| 265 |
-
# GPU配置
|
| 266 |
-
CUDA_VISIBLE_DEVICES=0
|
| 267 |
-
TORCH_CUDA_ARCH_LIST="8.9" # RTX 4090架构
|
| 268 |
-
|
| 269 |
-
# 模型配置
|
| 270 |
-
HF_HOME=/app/models
|
| 271 |
-
TRANSFORMERS_CACHE=/app/models
|
| 272 |
-
|
| 273 |
-
# 性能优化
|
| 274 |
-
OMP_NUM_THREADS=8
|
| 275 |
-
MKL_NUM_THREADS=8
|
| 276 |
-
EOF
|
| 277 |
-
```
|
| 278 |
-
|
| 279 |
-
## 🚀 步骤7:部署和启动
|
| 280 |
-
|
| 281 |
-
### 7.1 使用Docker部署
|
| 282 |
-
```bash
|
| 283 |
-
# 构建镜像
|
| 284 |
-
docker build -t adaptive-rag:gpu .
|
| 285 |
-
|
| 286 |
-
# 运行容器
|
| 287 |
-
docker run -d \
|
| 288 |
-
--gpus all \
|
| 289 |
-
--name adaptive-rag \
|
| 290 |
-
--env-file .env \
|
| 291 |
-
-p 8000:8000 \
|
| 292 |
-
-v $(pwd)/data:/app/data \
|
| 293 |
-
adaptive-rag:gpu
|
| 294 |
-
```
|
| 295 |
-
|
| 296 |
-
### 7.2 直接Python部署
|
| 297 |
-
```bash
|
| 298 |
-
# 激活虚拟环境
|
| 299 |
-
source rag_env/bin/activate
|
| 300 |
-
|
| 301 |
-
# 启动系统
|
| 302 |
-
python main.py
|
| 303 |
-
```
|
| 304 |
-
|
| 305 |
-
## 📊 步骤8:性能监控
|
| 306 |
-
|
| 307 |
-
### 8.1 创建监控脚本
|
| 308 |
-
```bash
|
| 309 |
-
cat > monitor_gpu.py << 'EOF'
|
| 310 |
-
import psutil
|
| 311 |
-
import GPUtil
|
| 312 |
-
import time
|
| 313 |
-
|
| 314 |
-
def monitor_system():
|
| 315 |
-
while True:
|
| 316 |
-
# GPU监控
|
| 317 |
-
gpus = GPUtil.getGPUs()
|
| 318 |
-
for gpu in gpus:
|
| 319 |
-
print(f"GPU {gpu.id}: {gpu.load*100}% | 内存: {gpu.memoryUsed}MB/{gpu.memoryTotal}MB")
|
| 320 |
-
|
| 321 |
-
# CPU和内存监控
|
| 322 |
-
print(f"CPU: {psutil.cpu_percent()}% | 内存: {psutil.virtual_memory().percent}%")
|
| 323 |
-
print("-" * 50)
|
| 324 |
-
time.sleep(5)
|
| 325 |
-
|
| 326 |
-
if __name__ == "__main__":
|
| 327 |
-
monitor_system()
|
| 328 |
-
EOF
|
| 329 |
-
|
| 330 |
-
pip install gputil
|
| 331 |
-
python monitor_gpu.py
|
| 332 |
-
```
|
| 333 |
-
|
| 334 |
-
## 🔧 步骤9:性能优化配置
|
| 335 |
-
|
| 336 |
-
### 9.1 创建优化启动脚本
|
| 337 |
-
```bash
|
| 338 |
-
cat > start_optimized.sh << 'EOF'
|
| 339 |
-
#!/bin/bash
|
| 340 |
-
|
| 341 |
-
# 设置GPU优化环境变量
|
| 342 |
-
export CUDA_VISIBLE_DEVICES=0
|
| 343 |
-
export PYTORCH_CUDA_ALLOC_CONF=max_split_size_mb:512
|
| 344 |
-
export TOKENIZERS_PARALLELISM=false
|
| 345 |
-
|
| 346 |
-
# 启动系统
|
| 347 |
-
source rag_env/bin/activate
|
| 348 |
-
python main.py
|
| 349 |
-
EOF
|
| 350 |
-
|
| 351 |
-
chmod +x start_optimized.sh
|
| 352 |
-
```
|
| 353 |
-
|
| 354 |
-
### 9.2 创建系统服务
|
| 355 |
-
```bash
|
| 356 |
-
# 创建systemd服务
|
| 357 |
-
sudo tee /etc/systemd/system/adaptive-rag.service > /dev/null << 'EOF'
|
| 358 |
-
[Unit]
|
| 359 |
-
Description=Adaptive RAG System
|
| 360 |
-
After=network.target
|
| 361 |
-
|
| 362 |
-
[Service]
|
| 363 |
-
Type=simple
|
| 364 |
-
User=your_username
|
| 365 |
-
WorkingDirectory=/path/to/adaptive_rag
|
| 366 |
-
Environment=PATH=/path/to/adaptive_rag/rag_env/bin
|
| 367 |
-
ExecStart=/path/to/adaptive_rag/rag_env/bin/python main.py
|
| 368 |
-
Restart=always
|
| 369 |
-
RestartSec=10
|
| 370 |
-
|
| 371 |
-
[Install]
|
| 372 |
-
WantedBy=multi-user.target
|
| 373 |
-
EOF
|
| 374 |
-
|
| 375 |
-
# 启用服务
|
| 376 |
-
sudo systemctl daemon-reload
|
| 377 |
-
sudo systemctl enable adaptive-rag
|
| 378 |
-
sudo systemctl start adaptive-rag
|
| 379 |
-
```
|
| 380 |
-
|
| 381 |
-
## 🐛 步骤10:故障排除
|
| 382 |
-
|
| 383 |
-
### 10.1 常见问题
|
| 384 |
-
|
| 385 |
-
1. **CUDA内存不足**
|
| 386 |
-
```bash
|
| 387 |
-
# 减少批处理大小
|
| 388 |
-
export EMBEDDING_BATCH_SIZE=16
|
| 389 |
-
# 或者启用梯度检查点
|
| 390 |
-
export PYTORCH_CUDA_ALLOC_CONF=max_split_size_mb:256
|
| 391 |
-
```
|
| 392 |
-
|
| 393 |
-
2. **Ollama连接问题**
|
| 394 |
-
```bash
|
| 395 |
-
# 检查Ollama状态
|
| 396 |
-
sudo systemctl status ollama
|
| 397 |
-
# 重启Ollama
|
| 398 |
-
sudo systemctl restart ollama
|
| 399 |
-
```
|
| 400 |
-
|
| 401 |
-
3. **权限问题**
|
| 402 |
-
```bash
|
| 403 |
-
# 添加用户到docker组
|
| 404 |
-
sudo usermod -aG docker $USER
|
| 405 |
-
# 重新登录
|
| 406 |
-
```
|
| 407 |
-
|
| 408 |
-
### 10.2 性能调优
|
| 409 |
-
|
| 410 |
-
```bash
|
| 411 |
-
# GPU性能模式
|
| 412 |
-
sudo nvidia-smi -pm 1
|
| 413 |
-
sudo nvidia-smi -ac 9251,2100
|
| 414 |
-
|
| 415 |
-
# 系统优化
|
| 416 |
-
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
|
| 417 |
-
sudo sysctl -p
|
| 418 |
-
```
|
| 419 |
-
|
| 420 |
-
## 📈 预期性能
|
| 421 |
-
|
| 422 |
-
在RTX 4090环境下的预期性能:
|
| 423 |
-
- **文档嵌入**: ~1000 documents/second
|
| 424 |
-
- **查询响应**: ~2-5 seconds per query
|
| 425 |
-
- **GPU利用率**: 60-80%
|
| 426 |
-
- **内存使用**: 8-12GB GPU memory
|
| 427 |
-
|
| 428 |
-
## 🎯 验证部署
|
| 429 |
-
|
| 430 |
-
```bash
|
| 431 |
-
# 测试GPU可用性
|
| 432 |
-
python -c "import torch; print(f'CUDA可用: {torch.cuda.is_available()}'); print(f'GPU数量: {torch.cuda.device_count()}')"
|
| 433 |
-
|
| 434 |
-
# 测试系统
|
| 435 |
-
curl -X POST http://localhost:8000/query \
|
| 436 |
-
-H "Content-Type: application/json" \
|
| 437 |
-
-d '{"question": "什么是LLM智能体?"}'
|
| 438 |
-
```
|
| 439 |
-
|
| 440 |
-
这个部署指南提供了完整的Linux GPU环境配置,确保您的自适应RAG系统能够充分利用RTX 4090的计算能力。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GRAPHRAG_GUIDE.md
DELETED
|
@@ -1,401 +0,0 @@
|
|
| 1 |
-
# GraphRAG 集成指南
|
| 2 |
-
|
| 3 |
-
## 📋 概述
|
| 4 |
-
|
| 5 |
-
本项目已集成**Microsoft GraphRAG**架构,通过知识图谱增强传统向量检索,提供更精准的信息提取和推理能力。
|
| 6 |
-
|
| 7 |
-
## 🏗️ GraphRAG 架构
|
| 8 |
-
|
| 9 |
-
### 核心组件
|
| 10 |
-
|
| 11 |
-
```
|
| 12 |
-
文档集合
|
| 13 |
-
↓
|
| 14 |
-
┌─────────────────────────────────────┐
|
| 15 |
-
│ 实体和关系提取 (Entity Extraction) │
|
| 16 |
-
│ - 使用LLM识别实体 │
|
| 17 |
-
│ - 提取实体间关系 │
|
| 18 |
-
└─────────────────────────────────────┘
|
| 19 |
-
↓
|
| 20 |
-
┌─────────────────────────────────────┐
|
| 21 |
-
│ 知识图谱构建 (Graph Construction) │
|
| 22 |
-
│ - 实体去重 │
|
| 23 |
-
│ - 构建图结构 │
|
| 24 |
-
└─────────────────────────────────────┘
|
| 25 |
-
↓
|
| 26 |
-
┌─────────────────────────────────────┐
|
| 27 |
-
│ 社区检测 (Community Detection) │
|
| 28 |
-
│ - Louvain算法 │
|
| 29 |
-
│ - 层次化聚类 │
|
| 30 |
-
└─────────────────────────────────────┘
|
| 31 |
-
↓
|
| 32 |
-
┌─────────────────────────────────────┐
|
| 33 |
-
│ 社区摘要生成 (Community Summaries) │
|
| 34 |
-
│ - LLM生成摘要 │
|
| 35 |
-
│ - 多层次索引 │
|
| 36 |
-
└─────────────────────────────────────┘
|
| 37 |
-
↓
|
| 38 |
-
查询阶段
|
| 39 |
-
↓
|
| 40 |
-
┌──────────────┬──────────────┐
|
| 41 |
-
│ 本地查询 │ 全局查询 │
|
| 42 |
-
│ (Local Query)│(Global Query)│
|
| 43 |
-
│ │ │
|
| 44 |
-
│ 实体邻域检索 │ 社区摘要查询 │
|
| 45 |
-
└──────────────┴──────────────┘
|
| 46 |
-
```
|
| 47 |
-
|
| 48 |
-
## 📦 新增文件说明
|
| 49 |
-
|
| 50 |
-
### 1. **entity_extractor.py** - 实体提取器
|
| 51 |
-
```python
|
| 52 |
-
EntityExtractor
|
| 53 |
-
├── extract_entities() # 从文本提取实体
|
| 54 |
-
├── extract_relations() # 提取实体关系
|
| 55 |
-
└── extract_from_document() # 完整文档处理
|
| 56 |
-
|
| 57 |
-
EntityDeduplicator
|
| 58 |
-
└── deduplicate_entities() # 实体去重
|
| 59 |
-
```
|
| 60 |
-
|
| 61 |
-
**功能**:
|
| 62 |
-
- 使用LLM识别6种实体类型 (PERSON, ORGANIZATION, CONCEPT, TECHNOLOGY, PAPER, EVENT)
|
| 63 |
-
- 提取8种关系类型 (AUTHOR_OF, USES, BASED_ON, etc.)
|
| 64 |
-
- 智能实体去重和合并
|
| 65 |
-
|
| 66 |
-
### 2. **knowledge_graph.py** - 知识图谱核心
|
| 67 |
-
```python
|
| 68 |
-
KnowledgeGraph
|
| 69 |
-
├── add_entity() # 添加节点
|
| 70 |
-
├── add_relation() # 添加边
|
| 71 |
-
├── build_from_extractions() # 构建图谱
|
| 72 |
-
├── detect_communities() # 社区检测
|
| 73 |
-
├── get_community_members() # 获取社区成员
|
| 74 |
-
└── get_statistics() # 统计信息
|
| 75 |
-
|
| 76 |
-
CommunitySummarizer
|
| 77 |
-
├── summarize_community() # 单社区摘要
|
| 78 |
-
└── summarize_all_communities() # 全部社区摘要
|
| 79 |
-
```
|
| 80 |
-
|
| 81 |
-
**功能**:
|
| 82 |
-
- 基于NetworkX的图谱管理
|
| 83 |
-
- 支持3种社区检测算法 (Louvain, Greedy, Label Propagation)
|
| 84 |
-
- LLM驱动的社区摘要生成
|
| 85 |
-
- 图谱持久化存储
|
| 86 |
-
|
| 87 |
-
### 3. **graph_indexer.py** - 索引构建器
|
| 88 |
-
```python
|
| 89 |
-
GraphRAGIndexer
|
| 90 |
-
├── index_documents() # 构建索引
|
| 91 |
-
├── get_graph() # 获取图谱
|
| 92 |
-
└── load_index() # 加载索引
|
| 93 |
-
```
|
| 94 |
-
|
| 95 |
-
**流程**:
|
| 96 |
-
1. 批量实体提取
|
| 97 |
-
2. 实体去重合并
|
| 98 |
-
3. 构建知识图谱
|
| 99 |
-
4. 社区检测
|
| 100 |
-
5. 生成摘要
|
| 101 |
-
|
| 102 |
-
### 4. **graph_retriever.py** - 图谱检索器
|
| 103 |
-
```python
|
| 104 |
-
GraphRetriever
|
| 105 |
-
├── recognize_entities() # 识别问题中的实体
|
| 106 |
-
├── local_query() # 本地查询
|
| 107 |
-
├── global_query() # 全局查询
|
| 108 |
-
├── hybrid_query() # 混合查询
|
| 109 |
-
└── smart_query() # 智能查询
|
| 110 |
-
```
|
| 111 |
-
|
| 112 |
-
**查询模式**:
|
| 113 |
-
- **本地查询**: 针对特定实体的详细问题
|
| 114 |
-
- **全局查询**: 需要整体理解的概括性问题
|
| 115 |
-
- **智能查询**: 自动选择最佳策略
|
| 116 |
-
|
| 117 |
-
### 5. **main_graphrag.py** - GraphRAG集成示例
|
| 118 |
-
完整的使用示例和交互式界面
|
| 119 |
-
|
| 120 |
-
### 6. **requirements_graphrag.txt** - 额外依赖
|
| 121 |
-
GraphRAG所需的图处理库
|
| 122 |
-
|
| 123 |
-
## 🚀 快速开始
|
| 124 |
-
|
| 125 |
-
### 安装依赖
|
| 126 |
-
|
| 127 |
-
```bash
|
| 128 |
-
# 安装基础依赖
|
| 129 |
-
pip install -r requirements.txt
|
| 130 |
-
|
| 131 |
-
# 安装GraphRAG依赖
|
| 132 |
-
pip install -r requirements_graphrag.txt
|
| 133 |
-
```
|
| 134 |
-
|
| 135 |
-
### 首次使用
|
| 136 |
-
|
| 137 |
-
```python
|
| 138 |
-
# 方式1: 使用集成示例
|
| 139 |
-
python main_graphrag.py
|
| 140 |
-
|
| 141 |
-
# 方式2: 在代码中集成
|
| 142 |
-
from config import setup_environment
|
| 143 |
-
from document_processor import initialize_document_processor
|
| 144 |
-
from graph_indexer import initialize_graph_indexer
|
| 145 |
-
from graph_retriever import initialize_graph_retriever
|
| 146 |
-
|
| 147 |
-
# 初始化
|
| 148 |
-
setup_environment()
|
| 149 |
-
processor, vectorstore, retriever, doc_splits = initialize_document_processor()
|
| 150 |
-
|
| 151 |
-
# 构建GraphRAG索引
|
| 152 |
-
graph_indexer = initialize_graph_indexer()
|
| 153 |
-
knowledge_graph = graph_indexer.index_documents(
|
| 154 |
-
documents=doc_splits,
|
| 155 |
-
save_path="./data/knowledge_graph.json"
|
| 156 |
-
)
|
| 157 |
-
|
| 158 |
-
# 初始化检索器
|
| 159 |
-
graph_retriever = initialize_graph_retriever(knowledge_graph)
|
| 160 |
-
|
| 161 |
-
# 查询
|
| 162 |
-
answer = graph_retriever.smart_query("LLM Agent的核心组件是什么?")
|
| 163 |
-
print(answer)
|
| 164 |
-
```
|
| 165 |
-
|
| 166 |
-
## 🔧 配置说明
|
| 167 |
-
|
| 168 |
-
在 `config.py` 中添加了以下配置:
|
| 169 |
-
|
| 170 |
-
```python
|
| 171 |
-
# GraphRAG配置
|
| 172 |
-
ENABLE_GRAPHRAG = True # 是否启用GraphRAG
|
| 173 |
-
GRAPHRAG_INDEX_PATH = "./data/knowledge_graph.json" # 图谱存储路径
|
| 174 |
-
GRAPHRAG_COMMUNITY_ALGORITHM = "louvain" # 社区检测算法
|
| 175 |
-
GRAPHRAG_MAX_HOPS = 2 # 本地查询最大跳数
|
| 176 |
-
GRAPHRAG_TOP_K_COMMUNITIES = 5 # 全局查询使用的社区数
|
| 177 |
-
GRAPHRAG_BATCH_SIZE = 10 # 实体提取批大小
|
| 178 |
-
```
|
| 179 |
-
|
| 180 |
-
## 📊 使用场景对比
|
| 181 |
-
|
| 182 |
-
### 传统向量检索 vs GraphRAG
|
| 183 |
-
|
| 184 |
-
| 场景 | 向量检索 | GraphRAG | 推荐 |
|
| 185 |
-
|-----|---------|----------|------|
|
| 186 |
-
| "AlphaCodium的作者是谁?" | ⚠️ 可能找到但不精确 | ✅ 直接查询实体关系 | GraphRAG本地查询 |
|
| 187 |
-
| "这些文档讨论什么主题?" | ⚠️ 需要读取多个片段 | ✅ 社区摘要直接回答 | GraphRAG全局查询 |
|
| 188 |
-
| "提示工程的应用场景" | ✅ 语义匹配效果好 | ✅ 可追踪关系链 | 混合查询 |
|
| 189 |
-
| "最新技术发展" | ✅ 适合模糊查询 | ❌ 需要明确实体 | 向量检索 |
|
| 190 |
-
|
| 191 |
-
## 🎯 查询策略选择
|
| 192 |
-
|
| 193 |
-
### 本地查询 (Local Query)
|
| 194 |
-
**适用**: 针对特定实体的详细问题
|
| 195 |
-
|
| 196 |
-
```python
|
| 197 |
-
# 示例问题
|
| 198 |
-
"LLM Agent包含哪些组件?"
|
| 199 |
-
"Transformer模型的作者是谁?"
|
| 200 |
-
"AlphaCodium使用了什么技术?"
|
| 201 |
-
|
| 202 |
-
# 代码
|
| 203 |
-
answer = graph_retriever.local_query(question, max_hops=2)
|
| 204 |
-
```
|
| 205 |
-
|
| 206 |
-
**工作原理**:
|
| 207 |
-
1. 识别问题中的实体
|
| 208 |
-
2. 扩展到邻居节点(支持多跳)
|
| 209 |
-
3. 收集实体信息和关系
|
| 210 |
-
4. 基于子图生成答案
|
| 211 |
-
|
| 212 |
-
### 全局查询 (Global Query)
|
| 213 |
-
**适用**: 需要整体视角的概括性问题
|
| 214 |
-
|
| 215 |
-
```python
|
| 216 |
-
# 示例问题
|
| 217 |
-
"这些文档的主要主题是什么?"
|
| 218 |
-
"涵盖了哪些研究领域?"
|
| 219 |
-
"关键的技术趋势有哪些?"
|
| 220 |
-
|
| 221 |
-
# 代码
|
| 222 |
-
answer = graph_retriever.global_query(question, top_k_communities=5)
|
| 223 |
-
```
|
| 224 |
-
|
| 225 |
-
**工作原理**:
|
| 226 |
-
1. 获取社区摘要
|
| 227 |
-
2. 基于摘要理解全局结构
|
| 228 |
-
3. 综合多个社区的信息
|
| 229 |
-
4. 生成高层次答案
|
| 230 |
-
|
| 231 |
-
### 智能查询 (Smart Query)
|
| 232 |
-
**适用**: 自动选择最佳策略
|
| 233 |
-
|
| 234 |
-
```python
|
| 235 |
-
# 自动判断使用本地还是全局查询
|
| 236 |
-
answer = graph_retriever.smart_query(question)
|
| 237 |
-
```
|
| 238 |
-
|
| 239 |
-
**决策逻辑**:
|
| 240 |
-
- 包含具体实体名称 → 本地查询
|
| 241 |
-
- 包含"主要"、"总体"、"概述"等关键词 → 全局查询
|
| 242 |
-
- 默认 → 本地查询
|
| 243 |
-
|
| 244 |
-
### 混合查询 (Hybrid Query)
|
| 245 |
-
**适用**: 需要多种视角的复杂问题
|
| 246 |
-
|
| 247 |
-
```python
|
| 248 |
-
result = graph_retriever.hybrid_query(question)
|
| 249 |
-
# 返回: {"local": "...", "global": "..."}
|
| 250 |
-
```
|
| 251 |
-
|
| 252 |
-
## 📈 性能优化
|
| 253 |
-
|
| 254 |
-
### 索引构建优化
|
| 255 |
-
|
| 256 |
-
```python
|
| 257 |
-
# 1. 批处理大小
|
| 258 |
-
graph_indexer.index_documents(
|
| 259 |
-
documents=doc_splits,
|
| 260 |
-
batch_size=20 # 增大批处理提高速度
|
| 261 |
-
)
|
| 262 |
-
|
| 263 |
-
# 2. 增量索引(开发中)
|
| 264 |
-
# 避免每次重建整个图谱
|
| 265 |
-
|
| 266 |
-
# 3. 缓存已有索引
|
| 267 |
-
if os.path.exists(GRAPHRAG_INDEX_PATH):
|
| 268 |
-
knowledge_graph = graph_indexer.load_index(GRAPHRAG_INDEX_PATH)
|
| 269 |
-
```
|
| 270 |
-
|
| 271 |
-
### 查询优化
|
| 272 |
-
|
| 273 |
-
```python
|
| 274 |
-
# 1. 调整跳数
|
| 275 |
-
answer = graph_retriever.local_query(question, max_hops=1) # 减少跳数提速
|
| 276 |
-
|
| 277 |
-
# 2. 限制社区数量
|
| 278 |
-
answer = graph_retriever.global_query(question, top_k_communities=3) # 减少社区数
|
| 279 |
-
|
| 280 |
-
# 3. 实体识别缓存(开发中)
|
| 281 |
-
```
|
| 282 |
-
|
| 283 |
-
## 🔍 调试和可视化
|
| 284 |
-
|
| 285 |
-
### 查看图谱统计
|
| 286 |
-
|
| 287 |
-
```python
|
| 288 |
-
stats = knowledge_graph.get_statistics()
|
| 289 |
-
print(f"节点数: {stats['num_nodes']}")
|
| 290 |
-
print(f"边数: {stats['num_edges']}")
|
| 291 |
-
print(f"社区数: {stats['num_communities']}")
|
| 292 |
-
```
|
| 293 |
-
|
| 294 |
-
### 导出图谱
|
| 295 |
-
|
| 296 |
-
```python
|
| 297 |
-
# 保存为JSON
|
| 298 |
-
knowledge_graph.save_to_file("my_graph.json")
|
| 299 |
-
|
| 300 |
-
# 加载图谱
|
| 301 |
-
knowledge_graph.load_from_file("my_graph.json")
|
| 302 |
-
```
|
| 303 |
-
|
| 304 |
-
### 可视化(可选)
|
| 305 |
-
|
| 306 |
-
```python
|
| 307 |
-
# 需要额外安装: pip install pyvis
|
| 308 |
-
from pyvis.network import Network
|
| 309 |
-
|
| 310 |
-
def visualize_graph(kg, output="graph.html"):
|
| 311 |
-
net = Network(height="750px", width="100%", bgcolor="#222222", font_color="white")
|
| 312 |
-
|
| 313 |
-
for node, data in kg.graph.nodes(data=True):
|
| 314 |
-
net.add_node(node, label=node, title=data.get('description', ''))
|
| 315 |
-
|
| 316 |
-
for u, v, data in kg.graph.edges(data=True):
|
| 317 |
-
net.add_edge(u, v, title=data.get('relation_type', ''))
|
| 318 |
-
|
| 319 |
-
net.show(output)
|
| 320 |
-
print(f"图谱已保存到: {output}")
|
| 321 |
-
```
|
| 322 |
-
|
| 323 |
-
## ⚠️ 常见问题
|
| 324 |
-
|
| 325 |
-
### Q1: 实体提取质量不高?
|
| 326 |
-
**A**:
|
| 327 |
-
- 调整LLM温度参数
|
| 328 |
-
- 优化实体提取提示词
|
| 329 |
-
- 使用更强大的LLM模型
|
| 330 |
-
|
| 331 |
-
### Q2: 索引构建时间长?
|
| 332 |
-
**A**:
|
| 333 |
-
- 增大批处理大小
|
| 334 |
-
- 减少文档数量进行测试
|
| 335 |
-
- 使用缓存的索引文件
|
| 336 |
-
|
| 337 |
-
### Q3: 查询结果不相关?
|
| 338 |
-
**A**:
|
| 339 |
-
- 检查实体识别是否准确
|
| 340 |
-
- 调整查询策略(本地/全局)
|
| 341 |
-
- 增加邻居跳数
|
| 342 |
-
|
| 343 |
-
### Q4: 内存占用过大?
|
| 344 |
-
**A**:
|
| 345 |
-
- 使用更轻量的图数据库
|
| 346 |
-
- 分批处理大文档集
|
| 347 |
-
- 限制社区检测的迭代次数
|
| 348 |
-
|
| 349 |
-
## 🔄 与现有系统集成
|
| 350 |
-
|
| 351 |
-
### 修改现有 main.py
|
| 352 |
-
|
| 353 |
-
```python
|
| 354 |
-
from config import ENABLE_GRAPHRAG
|
| 355 |
-
from graph_indexer import initialize_graph_indexer
|
| 356 |
-
from graph_retriever import initialize_graph_retriever
|
| 357 |
-
|
| 358 |
-
class AdaptiveRAGSystem:
|
| 359 |
-
def __init__(self):
|
| 360 |
-
# ... 现有初始化代码 ...
|
| 361 |
-
|
| 362 |
-
# 添加GraphRAG支持
|
| 363 |
-
if ENABLE_GRAPHRAG:
|
| 364 |
-
self._setup_graphrag()
|
| 365 |
-
|
| 366 |
-
def _setup_graphrag(self):
|
| 367 |
-
self.graph_indexer = initialize_graph_indexer()
|
| 368 |
-
# ... 索引构建 ...
|
| 369 |
-
self.graph_retriever = initialize_graph_retriever(self.knowledge_graph)
|
| 370 |
-
|
| 371 |
-
def query(self, question: str):
|
| 372 |
-
# 混合使用向量检索和图谱查询
|
| 373 |
-
vector_docs = self.retriever.get_relevant_documents(question)
|
| 374 |
-
|
| 375 |
-
if ENABLE_GRAPHRAG:
|
| 376 |
-
graph_answer = self.graph_retriever.smart_query(question)
|
| 377 |
-
# 融合两种结果
|
| 378 |
-
return self._merge_results(vector_docs, graph_answer)
|
| 379 |
-
|
| 380 |
-
return self._generate_from_docs(vector_docs)
|
| 381 |
-
```
|
| 382 |
-
|
| 383 |
-
## 📚 参考资料
|
| 384 |
-
|
| 385 |
-
- [Microsoft GraphRAG 论文](https://arxiv.org/abs/2404.16130)
|
| 386 |
-
- [NetworkX 文档](https://networkx.org/)
|
| 387 |
-
- [Louvain 社区检测算法](https://en.wikipedia.org/wiki/Louvain_method)
|
| 388 |
-
|
| 389 |
-
## 🛣️ 未来增强
|
| 390 |
-
|
| 391 |
-
- [ ] 增量索引更新
|
| 392 |
-
- [ ] 多模态知识图谱
|
| 393 |
-
- [ ] 图谱可视化界面
|
| 394 |
-
- [ ] Neo4j集成(生产环境)
|
| 395 |
-
- [ ] 知识图谱推理引擎
|
| 396 |
-
- [ ] 实体链接优化
|
| 397 |
-
- [ ] 自动实体消歧
|
| 398 |
-
|
| 399 |
-
---
|
| 400 |
-
|
| 401 |
-
**提示**: 首次使用建议先在小数据集上测试,验证效果后再应用到完整数据集。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GRAPHRAG_INTEGRATION_SUMMARY.md
DELETED
|
@@ -1,427 +0,0 @@
|
|
| 1 |
-
# GraphRAG 集成完成总结
|
| 2 |
-
|
| 3 |
-
## ✅ 已完成的工作
|
| 4 |
-
|
| 5 |
-
### 🆕 新增文件 (7个)
|
| 6 |
-
|
| 7 |
-
| 文件 | 行数 | 主要功能 |
|
| 8 |
-
|------|------|---------|
|
| 9 |
-
| **entity_extractor.py** | 225 | 实体和关系提取、实体去重 |
|
| 10 |
-
| **knowledge_graph.py** | 348 | 图谱构建、社区检测、摘要生成 |
|
| 11 |
-
| **graph_indexer.py** | 146 | GraphRAG索引构建流程 |
|
| 12 |
-
| **graph_retriever.py** | 276 | 本地/全局/智能查询 |
|
| 13 |
-
| **main_graphrag.py** | 294 | 完整使用示例和交互界面 |
|
| 14 |
-
| **requirements_graphrag.txt** | 32 | GraphRAG额外依赖 |
|
| 15 |
-
| **GRAPHRAG_GUIDE.md** | 402 | 详细使用指南 |
|
| 16 |
-
|
| 17 |
-
### 🔧 修改的文件 (3个)
|
| 18 |
-
|
| 19 |
-
| 文件 | 修改内容 |
|
| 20 |
-
|------|---------|
|
| 21 |
-
| **config.py** | 添加7个GraphRAG配置参数 |
|
| 22 |
-
| **document_processor.py** | 修改`setup_knowledge_base()`返回doc_splits |
|
| 23 |
-
| **requirements.txt** | 添加networkx和python-louvain依赖 |
|
| 24 |
-
|
| 25 |
-
---
|
| 26 |
-
|
| 27 |
-
## 📋 文件修改详情
|
| 28 |
-
|
| 29 |
-
### 1. config.py - 新增配置
|
| 30 |
-
|
| 31 |
-
```python
|
| 32 |
-
# GraphRAG配置
|
| 33 |
-
ENABLE_GRAPHRAG = True
|
| 34 |
-
GRAPHRAG_INDEX_PATH = "./data/knowledge_graph.json"
|
| 35 |
-
GRAPHRAG_COMMUNITY_ALGORITHM = "louvain"
|
| 36 |
-
GRAPHRAG_MAX_HOPS = 2
|
| 37 |
-
GRAPHRAG_TOP_K_COMMUNITIES = 5
|
| 38 |
-
GRAPHRAG_BATCH_SIZE = 10
|
| 39 |
-
```
|
| 40 |
-
|
| 41 |
-
### 2. document_processor.py - 函数修改
|
| 42 |
-
|
| 43 |
-
```python
|
| 44 |
-
# 修改前
|
| 45 |
-
def setup_knowledge_base(self, urls=None):
|
| 46 |
-
...
|
| 47 |
-
return vectorstore, retriever
|
| 48 |
-
|
| 49 |
-
# 修改后
|
| 50 |
-
def setup_knowledge_base(self, urls=None, enable_graphrag=False):
|
| 51 |
-
...
|
| 52 |
-
return vectorstore, retriever, doc_splits # 新增返回doc_splits
|
| 53 |
-
|
| 54 |
-
# 同步修改
|
| 55 |
-
def initialize_document_processor():
|
| 56 |
-
...
|
| 57 |
-
return processor, vectorstore, retriever, doc_splits # 新增doc_splits
|
| 58 |
-
```
|
| 59 |
-
|
| 60 |
-
### 3. requirements.txt - 新增依赖
|
| 61 |
-
|
| 62 |
-
```txt
|
| 63 |
-
# GraphRAG相关(可选)
|
| 64 |
-
networkx>=3.1
|
| 65 |
-
python-louvain>=0.16
|
| 66 |
-
```
|
| 67 |
-
|
| 68 |
-
---
|
| 69 |
-
|
| 70 |
-
## 🏗️ GraphRAG 架构概览
|
| 71 |
-
|
| 72 |
-
```
|
| 73 |
-
┌─────────────────────────────────────────────────────────────┐
|
| 74 |
-
│ 文档处理层 │
|
| 75 |
-
│ document_processor.py → doc_splits │
|
| 76 |
-
└────────────────────────┬────────────────────────────────────┘
|
| 77 |
-
↓
|
| 78 |
-
┌─────────────────────────────────────────────────────────────┐
|
| 79 |
-
│ 实体提取层 │
|
| 80 |
-
│ entity_extractor.py │
|
| 81 |
-
│ ├── EntityExtractor (实体和关系提取) │
|
| 82 |
-
│ └── EntityDeduplicator (实体去重) │
|
| 83 |
-
└────────────────────────┬────────────────────────────────────┘
|
| 84 |
-
↓
|
| 85 |
-
┌─────────────────────────────────────────────────────────────┐
|
| 86 |
-
│ 图谱构建层 │
|
| 87 |
-
│ knowledge_graph.py │
|
| 88 |
-
│ ├── KnowledgeGraph (图谱管理) │
|
| 89 |
-
│ │ ├── NetworkX图结构 │
|
| 90 |
-
│ │ ├── 社区检测 (Louvain/Greedy/LabelProp) │
|
| 91 |
-
│ │ └── 统计分析 │
|
| 92 |
-
│ └── CommunitySummarizer (社区摘要) │
|
| 93 |
-
└────────────────────────┬────────────────────────────────────┘
|
| 94 |
-
↓
|
| 95 |
-
┌─────────────────────────────────────────────────────────────┐
|
| 96 |
-
│ 索引构建层 │
|
| 97 |
-
│ graph_indexer.py │
|
| 98 |
-
│ └── GraphRAGIndexer │
|
| 99 |
-
│ ├── 5步索引流程 │
|
| 100 |
-
│ └── 图谱持久化 │
|
| 101 |
-
└────────────────────────┬────────────────────────────────────┘
|
| 102 |
-
↓
|
| 103 |
-
┌─────────────────────────────────────────────────────────────┐
|
| 104 |
-
│ 检索查询层 │
|
| 105 |
-
│ graph_retriever.py │
|
| 106 |
-
│ └── GraphRetriever │
|
| 107 |
-
│ ├── 本地查询 (Local Query) │
|
| 108 |
-
│ ├── 全局查询 (Global Query) │
|
| 109 |
-
│ ├── 混合查询 (Hybrid Query) │
|
| 110 |
-
│ └── 智能查询 (Smart Query) │
|
| 111 |
-
└────────────────────────┬────────────────────────────────────┘
|
| 112 |
-
↓
|
| 113 |
-
┌─────────────────────────────────────────────────────────────┐
|
| 114 |
-
│ 应用层 │
|
| 115 |
-
│ main_graphrag.py │
|
| 116 |
-
│ └── AdaptiveRAGWithGraph │
|
| 117 |
-
│ ├── 5种查询模式 │
|
| 118 |
-
│ ├── 统计信息展示 │
|
| 119 |
-
│ └── 交互式界面 │
|
| 120 |
-
└─────────────────────────────────────────────────────────────┘
|
| 121 |
-
```
|
| 122 |
-
|
| 123 |
-
---
|
| 124 |
-
|
| 125 |
-
## 🚀 使用流程
|
| 126 |
-
|
| 127 |
-
### 方式1: 直接运行示例
|
| 128 |
-
|
| 129 |
-
```bash
|
| 130 |
-
# 1. 安装依赖
|
| 131 |
-
pip install -r requirements.txt
|
| 132 |
-
pip install -r requirements_graphrag.txt
|
| 133 |
-
|
| 134 |
-
# 2. 运行GraphRAG示例
|
| 135 |
-
python main_graphrag.py
|
| 136 |
-
|
| 137 |
-
# 首次运行会自动构建索引,后续运行会加载缓存
|
| 138 |
-
```
|
| 139 |
-
|
| 140 |
-
### 方式2: 集成到现有代码
|
| 141 |
-
|
| 142 |
-
```python
|
| 143 |
-
# 在 main.py 中集成
|
| 144 |
-
from config import ENABLE_GRAPHRAG, GRAPHRAG_INDEX_PATH
|
| 145 |
-
from graph_indexer import initialize_graph_indexer
|
| 146 |
-
from graph_retriever import initialize_graph_retriever
|
| 147 |
-
|
| 148 |
-
class AdaptiveRAGSystem:
|
| 149 |
-
def __init__(self):
|
| 150 |
-
# ... 现有初始化 ...
|
| 151 |
-
|
| 152 |
-
if ENABLE_GRAPHRAG:
|
| 153 |
-
# 构建/加载图谱
|
| 154 |
-
self.graph_indexer = initialize_graph_indexer()
|
| 155 |
-
|
| 156 |
-
if os.path.exists(GRAPHRAG_INDEX_PATH):
|
| 157 |
-
self.kg = self.graph_indexer.load_index(GRAPHRAG_INDEX_PATH)
|
| 158 |
-
else:
|
| 159 |
-
self.kg = self.graph_indexer.index_documents(
|
| 160 |
-
self.doc_splits,
|
| 161 |
-
save_path=GRAPHRAG_INDEX_PATH
|
| 162 |
-
)
|
| 163 |
-
|
| 164 |
-
# 初始化检索器
|
| 165 |
-
self.graph_retriever = initialize_graph_retriever(self.kg)
|
| 166 |
-
|
| 167 |
-
def query(self, question: str):
|
| 168 |
-
if ENABLE_GRAPHRAG:
|
| 169 |
-
# 使用图谱智能查询
|
| 170 |
-
return self.graph_retriever.smart_query(question)
|
| 171 |
-
else:
|
| 172 |
-
# 原有逻辑
|
| 173 |
-
...
|
| 174 |
-
```
|
| 175 |
-
|
| 176 |
-
---
|
| 177 |
-
|
| 178 |
-
## 📊 功能对比
|
| 179 |
-
|
| 180 |
-
### 原系统 vs GraphRAG增强
|
| 181 |
-
|
| 182 |
-
| 功能 | 原系统 | GraphRAG增强 | 提升 |
|
| 183 |
-
|------|--------|--------------|------|
|
| 184 |
-
| **检索方式** | 向量相似度 | 向量 + 图谱 | ✅ 多模态检索 |
|
| 185 |
-
| **关系理解** | ❌ 无 | ✅ 显式关系 | ✅ 关系推理能力 |
|
| 186 |
-
| **多跳推理** | ❌ 有限 | ✅ 支持N跳 | ✅ 复杂推理 |
|
| 187 |
-
| **全局理解** | ⚠️ 需读取多文档 | ✅ 社区摘要 | ✅ 高效概览 |
|
| 188 |
-
| **实体消歧** | ❌ 无 | ✅ 图谱上下文 | ✅ 准确识别 |
|
| 189 |
-
| **事实验证** | 基于文档匹配 | 基于关系验证 | ✅ 更严格 |
|
| 190 |
-
|
| 191 |
-
---
|
| 192 |
-
|
| 193 |
-
## 🎯 适用场景
|
| 194 |
-
|
| 195 |
-
### GraphRAG特别适合:
|
| 196 |
-
|
| 197 |
-
✅ **知识密集型领域**
|
| 198 |
-
- 学术论文、技术文档
|
| 199 |
-
- 需要理解实体关系
|
| 200 |
-
- 例: "AlphaCodium的作者研究了哪些其他技术?"
|
| 201 |
-
|
| 202 |
-
✅ **需要推理的问题**
|
| 203 |
-
- 多跳关系查询
|
| 204 |
-
- 因果关系分析
|
| 205 |
-
- 例: "提示工程如何应用于对抗性攻击防御?"
|
| 206 |
-
|
| 207 |
-
✅ **概览性问题**
|
| 208 |
-
- 主题归纳
|
| 209 |
-
- 研究趋势
|
| 210 |
-
- 例: "这个领域的主要研究方向有哪些?"
|
| 211 |
-
|
| 212 |
-
### 仍使用向量检索:
|
| 213 |
-
|
| 214 |
-
⚠️ **模糊语义查询**
|
| 215 |
-
- 没有明确实体
|
| 216 |
-
- 需要语义相似匹配
|
| 217 |
-
|
| 218 |
-
⚠️ **最新资讯查询**
|
| 219 |
-
- 图谱未覆盖的新内容
|
| 220 |
-
- 需要网络搜索
|
| 221 |
-
|
| 222 |
-
---
|
| 223 |
-
|
| 224 |
-
## 🔧 配置参数说明
|
| 225 |
-
|
| 226 |
-
```python
|
| 227 |
-
# config.py
|
| 228 |
-
|
| 229 |
-
ENABLE_GRAPHRAG = True
|
| 230 |
-
# 是否启用GraphRAG,False则回退到纯向量检索
|
| 231 |
-
|
| 232 |
-
GRAPHRAG_INDEX_PATH = "./data/knowledge_graph.json"
|
| 233 |
-
# 图谱持久化路径,避免每次重建
|
| 234 |
-
|
| 235 |
-
GRAPHRAG_COMMUNITY_ALGORITHM = "louvain"
|
| 236 |
-
# 社区检测算法:
|
| 237 |
-
# - "louvain": 最优质量(推荐)
|
| 238 |
-
# - "greedy": 更快速度
|
| 239 |
-
# - "label_propagation": 快速近似
|
| 240 |
-
|
| 241 |
-
GRAPHRAG_MAX_HOPS = 2
|
| 242 |
-
# 本地查询时扩展的邻居深度
|
| 243 |
-
# 1: 只看直接邻居
|
| 244 |
-
# 2: 二跳邻居(推荐)
|
| 245 |
-
# 3+: 可能包含过多噪声
|
| 246 |
-
|
| 247 |
-
GRAPHRAG_TOP_K_COMMUNITIES = 5
|
| 248 |
-
# 全局查询时使用的社区数量
|
| 249 |
-
# 更多社区 = 更全面但更慢
|
| 250 |
-
|
| 251 |
-
GRAPHRAG_BATCH_SIZE = 10
|
| 252 |
-
# 实体提取的批处理大小
|
| 253 |
-
# 更大批次 = 更快但更耗内存
|
| 254 |
-
```
|
| 255 |
-
|
| 256 |
-
---
|
| 257 |
-
|
| 258 |
-
## 📈 性能特征
|
| 259 |
-
|
| 260 |
-
### 索引构建时间
|
| 261 |
-
|
| 262 |
-
| 文档数量 | 实体数 | 关系数 | 社区数 | 构建时间* |
|
| 263 |
-
|---------|--------|--------|--------|----------|
|
| 264 |
-
| 10个文档块 | ~50 | ~30 | 3-5 | ~2分钟 |
|
| 265 |
-
| 50个文档块 | ~200 | ~150 | 8-12 | ~8分钟 |
|
| 266 |
-
| 100个文档块 | ~400 | ~300 | 15-20 | ~15分钟 |
|
| 267 |
-
|
| 268 |
-
*基于Mistral模型,实际时间取决于LLM速度
|
| 269 |
-
|
| 270 |
-
### 查询速度
|
| 271 |
-
|
| 272 |
-
| 查询类型 | 平均耗时 | 说明 |
|
| 273 |
-
|---------|---------|------|
|
| 274 |
-
| 本地查询 | 2-5秒 | 需要LLM生成答案 |
|
| 275 |
-
| 全局查询 | 3-8秒 | 需要处理多个社区摘要 |
|
| 276 |
-
| 智能查询 | 2-8秒 | 取决于选择的策略 |
|
| 277 |
-
| 混合查询 | 5-12秒 | 执行两种查询 |
|
| 278 |
-
|
| 279 |
-
### 存储需求
|
| 280 |
-
|
| 281 |
-
- **图谱索引**: 100个文档块 ≈ 1-5 MB (JSON格式)
|
| 282 |
-
- **内存占用**: 运行时 ≈ 200-500 MB (取决于图大小)
|
| 283 |
-
|
| 284 |
-
---
|
| 285 |
-
|
| 286 |
-
## 🐛 故障排查
|
| 287 |
-
|
| 288 |
-
### 问题1: 实体提取失败
|
| 289 |
-
```
|
| 290 |
-
❌ 实体提取失败: timeout
|
| 291 |
-
```
|
| 292 |
-
|
| 293 |
-
**解决方案**:
|
| 294 |
-
- 检查Ollama服务是否运行: `ollama serve`
|
| 295 |
-
- 减少批处理大小: `GRAPHRAG_BATCH_SIZE = 5`
|
| 296 |
-
- 使用更快的LLM模型
|
| 297 |
-
|
| 298 |
-
### 问题2: 社区检测失败
|
| 299 |
-
```
|
| 300 |
-
⚠️ python-louvain未安装
|
| 301 |
-
```
|
| 302 |
-
|
| 303 |
-
**解决方案**:
|
| 304 |
-
```bash
|
| 305 |
-
pip install python-louvain
|
| 306 |
-
# 或使用其他算法
|
| 307 |
-
GRAPHRAG_COMMUNITY_ALGORITHM = "greedy"
|
| 308 |
-
```
|
| 309 |
-
|
| 310 |
-
### 问题3: 查询无结果
|
| 311 |
-
```
|
| 312 |
-
未能在知识图谱中找到相关实体
|
| 313 |
-
```
|
| 314 |
-
|
| 315 |
-
**解决方案**:
|
| 316 |
-
- 检查图谱是否构建: `rag_system.get_graph_statistics()`
|
| 317 |
-
- 使用全局查询代替本地查询
|
| 318 |
-
- 检查实体提取质量
|
| 319 |
-
|
| 320 |
-
### 问题4: 内存不足
|
| 321 |
-
```
|
| 322 |
-
MemoryError
|
| 323 |
-
```
|
| 324 |
-
|
| 325 |
-
**解决方案**:
|
| 326 |
-
- 减少文档数量测试
|
| 327 |
-
- 增加批处理间隔
|
| 328 |
-
- 使用轻量级图存储
|
| 329 |
-
|
| 330 |
-
---
|
| 331 |
-
|
| 332 |
-
## 📝 代码示例
|
| 333 |
-
|
| 334 |
-
### 示例1: 基本使用
|
| 335 |
-
|
| 336 |
-
```python
|
| 337 |
-
from main_graphrag import AdaptiveRAGWithGraph
|
| 338 |
-
|
| 339 |
-
# 初始化系统
|
| 340 |
-
rag = AdaptiveRAGWithGraph(enable_graphrag=True)
|
| 341 |
-
|
| 342 |
-
# 本地查询(针对特定实体)
|
| 343 |
-
answer = rag.query_graph_local("LLM Agent的主要组件是什么?")
|
| 344 |
-
|
| 345 |
-
# 全局查询(概览性问题)
|
| 346 |
-
answer = rag.query_graph_global("这些文档讨论了哪些主题?")
|
| 347 |
-
|
| 348 |
-
# 智能查询(自动选择策略)
|
| 349 |
-
answer = rag.query_smart("如何防御对抗性攻击?")
|
| 350 |
-
```
|
| 351 |
-
|
| 352 |
-
### 示例2: 混合检索
|
| 353 |
-
|
| 354 |
-
```python
|
| 355 |
-
# 同时使用向量和图谱
|
| 356 |
-
result = rag.query_hybrid("提示工程在LLM中的应用")
|
| 357 |
-
|
| 358 |
-
print("向量检索:", result["vector_retrieval"]["context"])
|
| 359 |
-
print("图谱本地:", result["graph_local"])
|
| 360 |
-
print("图谱全局:", result["graph_global"])
|
| 361 |
-
```
|
| 362 |
-
|
| 363 |
-
### 示例3: 手动控制
|
| 364 |
-
|
| 365 |
-
```python
|
| 366 |
-
from graph_indexer import initialize_graph_indexer
|
| 367 |
-
from graph_retriever import initialize_graph_retriever
|
| 368 |
-
|
| 369 |
-
# 构建索引
|
| 370 |
-
indexer = initialize_graph_indexer()
|
| 371 |
-
kg = indexer.index_documents(documents, save_path="my_graph.json")
|
| 372 |
-
|
| 373 |
-
# 查看统计
|
| 374 |
-
stats = kg.get_statistics()
|
| 375 |
-
print(f"实体: {stats['num_nodes']}, 关系: {stats['num_edges']}")
|
| 376 |
-
|
| 377 |
-
# 查询
|
| 378 |
-
retriever = initialize_graph_retriever(kg)
|
| 379 |
-
answer = retriever.local_query("specific question", max_hops=3)
|
| 380 |
-
```
|
| 381 |
-
|
| 382 |
-
---
|
| 383 |
-
|
| 384 |
-
## 🎓 学习资源
|
| 385 |
-
|
| 386 |
-
### 推荐阅读顺序
|
| 387 |
-
|
| 388 |
-
1. **GRAPHRAG_GUIDE.md** - 详细使用指南
|
| 389 |
-
2. **entity_extractor.py** - 了解实体提取
|
| 390 |
-
3. **knowledge_graph.py** - 理解图谱构建
|
| 391 |
-
4. **graph_retriever.py** - 学习查询策略
|
| 392 |
-
5. **main_graphrag.py** - 完整实践示例
|
| 393 |
-
|
| 394 |
-
### 关键概念
|
| 395 |
-
|
| 396 |
-
- **实体 (Entity)**: 图中的节点,如人物、概念、技术
|
| 397 |
-
- **关系 (Relation)**: 图中的边,连接两个实体
|
| 398 |
-
- **社区 (Community)**: 紧密连接的节点群组
|
| 399 |
-
- **本地查询**: 基于实体邻域的精确查询
|
| 400 |
-
- **全局查询**: 基于社区摘要的概览查询
|
| 401 |
-
|
| 402 |
-
---
|
| 403 |
-
|
| 404 |
-
## 🔮 未来计划
|
| 405 |
-
|
| 406 |
-
- [ ] **增量索引**: 添加新文档无需重建整个图谱
|
| 407 |
-
- [ ] **Neo4j集成**: 生产环境使用专业图数据库
|
| 408 |
-
- [ ] **可视化界面**: Web界面展示知识图谱
|
| 409 |
-
- [ ] **多模型融合**: 结合多个LLM提高提取质量
|
| 410 |
-
- [ ] **实时更新**: 动态更新图谱结构
|
| 411 |
-
- [ ] **知识推理**: 基于图谱的推理引擎
|
| 412 |
-
- [ ] **性能优化**: 并行处理、缓存机制
|
| 413 |
-
|
| 414 |
-
---
|
| 415 |
-
|
| 416 |
-
## 📞 支持
|
| 417 |
-
|
| 418 |
-
遇到问题?
|
| 419 |
-
|
| 420 |
-
1. 查看 **GRAPHRAG_GUIDE.md** 的"常见问题"章节
|
| 421 |
-
2. 检查日志输出中的错误信息
|
| 422 |
-
3. 运行 `python main_graphrag.py` 测试基本功能
|
| 423 |
-
4. 使用 `get_graph_statistics()` 检查图谱状态
|
| 424 |
-
|
| 425 |
-
---
|
| 426 |
-
|
| 427 |
-
**总结**: GraphRAG已成功集成到自适应RAG系统中,提供了从实体提取到智能查询的完整工作流。通过合理选择查询策略,可以显著提升复杂问题的回答质量。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GRAPHRAG_TROUBLESHOOTING.md
DELETED
|
@@ -1,328 +0,0 @@
|
|
| 1 |
-
# GraphRAG 故障排除指南
|
| 2 |
-
|
| 3 |
-
## 问题:处理批次时卡住不动
|
| 4 |
-
|
| 5 |
-
### 症状
|
| 6 |
-
- 处理到第6个批次时,实体提取后程序卡住
|
| 7 |
-
- 没有错误信息,只是停止响应
|
| 8 |
-
- CPU/GPU使用率下降到0
|
| 9 |
-
|
| 10 |
-
### 根本原因
|
| 11 |
-
|
| 12 |
-
#### 1. **LLM超时问题** ⏱️
|
| 13 |
-
- **原因**: Ollama服务可能在处理复杂请求时超时
|
| 14 |
-
- **表现**: 请求挂起,没有响应也没有错误
|
| 15 |
-
- **解决方案**: 已添加timeout参数和重试机制
|
| 16 |
-
|
| 17 |
-
#### 2. **内存泄漏** 💾
|
| 18 |
-
- **原因**: 多次LLM调用后,Ollama可能积累内存
|
| 19 |
-
- **表现**: 响应变慢,最终完全停止
|
| 20 |
-
- **解决方案**:
|
| 21 |
-
```bash
|
| 22 |
-
# 重启Ollama服务
|
| 23 |
-
pkill ollama
|
| 24 |
-
ollama serve
|
| 25 |
-
```
|
| 26 |
-
|
| 27 |
-
#### 3. **连接池耗尽** 🔌
|
| 28 |
-
- **原因**: 太多并发请求,没有正确关闭连接
|
| 29 |
-
- **表现**: 新请求无法建立连接
|
| 30 |
-
- **解决方案**: 已添加重试延迟和异常处理
|
| 31 |
-
|
| 32 |
-
#### 4. **文档内容过长** 📄
|
| 33 |
-
- **原因**: 某些文档chunk可能超过LLM的上下文窗口
|
| 34 |
-
- **表现**: LLM静默失败
|
| 35 |
-
- **解决方案**: 已限制为2000字符
|
| 36 |
-
|
| 37 |
-
## 已实施的修复
|
| 38 |
-
|
| 39 |
-
### 1. 添加超时控制
|
| 40 |
-
```python
|
| 41 |
-
EntityExtractor(timeout=60, max_retries=3)
|
| 42 |
-
```
|
| 43 |
-
- 每次LLM调用最多60秒超时
|
| 44 |
-
- 失败后最多重试3次
|
| 45 |
-
- 重试间隔递增(2s, 4s, 6s)
|
| 46 |
-
|
| 47 |
-
### 2. 改进的错误处理
|
| 48 |
-
```python
|
| 49 |
-
try:
|
| 50 |
-
result = extractor.extract_from_document(...)
|
| 51 |
-
except Exception as e:
|
| 52 |
-
print(f"❌ 文档处理失败: {e}")
|
| 53 |
-
extraction_results.append({"entities": [], "relations": []})
|
| 54 |
-
```
|
| 55 |
-
- 捕获所有异常
|
| 56 |
-
- 添加空结果而不是崩溃
|
| 57 |
-
- 继续处理下一个文档
|
| 58 |
-
|
| 59 |
-
### 3. 详细的进度日志
|
| 60 |
-
```
|
| 61 |
-
⚙️ === 批次 6/10 (文档 51-60) ===
|
| 62 |
-
🔍 文档 #51: 开始提取...
|
| 63 |
-
🔄 提取实体 (尝试 1/3)... ✅ 提取到 5 个实体
|
| 64 |
-
🔄 提取关系 (尝试 1/3)... ✅ 提取到 3 个关系
|
| 65 |
-
📊 文档 #51 完成: 5 实体, 3 关系
|
| 66 |
-
```
|
| 67 |
-
|
| 68 |
-
## 故障排除步骤
|
| 69 |
-
|
| 70 |
-
### 步骤 1: 检查Ollama服务状态
|
| 71 |
-
```bash
|
| 72 |
-
# 检查Ollama是否运行
|
| 73 |
-
ps aux | grep ollama
|
| 74 |
-
|
| 75 |
-
# 查看Ollama日志
|
| 76 |
-
tail -f ~/.ollama/logs/server.log
|
| 77 |
-
|
| 78 |
-
# 检查模型是否加载
|
| 79 |
-
ollama list
|
| 80 |
-
```
|
| 81 |
-
|
| 82 |
-
### 步骤 2: 检查系统资源
|
| 83 |
-
```bash
|
| 84 |
-
# 内存使用
|
| 85 |
-
free -h # Linux
|
| 86 |
-
top # 查看Ollama进程
|
| 87 |
-
|
| 88 |
-
# 在Colab中
|
| 89 |
-
!nvidia-smi # GPU内存
|
| 90 |
-
!ps aux | grep ollama
|
| 91 |
-
```
|
| 92 |
-
|
| 93 |
-
### 步骤 3: 减小批次大小
|
| 94 |
-
```python
|
| 95 |
-
# 在 main_graphrag.py 或调用代码中
|
| 96 |
-
graph = indexer.index_documents(
|
| 97 |
-
documents=doc_splits,
|
| 98 |
-
batch_size=5, # 从10降到5
|
| 99 |
-
save_path="./knowledge_graph.pkl"
|
| 100 |
-
)
|
| 101 |
-
```
|
| 102 |
-
|
| 103 |
-
### 步骤 4: 测试单个文档
|
| 104 |
-
```python
|
| 105 |
-
# 测试提取器是否工作
|
| 106 |
-
from entity_extractor import EntityExtractor
|
| 107 |
-
|
| 108 |
-
extractor = EntityExtractor(timeout=30, max_retries=2)
|
| 109 |
-
result = extractor.extract_from_document(
|
| 110 |
-
"测试文本...",
|
| 111 |
-
doc_index=0
|
| 112 |
-
)
|
| 113 |
-
print(result)
|
| 114 |
-
```
|
| 115 |
-
|
| 116 |
-
### 步骤 5: 重启Ollama服务
|
| 117 |
-
```bash
|
| 118 |
-
# 完全重启Ollama
|
| 119 |
-
pkill -9 ollama
|
| 120 |
-
sleep 2
|
| 121 |
-
ollama serve &
|
| 122 |
-
|
| 123 |
-
# 等待服务启动
|
| 124 |
-
sleep 5
|
| 125 |
-
|
| 126 |
-
# 验证服务
|
| 127 |
-
curl http://localhost:11434/api/tags
|
| 128 |
-
```
|
| 129 |
-
|
| 130 |
-
## 性能优化建议
|
| 131 |
-
|
| 132 |
-
### 1. 调整超时参数
|
| 133 |
-
```python
|
| 134 |
-
# 对于较慢的机器或GPU
|
| 135 |
-
extractor = EntityExtractor(
|
| 136 |
-
timeout=120, # 增加到2分钟
|
| 137 |
-
max_retries=5 # 更多重试次数
|
| 138 |
-
)
|
| 139 |
-
```
|
| 140 |
-
|
| 141 |
-
### 2. 使用更小的模型
|
| 142 |
-
```python
|
| 143 |
-
# 在 config.py 中
|
| 144 |
-
LOCAL_LLM = "mistral:7b" # 默认
|
| 145 |
-
# 改为
|
| 146 |
-
LOCAL_LLM = "llama2:7b" # 更快
|
| 147 |
-
# 或
|
| 148 |
-
LOCAL_LLM = "phi:latest" # 最快,但质量较低
|
| 149 |
-
```
|
| 150 |
-
|
| 151 |
-
### 3. 增加批次间延迟
|
| 152 |
-
```python
|
| 153 |
-
# 在 graph_indexer.py 中,批次循环后添加
|
| 154 |
-
import time
|
| 155 |
-
for i in range(0, len(documents), batch_size):
|
| 156 |
-
# ... 处理批次 ...
|
| 157 |
-
time.sleep(2) # 给Ollama 2秒恢复时间
|
| 158 |
-
```
|
| 159 |
-
|
| 160 |
-
### 4. 限制并发请求
|
| 161 |
-
```python
|
| 162 |
-
# 使用线程池控制并发
|
| 163 |
-
from concurrent.futures import ThreadPoolExecutor
|
| 164 |
-
|
| 165 |
-
with ThreadPoolExecutor(max_workers=2) as executor:
|
| 166 |
-
futures = [executor.submit(extract, doc) for doc in batch]
|
| 167 |
-
results = [f.result() for f in futures]
|
| 168 |
-
```
|
| 169 |
-
|
| 170 |
-
## 在Google Colab中的特殊问题
|
| 171 |
-
|
| 172 |
-
### 问题: Colab会话超时
|
| 173 |
-
**解决方案**: 使用checkpoint保存进度
|
| 174 |
-
```python
|
| 175 |
-
# 每处理N个批次保存一次
|
| 176 |
-
if batch_num % 5 == 0:
|
| 177 |
-
checkpoint = {
|
| 178 |
-
'extraction_results': extraction_results,
|
| 179 |
-
'processed_docs': i + len(batch)
|
| 180 |
-
}
|
| 181 |
-
import pickle
|
| 182 |
-
with open(f'/content/drive/MyDrive/checkpoint_{batch_num}.pkl', 'wb') as f:
|
| 183 |
-
pickle.dump(checkpoint, f)
|
| 184 |
-
```
|
| 185 |
-
|
| 186 |
-
### 问题: Ollama内存不足
|
| 187 |
-
**解决方案**: 在Colab中设置较小的上下文窗口
|
| 188 |
-
```python
|
| 189 |
-
# 启动Ollama时
|
| 190 |
-
!OLLAMA_NUM_GPU=1 OLLAMA_MAX_LOADED_MODELS=1 ollama serve > /tmp/ollama.log 2>&1 &
|
| 191 |
-
```
|
| 192 |
-
|
| 193 |
-
## 监控和调试
|
| 194 |
-
|
| 195 |
-
### 添加详细日志
|
| 196 |
-
```python
|
| 197 |
-
import logging
|
| 198 |
-
|
| 199 |
-
logging.basicConfig(
|
| 200 |
-
level=logging.DEBUG,
|
| 201 |
-
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
| 202 |
-
handlers=[
|
| 203 |
-
logging.FileHandler('graphrag_debug.log'),
|
| 204 |
-
logging.StreamHandler()
|
| 205 |
-
]
|
| 206 |
-
)
|
| 207 |
-
```
|
| 208 |
-
|
| 209 |
-
### 使用超时上下文管理器
|
| 210 |
-
```python
|
| 211 |
-
import signal
|
| 212 |
-
from contextlib import contextmanager
|
| 213 |
-
|
| 214 |
-
@contextmanager
|
| 215 |
-
def timeout(seconds):
|
| 216 |
-
def handler(signum, frame):
|
| 217 |
-
raise TimeoutError()
|
| 218 |
-
signal.signal(signal.SIGALRM, handler)
|
| 219 |
-
signal.alarm(seconds)
|
| 220 |
-
try:
|
| 221 |
-
yield
|
| 222 |
-
finally:
|
| 223 |
-
signal.alarm(0)
|
| 224 |
-
|
| 225 |
-
# 使用
|
| 226 |
-
with timeout(60):
|
| 227 |
-
result = extractor.extract_from_document(text)
|
| 228 |
-
```
|
| 229 |
-
|
| 230 |
-
## 常见错误信息
|
| 231 |
-
|
| 232 |
-
| 错误信息 | 原因 | 解决方案 |
|
| 233 |
-
|---------|------|---------|
|
| 234 |
-
| `Connection refused` | Ollama未运行 | `ollama serve` |
|
| 235 |
-
| `Timeout` | LLM响应慢 | 增加timeout参数 |
|
| 236 |
-
| `CUDA out of memory` | GPU内存不足 | 减小batch_size |
|
| 237 |
-
| `JSON decode error` | LLM输出格式错误 | 检查prompt模板 |
|
| 238 |
-
| 卡住无输出 | LLM挂起 | 重启Ollama,添加超时 |
|
| 239 |
-
|
| 240 |
-
## 快速修复清单
|
| 241 |
-
|
| 242 |
-
✅ **立即尝试这些步骤**:
|
| 243 |
-
|
| 244 |
-
1. **重启Ollama**
|
| 245 |
-
```bash
|
| 246 |
-
pkill ollama && sleep 2 && ollama serve &
|
| 247 |
-
```
|
| 248 |
-
|
| 249 |
-
2. **减小批次大小**
|
| 250 |
-
```python
|
| 251 |
-
batch_size=3 # 从10改为3
|
| 252 |
-
```
|
| 253 |
-
|
| 254 |
-
3. **增加超时时间**
|
| 255 |
-
```python
|
| 256 |
-
EntityExtractor(timeout=120, max_retries=5)
|
| 257 |
-
```
|
| 258 |
-
|
| 259 |
-
4. **检查第6个文档**
|
| 260 |
-
```python
|
| 261 |
-
# 单独处理第6个文档看是否有特殊问题
|
| 262 |
-
doc_6 = documents[5]
|
| 263 |
-
print(f"文档长度: {len(doc_6.page_content)}")
|
| 264 |
-
print(f"前500字符: {doc_6.page_content[:500]}")
|
| 265 |
-
```
|
| 266 |
-
|
| 267 |
-
5. **使用检查点恢复**
|
| 268 |
-
```python
|
| 269 |
-
# 从第6批次重新开始
|
| 270 |
-
start_index = 50 # 跳过前5批次
|
| 271 |
-
documents_remaining = documents[start_index:]
|
| 272 |
-
```
|
| 273 |
-
|
| 274 |
-
## 预防措施
|
| 275 |
-
|
| 276 |
-
1. **开始前验证环境**
|
| 277 |
-
```bash
|
| 278 |
-
# 检查所有依赖
|
| 279 |
-
python colab_install_deps.py
|
| 280 |
-
|
| 281 |
-
# 测试Ollama
|
| 282 |
-
ollama list
|
| 283 |
-
ollama run mistral "Hello"
|
| 284 |
-
```
|
| 285 |
-
|
| 286 |
-
2. **使用小数据集测试**
|
| 287 |
-
```python
|
| 288 |
-
# 先用5个文档测试
|
| 289 |
-
test_docs = doc_splits[:5]
|
| 290 |
-
graph = indexer.index_documents(test_docs, batch_size=2)
|
| 291 |
-
```
|
| 292 |
-
|
| 293 |
-
3. **监控资源使用**
|
| 294 |
-
```python
|
| 295 |
-
import psutil
|
| 296 |
-
print(f"内存使用: {psutil.virtual_memory().percent}%")
|
| 297 |
-
```
|
| 298 |
-
|
| 299 |
-
## 获取帮助
|
| 300 |
-
|
| 301 |
-
如果问题持续,请提供以下信息:
|
| 302 |
-
|
| 303 |
-
1. **系统信息**
|
| 304 |
-
- OS版本
|
| 305 |
-
- Python版本
|
| 306 |
-
- Ollama版本
|
| 307 |
-
- 可用内存/GPU
|
| 308 |
-
|
| 309 |
-
2. **错误日志**
|
| 310 |
-
- 最后一条成功的输出
|
| 311 |
-
- 完整的错误堆栈
|
| 312 |
-
- Ollama日志 (`~/.ollama/logs/server.log`)
|
| 313 |
-
|
| 314 |
-
3. **复现步骤**
|
| 315 |
-
- 文档数量
|
| 316 |
-
- batch_size
|
| 317 |
-
- 在哪个批次卡住
|
| 318 |
-
|
| 319 |
-
## 总结
|
| 320 |
-
|
| 321 |
-
**最可能的原因**: LLM调用超时或Ollama内存积累
|
| 322 |
-
|
| 323 |
-
**最快的解决方案**:
|
| 324 |
-
1. 重启Ollama服务
|
| 325 |
-
2. 减小batch_size到3-5
|
| 326 |
-
3. 使用更新后的带超时和重试的代码
|
| 327 |
-
|
| 328 |
-
现在的代码已经包含了所有这些保护措施,应该能够稳定运行!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
KAGGLE_DATASET_GUIDE.md
DELETED
|
@@ -1,478 +0,0 @@
|
|
| 1 |
-
# Kaggle Ollama Dataset 保存与加载指南
|
| 2 |
-
|
| 3 |
-
## 📋 目录
|
| 4 |
-
1. [问题背景](#问题背景)
|
| 5 |
-
2. [解决方案](#解决方案)
|
| 6 |
-
3. [详细步骤](#详细步骤)
|
| 7 |
-
4. [时间对比](#时间对比)
|
| 8 |
-
5. [故障排除](#故障排除)
|
| 9 |
-
|
| 10 |
-
---
|
| 11 |
-
|
| 12 |
-
## 问题背景
|
| 13 |
-
|
| 14 |
-
### Kaggle 存储特性
|
| 15 |
-
|
| 16 |
-
在 Kaggle 环境中:
|
| 17 |
-
|
| 18 |
-
| 目录 | 会话结束后 | 说明 |
|
| 19 |
-
|------|----------|------|
|
| 20 |
-
| `/usr/local` | ❌ 删除 | Ollama 安装位置 |
|
| 21 |
-
| `/kaggle/working` | ❌ 删除 | 工作目录 |
|
| 22 |
-
| `/home` | ❌ 删除 | 用户目录(模型存储位置) |
|
| 23 |
-
| `/kaggle/input` | ✅ 保留 | **Dataset 目录(永久)** |
|
| 24 |
-
|
| 25 |
-
### 当前问题
|
| 26 |
-
|
| 27 |
-
每次启动 Kaggle Notebook 都需要:
|
| 28 |
-
1. 下载 Ollama 安装脚本(~100MB)
|
| 29 |
-
2. 安装 Ollama
|
| 30 |
-
3. 下载模型(Mistral 4GB,需要 5-10 分钟)
|
| 31 |
-
|
| 32 |
-
**总耗时:约 10-15 分钟**
|
| 33 |
-
|
| 34 |
-
---
|
| 35 |
-
|
| 36 |
-
## 解决方案
|
| 37 |
-
|
| 38 |
-
### 核心思路
|
| 39 |
-
|
| 40 |
-
将 Ollama 和模型**一次性**保存到 Kaggle Dataset(永久存储),后续每次启动直接加载。
|
| 41 |
-
|
| 42 |
-
### 优势
|
| 43 |
-
|
| 44 |
-
- ✅ **只需上传一次**:将 Ollama 和模型保存为 Dataset
|
| 45 |
-
- ✅ **秒级加载**:后续启动只需 10-30 秒
|
| 46 |
-
- ✅ **节省时间**:每次节省 10+ 分钟
|
| 47 |
-
- ✅ **稳定可靠**:不受网络影响
|
| 48 |
-
|
| 49 |
-
---
|
| 50 |
-
|
| 51 |
-
## 详细步骤
|
| 52 |
-
|
| 53 |
-
### 阶段 1: 首次备份(一次性工作)
|
| 54 |
-
|
| 55 |
-
#### 1.1 在 Kaggle Notebook 中准备环境
|
| 56 |
-
|
| 57 |
-
```python
|
| 58 |
-
# 1. 克隆项目
|
| 59 |
-
!git clone https://github.com/你的用户名/adaptive_RAG.git
|
| 60 |
-
%cd adaptive_RAG
|
| 61 |
-
|
| 62 |
-
# 2. 安装 Ollama
|
| 63 |
-
!curl -fsSL https://ollama.com/install.sh | sh
|
| 64 |
-
|
| 65 |
-
# 3. 启动 Ollama 服务(后台运行)
|
| 66 |
-
import subprocess
|
| 67 |
-
subprocess.Popen(['ollama', 'serve'])
|
| 68 |
-
|
| 69 |
-
# 4. 等待服务启动
|
| 70 |
-
import time
|
| 71 |
-
time.sleep(15)
|
| 72 |
-
|
| 73 |
-
# 5. 下载模型
|
| 74 |
-
!ollama pull mistral # 或 phi, tinyllama 等
|
| 75 |
-
```
|
| 76 |
-
|
| 77 |
-
#### 1.2 运行备份脚本
|
| 78 |
-
|
| 79 |
-
```python
|
| 80 |
-
# 执行备份脚本
|
| 81 |
-
exec(open('KAGGLE_SAVE_OLLAMA.py').read())
|
| 82 |
-
```
|
| 83 |
-
|
| 84 |
-
**输出示例:**
|
| 85 |
-
```
|
| 86 |
-
====================================================================
|
| 87 |
-
💾 Kaggle Ollama 保存工具
|
| 88 |
-
====================================================================
|
| 89 |
-
|
| 90 |
-
📋 配置:
|
| 91 |
-
模型: mistral
|
| 92 |
-
输出目录: /kaggle/working/ollama_backup
|
| 93 |
-
|
| 94 |
-
📁 步骤 1/4: 创建备份目录...
|
| 95 |
-
✅ 目录创建成功
|
| 96 |
-
|
| 97 |
-
📦 步骤 2/4: 备份 Ollama 二进制文件...
|
| 98 |
-
找到 Ollama: /usr/local/bin/ollama
|
| 99 |
-
✅ Ollama 二进制文件已备份
|
| 100 |
-
|
| 101 |
-
🤖 步骤 3/4: 备份 mistral 模型...
|
| 102 |
-
找到模型目录: /root/.ollama/models
|
| 103 |
-
模型总大小: 4.12 GB
|
| 104 |
-
📦 创建压缩包(这可能需要几分钟)...
|
| 105 |
-
✅ 压缩完成
|
| 106 |
-
耗时: 180秒
|
| 107 |
-
压缩包大小: 4.10 GB
|
| 108 |
-
|
| 109 |
-
📝 步骤 4/4: 生成说明文件...
|
| 110 |
-
✅ 说明文件已生成
|
| 111 |
-
|
| 112 |
-
📊 备份内容:
|
| 113 |
-
• ollama: 0.05 GB
|
| 114 |
-
• ollama_models.tar.gz: 4.10 GB
|
| 115 |
-
• README.md: 0.00 MB
|
| 116 |
-
|
| 117 |
-
====================================================================
|
| 118 |
-
✅ 备份完成!
|
| 119 |
-
====================================================================
|
| 120 |
-
```
|
| 121 |
-
|
| 122 |
-
#### 1.3 下载备份文件
|
| 123 |
-
|
| 124 |
-
在 Kaggle Notebook 右侧:
|
| 125 |
-
1. 点击 **Output** 标签
|
| 126 |
-
2. 找到 `ollama_backup` 目录
|
| 127 |
-
3. 点击下载按钮
|
| 128 |
-
4. 等待下载完成(约 4GB,取决于网络速度)
|
| 129 |
-
|
| 130 |
-
#### 1.4 创建 Kaggle Dataset
|
| 131 |
-
|
| 132 |
-
1. **访问 Kaggle Datasets 页面**
|
| 133 |
-
- 打开:https://www.kaggle.com/datasets
|
| 134 |
-
- 点击右上角 **"New Dataset"** 按钮
|
| 135 |
-
|
| 136 |
-
2. **上传文件**
|
| 137 |
-
- 将下载的两个文件拖拽上传:
|
| 138 |
-
- `ollama` (二进制文件,约 50MB)
|
| 139 |
-
- `ollama_models.tar.gz` (模型压缩包,约 4GB)
|
| 140 |
-
|
| 141 |
-
3. **配置 Dataset**
|
| 142 |
-
- **Title**: `ollama-mistral-backup`(或其他名称)
|
| 143 |
-
- **Subtitle**: "Ollama with Mistral model for quick loading"
|
| 144 |
-
- **Visibility**: **Private**(避免占用公开配额)
|
| 145 |
-
- **License**: 选择合适的开源协议
|
| 146 |
-
|
| 147 |
-
4. **创建**
|
| 148 |
-
- 点击 **"Create"** 按钮
|
| 149 |
-
- 等待上传完成(4GB 大约需要 10-30 分钟,取决于网络)
|
| 150 |
-
|
| 151 |
-
---
|
| 152 |
-
|
| 153 |
-
### 阶段 2: 后续使用(每次启动)
|
| 154 |
-
|
| 155 |
-
#### 2.1 添加 Dataset 到 Notebook
|
| 156 |
-
|
| 157 |
-
在 Kaggle Notebook 中:
|
| 158 |
-
1. 点击右侧 **"Add data"** 按钮
|
| 159 |
-
2. 选择 **"Your Datasets"** 标签
|
| 160 |
-
3. 搜索并选择你的 `ollama-mistral-backup`
|
| 161 |
-
4. 点击 **"Add"** 按钮
|
| 162 |
-
|
| 163 |
-
#### 2.2 克隆项目
|
| 164 |
-
|
| 165 |
-
```python
|
| 166 |
-
# 在第一个单元格
|
| 167 |
-
import os
|
| 168 |
-
os.chdir('/kaggle/working')
|
| 169 |
-
|
| 170 |
-
!git clone https://github.com/你的用户名/adaptive_RAG.git
|
| 171 |
-
%cd adaptive_RAG
|
| 172 |
-
```
|
| 173 |
-
|
| 174 |
-
#### 2.3 加载 Ollama
|
| 175 |
-
|
| 176 |
-
```python
|
| 177 |
-
# 在第二个单元格
|
| 178 |
-
exec(open('KAGGLE_LOAD_OLLAMA.py').read())
|
| 179 |
-
```
|
| 180 |
-
|
| 181 |
-
**输出示例:**
|
| 182 |
-
```
|
| 183 |
-
====================================================================
|
| 184 |
-
📦 从 Dataset 加载 Ollama(快速启动)
|
| 185 |
-
====================================================================
|
| 186 |
-
|
| 187 |
-
📋 配置:
|
| 188 |
-
Dataset 路径: /kaggle/input/ollama-mistral-backup
|
| 189 |
-
|
| 190 |
-
🔍 步骤 1/5: 检查 Dataset...
|
| 191 |
-
✅ Dataset 存在
|
| 192 |
-
|
| 193 |
-
Dataset 内容:
|
| 194 |
-
• ollama: 0.05 GB
|
| 195 |
-
• ollama_models.tar.gz: 4.10 GB
|
| 196 |
-
|
| 197 |
-
🔧 步骤 2/5: 安装 Ollama 二进制文件...
|
| 198 |
-
✅ Ollama 已安装到: /usr/local/bin/ollama
|
| 199 |
-
📌 ollama version 0.1.x
|
| 200 |
-
|
| 201 |
-
📦 步骤 3/5: 解压模型文件...
|
| 202 |
-
找到模型压缩包: 4.10 GB
|
| 203 |
-
📦 开始解压(这可能需要 10-30 秒)...
|
| 204 |
-
✅ 解压完成(耗时: 25秒)
|
| 205 |
-
📊 模型总大小: 4.12 GB
|
| 206 |
-
|
| 207 |
-
🚀 步骤 4/5: 启动 Ollama 服务...
|
| 208 |
-
🔄 启动服务...
|
| 209 |
-
⏳ 等待服务启动(15秒)...
|
| 210 |
-
✅ Ollama 服务运行正常
|
| 211 |
-
|
| 212 |
-
✅ 步骤 5/5: 验证模型...
|
| 213 |
-
|
| 214 |
-
可用模型:
|
| 215 |
-
NAME ID SIZE MODIFIED
|
| 216 |
-
mistral:latest xxx 4.1 GB 2 minutes ago
|
| 217 |
-
|
| 218 |
-
====================================================================
|
| 219 |
-
✅ Ollama 加载完成!
|
| 220 |
-
====================================================================
|
| 221 |
-
|
| 222 |
-
📊 加载总结:
|
| 223 |
-
• Ollama 服务: ✅ 运行中
|
| 224 |
-
• 模型: ✅ 已加载
|
| 225 |
-
• 总耗时: < 1 分钟
|
| 226 |
-
|
| 227 |
-
💡 对比:
|
| 228 |
-
• 传统方式: 5-10 分钟(重新下载)
|
| 229 |
-
• Dataset 方式: < 1 分钟(直接加载)
|
| 230 |
-
• 节省时间: 约 90%!
|
| 231 |
-
```
|
| 232 |
-
|
| 233 |
-
#### 2.4 开始使用
|
| 234 |
-
|
| 235 |
-
```python
|
| 236 |
-
# 在第三个单元格
|
| 237 |
-
from document_processor import DocumentProcessor
|
| 238 |
-
from graph_indexer import GraphRAGIndexer
|
| 239 |
-
|
| 240 |
-
# 加载文档
|
| 241 |
-
processor = DocumentProcessor()
|
| 242 |
-
vectorstore, retriever, doc_splits = processor.setup_knowledge_base(enable_graphrag=True)
|
| 243 |
-
|
| 244 |
-
# 使用异步索引(速度快)
|
| 245 |
-
indexer = GraphRAGIndexer(async_batch_size=8)
|
| 246 |
-
graph = indexer.index_documents(doc_splits)
|
| 247 |
-
```
|
| 248 |
-
|
| 249 |
-
---
|
| 250 |
-
|
| 251 |
-
## 时间对比
|
| 252 |
-
|
| 253 |
-
### 传统方式(每次启动)
|
| 254 |
-
|
| 255 |
-
| 步骤 | 耗时 |
|
| 256 |
-
|------|------|
|
| 257 |
-
| 下载安装脚本 | 30秒 |
|
| 258 |
-
| 安装 Ollama | 1分钟 |
|
| 259 |
-
| 下载 Mistral 模型 | 5-10分钟 |
|
| 260 |
-
| 启动服务 | 15秒 |
|
| 261 |
-
| **总计** | **约 10-15 分钟** |
|
| 262 |
-
|
| 263 |
-
### Dataset 方式(每次启动)
|
| 264 |
-
|
| 265 |
-
| 步骤 | 耗时 |
|
| 266 |
-
|------|------|
|
| 267 |
-
| 加载 Dataset(自动) | 0秒 |
|
| 268 |
-
| 复制 Ollama 二进制 | 2秒 |
|
| 269 |
-
| 解压模型文件 | 20-30秒 |
|
| 270 |
-
| 启动服务 | 15秒 |
|
| 271 |
-
| **总计** | **约 40-50 秒** |
|
| 272 |
-
|
| 273 |
-
### 节省时间
|
| 274 |
-
|
| 275 |
-
- ✅ 首次上传:30 分钟(一次性工作)
|
| 276 |
-
- ✅ 后续每次:节省 **10+ 分钟**
|
| 277 |
-
- ✅ 运行 10 次后:累计节省 **100+ 分钟**
|
| 278 |
-
|
| 279 |
-
---
|
| 280 |
-
|
| 281 |
-
## 不同模型的大小对比
|
| 282 |
-
|
| 283 |
-
| 模型 | 原始大小 | 压缩后大小 | 下载时间 | 解压时间 |
|
| 284 |
-
|------|----------|-----------|----------|----------|
|
| 285 |
-
| qwen:0.5b | 350MB | ~300MB | 30秒 | 5秒 |
|
| 286 |
-
| tinyllama | 600MB | ~550MB | 1分钟 | 8秒 |
|
| 287 |
-
| phi | 1.6GB | ~1.5GB | 2-3分钟 | 15秒 |
|
| 288 |
-
| mistral | 4GB | ~4GB | 5-10分钟 | 25秒 |
|
| 289 |
-
| llama2:7b | 3.8GB | ~3.8GB | 5-10分钟 | 25秒 |
|
| 290 |
-
|
| 291 |
-
### 推荐选择
|
| 292 |
-
|
| 293 |
-
- **开发测试**:phi(平衡速度和质量)
|
| 294 |
-
- **快速验证**:tinyllama(最快)
|
| 295 |
-
- **最佳质量**:mistral(如果网络好)
|
| 296 |
-
|
| 297 |
-
---
|
| 298 |
-
|
| 299 |
-
## 故障排除
|
| 300 |
-
|
| 301 |
-
### 问题 1: Dataset 不存在
|
| 302 |
-
|
| 303 |
-
**症状:**
|
| 304 |
-
```
|
| 305 |
-
❌ Dataset 不存在: /kaggle/input/ollama-mistral-backup
|
| 306 |
-
```
|
| 307 |
-
|
| 308 |
-
**解决方案:**
|
| 309 |
-
1. 检查 Dataset 是否已添加到 Notebook
|
| 310 |
-
2. 检查 Dataset 名称是否正确
|
| 311 |
-
3. 修改 `KAGGLE_LOAD_OLLAMA.py` 中的 `DATASET_NAME`
|
| 312 |
-
|
| 313 |
-
### 问题 2: 上传 Dataset 失败
|
| 314 |
-
|
| 315 |
-
**症状:**
|
| 316 |
-
上传时卡住或失败
|
| 317 |
-
|
| 318 |
-
**解决方案:**
|
| 319 |
-
1. 检查网络连接
|
| 320 |
-
2. 使用更小的模型(如 phi 或 tinyllama)
|
| 321 |
-
3. 分多次尝试上传
|
| 322 |
-
|
| 323 |
-
### 问题 3: Ollama 无法运行
|
| 324 |
-
|
| 325 |
-
**症状:**
|
| 326 |
-
```
|
| 327 |
-
ollama: command not found
|
| 328 |
-
```
|
| 329 |
-
|
| 330 |
-
**解决方案:**
|
| 331 |
-
```bash
|
| 332 |
-
# 检查文件权限
|
| 333 |
-
chmod +x /usr/local/bin/ollama
|
| 334 |
-
|
| 335 |
-
# 验证安装
|
| 336 |
-
ollama --version
|
| 337 |
-
```
|
| 338 |
-
|
| 339 |
-
### 问题 4: 模型列表为空
|
| 340 |
-
|
| 341 |
-
**症状:**
|
| 342 |
-
```
|
| 343 |
-
ollama list
|
| 344 |
-
# 输出为空
|
| 345 |
-
```
|
| 346 |
-
|
| 347 |
-
**解决方案:**
|
| 348 |
-
```python
|
| 349 |
-
# 检查模型目录
|
| 350 |
-
import os
|
| 351 |
-
models_dir = os.path.expanduser("~/.ollama/models")
|
| 352 |
-
print(os.listdir(models_dir))
|
| 353 |
-
|
| 354 |
-
# 重新解压模型
|
| 355 |
-
# 重新运行 KAGGLE_LOAD_OLLAMA.py
|
| 356 |
-
```
|
| 357 |
-
|
| 358 |
-
### 问题 5: Dataset 超过大小限制
|
| 359 |
-
|
| 360 |
-
**症状:**
|
| 361 |
-
上传时提示 Dataset 过大
|
| 362 |
-
|
| 363 |
-
**解决方案:**
|
| 364 |
-
1. Kaggle 免费用户每个 Dataset 限制 20GB
|
| 365 |
-
2. 使用更小的模型
|
| 366 |
-
3. 或考虑升级为 Kaggle 专业版
|
| 367 |
-
|
| 368 |
-
---
|
| 369 |
-
|
| 370 |
-
## 高级优化
|
| 371 |
-
|
| 372 |
-
### 1. 多模型备份
|
| 373 |
-
|
| 374 |
-
如果想备份多个模型:
|
| 375 |
-
|
| 376 |
-
```bash
|
| 377 |
-
# 修改 KAGGLE_SAVE_OLLAMA.py
|
| 378 |
-
# 在下载模型步骤添加:
|
| 379 |
-
!ollama pull phi
|
| 380 |
-
!ollama pull tinyllama
|
| 381 |
-
!ollama pull mistral
|
| 382 |
-
|
| 383 |
-
# 然后运行备份脚本
|
| 384 |
-
# 所有模型会一起打包
|
| 385 |
-
```
|
| 386 |
-
|
| 387 |
-
### 2. 使用更快的压缩
|
| 388 |
-
|
| 389 |
-
```python
|
| 390 |
-
# 修改压缩命令(牺牲压缩率换取速度)
|
| 391 |
-
# 在 KAGGLE_SAVE_OLLAMA.py 中修改:
|
| 392 |
-
with tarfile.open(models_archive, 'w') as tar: # 去掉 :gz
|
| 393 |
-
tar.add(ollama_models_dir, arcname='models')
|
| 394 |
-
```
|
| 395 |
-
|
| 396 |
-
### 3. 增量更新
|
| 397 |
-
|
| 398 |
-
如果模型有更新:
|
| 399 |
-
1. 在 Kaggle Notebook 中下载新模型
|
| 400 |
-
2. 重新运行 `KAGGLE_SAVE_OLLAMA.py`
|
| 401 |
-
3. 下载新的压缩包
|
| 402 |
-
4. 更新 Dataset(覆盖旧文件)
|
| 403 |
-
|
| 404 |
-
---
|
| 405 |
-
|
| 406 |
-
## 完整工作流示例
|
| 407 |
-
|
| 408 |
-
### 第一次使用(约 45 分钟)
|
| 409 |
-
|
| 410 |
-
```python
|
| 411 |
-
# === Notebook Cell 1: 准备环境 ===
|
| 412 |
-
!git clone https://github.com/你的用户名/adaptive_RAG.git
|
| 413 |
-
%cd adaptive_RAG
|
| 414 |
-
|
| 415 |
-
# === Notebook Cell 2: 安装 Ollama ===
|
| 416 |
-
!curl -fsSL https://ollama.com/install.sh | sh
|
| 417 |
-
|
| 418 |
-
# === Notebook Cell 3: 启动服务 ===
|
| 419 |
-
import subprocess, time
|
| 420 |
-
subprocess.Popen(['ollama', 'serve'])
|
| 421 |
-
time.sleep(15)
|
| 422 |
-
|
| 423 |
-
# === Notebook Cell 4: 下载模型 ===
|
| 424 |
-
!ollama pull mistral # 5-10 分钟
|
| 425 |
-
|
| 426 |
-
# === Notebook Cell 5: 备份 ===
|
| 427 |
-
exec(open('KAGGLE_SAVE_OLLAMA.py').read()) # 3-5 分钟
|
| 428 |
-
|
| 429 |
-
# === 然后手动:===
|
| 430 |
-
# 1. 下载 ollama_backup 目录(5-15 分钟)
|
| 431 |
-
# 2. 创建 Kaggle Dataset 上传(10-30 分钟)
|
| 432 |
-
```
|
| 433 |
-
|
| 434 |
-
### 后续使用(约 2 分钟)
|
| 435 |
-
|
| 436 |
-
```python
|
| 437 |
-
# === Notebook Cell 1: 克隆项目 ===
|
| 438 |
-
%cd /kaggle/working
|
| 439 |
-
!git clone https://github.com/你的用户名/adaptive_RAG.git
|
| 440 |
-
%cd adaptive_RAG
|
| 441 |
-
|
| 442 |
-
# === Notebook Cell 2: 加载 Ollama ===
|
| 443 |
-
exec(open('KAGGLE_LOAD_OLLAMA.py').read()) # 40-50 秒
|
| 444 |
-
|
| 445 |
-
# === Notebook Cell 3: 开始工作 ===
|
| 446 |
-
from document_processor import DocumentProcessor
|
| 447 |
-
from graph_indexer import GraphRAGIndexer
|
| 448 |
-
|
| 449 |
-
processor = DocumentProcessor()
|
| 450 |
-
vectorstore, retriever, doc_splits = processor.setup_knowledge_base(enable_graphrag=True)
|
| 451 |
-
|
| 452 |
-
indexer = GraphRAGIndexer(async_batch_size=8)
|
| 453 |
-
graph = indexer.index_documents(doc_splits)
|
| 454 |
-
```
|
| 455 |
-
|
| 456 |
-
---
|
| 457 |
-
|
| 458 |
-
## 总结
|
| 459 |
-
|
| 460 |
-
### ✅ 优势
|
| 461 |
-
- 一次性上传,永久使用
|
| 462 |
-
- 每次启动节省 10+ 分钟
|
| 463 |
-
- 不受网络波动影响
|
| 464 |
-
- 稳定可靠
|
| 465 |
-
|
| 466 |
-
### ⚠️ 注意事项
|
| 467 |
-
- 首次上传需要时间和网络
|
| 468 |
-
- Dataset 有大小限制(20GB)
|
| 469 |
-
- 需要手动管理 Dataset
|
| 470 |
-
|
| 471 |
-
### 💡 建议
|
| 472 |
-
- **强烈推荐**用于频繁使用 Kaggle 的场景
|
| 473 |
-
- 选择合适大小的模型(推荐 phi)
|
| 474 |
-
- 保持 Dataset 为 Private 避免占用配额
|
| 475 |
-
|
| 476 |
-
---
|
| 477 |
-
|
| 478 |
-
**祝使用愉快!🎉**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
KAGGLE_INIT.py
DELETED
|
@@ -1,148 +0,0 @@
|
|
| 1 |
-
"""
|
| 2 |
-
Kaggle 会话初始化脚本
|
| 3 |
-
解决 Stop Session 后项目丢失的问题
|
| 4 |
-
|
| 5 |
-
使用方法:
|
| 6 |
-
在 Kaggle Notebook 第一个单元格运行:
|
| 7 |
-
exec(open('/kaggle/input/your-dataset/KAGGLE_INIT.py').read())
|
| 8 |
-
或者直接复制此脚本内容到第一个单元格
|
| 9 |
-
"""
|
| 10 |
-
|
| 11 |
-
import os
|
| 12 |
-
import subprocess
|
| 13 |
-
import sys
|
| 14 |
-
from pathlib import Path
|
| 15 |
-
|
| 16 |
-
print("🚀 Kaggle 会话自动初始化")
|
| 17 |
-
print("="*70)
|
| 18 |
-
|
| 19 |
-
# ==================== 配置区域 ====================
|
| 20 |
-
REPO_URL = "https://github.com/LannyCodes/adaptive_RAG.git"
|
| 21 |
-
PROJECT_DIR = "/kaggle/working/adaptive_RAG"
|
| 22 |
-
PREVIOUS_RUN_INPUT = "/kaggle/input/output" # 👈 修改为您保存的 Dataset 名称
|
| 23 |
-
|
| 24 |
-
# ==================== 1. 检查并克隆项目 ====================
|
| 25 |
-
print("\n📦 步骤 1: 检查项目状态...")
|
| 26 |
-
|
| 27 |
-
if os.path.exists(PROJECT_DIR):
|
| 28 |
-
print(f" ✅ 项目已存在: {PROJECT_DIR}")
|
| 29 |
-
print(" ℹ️ 如需更新代码,请运行:")
|
| 30 |
-
print(f" cd {PROJECT_DIR} && git pull origin main")
|
| 31 |
-
else:
|
| 32 |
-
print(f" 📥 项目不存在,开始克隆...")
|
| 33 |
-
|
| 34 |
-
os.chdir('/kaggle/working')
|
| 35 |
-
|
| 36 |
-
result = subprocess.run(
|
| 37 |
-
['git', 'clone', REPO_URL],
|
| 38 |
-
capture_output=True,
|
| 39 |
-
text=True
|
| 40 |
-
)
|
| 41 |
-
|
| 42 |
-
if result.returncode == 0:
|
| 43 |
-
print(f" ✅ 项目克隆成功")
|
| 44 |
-
else:
|
| 45 |
-
print(f" ❌ 克隆失败:")
|
| 46 |
-
print(f" {result.stderr}")
|
| 47 |
-
print("\n 💡 可能的原因:")
|
| 48 |
-
print(" 1. 网络问题")
|
| 49 |
-
print(" 2. 仓库地址错误")
|
| 50 |
-
print(" 3. 仓库是私有的(需要认证)")
|
| 51 |
-
sys.exit(1)
|
| 52 |
-
|
| 53 |
-
# ==================== 2. 恢复之前的数据 ====================
|
| 54 |
-
print("\n💾 步骤 2: 检查之前的运行数据...")
|
| 55 |
-
|
| 56 |
-
if os.path.exists(PREVIOUS_RUN_INPUT):
|
| 57 |
-
print(f" ✅ 发现之前的数据: {PREVIOUS_RUN_INPUT}")
|
| 58 |
-
|
| 59 |
-
# 列出可恢复的文件
|
| 60 |
-
saved_files = list(Path(PREVIOUS_RUN_INPUT).glob('*'))
|
| 61 |
-
|
| 62 |
-
if saved_files:
|
| 63 |
-
print(f" 📂 可恢复的文件:")
|
| 64 |
-
for file in saved_files[:10]: # 只显示前10个
|
| 65 |
-
print(f" • {file.name}")
|
| 66 |
-
|
| 67 |
-
# 恢复知识图谱(如果存在)
|
| 68 |
-
kg_file = Path(PREVIOUS_RUN_INPUT) / 'knowledge_graph.pkl'
|
| 69 |
-
if kg_file.exists():
|
| 70 |
-
import shutil
|
| 71 |
-
dest = Path(PROJECT_DIR) / 'knowledge_graph.pkl'
|
| 72 |
-
shutil.copy2(kg_file, dest)
|
| 73 |
-
print(f" ✅ 已恢复知识图谱")
|
| 74 |
-
|
| 75 |
-
print(f"\n 💡 如需恢复其他文件,使用:")
|
| 76 |
-
print(f" import shutil")
|
| 77 |
-
print(f" shutil.copy2('{PREVIOUS_RUN_INPUT}/文件名', '{PROJECT_DIR}/文件名')")
|
| 78 |
-
else:
|
| 79 |
-
print(" ⚠️ 数据目录为空")
|
| 80 |
-
else:
|
| 81 |
-
print(" ℹ️ 未发现之前的运行数据(首次运行)")
|
| 82 |
-
print(f" 💡 会话结束时,将 /kaggle/working 保存为 Dataset")
|
| 83 |
-
print(f" 命名为: output")
|
| 84 |
-
|
| 85 |
-
# ==================== 3. 设置工作环境 ====================
|
| 86 |
-
print("\n⚙️ 步骤 3: 设置工作环境...")
|
| 87 |
-
|
| 88 |
-
# 进入项目目录
|
| 89 |
-
os.chdir(PROJECT_DIR)
|
| 90 |
-
|
| 91 |
-
# 添加到 Python 路径
|
| 92 |
-
if PROJECT_DIR not in sys.path:
|
| 93 |
-
sys.path.insert(0, PROJECT_DIR)
|
| 94 |
-
|
| 95 |
-
print(f" ✅ 当前目录: {os.getcwd()}")
|
| 96 |
-
print(f" ✅ Python 路径已更新")
|
| 97 |
-
|
| 98 |
-
# ==================== 4. 显示系统信息 ====================
|
| 99 |
-
print("\n📊 步骤 4: 系统信息...")
|
| 100 |
-
|
| 101 |
-
# Python 版本
|
| 102 |
-
print(f" • Python: {sys.version.split()[0]}")
|
| 103 |
-
|
| 104 |
-
# GPU 状态
|
| 105 |
-
gpu_check = subprocess.run(['nvidia-smi'], capture_output=True, text=True)
|
| 106 |
-
if gpu_check.returncode == 0:
|
| 107 |
-
# 提取 GPU 信息
|
| 108 |
-
for line in gpu_check.stdout.split('\n'):
|
| 109 |
-
if 'Tesla' in line or 'P100' in line or 'T4' in line:
|
| 110 |
-
print(f" • GPU: {line.strip()}")
|
| 111 |
-
break
|
| 112 |
-
else:
|
| 113 |
-
print(" • GPU: 不可用")
|
| 114 |
-
|
| 115 |
-
# 磁盘空间
|
| 116 |
-
disk_check = subprocess.run(['df', '-h', '/kaggle/working'], capture_output=True, text=True)
|
| 117 |
-
if disk_check.returncode == 0:
|
| 118 |
-
lines = disk_check.stdout.strip().split('\n')
|
| 119 |
-
if len(lines) > 1:
|
| 120 |
-
info = lines[1].split()
|
| 121 |
-
print(f" • 可用空间: {info[3]}")
|
| 122 |
-
|
| 123 |
-
# ==================== 5. 快速测试 ====================
|
| 124 |
-
print("\n🧪 步骤 5: 快速测试...")
|
| 125 |
-
|
| 126 |
-
# 检查关键文件
|
| 127 |
-
key_files = [
|
| 128 |
-
'entity_extractor.py',
|
| 129 |
-
'graph_indexer.py',
|
| 130 |
-
'knowledge_graph.py',
|
| 131 |
-
'config.py'
|
| 132 |
-
]
|
| 133 |
-
|
| 134 |
-
all_files_exist = True
|
| 135 |
-
for file in key_files:
|
| 136 |
-
if os.path.exists(file):
|
| 137 |
-
print(f" ✅ {file}")
|
| 138 |
-
else:
|
| 139 |
-
print(f" ❌ {file} 缺失")
|
| 140 |
-
all_files_exist = False
|
| 141 |
-
|
| 142 |
-
if not all_files_exist:
|
| 143 |
-
print("\n ⚠️ 部分关键文件缺失,请检查仓库")
|
| 144 |
-
|
| 145 |
-
# ==================== 完成 ====================
|
| 146 |
-
print("\n" + "="*70)
|
| 147 |
-
print("✅ 初始化完成!")
|
| 148 |
-
print("="*70)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
KAGGLE_OLLAMA_PERSISTENCE.md
DELETED
|
@@ -1,404 +0,0 @@
|
|
| 1 |
-
# Kaggle Ollama 持久化方案
|
| 2 |
-
|
| 3 |
-
## 🎯 问题
|
| 4 |
-
|
| 5 |
-
在 Kaggle 上每次会话结束后:
|
| 6 |
-
- ❌ Ollama 安装被删除(位于 `/usr/local/bin/`)
|
| 7 |
-
- ❌ 模型被删除(位于 `~/.ollama/`)
|
| 8 |
-
- ❌ 每次重启需要 10-15 分钟重新下载
|
| 9 |
-
|
| 10 |
-
## ✅ 解决方案
|
| 11 |
-
|
| 12 |
-
将 Ollama 和模型保存到 **Kaggle Dataset**(永久存储),后续加载只需 40-50 秒。
|
| 13 |
-
|
| 14 |
-
---
|
| 15 |
-
|
| 16 |
-
## 📋 完整流程
|
| 17 |
-
|
| 18 |
-
### 阶段 1: 首次备份(一次性,约 30-60 分钟)
|
| 19 |
-
|
| 20 |
-
#### 步骤 1: 在 Kaggle Notebook 中准备
|
| 21 |
-
|
| 22 |
-
```python
|
| 23 |
-
# Cell 1: 克隆项目
|
| 24 |
-
import os
|
| 25 |
-
os.chdir('/kaggle/working')
|
| 26 |
-
!git clone https://github.com/你的用户名/adaptive_RAG.git
|
| 27 |
-
%cd adaptive_RAG
|
| 28 |
-
|
| 29 |
-
# Cell 2: 安装 Ollama
|
| 30 |
-
!curl -fsSL https://ollama.com/install.sh | sh
|
| 31 |
-
|
| 32 |
-
# Cell 3: 启动服务
|
| 33 |
-
import subprocess
|
| 34 |
-
import time
|
| 35 |
-
subprocess.Popen(['ollama', 'serve'])
|
| 36 |
-
time.sleep(15)
|
| 37 |
-
|
| 38 |
-
# Cell 4: 下载模型
|
| 39 |
-
!ollama pull mistral # 或 phi, tinyllama
|
| 40 |
-
|
| 41 |
-
# Cell 5: 验证环境(可选但推荐)
|
| 42 |
-
exec(open('KAGGLE_CHECK_OLLAMA.py').read())
|
| 43 |
-
```
|
| 44 |
-
|
| 45 |
-
#### 步骤 2: 运行备份脚本
|
| 46 |
-
|
| 47 |
-
```python
|
| 48 |
-
# Cell 6: 执行备份
|
| 49 |
-
exec(open('KAGGLE_SAVE_OLLAMA.py').read())
|
| 50 |
-
```
|
| 51 |
-
|
| 52 |
-
**输出示例:**
|
| 53 |
-
```
|
| 54 |
-
====================================================================
|
| 55 |
-
💾 Kaggle Ollama 保存工具
|
| 56 |
-
====================================================================
|
| 57 |
-
|
| 58 |
-
📋 配置:
|
| 59 |
-
模型: mistral
|
| 60 |
-
输出目录: /kaggle/working/ollama_backup
|
| 61 |
-
|
| 62 |
-
📁 步骤 1/4: 创建备份目录...
|
| 63 |
-
✅ 目录创建成功
|
| 64 |
-
|
| 65 |
-
📦 步骤 2/4: 备份 Ollama 二进制文件...
|
| 66 |
-
找到 Ollama: /usr/local/bin/ollama
|
| 67 |
-
✅ Ollama 二进制文件已备份
|
| 68 |
-
|
| 69 |
-
🤖 步骤 3/4: 备份 mistral 模型...
|
| 70 |
-
找到模型目录: /root/.ollama
|
| 71 |
-
模型总大小: 4.12 GB
|
| 72 |
-
📦 创建压缩包(这可能需要几分钟)...
|
| 73 |
-
正在压缩: /root/.ollama
|
| 74 |
-
✅ 压缩完成
|
| 75 |
-
耗时: 180秒
|
| 76 |
-
压缩包大小: 4.10 GB
|
| 77 |
-
|
| 78 |
-
📝 步骤 4/4: 生成说明文件...
|
| 79 |
-
✅ 说明文件已生成
|
| 80 |
-
|
| 81 |
-
====================================================================
|
| 82 |
-
✅ 备份完成!
|
| 83 |
-
====================================================================
|
| 84 |
-
```
|
| 85 |
-
|
| 86 |
-
#### 步骤 3: 下载备份文件
|
| 87 |
-
|
| 88 |
-
1. 在 Kaggle Notebook 右侧点击 **"Output"** 标签
|
| 89 |
-
2. 找到 `ollama_backup` 目录
|
| 90 |
-
3. 点击下载(约 4GB,需要 5-15 分钟取决于网络)
|
| 91 |
-
|
| 92 |
-
#### 步骤 4: 创建 Kaggle Dataset
|
| 93 |
-
|
| 94 |
-
1. **访问 Kaggle Datasets**
|
| 95 |
-
- URL: https://www.kaggle.com/datasets
|
| 96 |
-
- 点击 **"New Dataset"**
|
| 97 |
-
|
| 98 |
-
2. **上传文件**
|
| 99 |
-
- 拖拽或选择:
|
| 100 |
-
- `ollama` (约 50MB)
|
| 101 |
-
- `ollama_models.tar.gz` (约 4GB)
|
| 102 |
-
|
| 103 |
-
3. **配置 Dataset**
|
| 104 |
-
- **Title**: `ollama-mistral-backup`
|
| 105 |
-
- **Visibility**: Private
|
| 106 |
-
- 点击 **"Create"**
|
| 107 |
-
|
| 108 |
-
4. **等待上传**
|
| 109 |
-
- 约 10-30 分钟(取决于网络)
|
| 110 |
-
|
| 111 |
-
---
|
| 112 |
-
|
| 113 |
-
### 阶段 2: 后续使用(每次约 1-2 分钟)
|
| 114 |
-
|
| 115 |
-
#### 步骤 1: 新建 Notebook
|
| 116 |
-
|
| 117 |
-
1. 添加 Dataset
|
| 118 |
-
- 点击右侧 **"Add data"**
|
| 119 |
-
- 选择 **"Your Datasets"**
|
| 120 |
-
- 搜索 `ollama-mistral-backup`
|
| 121 |
-
- 点击 **"Add"**
|
| 122 |
-
|
| 123 |
-
#### 步骤 2: 克隆项目并加载 Ollama
|
| 124 |
-
|
| 125 |
-
```python
|
| 126 |
-
# Cell 1: 克隆项目
|
| 127 |
-
import os
|
| 128 |
-
os.chdir('/kaggle/working')
|
| 129 |
-
!git clone https://github.com/你的用户名/adaptive_RAG.git
|
| 130 |
-
%cd adaptive_RAG
|
| 131 |
-
|
| 132 |
-
# Cell 2: 加载 Ollama(快速!)
|
| 133 |
-
exec(open('KAGGLE_LOAD_OLLAMA.py').read())
|
| 134 |
-
```
|
| 135 |
-
|
| 136 |
-
**输出示例:**
|
| 137 |
-
```
|
| 138 |
-
====================================================================
|
| 139 |
-
📦 从 Dataset 加载 Ollama(快速启动)
|
| 140 |
-
====================================================================
|
| 141 |
-
|
| 142 |
-
📋 配置:
|
| 143 |
-
Dataset 路径: /kaggle/input/ollama-mistral-backup
|
| 144 |
-
|
| 145 |
-
🔍 步骤 1/5: 检查 Dataset...
|
| 146 |
-
✅ Dataset 存在
|
| 147 |
-
|
| 148 |
-
🔧 步骤 2/5: 安装 Ollama 二进制文件...
|
| 149 |
-
✅ Ollama 已安装到: /usr/local/bin/ollama
|
| 150 |
-
📌 ollama version 0.1.x
|
| 151 |
-
|
| 152 |
-
📦 步骤 3/5: 解压模型文件...
|
| 153 |
-
找到模型压缩包: 4.10 GB
|
| 154 |
-
📦 开始解压(这可能需要 10-30 秒)...
|
| 155 |
-
✅ 解压完成(耗时: 25秒)
|
| 156 |
-
📊 模型总大小: 4.12 GB
|
| 157 |
-
|
| 158 |
-
🚀 步骤 4/5: 启动 Ollama 服务...
|
| 159 |
-
🔄 启动服务...
|
| 160 |
-
⏳ 等待服务启动(15秒)...
|
| 161 |
-
✅ Ollama 服务运行正常
|
| 162 |
-
|
| 163 |
-
✅ 步骤 5/5: 验证模型...
|
| 164 |
-
可用模型:
|
| 165 |
-
NAME ID SIZE MODIFIED
|
| 166 |
-
mistral:latest xxx 4.1 GB 2 minutes ago
|
| 167 |
-
|
| 168 |
-
====================================================================
|
| 169 |
-
✅ Ollama 加载完成!
|
| 170 |
-
====================================================================
|
| 171 |
-
|
| 172 |
-
📊 加载总结:
|
| 173 |
-
• Ollama 服务: ✅ 运行中
|
| 174 |
-
• 模型: ✅ 已加载
|
| 175 |
-
• 总耗时: < 1 分钟
|
| 176 |
-
```
|
| 177 |
-
|
| 178 |
-
#### 步骤 3: 开始使用
|
| 179 |
-
|
| 180 |
-
```python
|
| 181 |
-
# Cell 3: 运行你的 GraphRAG 项目
|
| 182 |
-
from document_processor import DocumentProcessor
|
| 183 |
-
from graph_indexer import GraphRAGIndexer
|
| 184 |
-
|
| 185 |
-
processor = DocumentProcessor()
|
| 186 |
-
vectorstore, retriever, doc_splits = processor.setup_knowledge_base(enable_graphrag=True)
|
| 187 |
-
|
| 188 |
-
indexer = GraphRAGIndexer(async_batch_size=8)
|
| 189 |
-
graph = indexer.index_documents(doc_splits)
|
| 190 |
-
```
|
| 191 |
-
|
| 192 |
-
---
|
| 193 |
-
|
| 194 |
-
## ⏱️ 时间对比
|
| 195 |
-
|
| 196 |
-
### 传统方式(每���启动)
|
| 197 |
-
|
| 198 |
-
| 步骤 | 时间 |
|
| 199 |
-
|------|------|
|
| 200 |
-
| 下载安装脚本 | 30秒 |
|
| 201 |
-
| 安装 Ollama | 1分钟 |
|
| 202 |
-
| 下载 Mistral | 5-10分钟 |
|
| 203 |
-
| 启动服务 | 15秒 |
|
| 204 |
-
| **总计** | **10-15分钟** ❌ |
|
| 205 |
-
|
| 206 |
-
### Dataset 方式(每次启动)
|
| 207 |
-
|
| 208 |
-
| 步骤 | 时间 |
|
| 209 |
-
|------|------|
|
| 210 |
-
| 复制二进制 | 2秒 |
|
| 211 |
-
| 解压模型 | 25秒 |
|
| 212 |
-
| 启动服务 | 15秒 |
|
| 213 |
-
| **总计** | **40-50秒** ✅ |
|
| 214 |
-
|
| 215 |
-
### 收益分析
|
| 216 |
-
|
| 217 |
-
- **首次投入**:30-60 分钟(一次性)
|
| 218 |
-
- **每次节省**:10+ 分钟
|
| 219 |
-
- **运行 5 次回本**:5 × 10 = 50 分钟 > 30 分钟
|
| 220 |
-
- **运行 10 次后**:累计节省 **100+ 分钟**!
|
| 221 |
-
|
| 222 |
-
---
|
| 223 |
-
|
| 224 |
-
## 🔍 验证脚本
|
| 225 |
-
|
| 226 |
-
在备份前建议运行验证脚本,确保环境正确:
|
| 227 |
-
|
| 228 |
-
```python
|
| 229 |
-
# 检查 Ollama 安装和模型位置
|
| 230 |
-
exec(open('KAGGLE_CHECK_OLLAMA.py').read())
|
| 231 |
-
```
|
| 232 |
-
|
| 233 |
-
**该脚本会检查:**
|
| 234 |
-
- ✅ Ollama 安装位置
|
| 235 |
-
- ✅ Ollama 服务状态
|
| 236 |
-
- ✅ 模型存储目录
|
| 237 |
-
- ✅ 已下载的模型列表
|
| 238 |
-
- ✅ 推荐备份方案
|
| 239 |
-
|
| 240 |
-
---
|
| 241 |
-
|
| 242 |
-
## 📊 不同模型的对比
|
| 243 |
-
|
| 244 |
-
| 模型 | 原始大小 | 压缩后 | 下载时间 | 解压时间 | 推荐度 |
|
| 245 |
-
|------|----------|--------|----------|----------|--------|
|
| 246 |
-
| qwen:0.5b | 350MB | ~300MB | 30秒 | 5秒 | ⭐⭐ 快但质量低 |
|
| 247 |
-
| tinyllama | 600MB | ~550MB | 1分钟 | 8秒 | ⭐⭐⭐ 快速测试 |
|
| 248 |
-
| phi | 1.6GB | ~1.5GB | 2-3分钟 | 15秒 | ⭐⭐⭐⭐ **推荐** |
|
| 249 |
-
| mistral | 4GB | ~4GB | 5-10分钟 | 25秒 | ⭐⭐⭐⭐⭐ 质量最好 |
|
| 250 |
-
|
| 251 |
-
**建议:**
|
| 252 |
-
- 开发测试:使用 `phi`(平衡)
|
| 253 |
-
- 快速验证:使用 `tinyllama`
|
| 254 |
-
- 生产环境:使用 `mistral`
|
| 255 |
-
|
| 256 |
-
---
|
| 257 |
-
|
| 258 |
-
## ❓ 常见问题
|
| 259 |
-
|
| 260 |
-
### Q1: 脚本是否正确?
|
| 261 |
-
|
| 262 |
-
**A**: 是的,已修正。脚本会:
|
| 263 |
-
- ✅ 自动查找 Ollama 安装位置(`/usr/local/bin/ollama`)
|
| 264 |
-
- ✅ 自动查找模型目录(`~/.ollama` 或 `/root/.ollama`)
|
| 265 |
-
- ✅ 完整备份整个 `.ollama` 目录(包括 models, manifests 等)
|
| 266 |
-
- ✅ 正确解压到 `~/.ollama`
|
| 267 |
-
|
| 268 |
-
### Q2: Dataset 名称可以改吗?
|
| 269 |
-
|
| 270 |
-
**A**: 可以!修改 `KAGGLE_LOAD_OLLAMA.py` 中的:
|
| 271 |
-
```python
|
| 272 |
-
DATASET_NAME = "你的Dataset名称" # 第18行
|
| 273 |
-
```
|
| 274 |
-
|
| 275 |
-
### Q3: 上传失败怎么办?
|
| 276 |
-
|
| 277 |
-
**A**: 可能原因:
|
| 278 |
-
1. 网络不稳定 → 重试或使用稳定网络
|
| 279 |
-
2. 文件太大 → 使用更小的模型(如 phi)
|
| 280 |
-
3. 浏览器问题 → 尝试更换浏览器
|
| 281 |
-
|
| 282 |
-
### Q4: 可以备份多个模型吗?
|
| 283 |
-
|
| 284 |
-
**A**: 可以!在备份前下载多个模型:
|
| 285 |
-
```python
|
| 286 |
-
!ollama pull phi
|
| 287 |
-
!ollama pull tinyllama
|
| 288 |
-
!ollama pull mistral
|
| 289 |
-
# 然后运行备份脚本,会一起打包
|
| 290 |
-
```
|
| 291 |
-
|
| 292 |
-
### Q5: Dataset 有大小限制吗?
|
| 293 |
-
|
| 294 |
-
**A**: 是的
|
| 295 |
-
- 免费用户:每个 Dataset ≤ 20GB
|
| 296 |
-
- Kaggle 专业版:更大限额
|
| 297 |
-
|
| 298 |
-
---
|
| 299 |
-
|
| 300 |
-
## 🎯 最佳实践
|
| 301 |
-
|
| 302 |
-
### ✅ 推荐做法
|
| 303 |
-
|
| 304 |
-
1. **使用较小模型**:首选 `phi`(1.6GB)
|
| 305 |
-
2. **验证后再备份**:运行 `KAGGLE_CHECK_OLLAMA.py`
|
| 306 |
-
3. **Dataset 设为 Private**:避免占用公开配额
|
| 307 |
-
4. **定期更新**:模型有更新时重新备份
|
| 308 |
-
|
| 309 |
-
### ⚠️ 注意事项
|
| 310 |
-
|
| 311 |
-
1. **首次上传需要时间**:计划好 30-60 分钟
|
| 312 |
-
2. **网络稳定性**:确保上传期间网络稳定
|
| 313 |
-
3. **Dataset 管理**:定期清理不用的 Datasets
|
| 314 |
-
4. **备份验证**:首次加载后测试模型是否正常
|
| 315 |
-
|
| 316 |
-
---
|
| 317 |
-
|
| 318 |
-
## 📝 完整示例
|
| 319 |
-
|
| 320 |
-
### 首次使用(Kaggle Notebook)
|
| 321 |
-
|
| 322 |
-
```python
|
| 323 |
-
# ========== Cell 1: 环境准备 ==========
|
| 324 |
-
import os
|
| 325 |
-
os.chdir('/kaggle/working')
|
| 326 |
-
!git clone https://github.com/你的仓库/adaptive_RAG.git
|
| 327 |
-
%cd adaptive_RAG
|
| 328 |
-
|
| 329 |
-
# ========== Cell 2: 安装 Ollama ==========
|
| 330 |
-
!curl -fsSL https://ollama.com/install.sh | sh
|
| 331 |
-
|
| 332 |
-
# ========== Cell 3: 启动服务 ==========
|
| 333 |
-
import subprocess, time
|
| 334 |
-
subprocess.Popen(['ollama', 'serve'])
|
| 335 |
-
time.sleep(15)
|
| 336 |
-
|
| 337 |
-
# ========== Cell 4: 下载模型 ==========
|
| 338 |
-
!ollama pull phi # 推荐使用 phi
|
| 339 |
-
|
| 340 |
-
# ========== Cell 5: 验证环境 ==========
|
| 341 |
-
exec(open('KAGGLE_CHECK_OLLAMA.py').read())
|
| 342 |
-
|
| 343 |
-
# ========== Cell 6: 备份 ==========
|
| 344 |
-
exec(open('KAGGLE_SAVE_OLLAMA.py').read())
|
| 345 |
-
|
| 346 |
-
# ========== 手动操作 ==========
|
| 347 |
-
# 1. 在右侧 Output 下载 ollama_backup
|
| 348 |
-
# 2. 访问 kaggle.com/datasets 创建 Dataset
|
| 349 |
-
# 3. 上传 ollama 和 ollama_models.tar.gz
|
| 350 |
-
```
|
| 351 |
-
|
| 352 |
-
### 后续使用(每次新 Notebook)
|
| 353 |
-
|
| 354 |
-
```python
|
| 355 |
-
# ========== Cell 1: 克隆项目 ==========
|
| 356 |
-
import os
|
| 357 |
-
os.chdir('/kaggle/working')
|
| 358 |
-
!git clone https://github.com/你的仓库/adaptive_RAG.git
|
| 359 |
-
%cd adaptive_RAG
|
| 360 |
-
|
| 361 |
-
# ========== Cell 2: 快速加载 ==========
|
| 362 |
-
# 注意:需要先在右侧 Add data 添加你的 Dataset
|
| 363 |
-
exec(open('KAGGLE_LOAD_OLLAMA.py').read())
|
| 364 |
-
|
| 365 |
-
# ========== Cell 3: 开始工作 ==========
|
| 366 |
-
from graph_indexer import GraphRAGIndexer
|
| 367 |
-
from document_processor import DocumentProcessor
|
| 368 |
-
|
| 369 |
-
processor = DocumentProcessor()
|
| 370 |
-
vectorstore, retriever, doc_splits = processor.setup_knowledge_base(enable_graphrag=True)
|
| 371 |
-
|
| 372 |
-
indexer = GraphRAGIndexer(async_batch_size=8)
|
| 373 |
-
graph = indexer.index_documents(doc_splits)
|
| 374 |
-
|
| 375 |
-
print("✅ 一切就绪!开始使用 GraphRAG!")
|
| 376 |
-
```
|
| 377 |
-
|
| 378 |
-
---
|
| 379 |
-
|
| 380 |
-
## 🎉 总结
|
| 381 |
-
|
| 382 |
-
### ✅ 优势
|
| 383 |
-
- **大幅节省时间**:每次启动从 10-15 分钟 → 40-50 秒
|
| 384 |
-
- **稳定可靠**:不受网络波动���响
|
| 385 |
-
- **一次投入**:首次 30-60 分钟,之后永久受益
|
| 386 |
-
- **易于使用**:两个脚本自动化全流程
|
| 387 |
-
|
| 388 |
-
### 📈 投资回报
|
| 389 |
-
- 首次投入:30-60 分钟
|
| 390 |
-
- 每次节省:10+ 分钟
|
| 391 |
-
- 5 次使用后回本
|
| 392 |
-
- 长期收益:**节省数小时**
|
| 393 |
-
|
| 394 |
-
### 💡 强烈推荐
|
| 395 |
-
如果你经常使用 Kaggle 运行这个项目,**强烈建议**使用这个方案!
|
| 396 |
-
|
| 397 |
-
---
|
| 398 |
-
|
| 399 |
-
**祝使用愉快!🚀**
|
| 400 |
-
|
| 401 |
-
有问题请参考:
|
| 402 |
-
- 验证脚本:`KAGGLE_CHECK_OLLAMA.py`
|
| 403 |
-
- 备份脚本:`KAGGLE_SAVE_OLLAMA.py`
|
| 404 |
-
- 加载脚本:`KAGGLE_LOAD_OLLAMA.py`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
KAGGLE_OPTIMIZATION_GUIDE.md
DELETED
|
@@ -1,367 +0,0 @@
|
|
| 1 |
-
# Kaggle 环境优化指南 - 避免重复下载模型
|
| 2 |
-
|
| 3 |
-
## 🚨 问题
|
| 4 |
-
|
| 5 |
-
每次 Kaggle 会话重启后,Ollama 模型需要重新下载,Mistral 模型约 4GB,非常耗时。
|
| 6 |
-
|
| 7 |
-
## 💡 解决方案
|
| 8 |
-
|
| 9 |
-
### 方案 1: 使用更小的模型(推荐⭐⭐⭐⭐⭐)
|
| 10 |
-
|
| 11 |
-
**最佳选择**:不需要修改代码,只需在下载模型时选择更小的版本。
|
| 12 |
-
|
| 13 |
-
#### 可选模型对比
|
| 14 |
-
|
| 15 |
-
| 模型 | 大小 | 下载时间 | 质量 | 推荐场景 |
|
| 16 |
-
|-----|------|---------|------|---------|
|
| 17 |
-
| `mistral` | ~4GB | 5-10分钟 | ⭐⭐⭐⭐⭐ | 本地开发 |
|
| 18 |
-
| `phi` | ~1.6GB | 2-3分钟 | ⭐⭐⭐⭐ | **Kaggle推荐** |
|
| 19 |
-
| `tinyllama` | ~600MB | 1分钟 | ⭐⭐⭐ | 快速测试 |
|
| 20 |
-
| `qwen:0.5b` | ~350MB | 30秒 | ⭐⭐ | 极速测试 |
|
| 21 |
-
|
| 22 |
-
#### 使用方法
|
| 23 |
-
|
| 24 |
-
**选项 A**: 修改 `config.py`
|
| 25 |
-
```python
|
| 26 |
-
# 在 /kaggle/working/adaptive_RAG/config.py 中
|
| 27 |
-
LOCAL_LLM = "phi" # 👈 改为 phi 或 tinyllama
|
| 28 |
-
```
|
| 29 |
-
|
| 30 |
-
**选项 B**: 运行时覆盖(不修改代码)
|
| 31 |
-
```python
|
| 32 |
-
# 在 Kaggle Notebook 中
|
| 33 |
-
import os
|
| 34 |
-
os.environ['LOCAL_LLM_OVERRIDE'] = 'phi'
|
| 35 |
-
|
| 36 |
-
# 然后正常导入
|
| 37 |
-
from config import LOCAL_LLM
|
| 38 |
-
# LOCAL_LLM 会自动使用 'phi'
|
| 39 |
-
```
|
| 40 |
-
|
| 41 |
-
**选项 C**: 直接在下载时指定
|
| 42 |
-
```python
|
| 43 |
-
# 下载更小的模型
|
| 44 |
-
!ollama pull phi # 代替 mistral
|
| 45 |
-
|
| 46 |
-
# 或者
|
| 47 |
-
!ollama pull tinyllama
|
| 48 |
-
```
|
| 49 |
-
|
| 50 |
-
---
|
| 51 |
-
|
| 52 |
-
### 方案 2: 持久化模型到 Kaggle Dataset(中等推荐⭐⭐⭐)
|
| 53 |
-
|
| 54 |
-
将下载好的模型保存为 Dataset,下次会话直接加载。
|
| 55 |
-
|
| 56 |
-
#### 步骤
|
| 57 |
-
|
| 58 |
-
**会话 1(首次):**
|
| 59 |
-
```python
|
| 60 |
-
import subprocess
|
| 61 |
-
import shutil
|
| 62 |
-
import os
|
| 63 |
-
|
| 64 |
-
# 1. 下载模型
|
| 65 |
-
subprocess.run(['ollama', 'pull', 'phi'])
|
| 66 |
-
|
| 67 |
-
# 2. 找到模型存储位置
|
| 68 |
-
# Ollama 模型通常存储在 ~/.ollama/models
|
| 69 |
-
ollama_models = os.path.expanduser('~/.ollama/models')
|
| 70 |
-
|
| 71 |
-
# 3. 复制到工作目录(会被保存为输出)
|
| 72 |
-
if os.path.exists(ollama_models):
|
| 73 |
-
shutil.copytree(
|
| 74 |
-
ollama_models,
|
| 75 |
-
'/kaggle/working/ollama_models',
|
| 76 |
-
dirs_exist_ok=True
|
| 77 |
-
)
|
| 78 |
-
print("✅ 模型已复制到 /kaggle/working/ollama_models")
|
| 79 |
-
print("📌 会话结束后,将此目录保存为 Dataset")
|
| 80 |
-
|
| 81 |
-
# 4. 会话结束时:Save Version → Save as Dataset
|
| 82 |
-
# 命名为: ollama-models-cache
|
| 83 |
-
```
|
| 84 |
-
|
| 85 |
-
**会话 2(后续):**
|
| 86 |
-
```python
|
| 87 |
-
import shutil
|
| 88 |
-
import os
|
| 89 |
-
|
| 90 |
-
# 1. 从 Dataset 恢复模型
|
| 91 |
-
models_cache = '/kaggle/input/ollama-models-cache'
|
| 92 |
-
|
| 93 |
-
if os.path.exists(models_cache):
|
| 94 |
-
print("📥 恢复 Ollama 模型...")
|
| 95 |
-
|
| 96 |
-
# 创建 Ollama 模型目录
|
| 97 |
-
ollama_dir = os.path.expanduser('~/.ollama/models')
|
| 98 |
-
os.makedirs(ollama_dir, exist_ok=True)
|
| 99 |
-
|
| 100 |
-
# 复制模型文件
|
| 101 |
-
shutil.copytree(
|
| 102 |
-
models_cache,
|
| 103 |
-
ollama_dir,
|
| 104 |
-
dirs_exist_ok=True
|
| 105 |
-
)
|
| 106 |
-
|
| 107 |
-
print("✅ 模型已恢复,无需重新下载!")
|
| 108 |
-
else:
|
| 109 |
-
print("⚠️ 未找到缓存,需要重新下载")
|
| 110 |
-
```
|
| 111 |
-
|
| 112 |
-
**注意**:此方法有局限性,因为 Ollama 的模型存储结构复杂,可能不完全兼容。
|
| 113 |
-
|
| 114 |
-
---
|
| 115 |
-
|
| 116 |
-
### 方案 3: 使用云端 LLM API(高级方案⭐⭐⭐⭐)
|
| 117 |
-
|
| 118 |
-
完全避免本地模型,使用云端 API。
|
| 119 |
-
|
| 120 |
-
#### 可选 API
|
| 121 |
-
|
| 122 |
-
1. **OpenAI API**(需付费)
|
| 123 |
-
2. **Anthropic Claude API**(需付费)
|
| 124 |
-
3. **Hugging Face Inference API**(免费,有限额)
|
| 125 |
-
4. **Together AI**(免费额度)
|
| 126 |
-
|
| 127 |
-
#### 代码修改示例
|
| 128 |
-
|
| 129 |
-
修改 `entity_extractor.py`:
|
| 130 |
-
|
| 131 |
-
```python
|
| 132 |
-
# 原代码
|
| 133 |
-
from langchain_community.chat_models import ChatOllama
|
| 134 |
-
self.llm = ChatOllama(model=LOCAL_LLM, format="json", temperature=0)
|
| 135 |
-
|
| 136 |
-
# 改为使用 OpenAI API
|
| 137 |
-
from langchain_openai import ChatOpenAI
|
| 138 |
-
self.llm = ChatOpenAI(
|
| 139 |
-
model="gpt-3.5-turbo", # 或 gpt-4
|
| 140 |
-
temperature=0,
|
| 141 |
-
openai_api_key=os.getenv("OPENAI_API_KEY")
|
| 142 |
-
)
|
| 143 |
-
|
| 144 |
-
# 或使用 Hugging Face
|
| 145 |
-
from langchain_community.llms import HuggingFaceHub
|
| 146 |
-
self.llm = HuggingFaceHub(
|
| 147 |
-
repo_id="mistralai/Mistral-7B-Instruct-v0.1",
|
| 148 |
-
huggingfacehub_api_token=os.getenv("HUGGINGFACE_API_TOKEN")
|
| 149 |
-
)
|
| 150 |
-
```
|
| 151 |
-
|
| 152 |
-
**优点**:
|
| 153 |
-
- ✅ 无需下载模型
|
| 154 |
-
- ✅ 速度快(云端 GPU)
|
| 155 |
-
- ✅ 质量好(GPT-4 等高级模型)
|
| 156 |
-
|
| 157 |
-
**缺点**:
|
| 158 |
-
- ❌ 需要 API Key
|
| 159 |
-
- ❌ 可能产生费用
|
| 160 |
-
- ❌ 依赖网络
|
| 161 |
-
|
| 162 |
-
---
|
| 163 |
-
|
| 164 |
-
### 方案 4: 预构建 Docker 镜像(技术方案⭐⭐)
|
| 165 |
-
|
| 166 |
-
创建包含预下载模型的 Docker 镜像。
|
| 167 |
-
|
| 168 |
-
**步骤**:
|
| 169 |
-
1. 本地构建包含 Ollama + 模型的 Docker 镜像
|
| 170 |
-
2. 推送到 Docker Hub
|
| 171 |
-
3. 在 Kaggle 中拉取该镜像
|
| 172 |
-
|
| 173 |
-
**局限**:Kaggle 对 Docker 支持有限。
|
| 174 |
-
|
| 175 |
-
---
|
| 176 |
-
|
| 177 |
-
## 🎯 最佳实践推荐
|
| 178 |
-
|
| 179 |
-
### 推荐组合策略
|
| 180 |
-
|
| 181 |
-
**快速开发/测试**:
|
| 182 |
-
```python
|
| 183 |
-
# 使用 phi 模型(平衡速度和质量)
|
| 184 |
-
LOCAL_LLM = "phi"
|
| 185 |
-
```
|
| 186 |
-
|
| 187 |
-
**生产环境**:
|
| 188 |
-
```python
|
| 189 |
-
# 使用云端 API(速度快、质量高)
|
| 190 |
-
# 在 Kaggle Secrets 中设置 OPENAI_API_KEY
|
| 191 |
-
from langchain_openai import ChatOpenAI
|
| 192 |
-
llm = ChatOpenAI(model="gpt-3.5-turbo")
|
| 193 |
-
```
|
| 194 |
-
|
| 195 |
-
**完全离线**:
|
| 196 |
-
```python
|
| 197 |
-
# 使用 tinyllama(最快下载)
|
| 198 |
-
LOCAL_LLM = "tinyllama"
|
| 199 |
-
```
|
| 200 |
-
|
| 201 |
-
---
|
| 202 |
-
|
| 203 |
-
## 📋 Kaggle 完整工作流程(优化版)
|
| 204 |
-
|
| 205 |
-
### 单元格 1: 初始化
|
| 206 |
-
```python
|
| 207 |
-
import os, subprocess, sys
|
| 208 |
-
|
| 209 |
-
os.chdir('/kaggle/working')
|
| 210 |
-
if not os.path.exists('adaptive_RAG'):
|
| 211 |
-
subprocess.run(['git', 'clone', 'https://github.com/LannyCodes/adaptive_RAG.git'])
|
| 212 |
-
|
| 213 |
-
os.chdir('adaptive_RAG')
|
| 214 |
-
|
| 215 |
-
# 修改配置使用更小的模型
|
| 216 |
-
with open('config.py', 'r') as f:
|
| 217 |
-
content = f.read()
|
| 218 |
-
|
| 219 |
-
content = content.replace('LOCAL_LLM = "mistral"', 'LOCAL_LLM = "phi"')
|
| 220 |
-
|
| 221 |
-
with open('config.py', 'w') as f:
|
| 222 |
-
f.write(content)
|
| 223 |
-
|
| 224 |
-
print("✅ 已切换到 phi 模型")
|
| 225 |
-
|
| 226 |
-
sys.path.insert(0, '/kaggle/working/adaptive_RAG')
|
| 227 |
-
```
|
| 228 |
-
|
| 229 |
-
### 单元格 2: 安装 Ollama
|
| 230 |
-
```python
|
| 231 |
-
# 安装 Ollama
|
| 232 |
-
subprocess.run('curl -fsSL https://ollama.com/install.sh | sh', shell=True)
|
| 233 |
-
|
| 234 |
-
# 启动服务
|
| 235 |
-
subprocess.Popen(['ollama', 'serve'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
| 236 |
-
time.sleep(15)
|
| 237 |
-
```
|
| 238 |
-
|
| 239 |
-
### 单元格 3: 下载优化的模型
|
| 240 |
-
```python
|
| 241 |
-
import time
|
| 242 |
-
|
| 243 |
-
# 使用更小的模型
|
| 244 |
-
print("📥 下载 phi 模型(约1.6GB,2-3分钟)...")
|
| 245 |
-
subprocess.run(['ollama', 'pull', 'phi'])
|
| 246 |
-
|
| 247 |
-
print("✅ 模型下载完成")
|
| 248 |
-
```
|
| 249 |
-
|
| 250 |
-
### 单元格 4: 安装依赖并运行
|
| 251 |
-
```python
|
| 252 |
-
!pip install -r requirements_graphrag.txt -q
|
| 253 |
-
|
| 254 |
-
# 继续您的处理...
|
| 255 |
-
```
|
| 256 |
-
|
| 257 |
-
---
|
| 258 |
-
|
| 259 |
-
## 🔢 时间对比
|
| 260 |
-
|
| 261 |
-
| 场景 | Mistral | Phi | TinyLlama | 云端API |
|
| 262 |
-
|-----|---------|-----|-----------|---------|
|
| 263 |
-
| **首次下载** | 5-10分钟 | 2-3分钟 | 1分钟 | 0分钟 |
|
| 264 |
-
| **后续会话** | 5-10分钟 | 2-3分钟 | 1分钟 | 0分钟 |
|
| 265 |
-
| **每周总耗时**<br>(5次会话) | 25-50分钟 | 10-15分钟 | 5分钟 | 0分钟 |
|
| 266 |
-
|
| 267 |
-
---
|
| 268 |
-
|
| 269 |
-
## 💰 成本对比
|
| 270 |
-
|
| 271 |
-
| 方案 | 时间成本 | 金钱成本 | 质量 |
|
| 272 |
-
|-----|---------|---------|------|
|
| 273 |
-
| Mistral | 高 ❌ | 免费 ✅ | 高 ✅ |
|
| 274 |
-
| Phi | 中 ✅ | 免费 ✅ | 中高 ✅ |
|
| 275 |
-
| TinyLlama | 低 ✅ | 免费 ✅ | 中 ⚠️ |
|
| 276 |
-
| GPT-3.5 API | 极低 ✅ | 约$0.5-2/天 ⚠️ | 极高 ✅ |
|
| 277 |
-
|
| 278 |
-
---
|
| 279 |
-
|
| 280 |
-
## 🎁 快速配置脚本
|
| 281 |
-
|
| 282 |
-
将以下代码保存为 `KAGGLE_QUICK_START.py`:
|
| 283 |
-
|
| 284 |
-
```python
|
| 285 |
-
"""
|
| 286 |
-
Kaggle 快速启动脚本 - 自动使用优化配置
|
| 287 |
-
"""
|
| 288 |
-
|
| 289 |
-
import os
|
| 290 |
-
import subprocess
|
| 291 |
-
import sys
|
| 292 |
-
import time
|
| 293 |
-
|
| 294 |
-
print("🚀 Kaggle 快速启动(优化版)")
|
| 295 |
-
print("="*60)
|
| 296 |
-
|
| 297 |
-
# 1. 克隆项目
|
| 298 |
-
os.chdir('/kaggle/working')
|
| 299 |
-
if not os.path.exists('adaptive_RAG'):
|
| 300 |
-
subprocess.run(['git', 'clone', 'https://github.com/LannyCodes/adaptive_RAG.git'])
|
| 301 |
-
|
| 302 |
-
os.chdir('adaptive_RAG')
|
| 303 |
-
|
| 304 |
-
# 2. 自动选择模型(根据配置)
|
| 305 |
-
USE_SMALL_MODEL = True # 👈 改为 False 使用 Mistral
|
| 306 |
-
|
| 307 |
-
if USE_SMALL_MODEL:
|
| 308 |
-
MODEL_NAME = "phi"
|
| 309 |
-
print("✅ 使用优化模型: phi (1.6GB)")
|
| 310 |
-
else:
|
| 311 |
-
MODEL_NAME = "mistral"
|
| 312 |
-
print("✅ 使用标准模型: mistral (4GB)")
|
| 313 |
-
|
| 314 |
-
# 修改配置
|
| 315 |
-
with open('config.py', 'r') as f:
|
| 316 |
-
content = f.read()
|
| 317 |
-
|
| 318 |
-
content = content.replace(
|
| 319 |
-
'LOCAL_LLM = "mistral"',
|
| 320 |
-
f'LOCAL_LLM = "{MODEL_NAME}"'
|
| 321 |
-
)
|
| 322 |
-
|
| 323 |
-
with open('config.py', 'w') as f:
|
| 324 |
-
f.write(content)
|
| 325 |
-
|
| 326 |
-
# 3. 安装 Ollama
|
| 327 |
-
check = subprocess.run(['which', 'ollama'], capture_output=True)
|
| 328 |
-
if check.returncode != 0:
|
| 329 |
-
print("📥 安装 Ollama...")
|
| 330 |
-
subprocess.run('curl -fsSL https://ollama.com/install.sh | sh', shell=True)
|
| 331 |
-
|
| 332 |
-
# 4. 启动服务
|
| 333 |
-
subprocess.Popen(['ollama', 'serve'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
| 334 |
-
time.sleep(15)
|
| 335 |
-
|
| 336 |
-
# 5. 下载模型
|
| 337 |
-
print(f"📦 下载 {MODEL_NAME} 模型...")
|
| 338 |
-
subprocess.run(['ollama', 'pull', MODEL_NAME])
|
| 339 |
-
|
| 340 |
-
# 6. 安装依赖
|
| 341 |
-
print("📦 安装依赖...")
|
| 342 |
-
subprocess.run([sys.executable, '-m', 'pip', 'install', '-r', 'requirements_graphrag.txt', '-q'])
|
| 343 |
-
|
| 344 |
-
sys.path.insert(0, '/kaggle/working/adaptive_RAG')
|
| 345 |
-
|
| 346 |
-
print("\n" + "="*60)
|
| 347 |
-
print("✅ 环境准备完成!")
|
| 348 |
-
print("="*60)
|
| 349 |
-
print(f"\n📌 使用模型: {MODEL_NAME}")
|
| 350 |
-
print("📌 现在可以运行 GraphRAG 索引了")
|
| 351 |
-
```
|
| 352 |
-
|
| 353 |
-
---
|
| 354 |
-
|
| 355 |
-
## 总结
|
| 356 |
-
|
| 357 |
-
**最推荐的解决方案**:
|
| 358 |
-
|
| 359 |
-
1. ⭐⭐⭐⭐⭐ **使用 Phi 模型** - 平衡了速度和质量
|
| 360 |
-
2. ⭐⭐⭐⭐ **使用云端 API** - 适合生产环境
|
| 361 |
-
3. ⭐⭐⭐ **使用 TinyLlama** - 快速测试
|
| 362 |
-
|
| 363 |
-
**实际操作**:
|
| 364 |
-
- 只需将 `config.py` 中的 `LOCAL_LLM = "mistral"` 改为 `LOCAL_LLM = "phi"`
|
| 365 |
-
- 或在 Kaggle 中运行时自动替换(见快速启动脚本)
|
| 366 |
-
|
| 367 |
-
这样每次会话只需 2-3 分钟下载模型,而不是 5-10 分钟!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TIMEOUT_QUICK_FIX_CN.md
DELETED
|
@@ -1,324 +0,0 @@
|
|
| 1 |
-
# 超时问题快速修复指南
|
| 2 |
-
|
| 3 |
-
## 🚨 当前问题
|
| 4 |
-
|
| 5 |
-
您遇到了这个错误:
|
| 6 |
-
```
|
| 7 |
-
🔄 提取实体 (尝试 1/3)... ❌ 错误: HTTPConnectionPool(host='localhost', port=11434): Read timed out. (read timeout=60)
|
| 8 |
-
```
|
| 9 |
-
|
| 10 |
-
**原因**: 文档 #56 处理时间超过60秒,Ollama 没有在规定时间内返回结果。
|
| 11 |
-
|
| 12 |
-
## ⚡ 立即修复(3步搞定)
|
| 13 |
-
|
| 14 |
-
### 步骤 1: 重启 Ollama 服务
|
| 15 |
-
|
| 16 |
-
在 Colab 中运行:
|
| 17 |
-
```bash
|
| 18 |
-
!pkill -9 ollama
|
| 19 |
-
!sleep 2
|
| 20 |
-
!nohup ollama serve > /tmp/ollama.log 2>&1 &
|
| 21 |
-
!sleep 5
|
| 22 |
-
!curl http://localhost:11434/api/tags
|
| 23 |
-
```
|
| 24 |
-
|
| 25 |
-
### 步骤 2: 增加超时时间
|
| 26 |
-
|
| 27 |
-
在您的 Colab 笔记本中,修改初始化代码:
|
| 28 |
-
|
| 29 |
-
```python
|
| 30 |
-
# 找到 entity_extractor.py 的导入位置,修改为:
|
| 31 |
-
from entity_extractor import EntityExtractor
|
| 32 |
-
|
| 33 |
-
# 创建带更长超时的提取器
|
| 34 |
-
# 直接在 Python 中猴子补丁修复
|
| 35 |
-
import entity_extractor
|
| 36 |
-
|
| 37 |
-
# 保存原始初始化方法
|
| 38 |
-
_original_init = entity_extractor.EntityExtractor.__init__
|
| 39 |
-
|
| 40 |
-
# 创建新的初始化方法,默认使用更长的超时
|
| 41 |
-
def _new_init(self, timeout=180, max_retries=5):
|
| 42 |
-
_original_init(self, timeout=timeout, max_retries=max_retries)
|
| 43 |
-
|
| 44 |
-
# 替换初始化方法
|
| 45 |
-
entity_extractor.EntityExtractor.__init__ = _new_init
|
| 46 |
-
|
| 47 |
-
print("✅ 已将超时时间增加到 180 秒(3分钟)")
|
| 48 |
-
```
|
| 49 |
-
|
| 50 |
-
### 步骤 3: 继续处理(跳过已完成的)
|
| 51 |
-
|
| 52 |
-
```python
|
| 53 |
-
# 从文档 #56 继续(索引 55)
|
| 54 |
-
processed_count = 55
|
| 55 |
-
|
| 56 |
-
remaining_docs = doc_splits[processed_count:]
|
| 57 |
-
|
| 58 |
-
graph = indexer.index_documents(
|
| 59 |
-
documents=remaining_docs,
|
| 60 |
-
batch_size=3, # 减小批次大小
|
| 61 |
-
save_path="/content/drive/MyDrive/knowledge_graph.pkl"
|
| 62 |
-
)
|
| 63 |
-
```
|
| 64 |
-
|
| 65 |
-
## 🎯 完整的 Colab 代码块
|
| 66 |
-
|
| 67 |
-
直接复制粘贴到 Colab 新的代码单元格:
|
| 68 |
-
|
| 69 |
-
```python
|
| 70 |
-
print("🔧 开始修复超时问题...")
|
| 71 |
-
print("="*60)
|
| 72 |
-
|
| 73 |
-
# ========== 第1步: 重启 Ollama ==========
|
| 74 |
-
print("\n1️⃣ 重启 Ollama 服务...")
|
| 75 |
-
!pkill -9 ollama
|
| 76 |
-
!sleep 2
|
| 77 |
-
!nohup ollama serve > /tmp/ollama.log 2>&1 &
|
| 78 |
-
!sleep 5
|
| 79 |
-
|
| 80 |
-
# 验证 Ollama 已启动
|
| 81 |
-
import requests
|
| 82 |
-
try:
|
| 83 |
-
response = requests.get('http://localhost:11434/api/tags', timeout=5)
|
| 84 |
-
if response.status_code == 200:
|
| 85 |
-
print("✅ Ollama 服务运行正常")
|
| 86 |
-
else:
|
| 87 |
-
print("⚠️ Ollama 可能未正常启动")
|
| 88 |
-
except:
|
| 89 |
-
print("❌ Ollama 服务未响应,请检查日志")
|
| 90 |
-
|
| 91 |
-
# ========== 第2步: 增加超时时间 ==========
|
| 92 |
-
print("\n2️⃣ 修改超时配置...")
|
| 93 |
-
|
| 94 |
-
import sys
|
| 95 |
-
sys.path.insert(0, '/content/drive/MyDrive/adaptive_RAG')
|
| 96 |
-
|
| 97 |
-
import entity_extractor
|
| 98 |
-
|
| 99 |
-
# 保存原始初始化
|
| 100 |
-
_original_init = entity_extractor.EntityExtractor.__init__
|
| 101 |
-
|
| 102 |
-
# 新的初始化方法:默认3分钟超时,5次重试
|
| 103 |
-
def _new_init(self, timeout=180, max_retries=5):
|
| 104 |
-
from langchain_community.chat_models import ChatOllama
|
| 105 |
-
from langchain_core.output_parsers import JsonOutputParser
|
| 106 |
-
from config import LOCAL_LLM
|
| 107 |
-
try:
|
| 108 |
-
from langchain_core.prompts import PromptTemplate
|
| 109 |
-
except ImportError:
|
| 110 |
-
from langchain.prompts import PromptTemplate
|
| 111 |
-
import time
|
| 112 |
-
|
| 113 |
-
self.llm = ChatOllama(
|
| 114 |
-
model=LOCAL_LLM,
|
| 115 |
-
format="json",
|
| 116 |
-
temperature=0,
|
| 117 |
-
timeout=timeout
|
| 118 |
-
)
|
| 119 |
-
self.max_retries = max_retries
|
| 120 |
-
|
| 121 |
-
# 实体提取提示模板
|
| 122 |
-
self.entity_prompt = PromptTemplate(
|
| 123 |
-
template="""你是一个专业的实体识别专家。从以下文本中提取所有重要的实体。
|
| 124 |
-
|
| 125 |
-
实体类型包括:
|
| 126 |
-
- PERSON: 人物、作者、研究者
|
| 127 |
-
- ORGANIZATION: 组织、机构、公司
|
| 128 |
-
- CONCEPT: 技术概念、算法、方法论
|
| 129 |
-
- TECHNOLOGY: 具体技术、工具、框架
|
| 130 |
-
- PAPER: 论文、出版物
|
| 131 |
-
- EVENT: 事件、会议
|
| 132 |
-
|
| 133 |
-
文本内容:
|
| 134 |
-
{text}
|
| 135 |
-
|
| 136 |
-
请以JSON格式返回,包含以下字段:
|
| 137 |
-
{{
|
| 138 |
-
"entities": [
|
| 139 |
-
{{
|
| 140 |
-
"name": "实体名称",
|
| 141 |
-
"type": "实体类型",
|
| 142 |
-
"description": "简短描述"
|
| 143 |
-
}}
|
| 144 |
-
]
|
| 145 |
-
}}
|
| 146 |
-
|
| 147 |
-
不要包含前言或解释,只返回JSON。
|
| 148 |
-
""",
|
| 149 |
-
input_variables=["text"]
|
| 150 |
-
)
|
| 151 |
-
|
| 152 |
-
# 关系提取提示模板
|
| 153 |
-
self.relation_prompt = PromptTemplate(
|
| 154 |
-
template="""你是一个关系抽取专家。从文本中识别实体之间的关系。
|
| 155 |
-
|
| 156 |
-
已识别的实体:
|
| 157 |
-
{entities}
|
| 158 |
-
|
| 159 |
-
文本内容:
|
| 160 |
-
{text}
|
| 161 |
-
|
| 162 |
-
请识别实体之间的关系,以JSON格式返回:
|
| 163 |
-
{{
|
| 164 |
-
"relations": [
|
| 165 |
-
{{
|
| 166 |
-
"source": "源实体名称",
|
| 167 |
-
"target": "目标实体名称",
|
| 168 |
-
"relation_type": "关系类型",
|
| 169 |
-
"description": "关系描述"
|
| 170 |
-
}}
|
| 171 |
-
]
|
| 172 |
-
}}
|
| 173 |
-
|
| 174 |
-
关系类型包括: AUTHOR_OF, USES, BASED_ON, RELATED_TO, PART_OF, APPLIES_TO, IMPROVES, CITES
|
| 175 |
-
|
| 176 |
-
不要包含前言或解释,只返回JSON。
|
| 177 |
-
""",
|
| 178 |
-
input_variables=["text", "entities"]
|
| 179 |
-
)
|
| 180 |
-
|
| 181 |
-
self.entity_chain = self.entity_prompt | self.llm | JsonOutputParser()
|
| 182 |
-
self.relation_chain = self.relation_prompt | self.llm | JsonOutputParser()
|
| 183 |
-
|
| 184 |
-
# 应用补丁
|
| 185 |
-
entity_extractor.EntityExtractor.__init__ = _new_init
|
| 186 |
-
|
| 187 |
-
print("✅ 超时时间已增加到 180 秒(3分钟)")
|
| 188 |
-
print("✅ 重��次数已增加到 5 次")
|
| 189 |
-
|
| 190 |
-
# ========== 第3步: 继续处理 ==========
|
| 191 |
-
print("\n3️⃣ 准备继续处理...")
|
| 192 |
-
|
| 193 |
-
# 重新导入模块以应用更改
|
| 194 |
-
import importlib
|
| 195 |
-
if 'graph_indexer' in sys.modules:
|
| 196 |
-
importlib.reload(sys.modules['graph_indexer'])
|
| 197 |
-
|
| 198 |
-
from graph_indexer import GraphRAGIndexer
|
| 199 |
-
|
| 200 |
-
# 创建新的索引器
|
| 201 |
-
indexer = GraphRAGIndexer()
|
| 202 |
-
|
| 203 |
-
print("\n📋 当前状态:")
|
| 204 |
-
print(f" • 总文档数: {len(doc_splits)}")
|
| 205 |
-
print(f" • 已处理: 55 个文档(0-55)")
|
| 206 |
-
print(f" • 待处理: {len(doc_splits) - 55} 个文档(56-{len(doc_splits)-1})")
|
| 207 |
-
|
| 208 |
-
# 从文档 #56 继续
|
| 209 |
-
processed_count = 55
|
| 210 |
-
remaining_docs = doc_splits[processed_count:]
|
| 211 |
-
|
| 212 |
-
print("\n🚀 开始处理剩余文档...")
|
| 213 |
-
print("="*60)
|
| 214 |
-
|
| 215 |
-
graph = indexer.index_documents(
|
| 216 |
-
documents=remaining_docs,
|
| 217 |
-
batch_size=3, # 减小批次大小以降低负载
|
| 218 |
-
save_path="/content/drive/MyDrive/knowledge_graph_partial.pkl"
|
| 219 |
-
)
|
| 220 |
-
|
| 221 |
-
print("\n✅ 处理完成!")
|
| 222 |
-
```
|
| 223 |
-
|
| 224 |
-
## 📊 如果文档 #56 仍然超时
|
| 225 |
-
|
| 226 |
-
如果增加超时后,文档 #56 仍然失败,可能是该文档内容特别复杂。可以选择跳过它:
|
| 227 |
-
|
| 228 |
-
```python
|
| 229 |
-
# 方案A: 跳过文档 #56
|
| 230 |
-
print("跳过文档 #56,从 #57 继续...")
|
| 231 |
-
processed_count = 56 # 跳过 #56
|
| 232 |
-
remaining_docs = doc_splits[processed_count:]
|
| 233 |
-
|
| 234 |
-
graph = indexer.index_documents(
|
| 235 |
-
documents=remaining_docs,
|
| 236 |
-
batch_size=3,
|
| 237 |
-
save_path="/content/drive/MyDrive/knowledge_graph_partial.pkl"
|
| 238 |
-
)
|
| 239 |
-
```
|
| 240 |
-
|
| 241 |
-
或者单独检查该文档:
|
| 242 |
-
|
| 243 |
-
```python
|
| 244 |
-
# 方案B: 检查文档 #56 的内容
|
| 245 |
-
problem_doc = doc_splits[55] # 文档 #56(索引55)
|
| 246 |
-
|
| 247 |
-
print(f"文档 #56 信息:")
|
| 248 |
-
print(f" 长度: {len(problem_doc.page_content)} 字符")
|
| 249 |
-
print(f" 前500字符:")
|
| 250 |
-
print(f" {problem_doc.page_content[:500]}")
|
| 251 |
-
print(f"\n 后500字符:")
|
| 252 |
-
print(f" {problem_doc.page_content[-500:]}")
|
| 253 |
-
|
| 254 |
-
# 如果文档太长,可以考虑分割它
|
| 255 |
-
if len(problem_doc.page_content) > 3000:
|
| 256 |
-
print("\n⚠️ 文档较长,可能需要更多处理时间或分割处理")
|
| 257 |
-
```
|
| 258 |
-
|
| 259 |
-
## 🔍 监控进度
|
| 260 |
-
|
| 261 |
-
修复后,您将看到更详细的输出:
|
| 262 |
-
|
| 263 |
-
```
|
| 264 |
-
⚙️ === 批次 19/20 (文档 56-58) ===
|
| 265 |
-
|
| 266 |
-
🔍 文档 #56: 开始提取...
|
| 267 |
-
🔄 提取实体 (尝试 1/5)... ✅ 提取到 8 个实体
|
| 268 |
-
🔄 提取关系 (尝试 1/5)... ✅ 提取到 5 个关系
|
| 269 |
-
📊 文档 #56 完成: 8 实体, 5 关系
|
| 270 |
-
```
|
| 271 |
-
|
| 272 |
-
## 📌 参数说明
|
| 273 |
-
|
| 274 |
-
| 参数 | 原值 | 新值 | 说明 |
|
| 275 |
-
|-----|------|------|------|
|
| 276 |
-
| `timeout` | 60秒 | 180秒 | 单次请求最大等待时间 |
|
| 277 |
-
| `max_retries` | 3次 | 5次 | 失败后重试次数 |
|
| 278 |
-
| `batch_size` | 10 | 3 | 每批次处理的文档数 |
|
| 279 |
-
|
| 280 |
-
## ⏱️ 预计时间
|
| 281 |
-
|
| 282 |
-
- **每个文档**: 10-180秒(取决于复杂度)
|
| 283 |
-
- **批次间隔**: 重试时有2-10秒等待
|
| 284 |
-
- **总时间**: 对于100个文档,预计20-60分钟
|
| 285 |
-
|
| 286 |
-
## 🆘 如果问题持续
|
| 287 |
-
|
| 288 |
-
### 检查 Ollama 日志
|
| 289 |
-
```bash
|
| 290 |
-
!tail -n 50 /tmp/ollama.log
|
| 291 |
-
```
|
| 292 |
-
|
| 293 |
-
### 检查系统资源
|
| 294 |
-
```python
|
| 295 |
-
# 检查 GPU 内存
|
| 296 |
-
!nvidia-smi
|
| 297 |
-
|
| 298 |
-
# 检查 RAM
|
| 299 |
-
import psutil
|
| 300 |
-
print(f"内存使用: {psutil.virtual_memory().percent}%")
|
| 301 |
-
```
|
| 302 |
-
|
| 303 |
-
### 使用更小的模型
|
| 304 |
-
如果 Mistral 太慢,可以在 `config.py` 中切换到更快的模型:
|
| 305 |
-
```python
|
| 306 |
-
LOCAL_LLM = "phi:latest" # 更快但质量稍低
|
| 307 |
-
# 或
|
| 308 |
-
LOCAL_LLM = "llama2:7b" # 平衡选择
|
| 309 |
-
```
|
| 310 |
-
|
| 311 |
-
## 📝 总结
|
| 312 |
-
|
| 313 |
-
**最可能的解决方案**:
|
| 314 |
-
1. ✅ 重启 Ollama(清理内存)
|
| 315 |
-
2. ✅ 增加超时到 180 秒
|
| 316 |
-
3. ✅ 减小批次大小到 3
|
| 317 |
-
4. ✅ 从断点继续处理
|
| 318 |
-
|
| 319 |
-
**紧急情况**:
|
| 320 |
-
- 如果某个文档持续失败 → 跳过它
|
| 321 |
-
- 如果 Ollama 崩溃 → 重启服务
|
| 322 |
-
- 如果内存不足 → 使用更小的模型
|
| 323 |
-
|
| 324 |
-
现在请运行上面的"完整 Colab 代码块",应该就能解决问题了! 🚀
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|