diff --git a/backend/app/services/graph_builder.py b/backend/app/services/graph_builder.py index 37c9969c..982ad3c1 100644 --- a/backend/app/services/graph_builder.py +++ b/backend/app/services/graph_builder.py @@ -18,6 +18,7 @@ from ..models.task import TaskManager, TaskStatus from ..utils.zep_paging import fetch_all_nodes, fetch_all_edges from .text_processor import TextProcessor from ..utils.locale import t, get_locale, set_locale +from ..utils.zep_retry import with_zep_retry @dataclass @@ -190,6 +191,7 @@ class GraphBuilderService: error_msg = f"{str(e)}\n{traceback.format_exc()}" self.task_manager.fail_task(task_id, error_msg) + @with_zep_retry(max_retries=3, operation_name="create_graph") def create_graph(self, name: str) -> str: """创建Zep图谱(公开方法)""" graph_id = f"mirofish_{uuid.uuid4().hex[:16]}" @@ -285,11 +287,14 @@ class GraphBuilderService: # 调用Zep API设置本体 if entity_types or edge_definitions: - self.client.graph.set_ontology( - graph_ids=[graph_id], - entities=entity_types if entity_types else None, - edges=edge_definitions if edge_definitions else None, - ) + @with_zep_retry(max_retries=3, operation_name="set_ontology") + def _set_ontology(): + self.client.graph.set_ontology( + graph_ids=[graph_id], + entities=entity_types if entity_types else None, + edges=edge_definitions if edge_definitions else None, + ) + _set_ontology() def add_text_batches( self, @@ -322,10 +327,14 @@ class GraphBuilderService: # 发送到Zep try: - batch_result = self.client.graph.add_batch( - graph_id=graph_id, - episodes=episodes - ) + @with_zep_retry(max_retries=3, operation_name=f"add_batch {batch_num}/{total_batches}") + def _add_batch(): + return self.client.graph.add_batch( + graph_id=graph_id, + episodes=episodes + ) + + batch_result = _add_batch() # 收集返回的 episode uuid if batch_result and isinstance(batch_result, list): @@ -376,7 +385,11 @@ class GraphBuilderService: # 检查每个 episode 的处理状态 for ep_uuid in list(pending_episodes): try: - episode = self.client.graph.episode.get(uuid_=ep_uuid) + @with_zep_retry(max_retries=2, initial_delay=1.0, operation_name="get_episode") + def _get_episode(): + return self.client.graph.episode.get(uuid_=ep_uuid) + + episode = _get_episode() is_processed = getattr(episode, 'processed', False) if is_processed: @@ -500,6 +513,7 @@ class GraphBuilderService: "edge_count": len(edges_data), } + @with_zep_retry(max_retries=3, operation_name="delete_graph") def delete_graph(self, graph_id: str): """删除图谱""" self.client.graph.delete(graph_id=graph_id) diff --git a/backend/app/services/oasis_profile_generator.py b/backend/app/services/oasis_profile_generator.py index 7704a627..e7625431 100644 --- a/backend/app/services/oasis_profile_generator.py +++ b/backend/app/services/oasis_profile_generator.py @@ -21,6 +21,7 @@ from zep_cloud.client import Zep from ..config import Config from ..utils.logger import get_logger from ..utils.locale import get_language_instruction, get_locale, set_locale, t +from ..utils.zep_retry import with_zep_retry from .zep_entity_reader import EntityNode, ZepEntityReader logger = get_logger('mirofish.oasis_profile') @@ -316,55 +317,27 @@ class OasisProfileGenerator: comprehensive_query = t('progress.zepSearchQuery', name=entity_name) + @with_zep_retry(max_retries=3, initial_delay=2.0, operation_name="Zep Edge Search") def search_edges(): """搜索边(事实/关系)- 带重试机制""" - max_retries = 3 - last_exception = None - delay = 2.0 - - for attempt in range(max_retries): - try: - return self.zep_client.graph.search( - query=comprehensive_query, - graph_id=self.graph_id, - limit=30, - scope="edges", - reranker="rrf" - ) - except Exception as e: - last_exception = e - if attempt < max_retries - 1: - logger.debug(f"Zep边搜索第 {attempt + 1} 次失败: {str(e)[:80]}, 重试中...") - time.sleep(delay) - delay *= 2 - else: - logger.debug(f"Zep边搜索在 {max_retries} 次尝试后仍失败: {e}") - return None + return self.zep_client.graph.search( + query=comprehensive_query, + graph_id=self.graph_id, + limit=30, + scope="edges", + reranker="rrf" + ) + @with_zep_retry(max_retries=3, initial_delay=2.0, operation_name="Zep Node Search") def search_nodes(): """搜索节点(实体摘要)- 带重试机制""" - max_retries = 3 - last_exception = None - delay = 2.0 - - for attempt in range(max_retries): - try: - return self.zep_client.graph.search( - query=comprehensive_query, - graph_id=self.graph_id, - limit=20, - scope="nodes", - reranker="rrf" - ) - except Exception as e: - last_exception = e - if attempt < max_retries - 1: - logger.debug(f"Zep节点搜索第 {attempt + 1} 次失败: {str(e)[:80]}, 重试中...") - time.sleep(delay) - delay *= 2 - else: - logger.debug(f"Zep节点搜索在 {max_retries} 次尝试后仍失败: {e}") - return None + return self.zep_client.graph.search( + query=comprehensive_query, + graph_id=self.graph_id, + limit=20, + scope="nodes", + reranker="rrf" + ) try: # 并行执行edges和nodes搜索 diff --git a/backend/app/services/ontology_generator.py b/backend/app/services/ontology_generator.py index 01a3d799..be1fefd2 100644 --- a/backend/app/services/ontology_generator.py +++ b/backend/app/services/ontology_generator.py @@ -225,8 +225,9 @@ class OntologyGenerator: return result - # 传给 LLM 的文本最大长度(5万字) - MAX_TEXT_LENGTH_FOR_LLM = 50000 + # 传给 LLM 的文本最大长度(2万字) + # 本体分析只需识别实体/关系类型,不需要完整文本;完整文本仍用于后续图谱构建 + MAX_TEXT_LENGTH_FOR_LLM = 20000 def _build_user_message( self,