Add comprehensive documentation covering 6 modules: - 01-API-LAYER: Authentication, routing, SSE streaming - 02-SERVICE-LAYER: Dialog, Task, LLM service analysis - 03-RAG-ENGINE: Hybrid search, embedding, reranking - 04-AGENT-SYSTEM: Canvas engine, components, tools - 05-DOCUMENT-PROCESSING: Task executor, PDF parsing - 06-ALGORITHMS: BM25, fusion, RAPTOR Total 28 documentation files with code analysis, diagrams, and formulas.
356 lines
13 KiB
Markdown
356 lines
13 KiB
Markdown
# 02-SERVICE-LAYER - Business Logic Layer
|
|
|
|
## Tổng Quan
|
|
|
|
Service Layer là tầng business logic của RAGFlow, xử lý tất cả operations phức tạp và orchestrate các components khác nhau.
|
|
|
|
## Kiến Trúc Service Layer
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────────┐
|
|
│ API LAYER (Blueprints) │
|
|
└────────────────────────────────┬────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────────────┐
|
|
│ SERVICE LAYER │
|
|
│ │
|
|
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
|
│ │ DialogService │ │ DocumentService │ │ KnowledgebaseS. │ │
|
|
│ │ │ │ │ │ │ │
|
|
│ │ • chat() │ │ • insert() │ │ • create() │ │
|
|
│ │ • ask() │ │ • remove() │ │ • update() │ │
|
|
│ │ • gen_mindmap() │ │ • get_list() │ │ • get_by_id() │ │
|
|
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
|
|
│ │ │ │ │
|
|
│ ┌────────┴────────┐ ┌────────┴────────┐ ┌────────┴────────┐ │
|
|
│ │ TaskService │ │ FileService │ │ LLMService │ │
|
|
│ │ │ │ │ │ (LLMBundle) │ │
|
|
│ │ • queue_tasks() │ │ • upload() │ │ │ │
|
|
│ │ • get_task() │ │ • download() │ │ • encode() │ │
|
|
│ │ • update_prog() │ │ • delete() │ │ • chat() │ │
|
|
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
|
|
│ │
|
|
└────────────────────────────────┬────────────────────────────────────────┘
|
|
│
|
|
┌──────────────────────┼──────────────────────┐
|
|
│ │ │
|
|
▼ ▼ ▼
|
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
│ DATABASE │ │ VECTOR STORE │ │ STORAGE │
|
|
│ (MySQL) │ │ (Elasticsearch) │ │ (MinIO) │
|
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
```
|
|
|
|
## Cấu Trúc Thư Mục
|
|
|
|
```
|
|
/api/db/
|
|
├── db_models.py # Peewee ORM models (54KB)
|
|
├── db_utils.py # Database utilities
|
|
├── init_data.py # Initial data seeding
|
|
├── runtime_config.py # Runtime configuration
|
|
│
|
|
└── services/
|
|
├── dialog_service.py # Chat/RAG service (37KB) ⭐
|
|
├── document_service.py # Document management (39KB) ⭐
|
|
├── knowledgebase_service.py # KB operations (21KB)
|
|
├── task_service.py # Task queue (20KB) ⭐
|
|
├── file_service.py # File operations (22KB)
|
|
├── llm_service.py # LLM abstraction ⭐
|
|
├── user_service.py # User management
|
|
├── conversation_service.py # Conversation storage
|
|
├── canvas_service.py # Canvas/workflow storage
|
|
├── connector_service.py # Data source connectors
|
|
├── api_service.py # API token management
|
|
├── search_service.py # Search operations
|
|
└── common_service.py # Base service class
|
|
```
|
|
|
|
## Files Trong Module Này
|
|
|
|
| File | Mô Tả |
|
|
|------|-------|
|
|
| [dialog_service_analysis.md](./dialog_service_analysis.md) | **Core RAG Chat** - Retrieval, reranking, generation |
|
|
| [document_service_analysis.md](./document_service_analysis.md) | Document lifecycle management |
|
|
| [task_service_analysis.md](./task_service_analysis.md) | Background task queue system |
|
|
| [llm_service_analysis.md](./llm_service_analysis.md) | LLM abstraction và token tracking |
|
|
| [knowledgebase_service_analysis.md](./knowledgebase_service_analysis.md) | Knowledge base operations |
|
|
|
|
## Core Patterns
|
|
|
|
### 1. CommonService Base Class
|
|
|
|
```python
|
|
class CommonService:
|
|
"""Base class for all services with common CRUD operations."""
|
|
|
|
model = None # Override in subclass
|
|
|
|
@classmethod
|
|
@DB.connection_context()
|
|
def query(cls, cols=None, reverse=None, order_by=None, **kwargs):
|
|
"""
|
|
Flexible query builder.
|
|
|
|
Args:
|
|
cols: Columns to select
|
|
reverse: Reverse sort order
|
|
order_by: Sort field
|
|
**kwargs: Filter conditions
|
|
|
|
Returns:
|
|
List of matching records
|
|
"""
|
|
query = cls.model.select(*cols) if cols else cls.model.select()
|
|
|
|
for k, v in kwargs.items():
|
|
query = query.where(getattr(cls.model, k) == v)
|
|
|
|
if order_by:
|
|
query = query.order_by(
|
|
getattr(cls.model, order_by).desc() if reverse
|
|
else getattr(cls.model, order_by)
|
|
)
|
|
|
|
return list(query)
|
|
|
|
@classmethod
|
|
@DB.connection_context()
|
|
def get_by_id(cls, id):
|
|
"""Get record by primary key."""
|
|
try:
|
|
record = cls.model.get_by_id(id)
|
|
return True, record
|
|
except DoesNotExist:
|
|
return False, None
|
|
|
|
@classmethod
|
|
@DB.connection_context()
|
|
def save(cls, **kwargs):
|
|
"""Insert new record."""
|
|
return cls.model.create(**kwargs)
|
|
|
|
@classmethod
|
|
@DB.connection_context()
|
|
def update_by_id(cls, id, data):
|
|
"""Update record by ID."""
|
|
data["update_time"] = int(time.time() * 1000)
|
|
data["update_date"] = datetime.now()
|
|
return cls.model.update(data).where(cls.model.id == id).execute()
|
|
```
|
|
|
|
### 2. Transaction Handling
|
|
|
|
```python
|
|
# Atomic operations
|
|
with DB.atomic():
|
|
for item in items:
|
|
cls.model.update(data).where(...).execute()
|
|
|
|
# Connection context for query isolation
|
|
@DB.connection_context()
|
|
def critical_operation():
|
|
# Automatic connection management
|
|
pass
|
|
|
|
# Database locking for critical sections
|
|
with DB.lock("operation_name", timeout=60):
|
|
# Only one process can execute this
|
|
pass
|
|
```
|
|
|
|
### 3. Service-to-Service Communication
|
|
|
|
```python
|
|
# Services call other services
|
|
class DialogService:
|
|
@classmethod
|
|
def chat(cls, dialog, messages, **kwargs):
|
|
# Get knowledge bases
|
|
kbs = KnowledgebaseService.get_by_ids(dialog.kb_ids)
|
|
|
|
# Get embedding model
|
|
embd_mdl = LLMBundle(tenant_id, LLMType.EMBEDDING, kb.embd_id)
|
|
|
|
# Retrieve documents
|
|
kbinfos = retriever.retrieval(query, embd_mdl, ...)
|
|
|
|
# Generate response
|
|
for token in chat_mdl.chat_streamly(...):
|
|
yield token
|
|
```
|
|
|
|
## Database Models Overview
|
|
|
|
### Core Models
|
|
|
|
```python
|
|
# User & Multi-tenancy
|
|
User # id, email, password, access_token
|
|
Tenant # id, name, llm_id, embd_id
|
|
UserTenant # user_id, tenant_id, role
|
|
|
|
# Knowledge Management
|
|
Knowledgebase # id, tenant_id, name, embd_id, parser_config
|
|
Document # id, kb_id, name, status, progress, chunk_num
|
|
File # id, tenant_id, name, location, type
|
|
File2Document # file_id, document_id
|
|
|
|
# Chat & Dialog
|
|
Dialog # id, tenant_id, kb_ids, llm_id, prompt_config
|
|
Conversation # id, dialog_id, message (JSON array)
|
|
|
|
# Task Queue
|
|
Task # id, doc_id, progress, chunk_ids
|
|
|
|
# API Integration
|
|
APIToken # id, tenant_id, token, dialog_id
|
|
```
|
|
|
|
### JSON Fields Usage
|
|
|
|
```python
|
|
# Parser configuration
|
|
Document.parser_config = {
|
|
"chunk_token_num": 512,
|
|
"delimiter": "\n。;!?",
|
|
"layout_recognize": "DeepDOC"
|
|
}
|
|
|
|
# LLM settings
|
|
Dialog.llm_setting = {
|
|
"temperature": 0.7,
|
|
"max_tokens": 2048,
|
|
"top_p": 1.0
|
|
}
|
|
|
|
# Prompt configuration
|
|
Dialog.prompt_config = {
|
|
"system": "You are a helpful assistant...",
|
|
"prologue": "Hi! How can I help?",
|
|
"quote": True,
|
|
"reasoning": False
|
|
}
|
|
```
|
|
|
|
## Key Service Interactions
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────────┐
|
|
│ SERVICE INTERACTION FLOW │
|
|
└─────────────────────────────────────────────────────────────────────────┘
|
|
|
|
[Document Upload]
|
|
API
|
|
│
|
|
├──► FileService.upload_document()
|
|
│ │
|
|
│ ├──► Store file in MinIO
|
|
│ ├──► Create File record
|
|
│ └──► Create Document record
|
|
│
|
|
└──► TaskService.queue_tasks()
|
|
│
|
|
└──► Create Task records
|
|
└──► Push to Redis queue
|
|
|
|
[Document Processing]
|
|
TaskExecutor (Background)
|
|
│
|
|
├──► TaskService.get_task()
|
|
├──► DocumentService.get_by_id()
|
|
├──► Parse & chunk document
|
|
├──► LLMBundle.encode() → Generate embeddings
|
|
├──► Store chunks in Elasticsearch
|
|
├──► TaskService.update_progress()
|
|
└──► DocumentService.increment_chunk_num()
|
|
|
|
[Chat/RAG]
|
|
API
|
|
│
|
|
└──► DialogService.chat()
|
|
│
|
|
├──► KnowledgebaseService.get_by_ids()
|
|
├──► LLMBundle (embedding) → Query vector
|
|
├──► retriever.retrieval() → Hybrid search
|
|
├──► LLMBundle (rerank) → Rerank results
|
|
├──► LLMBundle (chat) → Generate response
|
|
└──► ConversationService.save()
|
|
```
|
|
|
|
## Performance Patterns
|
|
|
|
### 1. Batch Operations
|
|
|
|
```python
|
|
def bulk_create_chunks(chunks: List[dict]):
|
|
"""Bulk insert for efficiency."""
|
|
with db.atomic():
|
|
for batch in chunked(chunks, 1000):
|
|
Chunk.insert_many(batch).execute()
|
|
```
|
|
|
|
### 2. Connection Pooling
|
|
|
|
```python
|
|
db = PooledMySQLDatabase(
|
|
database,
|
|
max_connections=32,
|
|
stale_timeout=300,
|
|
**connection_params
|
|
)
|
|
```
|
|
|
|
### 3. Caching Strategies
|
|
|
|
```python
|
|
# Metadata caching for filtering
|
|
@cache_result(ttl=600)
|
|
def get_meta_by_kbs(kb_ids):
|
|
"""Cache metadata index for 10 minutes."""
|
|
return DocumentService.get_meta_by_kbs(kb_ids)
|
|
```
|
|
|
|
### 4. Token Tracking
|
|
|
|
```python
|
|
class LLMBundle:
|
|
def encode(self, texts):
|
|
embeddings, tokens = self.mdl.encode(texts)
|
|
# Track token usage
|
|
TenantLLMService.increase_usage(
|
|
self.tenant_id,
|
|
LLMType.EMBEDDING,
|
|
tokens
|
|
)
|
|
return embeddings
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
```python
|
|
class ServiceException(Exception):
|
|
"""Base exception for service errors."""
|
|
pass
|
|
|
|
class DocumentNotFoundError(ServiceException):
|
|
pass
|
|
|
|
class InsufficientQuotaError(ServiceException):
|
|
pass
|
|
|
|
# Usage
|
|
try:
|
|
result = DocumentService.get_by_id(doc_id)
|
|
if not result[0]:
|
|
raise DocumentNotFoundError(f"Document {doc_id} not found")
|
|
except DocumentNotFoundError as e:
|
|
return get_json_result(code=404, message=str(e))
|
|
```
|
|
|
|
## Related Files
|
|
|
|
- `/api/db/db_models.py` - All database models
|
|
- `/rag/llm/*.py` - LLM implementations
|
|
- `/rag/nlp/search.py` - Search/retrieval logic
|