From f2d68ebdaa7e2b0869b5ec86caade75cf7e477d8 Mon Sep 17 00:00:00 2001 From: Wenjie Zhang Date: Sun, 17 May 2026 19:54:54 +0800 Subject: [PATCH] =?UTF-8?q?fix(kb):=20=E4=BF=AE=E5=A4=8D=20metadata=20?= =?UTF-8?q?=E8=A6=86=E5=86=99=E6=95=B0=E6=8D=AE=E5=BA=93=E5=9B=BE=E8=B0=B1?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=EF=BC=8C=E6=94=B9=E7=94=A8=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=BA=A7=E6=8C=81=E4=B9=85=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - update_kb_config 不再触发全量 _save_metadata,避免内存 metadata 覆盖数据库已有图谱配置 - 补全文件大小时改用 _persist_file 逐文件写入 - delete_file_chunks_only 通过 chunk_repo 检查文件是否有图谱数据再决定是否清理 --- backend/package/yuxi/knowledge/base.py | 19 +++---------------- .../yuxi/knowledge/implementations/milvus.py | 8 ++++---- .../knowledge_chunk_repository.py | 9 +++++++++ 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/backend/package/yuxi/knowledge/base.py b/backend/package/yuxi/knowledge/base.py index 0b1477d7..dec17072 100644 --- a/backend/package/yuxi/knowledge/base.py +++ b/backend/package/yuxi/knowledge/base.py @@ -1242,8 +1242,6 @@ class KnowledgeBase(ABC): if update_llm_model_spec: self.databases_meta[db_id]["llm_model_spec"] = llm_model_spec - asyncio.create_task(self._save_metadata()) - return self.get_database_info(db_id) def get_retrievers(self) -> dict[str, dict]: @@ -1394,7 +1392,9 @@ class KnowledgeBase(ABC): if updated: logger.info(f"Filled {updated}/{len(files_to_update)} missing file sizes from MinIO for {self.kb_type}") - await self._save_metadata() + for file_id, file_size in results: + if file_size is not None: + await self._persist_file(file_id) async def _save_metadata(self) -> None: from yuxi.repositories.evaluation_repository import EvaluationRepository @@ -1421,19 +1421,6 @@ class KnowledgeBase(ABC): } if existing is None: await kb_repo.create(payload) - else: - await kb_repo.update( - db_id, - { - "name": payload["name"], - "description": payload["description"], - "kb_type": payload["kb_type"], - "embedding_model_spec": payload["embedding_model_spec"], - "llm_model_spec": payload["llm_model_spec"], - "query_params": payload["query_params"], - "additional_params": payload["additional_params"], - }, - ) for file_id, meta in self.files_meta.items(): db_id = meta.get("database_id") diff --git a/backend/package/yuxi/knowledge/implementations/milvus.py b/backend/package/yuxi/knowledge/implementations/milvus.py index 024b4a33..b3486df1 100644 --- a/backend/package/yuxi/knowledge/implementations/milvus.py +++ b/backend/package/yuxi/knowledge/implementations/milvus.py @@ -633,7 +633,7 @@ class MilvusKB(KnowledgeBase): request_params=params, ) self.files_meta[file_id]["processing_params"] = params - await self._save_metadata() + await self._persist_file(file_id) logger.debug(f"[index_file] file_id={file_id}, processing_params={params}") # Add to processing queue @@ -1189,15 +1189,15 @@ class MilvusKB(KnowledgeBase): async def delete_file_chunks_only(self, db_id: str, file_id: str) -> None: """仅删除文件的chunks数据,保留元数据(用于更新操作)""" - graph_config = (self.databases_meta.get(db_id, {}).get("metadata") or {}).get("graph_build_config") - if graph_config: + chunk_repo = KnowledgeChunkRepository() + if await chunk_repo.count_graph_indexed_by_file_id(file_id): from yuxi.knowledge.graphs.milvus_graph_service import MilvusGraphService try: await MilvusGraphService().delete_file_graph(db_id, file_id) except Exception as e: logger.error(f"Failed to delete graph data for file {file_id}: {e}") - await KnowledgeChunkRepository().delete_by_file_id(file_id) + await chunk_repo.delete_by_file_id(file_id) collection = await self._get_milvus_collection(db_id) if collection: diff --git a/backend/package/yuxi/repositories/knowledge_chunk_repository.py b/backend/package/yuxi/repositories/knowledge_chunk_repository.py index e0d12d1d..4a828d34 100644 --- a/backend/package/yuxi/repositories/knowledge_chunk_repository.py +++ b/backend/package/yuxi/repositories/knowledge_chunk_repository.py @@ -97,6 +97,15 @@ class KnowledgeChunkRepository: async def count_graph_indexed_by_db_id(self, db_id: str) -> int: return await self._count_by_db_id(db_id, KnowledgeChunk.graph_indexed.is_(True)) + async def count_graph_indexed_by_file_id(self, file_id: str) -> int: + async with pg_manager.get_async_session_context() as session: + result = await session.execute( + select(func.count()) + .select_from(KnowledgeChunk) + .where(KnowledgeChunk.file_id == file_id, KnowledgeChunk.graph_indexed.is_(True)) + ) + return int(result.scalar() or 0) + async def count_graph_pending_by_db_id(self, db_id: str) -> int: return await self._count_by_db_id(db_id, KnowledgeChunk.graph_indexed.is_not(True))