deepdata: core product code (backend, frontend, runtime, deepflow module)

This commit is contained in:
figmar
2026-08-30 19:23:38 +08:00
commit bd3db30be9
1405 changed files with 271727 additions and 0 deletions
@@ -0,0 +1,58 @@
"""
RAG 模块 Schema 导出
集中导出所有数据模型、请求和响应 DTO
"""
from .enums import ProcessType
from app.db.models.knowledge_gen import RagType, FileStatus
from .types import RagChunk
from app.db.models.knowledge_gen import KnowledgeBase, RagFile
from .request import (
KnowledgeBaseCreateReq,
KnowledgeBaseUpdateReq,
KnowledgeBaseQueryReq,
AddFilesReq,
DeleteFilesReq,
RagFileReq,
RetrieveReq,
FileInfo,
PagingQuery,
QueryRequest,
)
from .response import (
ModelConfig,
KnowledgeBaseResp,
RagFileResp,
RagChunkResp,
SearchResult,
PagedResponse,
)
__all__ = [
# Enums
"RagType",
"ProcessType",
"FileStatus",
# Entities
"KnowledgeBase",
"RagFile",
"RagChunk",
# Requests
"KnowledgeBaseCreateReq",
"KnowledgeBaseUpdateReq",
"KnowledgeBaseQueryReq",
"AddFilesReq",
"DeleteFilesReq",
"RagFileReq",
"RetrieveReq",
"FileInfo",
"PagingQuery",
"QueryRequest",
# Responses
"ModelConfig",
"KnowledgeBaseResp",
"RagFileResp",
"RagChunkResp",
"SearchResult",
"PagedResponse",
]
@@ -0,0 +1,21 @@
"""
RAG 模块枚举定义
包含所有 RAG 相关的枚举类型,与 Java 枚举保持一致
从 app.db.models.knowledge_gen 导入以避免循环依赖
"""
from enum import Enum
# 从模型导入以避免循环依赖
class ProcessType(str, Enum):
"""分块处理类型枚举
对应 Java: com.deepdata.rag.indexer.interfaces.dto.ProcessType
"""
PARAGRAPH_CHUNK = "PARAGRAPH_CHUNK" # 段落分块
SENTENCE_CHUNK = "SENTENCE_CHUNK" # 按句子分块
LENGTH_CHUNK = "LENGTH_CHUNK" # 按长度分块(字符)
DEFAULT_CHUNK = "DEFAULT_CHUNK" # 默认分块(单词)
CUSTOM_SEPARATOR_CHUNK = "CUSTOM_SEPARATOR_CHUNK" # 自定义分隔符分块
@@ -0,0 +1,393 @@
"""
RAG 模块请求 DTO
使用 Pydantic 定义所有请求参数验证
与 Java DTO 保持字段一致和验证规则一致
"""
from pydantic import BaseModel, Field, field_validator
from typing import List, Optional
from .enums import ProcessType
from app.db.models.knowledge_gen import RagType, FileStatus
class KnowledgeBaseCreateReq(BaseModel):
"""知识库创建请求
对应 Java: com.deepdata.rag.indexer.interfaces.dto.KnowledgeBaseCreateReq
"""
name: str = Field(
...,
min_length=1,
max_length=255,
pattern=r"^[a-zA-Z][a-zA-Z0-9_]*$",
description="知识库名称(必须以字母开头,只能包含字母、数字和下划线)"
)
description: Optional[str] = Field(
None,
max_length=512,
description="知识库描述"
)
type: RagType = Field(
default=RagType.DOCUMENT,
description="RAG 类型"
)
embedding_model: str = Field(
...,
min_length=1,
alias="embeddingModel",
description="嵌入模型ID"
)
chat_model: Optional[str] = Field(
None,
alias="chatModel",
description="聊天模型ID"
)
class Config:
populate_by_name = True
json_schema_extra = {
"example": {
"name": "my_knowledge_base",
"description": "我的知识库",
"type": "DOCUMENT",
"embeddingModel": "text-embedding-ada-002",
"chatModel": "gpt-4"
}
}
class KnowledgeBaseUpdateReq(BaseModel):
"""知识库更新请求
对应 Java: com.deepdata.rag.indexer.interfaces.dto.KnowledgeBaseUpdateReq
"""
name: str = Field(
...,
min_length=1,
max_length=255,
pattern=r"^[a-zA-Z][a-zA-Z0-9_]*$",
description="知识库名称"
)
description: Optional[str] = Field(
None,
max_length=512,
description="知识库描述"
)
class Config:
populate_by_name = True
json_schema_extra = {
"example": {
"name": "updated_knowledge_base",
"description": "更新后的描述"
}
}
class KnowledgeBaseQueryReq(BaseModel):
"""知识库查询请求
对应 Java: com.deepdata.rag.indexer.interfaces.dto.KnowledgeBaseQueryReq
"""
page: int = Field(
default=1,
ge=1,
description="页码(从 1 开始)"
)
page_size: int = Field(
default=10,
ge=1,
le=100,
alias="size",
description="每页数量"
)
keyword: Optional[str] = Field(
None,
max_length=255,
alias="name",
description="搜索关键词(模糊匹配知识库名称或描述)"
)
type: Optional[RagType] = Field(
None,
description="按 RAG 类型筛选"
)
class Config:
populate_by_name = True
json_schema_extra = {
"example": {
"page": 1,
"size": 10,
"name": "测试",
"type": "DOCUMENT"
}
}
class FileInfo(BaseModel):
"""文件信息
对应 Java: com.deepdata.rag.indexer.interfaces.dto.AddFilesReq.FileInfo
"""
id: str = Field(..., description="文件ID (对应 t_dm_dataset_files.id)")
file_name: str = Field(alias="fileName", description="文件名")
class Config:
populate_by_name = True
json_schema_extra = {
"example": {
"id": "file-uuid-123",
"fileName": "document.pdf"
}
}
class AddFilesReq(BaseModel):
"""添加文件请求
对应 Java: com.deepdata.rag.indexer.interfaces.dto.AddFilesReq
"""
knowledge_base_id: Optional[str] = Field(None, alias="knowledgeBaseId", description="知识库ID(从路径参数获取,这里保留用于兼容)")
process_type: ProcessType = Field(
default=ProcessType.DEFAULT_CHUNK,
alias="processType",
description="分块处理类型"
)
chunk_size: int = Field(
default=500,
ge=50,
le=2000,
alias="chunkSize",
description="分块大小"
)
overlap_size: int = Field(
default=50,
ge=0,
le=500,
alias="overlapSize",
description="重叠大小"
)
delimiter: Optional[str] = Field(
None,
description="自定义分隔符(仅用于 CUSTOM_SEPARATOR_CHUNK)"
)
files: List[FileInfo] = Field(
...,
min_length=1,
description="文件列表"
)
@field_validator("delimiter")
@classmethod
def validate_delimiter(cls, v, info):
"""验证自定义分隔符"""
if info.data.get("process_type") == ProcessType.CUSTOM_SEPARATOR_CHUNK and not v:
raise ValueError("使用自定义分隔符分块时,delimiter 不能为空")
return v
class Config:
populate_by_name = True
json_schema_extra = {
"example": {
"knowledgeBaseId": "kb-uuid-123",
"processType": "DEFAULT_CHUNK",
"chunkSize": 500,
"overlapSize": 50,
"files": [
{"id": "file-1", "fileName": "doc1.pdf"},
{"id": "file-2", "fileName": "doc2.pdf"}
]
}
}
class DeleteFilesReq(BaseModel):
"""删除文件请求
对应 Java: com.deepdata.rag.indexer.interfaces.dto.DeleteFilesReq
"""
file_ids: List[str] = Field(
...,
min_length=1,
alias="ids",
description="要删除的文件ID列表"
)
class Config:
populate_by_name = True
json_schema_extra = {
"example": {
"ids": ["file-1", "file-2", "file-3"]
}
}
class RagFileReq(BaseModel):
"""RAG 文件查询请求
对应 Java: com.deepdata.rag.indexer.interfaces.dto.RagFileReq
"""
page: int = Field(
default=1,
ge=1,
description="页码"
)
page_size: int = Field(
default=10,
ge=1,
le=100,
alias="size",
description="每页数量"
)
keyword: Optional[str] = Field(
None,
max_length=255,
alias="fileName",
description="搜索关键词(模糊匹配文件名)"
)
status: Optional[FileStatus] = Field(
None,
description="按状态筛选"
)
class Config:
populate_by_name = True
json_schema_extra = {
"example": {
"page": 1,
"size": 10,
"fileName": "测试",
"status": "PROCESSED"
}
}
class RetrieveReq(BaseModel):
"""检索请求
对应 Java: com.deepdata.rag.indexer.interfaces.dto.RetrieveReq
"""
query: str = Field(
...,
min_length=1,
description="检索查询文本"
)
top_k: int = Field(
default=5,
ge=1,
le=20,
alias="topK",
description="返回前 K 个结果"
)
threshold: Optional[float] = Field(
None,
ge=0.0,
le=1.0,
description="相似度阈值(仅返回分数大于等于该值的结果)"
)
knowledge_base_ids: List[str] = Field(
...,
min_length=1,
alias="knowledgeBaseIds",
description="要检索的知识库ID列表"
)
class Config:
populate_by_name = True
json_schema_extra = {
"example": {
"query": "什么是机器学习?",
"topK": 5,
"threshold": 0.7,
"knowledgeBaseIds": ["kb-1", "kb-2"]
}
}
class PagingQuery(BaseModel):
"""分页查询请求
对应 Java: com.deepdata.common.interfaces.PagingQuery
"""
page: int = Field(
default=1,
ge=1,
description="页码(从 1 开始)"
)
size: int = Field(
default=10,
ge=1,
le=100,
description="每页数量"
)
class Config:
json_schema_extra = {
"example": {
"page": 1,
"size": 10
}
}
class ChunkFilterQuery(BaseModel):
"""分块过滤查询请求
支持分页和 Milvus 表达式过滤
"""
page: int = Field(
default=1,
ge=1,
description="页码(从 1 开始)"
)
size: int = Field(
default=10,
ge=1,
le=100,
description="每页数量"
)
expr: Optional[str] = Field(
None,
description="Milvus 过滤表达式(如 id > \"1\" && text like \"%keyword%\")"
)
class Config:
json_schema_extra = {
"example": {
"page": 1,
"size": 10,
"expr": "id > \"1\""
}
}
class QueryRequest(BaseModel):
"""知识图谱查询请求"""
knowledge_base_id: str = Field(..., description="知识库ID")
query: str = Field(..., description="查询文本")
class Config:
json_schema_extra = {
"example": {
"knowledge_base_id": "kb-uuid-123",
"query": "什么是机器学习?"
}
}
class ChunkUpdateReq(BaseModel):
"""Chunk更新请求"""
text: str = Field(..., min_length=1, description="分块文本内容")
metadata: Optional[dict] = Field(default=None, description="元数据")
class Config:
json_schema_extra = {
"example": {
"text": "这是修改后的分块内容...",
"metadata": {
"fileName": "document.pdf",
"chunkIndex": 0,
"customField": "custom value"
}
}
}
@@ -0,0 +1,235 @@
"""
RAG 模块响应 DTO
定义所有 API 响应的数据结构
与 Java 响应 DTO 保持字段一致
"""
from pydantic import BaseModel, Field, ConfigDict
from typing import List, Optional, Any
from datetime import datetime
from app.db.models.knowledge_gen import RagType, FileStatus
class ModelConfig(BaseModel):
"""模型配置信息
对应 Java: com.deepdata.common.setting.domain.entity.ModelConfig
"""
model_config = ConfigDict(from_attributes=True, populate_by_name=True)
id: str = Field(..., description="模型ID")
created_at: Optional[datetime] = Field(None, alias="createdAt", description="创建时间")
updated_at: Optional[datetime] = Field(None, alias="updatedAt", description="更新时间")
created_by: Optional[str] = Field(None, alias="createdBy", description="创建人")
updated_by: Optional[str] = Field(None, alias="updatedBy", description="更新人")
model_name: str = Field(..., alias="modelName", description="模型名称")
provider: str = Field(..., description="模型提供商")
base_url: str = Field(..., alias="baseUrl", description="API 基础地址")
api_key: str = Field(default="", alias="apiKey", description="API 密钥")
type: str = Field(..., description="模型类型")
is_enabled: bool = Field(default=True, alias="isEnabled", description="是否启用")
is_default: bool = Field(default=False, alias="isDefault", description="是否默认")
is_deleted: bool = Field(default=False, alias="isDeleted", description="是否删除")
class KnowledgeBaseResp(BaseModel):
"""知识库响应
对应 Java: com.deepdata.rag.indexer.interfaces.dto.KnowledgeBaseResp
"""
model_config = ConfigDict(
from_attributes=True,
populate_by_name=True,
json_schema_extra={
"example": {
"id": "kb-uuid-123",
"name": "my_knowledge_base",
"description": "我的知识库",
"type": "DOCUMENT",
"embeddingModel": "text-embedding-ada-002",
"chatModel": "gpt-4",
"fileCount": 10,
"chunkCount": 150,
"embedding": {
"id": "model-1",
"modelName": "text-embedding-ada-002",
"provider": "openai"
}
}
}
)
id: str = Field(..., description="知识库ID")
name: str = Field(..., description="知识库名称")
description: Optional[str] = Field(None, description="知识库描述")
type: RagType = Field(..., description="RAG类型")
embedding_model: str = Field(alias="embeddingModel", description="嵌入模型ID")
chat_model: Optional[str] = Field(None, alias="chatModel", description="聊天模型ID")
file_count: Optional[int] = Field(None, alias="fileCount", description="文件数量")
chunk_count: Optional[int] = Field(None, alias="chunkCount", description="分块数量")
embedding: Optional[ModelConfig] = Field(None, description="嵌入模型配置")
chat: Optional[ModelConfig] = Field(None, description="聊天模型配置")
created_at: Optional[datetime] = Field(None, alias="createdAt", description="创建时间")
updated_at: Optional[datetime] = Field(None, alias="updatedAt", description="更新时间")
created_by: Optional[str] = Field(None, alias="createdBy", description="创建人")
updated_by: Optional[str] = Field(None, alias="updatedBy", description="更新人")
class RagFileResp(BaseModel):
"""RAG 文件响应
对应 Java: com.deepdata.rag.indexer.domain.model.RagFile
"""
model_config = ConfigDict(
from_attributes=True,
populate_by_name=True,
json_schema_extra={
"example": {
"id": "rag-file-uuid-123",
"knowledgeBaseId": "kb-uuid-123",
"fileName": "document.pdf",
"fileId": "file-uuid-456",
"chunkCount": 15,
"metadata": {"size": 1024, "format": "pdf"},
"status": "PROCESSED",
"progress": 100,
"createdAt": "2025-01-01T00:00:00"
}
}
)
id: str = Field(..., description="RAG文件ID")
knowledge_base_id: str = Field(alias="knowledgeBaseId", description="知识库ID")
file_name: str = Field(alias="fileName", description="文件名")
file_id: str = Field(alias="fileId", description="原始文件ID")
chunk_count: Optional[int] = Field(None, alias="chunkCount", description="分块数量")
metadata: Optional[dict] = Field(None, validation_alias="file_metadata", description="元数据")
status: FileStatus = Field(..., description="处理状态")
err_msg: Optional[str] = Field(None, alias="errMsg", description="错误信息")
progress: int = Field(default=0, ge=0, le=100, description="处理进度(0-100)")
created_at: Optional[datetime] = Field(None, alias="createdAt", description="创建时间")
updated_at: Optional[datetime] = Field(None, alias="updatedAt", description="更新时间")
created_by: Optional[str] = Field(None, alias="createdBy", description="创建人")
updated_by: Optional[str] = Field(None, alias="updatedBy", description="更新人")
class RagChunkResp(BaseModel):
"""RAG 分块响应
对应 Milvus 查询结果
"""
id: str = Field(..., description="分块ID")
text: str = Field(..., description="分块文本")
metadata: dict = Field(..., description="元数据")
score: float = Field(..., description="相似度分数")
distance: Optional[float] = Field(None, description="距离(可选)")
class Config:
populate_by_name = True # 允许使用 snake_case 或 camelCase
json_schema_extra = {
"example": {
"id": "chunk-uuid-123",
"text": "这是文档的一个分块内容...",
"metadata": {
"fileName": "document.pdf",
"chunkIndex": 0
},
"score": 0.95
}
}
class SearchResult(BaseModel):
"""检索结果
对应 Java: io.milvus.v2.service.vector.response.SearchResp.SearchResult
"""
id: str = Field(..., description="结果ID")
score: float = Field(..., description="相似度分数")
text: str = Field(..., description="文本内容")
metadata: dict = Field(default_factory=dict, description="元数据")
class Config:
json_schema_extra = {
"example": {
"id": "chunk-uuid-123",
"score": 0.95,
"text": "相关文档内容...",
"metadata": {"file_name": "doc.pdf"}
}
}
class UnifiedSearchResult(BaseModel):
"""统一检索结果
所有知识库类型(向量、知识图谱)的检索接口必须返回此格式
"""
model_config = ConfigDict(
populate_by_name=True,
json_schema_extra={
"example": {
"id": "result-uuid-123",
"text": "相关文档内容...",
"score": 0.95,
"metadata": {"fileName": "document.pdf", "chunkIndex": 0},
"resultType": "vector",
"knowledgeBaseId": "kb-uuid-123",
"knowledgeBaseName": "my_knowledge_base"
}
}
)
id: str = Field(..., description="结果ID")
text: str = Field(..., description="文本内容")
score: float = Field(..., description="相似度分数")
metadata: dict = Field(default_factory=dict, description="元数据")
result_type: str = Field(alias="resultType", description="结果类型(vector/graph)")
knowledge_base_id: str = Field(alias="knowledgeBaseId", description="知识库ID")
knowledge_base_name: str = Field(alias="knowledgeBaseName", description="知识库名称")
class PagedResponse(BaseModel):
"""分页响应
对应 Java: com.deepdata.common.interfaces.PagedResponse
"""
content: List[Any] = Field(..., description="数据列表")
total_elements: int = Field(alias="totalElements", description="总记录数")
page: int = Field(..., description="当前页码")
size: int = Field(..., description="每页数量")
total_pages: int = Field(alias="totalPages", description="总页数")
@classmethod
def create(cls, content: List[Any], total_elements: int, page: int, size: int):
"""创建分页响应
Args:
content: 数据列表
total_elements: 总记录数
page: 当前页码
size: 每页数量
Returns:
PagedResponse 实例
"""
total_pages = (total_elements + size - 1) // size if size > 0 else 0
return cls(
content=content,
total_elements=total_elements,
page=page,
size=size,
total_pages=total_pages
)
class Config:
populate_by_name = True # 允许使用 snake_case 或 camelCase
json_schema_extra = {
"example": {
"content": [],
"totalElements": 100,
"page": 1,
"size": 10,
"totalPages": 10
}
}
@@ -0,0 +1,58 @@
"""
RAG 模块非 ORM 实体
RagChunk 为 Milvus 中存储的文档分块 DTO,非数据库表。
ORM 实体 KnowledgeBase、RagFile 已移至 app.db.models.knowledge_gen。
"""
# noqa: D104 (RagChunk 是领域模型,不是 DB 表)
class RagChunk:
"""RAG 分块模型
对应 Java: com.deepdata.rag.indexer.domain.model.RagChunk
注意:这不是数据库实体,而是 Milvus 中存储的文档分块
"""
def __init__(
self,
chunk_id: str,
rag_file_id: str,
text: str,
metadata: dict,
vector: list[float] = None,
sparse_vector: dict[int, float] = None
):
"""初始化文档分块
Args:
chunk_id: 分块ID
rag_file_id: 关联的 RAG 文件 ID
text: 分块文本内容
metadata: 元数据(包含文件信息、分块索引等)
vector: 密集向量(嵌入向量)
sparse_vector: 稀疏向量(BM25 向量)
"""
self.chunk_id = chunk_id
self.rag_file_id = rag_file_id
self.text = text
self.metadata = metadata
self.vector = vector
self.sparse_vector = sparse_vector
def to_dict(self) -> dict:
"""转换为字典格式(用于 Milvus 插入)
Returns:
包含所有字段的字典
"""
return {
"id": self.chunk_id,
"text": self.text,
"metadata": self.metadata,
"vector": self.vector,
"sparse": self.sparse_vector or {}
}
def __repr__(self):
return f"<RagChunk(id={self.chunk_id}, text={self.text[:50]}...)>"