From 6e77f5b0686124fb01069599918cb4bdd10664e6 Mon Sep 17 00:00:00 2001 From: lixinyue <2569494688@qq.com> Date: Tue, 20 Jan 2026 11:11:45 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E5=8F=8D=E6=80=9D=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/app/services/memory_reflection_service.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/api/app/services/memory_reflection_service.py b/api/app/services/memory_reflection_service.py index 08ef2bbe..46e42b46 100644 --- a/api/app/services/memory_reflection_service.py +++ b/api/app/services/memory_reflection_service.py @@ -239,8 +239,6 @@ class MemoryReflectionService: "reflection_results": reflection_results } - - except Exception as e: config_id = config_data.get("config_id", "unknown") api_logger.error(f"启动反思失败,config_id: {config_id}, end_user_id: {end_user_id}, 错误: {str(e)}") From a5ecbec9a63bc5f1e9f62884784aaf1be3874dfd Mon Sep 17 00:00:00 2001 From: lixinyue <2569494688@qq.com> Date: Tue, 20 Jan 2026 16:32:52 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E8=AF=BB=E5=8F=96=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=86=85=E5=B1=82=E5=B5=8C=E5=A5=97BUG=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../agent/langgraph_graph/routing/routers.py | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/api/app/core/memory/agent/langgraph_graph/routing/routers.py b/api/app/core/memory/agent/langgraph_graph/routing/routers.py index c0b01be1..004e03b3 100644 --- a/api/app/core/memory/agent/langgraph_graph/routing/routers.py +++ b/api/app/core/memory/agent/langgraph_graph/routing/routers.py @@ -45,18 +45,17 @@ def Retrieve_continue(state) -> Literal["Verify", "Retrieve_Summary"]: return 'Retrieve_Summary' # Default based on business logic def Verify_continue(state: ReadState) -> Literal["Summary", "Summary_fails", "content_input"]: status=state.get('verify', '')['status'] - loop_count = counter.get_total() - print(status) + # loop_count = counter.get_total() if "success" in status: - counter.reset() + # counter.reset() return "Summary" elif "failed" in status: - if loop_count < 2: # Maximum loop count is 3 - return "content_input" - else: - counter.reset() - return "Summary_fails" - # else: - # # Add default return value to avoid returning None - # counter.reset() - # return "Summary" # Default based on business requirements + # if loop_count < 2: # Maximum loop count is 3 + # return "content_input" + # else: + # counter.reset() + return "Summary_fails" + else: + # Add default return value to avoid returning None + # counter.reset() + return "Summary" # Default based on business requirements From a634565296d677fe5357ed0036d1ea9d34895e82 Mon Sep 17 00:00:00 2001 From: lixinyue <2569494688@qq.com> Date: Tue, 20 Jan 2026 18:46:53 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E8=AF=BB=E5=8F=96=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=86=85=E5=B1=82=E5=B5=8C=E5=A5=97BUG=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../langgraph_graph/nodes/problem_nodes.py | 17 +- .../langgraph_graph/nodes/summary_nodes.py | 3 +- .../agent/langgraph_graph/read_graph.py | 1 + .../agent/langgraph_graph/routing/routers.py | 3 + .../agent/services/optimized_llm_service.py | 29 +- .../core/memory/llm_tools/openai_client.py | 297 ++++++++++++++++-- 6 files changed, 311 insertions(+), 39 deletions(-) diff --git a/api/app/core/memory/agent/langgraph_graph/nodes/problem_nodes.py b/api/app/core/memory/agent/langgraph_graph/nodes/problem_nodes.py index 0c68a47e..e02ef62b 100644 --- a/api/app/core/memory/agent/langgraph_graph/nodes/problem_nodes.py +++ b/api/app/core/memory/agent/langgraph_graph/nodes/problem_nodes.py @@ -1,3 +1,4 @@ +import os import json import time from app.core.logging_config import get_agent_logger @@ -13,7 +14,7 @@ from app.core.memory.agent.utils.session_tools import SessionService from app.core.memory.agent.utils.template_tools import TemplateService from app.core.memory.agent.services.optimized_llm_service import LLMServiceMixin -template_root = PROJECT_ROOT_ + '/agent/utils/prompt' +template_root = os.path.join(PROJECT_ROOT_, 'agent', 'utils', 'prompt') db_session = next(get_db()) logger = get_agent_logger(__name__) @@ -35,11 +36,16 @@ async def Split_The_Problem(state: ReadState) -> ReadState: memory_config = state.get('memory_config', None) history = await SessionService(store).get_history(group_id, group_id, group_id) + + # 生成 JSON schema 以指导 LLM 输出正确格式 + json_schema = ProblemExtensionResponse.model_json_schema() + system_prompt = await problem_service.template_service.render_template( template_name='problem_breakdown_prompt.jinja2', operation_name='split_the_problem', history=history, - sentence=content + sentence=content, + json_schema=json_schema ) try: @@ -147,11 +153,16 @@ async def Problem_Extension(state: ReadState) -> ReadState: data = [] history = await SessionService(store).get_history(group_id, group_id, group_id) + + # 生成 JSON schema 以指导 LLM 输出正确格式 + json_schema = ProblemExtensionResponse.model_json_schema() + system_prompt = await problem_service.template_service.render_template( template_name='Problem_Extension_prompt.jinja2', operation_name='problem_extension', history=history, - questions=databasets + questions=databasets, + json_schema=json_schema ) try: diff --git a/api/app/core/memory/agent/langgraph_graph/nodes/summary_nodes.py b/api/app/core/memory/agent/langgraph_graph/nodes/summary_nodes.py index 7b727da5..0d0b57b0 100644 --- a/api/app/core/memory/agent/langgraph_graph/nodes/summary_nodes.py +++ b/api/app/core/memory/agent/langgraph_graph/nodes/summary_nodes.py @@ -1,5 +1,6 @@ +import os import time from app.core.logging_config import get_agent_logger, log_time @@ -19,7 +20,7 @@ from app.core.memory.agent.utils.session_tools import SessionService from app.core.memory.agent.utils.template_tools import TemplateService from app.core.memory.agent.services.optimized_llm_service import LLMServiceMixin -template_root = PROJECT_ROOT_ + '/agent/utils/prompt' +template_root = os.path.join(PROJECT_ROOT_, 'agent', 'utils', 'prompt') logger = get_agent_logger(__name__) db_session = next(get_db()) diff --git a/api/app/core/memory/agent/langgraph_graph/read_graph.py b/api/app/core/memory/agent/langgraph_graph/read_graph.py index 19011a5f..c01889a9 100644 --- a/api/app/core/memory/agent/langgraph_graph/read_graph.py +++ b/api/app/core/memory/agent/langgraph_graph/read_graph.py @@ -59,6 +59,7 @@ async def make_read_graph(): workflow.add_conditional_edges("Retrieve", Retrieve_continue) workflow.add_edge("Retrieve_Summary", END) workflow.add_conditional_edges("Verify", Verify_continue) + workflow.add_edge("Summary_fails", END) workflow.add_edge("Summary", END) diff --git a/api/app/core/memory/agent/langgraph_graph/routing/routers.py b/api/app/core/memory/agent/langgraph_graph/routing/routers.py index 004e03b3..151ce1c5 100644 --- a/api/app/core/memory/agent/langgraph_graph/routing/routers.py +++ b/api/app/core/memory/agent/langgraph_graph/routing/routers.py @@ -45,6 +45,9 @@ def Retrieve_continue(state) -> Literal["Verify", "Retrieve_Summary"]: return 'Retrieve_Summary' # Default based on business logic def Verify_continue(state: ReadState) -> Literal["Summary", "Summary_fails", "content_input"]: status=state.get('verify', '')['status'] + print(100*'-') + print(status) + print(100*'-') # loop_count = counter.get_total() if "success" in status: # counter.reset() diff --git a/api/app/core/memory/agent/services/optimized_llm_service.py b/api/app/core/memory/agent/services/optimized_llm_service.py index 6942d421..fce1cd76 100644 --- a/api/app/core/memory/agent/services/optimized_llm_service.py +++ b/api/app/core/memory/agent/services/optimized_llm_service.py @@ -162,22 +162,35 @@ class OptimizedLLMService: return fallback_value elif isinstance(fallback_value, dict): return response_model(**fallback_value) + elif isinstance(fallback_value, list): + # 对于 RootModel[List[...]] 类型,直接传入列表 + if hasattr(response_model, 'model_fields') and 'root' in response_model.model_fields: + return response_model(root=fallback_value) + # 或者尝试直接传入(Pydantic v2 的 RootModel 支持) + return response_model(fallback_value) # 尝试创建空的响应模型 - if hasattr(response_model, 'root'): - # RootModel类型 + # 检查是否是 RootModel 类型(通过检查 __pydantic_root_model__ 属性) + if hasattr(response_model, '__pydantic_root_model__') and response_model.__pydantic_root_model__: + # RootModel类型 - 传入空列表 + logger.debug(f"创建 RootModel 类型的空响应: {response_model.__name__}") return response_model([]) else: - # 普通BaseModel类型 + # 普通BaseModel类型 - 尝试无参数构造 + logger.debug(f"创建普通 BaseModel 类型的空响应: {response_model.__name__}") return response_model() except Exception as e: - logger.error(f"创建降级响应失败: {e}") + logger.error(f"创建降级响应失败: {e}", exc_info=True) # 最后的降级策略 - if hasattr(response_model, 'root'): - return response_model([]) - else: - return response_model() + try: + if hasattr(response_model, '__pydantic_root_model__') and response_model.__pydantic_root_model__: + return response_model([]) + else: + return response_model() + except Exception as final_error: + logger.error(f"最终降级策略也失败: {final_error}") + raise def clear_cache(self): """清理客户端缓存""" diff --git a/api/app/core/memory/llm_tools/openai_client.py b/api/app/core/memory/llm_tools/openai_client.py index dce7b495..93c0efd6 100644 --- a/api/app/core/memory/llm_tools/openai_client.py +++ b/api/app/core/memory/llm_tools/openai_client.py @@ -100,6 +100,41 @@ class OpenAIClient(LLMClient): logger.error(f"LLM 调用失败: {e}") raise LLMClientException(f"LLM 调用失败: {e}") from e + async def response(self, messages: List[Dict[str, str]], **kwargs) -> str: + """ + 简单响应接口实现(用于fallback机制) + + Args: + messages: 消息列表 + **kwargs: 额外参数 + + Returns: + LLM 响应文本 + + Raises: + LLMClientException: LLM 调用失败 + """ + try: + template = """{messages}""" + prompt = ChatPromptTemplate.from_template(template) + chain = prompt | self.client + + # 添加 Langfuse 回调(如果可用) + config = {} + if self.langfuse_handler: + config["callbacks"] = [self.langfuse_handler] + + response = await chain.ainvoke({"messages": messages}, config=config) + + # 提取文本内容 + if hasattr(response, "content"): + return str(response.content) + return str(response) + + except Exception as e: + logger.error(f"LLM 调用失败: {e}") + raise LLMClientException(f"LLM 调用失败: {e}") from e + async def response_structured( self, messages: List[Dict[str, str]], @@ -131,44 +166,206 @@ class OpenAIClient(LLMClient): if self.langfuse_handler: config["callbacks"] = [self.langfuse_handler] - # 方法 1: 使用 PydanticOutputParser + template = """{question}""" + prompt = ChatPromptTemplate.from_template(template) + + # 对于 DashScope 等不支持 with_structured_output 的模型,优先使用手动JSON解析 + # 这样可以避免不必要的尝试和错误 + if self.provider: #.lower() == "dashscope" + logger.info("DashScope 模型,直接使用手动JSON解析方法") + try: + # 获取原始响应,添加超时保护 + chain = prompt | self.client + response = await asyncio.wait_for( + chain.ainvoke({"question": question_text}, config=config), + timeout=self.timeout + ) + + # 提取响应文本 + response_text = "" + if hasattr(response, "content"): + response_text = str(response.content) + else: + response_text = str(response) + + logger.debug(f"LLM原始响应长度: {len(response_text)}") + + # 尝试提取JSON内容 + json_text = response_text.strip() + + # 如果响应包含markdown代码块,提取其中的JSON + if "```json" in json_text: + json_text = json_text.split("```json")[1].split("```")[0].strip() + elif "```" in json_text: + json_text = json_text.split("```")[1].split("```")[0].strip() + + # 尝试修复常见的JSON格式问题 + # 1. 移除可能的BOM标记 + json_text = json_text.lstrip('\ufeff') + + # 2. 如果JSON被截断(缺少结尾的 ] 或 }),尝试修复 + if json_text.startswith('[') and not json_text.rstrip().endswith(']'): + logger.warning("检测到JSON数组被截断,尝试修复") + # 找到最后一个完整的对象 + last_complete_brace = json_text.rfind('}') + if last_complete_brace > 0: + json_text = json_text[:last_complete_brace + 1] + ']' + logger.info(f"修复后的JSON长度: {len(json_text)}") + elif json_text.startswith('{') and not json_text.rstrip().endswith('}'): + logger.warning("检测到JSON对象被截断,尝试修复") + # 找到最后一个完整的字段 + last_complete_brace = json_text.rfind('}') + if last_complete_brace > 0: + json_text = json_text[:last_complete_brace + 1] + logger.info(f"修复后的JSON长度: {len(json_text)}") + + # 解析JSON + try: + parsed_dict = json.loads(json_text) + logger.debug(f"JSON解析成功,类型: {type(parsed_dict)}") + + # 如果是列表,记录第一个元素的结构 + if isinstance(parsed_dict, list) and len(parsed_dict) > 0: + logger.debug(f"第一个元素的键: {list(parsed_dict[0].keys()) if isinstance(parsed_dict[0], dict) else 'not a dict'}") + + # 尝试字段映射转换(处理LLM返回格式不匹配的情况) + if isinstance(parsed_dict, list): + transformed_list = [] + for item in parsed_dict: + if isinstance(item, dict): + transformed_item = {} + + # 常见的字段映射规则 + field_mappings = { + 'question': ['extended_question', 'question', 'query'], + 'original_question': ['original_question', 'original', 'source_question'], + 'extended_question': ['extended_question', 'question', 'query', 'extended'], + 'type': ['type', 'category', 'question_type'], + 'reason': ['reason', 'explanation', 'rationale'], + 'query': ['query', 'question', 'text'], + 'split_result': ['split_result', 'result', 'status'], + 'expansion_issue': ['expansion_issue', 'issues', 'expansions'], + } + + # 对于每个期望的字段,尝试从多个可能的源字段中获取 + for target_field, source_fields in field_mappings.items(): + for source_field in source_fields: + if source_field in item: + transformed_item[target_field] = item[source_field] + break + + # 特殊处理:如果只有 'question' 但缺少 'original_question' 和 'extended_question' + if 'question' in item and 'original_question' not in transformed_item: + transformed_item['original_question'] = item['question'] + if 'question' in item and 'extended_question' not in transformed_item: + transformed_item['extended_question'] = item['question'] + + # 保留原始字段(如果没有被映射) + for key, value in item.items(): + if key not in transformed_item: + transformed_item[key] = value + + transformed_list.append(transformed_item) + else: + transformed_list.append(item) + + logger.info(f"字段映射完成,尝试重新验证") + logger.debug(f"转换后的数据: {transformed_list}") + + try: + return response_model.model_validate(transformed_list) + except Exception as retry_error: + logger.error(f"字段映射后仍然验证失败: {retry_error}") + logger.error(f"完整的LLM响应: {response_text}") + logger.error(f"原始解析字典: {parsed_dict}") + logger.error(f"转换后的字典: {transformed_list}") + raise + else: + # 非列表类型,记录并抛出原始错误 + logger.error(f"完整的LLM响应: {response_text}") + logger.error(f"解析后的字典: {parsed_dict}") + raise + except json.JSONDecodeError as je: + logger.error(f"JSON解析失败: {je}") + logger.error(f"问题位置附近的文本: {json_text[max(0, je.pos-50):min(len(json_text), je.pos+50)]}") + + # 尝试更激进的修复:逐行解析,找到有效的JSON部分 + logger.info("尝试逐行解析JSON") + lines = json_text.split('\n') + for i in range(len(lines), 0, -1): + try: + partial_json = '\n'.join(lines[:i]) + if partial_json.startswith('['): + partial_json = partial_json.rstrip().rstrip(',') + ']' + elif partial_json.startswith('{'): + partial_json = partial_json.rstrip().rstrip(',') + '}' + + parsed_dict = json.loads(partial_json) + logger.info(f"成功解析部分JSON(前{i}行)") + return response_model.model_validate(parsed_dict) + except: + continue + + # 如果所有尝试都失败,抛出原始错误 + raise LLMClientException(f"JSON解析失败: {je}") from je + + except asyncio.TimeoutError: + logger.error(f"LLM调用超时({self.timeout}秒)") + raise LLMClientException(f"LLM调用超时({self.timeout}秒)") + except LLMClientException: + raise + except Exception as e: + logger.error(f"手动JSON解析失败: {e}", exc_info=True) + raise LLMClientException(f"手动JSON解析失败: {e}") from e + + + + + + # 方法 1: 使用 PydanticOutputParser(适用于支持的模型) if PydanticOutputParser is not None: try: parser = PydanticOutputParser(pydantic_object=response_model) format_instructions = parser.get_format_instructions() - prompt = ChatPromptTemplate.from_template( + prompt_with_instructions = ChatPromptTemplate.from_template( "{question}\n{format_instructions}" ) - chain = prompt | self.client | parser + chain = prompt_with_instructions | self.client | parser - parsed = await chain.ainvoke( - { - "question": question_text, - "format_instructions": format_instructions, - }, - config=config + parsed = await asyncio.wait_for( + chain.ainvoke( + { + "question": question_text, + "format_instructions": format_instructions, + }, + config=config + ), + timeout=self.timeout ) logger.debug(f"使用 PydanticOutputParser 解析成功") return parsed + except asyncio.TimeoutError: + logger.error(f"PydanticOutputParser 调用超时({self.timeout}秒)") + raise LLMClientException(f"LLM调用超时({self.timeout}秒)") except Exception as e: logger.warning( f"PydanticOutputParser 解析失败,尝试其他方法: {e}" ) - # 方法 2: 使用 LangChain 的 with_structured_output - template = """{question}""" - prompt = ChatPromptTemplate.from_template(template) - - try: - with_so = getattr(self.client, "with_structured_output", None) - - if callable(with_so): + # 方法 2: 使用 LangChain 的 with_structured_output (如果支持) + with_so = getattr(self.client, "with_structured_output", None) + + if callable(with_so): + try: structured_chain = prompt | with_so(response_model, strict=True) - parsed = await structured_chain.ainvoke( - {"question": question_text}, - config=config + parsed = await asyncio.wait_for( + structured_chain.ainvoke( + {"question": question_text}, + config=config + ), + timeout=self.timeout ) # 验证并返回结果 @@ -181,14 +378,60 @@ class OpenAIClient(LLMClient): # 尝试从 JSON 解析 return response_model.model_validate_json(json.dumps(parsed)) - except Exception as e: - logger.error(f"结构化输出失败: {e}") - raise LLMClientException(f"结构化输出失败: {e}") from e + except asyncio.TimeoutError: + logger.error(f"with_structured_output 调用超时({self.timeout}秒)") + raise LLMClientException(f"LLM调用超时({self.timeout}秒)") + except NotImplementedError: + logger.warning( + f"模型 {self.model_name} 不支持 with_structured_output,使用手动JSON解析" + ) + except Exception as e: + logger.warning(f"with_structured_output 失败: {e},尝试手动解析") - # 如果所有方法都失败,抛出异常 - raise LLMClientException( - "无法生成结构化输出,所有解析方法均失败" - ) + # 方法 3: 手动JSON解析(fallback方法) + logger.info("使用手动JSON解析方法(fallback)") + try: + # 获取原始响应 + chain = prompt | self.client + response = await asyncio.wait_for( + chain.ainvoke({"question": question_text}, config=config), + timeout=self.timeout + ) + + # 提取响应文本 + response_text = "" + if hasattr(response, "content"): + response_text = str(response.content) + else: + response_text = str(response) + + logger.debug(f"LLM原始响应: {response_text[:500]}...") + + # 尝试提取JSON内容 + json_text = response_text.strip() + + # 如果响应包含markdown代码块,提取其中的JSON + if "```json" in json_text: + json_text = json_text.split("```json")[1].split("```")[0].strip() + elif "```" in json_text: + json_text = json_text.split("```")[1].split("```")[0].strip() + + # 解析JSON + parsed_dict = json.loads(json_text) + logger.debug(f"JSON解析成功: {parsed_dict}") + + # 验证并创建Pydantic模型 + return response_model.model_validate(parsed_dict) + + except asyncio.TimeoutError: + logger.error(f"手动JSON解析调用超时({self.timeout}秒)") + raise LLMClientException(f"LLM调用超时({self.timeout}秒)") + except json.JSONDecodeError as je: + logger.error(f"JSON解析失败: {je}, 原始文本: {json_text[:200]}...") + raise LLMClientException(f"JSON解析失败: {je}") from je + except Exception as e: + logger.error(f"手动JSON解析失败: {e}") + raise LLMClientException(f"手动JSON解析失败: {e}") from e except LLMClientException: raise From 398964c747e108bab38430d3bcc72f3c5ba349cd Mon Sep 17 00:00:00 2001 From: lixinyue <2569494688@qq.com> Date: Tue, 20 Jan 2026 18:51:18 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E8=AF=BB=E5=8F=96=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=86=85=E5=B1=82=E5=B5=8C=E5=A5=97BUG=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nodes/verification_nodes.py | 120 +++++++++++++----- 1 file changed, 86 insertions(+), 34 deletions(-) diff --git a/api/app/core/memory/agent/langgraph_graph/nodes/verification_nodes.py b/api/app/core/memory/agent/langgraph_graph/nodes/verification_nodes.py index f3a39afb..fbfbe86d 100644 --- a/api/app/core/memory/agent/langgraph_graph/nodes/verification_nodes.py +++ b/api/app/core/memory/agent/langgraph_graph/nodes/verification_nodes.py @@ -1,4 +1,4 @@ - +import os from app.core.logging_config import get_agent_logger from app.db import get_db @@ -12,7 +12,7 @@ from app.core.memory.agent.utils.session_tools import SessionService from app.core.memory.agent.utils.template_tools import TemplateService from app.core.memory.agent.services.optimized_llm_service import LLMServiceMixin -template_root = PROJECT_ROOT_ + '/agent/utils/prompt' +template_root = os.path.join(PROJECT_ROOT_, 'agent', 'utils', 'prompt') db_session = next(get_db()) logger = get_agent_logger(__name__) @@ -48,38 +48,90 @@ async def Verify_prompt(state: ReadState,messages_deal): } return Verify_result async def Verify(state: ReadState): - content = state.get('data', '') - group_id = state.get('group_id', '') - memory_config = state.get('memory_config', None) + logger.info("=== Verify 节点开始执行 ===") + try: + content = state.get('data', '') + group_id = state.get('group_id', '') + memory_config = state.get('memory_config', None) + + logger.info(f"Verify: content={content[:50] if content else 'empty'}..., group_id={group_id}") - history = await SessionService(store).get_history(group_id, group_id, group_id) + history = await SessionService(store).get_history(group_id, group_id, group_id) + logger.info(f"Verify: 获取历史记录完成,history length={len(history)}") - retrieve = state.get("retrieve", '') - retrieve = retrieve.get("Expansion_issue", []) - messages = { - "Query": content, - "Expansion_issue": retrieve - } - - system_prompt = await verification_service.template_service.render_template( - template_name='split_verify_prompt.jinja2', - operation_name='split_verify_prompt', - history=history, - sentence=messages - ) - - # 使用优化的LLM服务 - structured = await verification_service.call_llm_structured( - state=state, - db_session=db_session, - system_prompt=system_prompt, - response_model=VerificationResult, - fallback_value={ - "split_result": "fail", - "expansion_issue": [], - "reason": "验证失败" + retrieve = state.get("retrieve", {}) + logger.info(f"Verify: retrieve data type={type(retrieve)}, keys={retrieve.keys() if isinstance(retrieve, dict) else 'N/A'}") + + retrieve_expansion = retrieve.get("Expansion_issue", []) if isinstance(retrieve, dict) else [] + logger.info(f"Verify: Expansion_issue length={len(retrieve_expansion)}") + + messages = { + "Query": content, + "Expansion_issue": retrieve_expansion } - ) - - result = await Verify_prompt(state, structured) - return {"verify": result} \ No newline at end of file + + logger.info("Verify: 开始渲染模板") + system_prompt = await verification_service.template_service.render_template( + template_name='split_verify_prompt.jinja2', + operation_name='split_verify_prompt', + history=history, + sentence=messages + ) + logger.info(f"Verify: 模板渲染完成,prompt length={len(system_prompt)}") + + # 使用优化的LLM服务,添加超时保护 + logger.info("Verify: 开始调用 LLM") + try: + # 添加 asyncio.wait_for 超时包裹,防止无限等待 + # 超时时间设置为 150 秒(比 LLM 配置的 120 秒稍长) + import asyncio + structured = await asyncio.wait_for( + verification_service.call_llm_structured( + state=state, + db_session=db_session, + system_prompt=system_prompt, + response_model=VerificationResult, + fallback_value={ + "query": content, # 添加必填的 query 字段 + "split_result": "fail", + "expansion_issue": [], + "reason": "验证失败" + } + ), + timeout=150.0 # 150秒超时 + ) + logger.info(f"Verify: LLM 调用完成,result={structured}") + except asyncio.TimeoutError: + logger.error("Verify: LLM 调用超时(150秒),使用 fallback 值") + structured = VerificationResult( + query=content, + split_result="fail", + expansion_issue=[], + reason="LLM调用超时" + ) + + result = await Verify_prompt(state, structured) + logger.info("=== Verify 节点执行完成 ===") + return {"verify": result} + + except Exception as e: + logger.error(f"Verify 节点执行失败: {e}", exc_info=True) + # 返回失败的验证结果 + return { + "verify": { + "status": "failed", + "verified_data": [], + "storage_type": state.get('storage_type', ''), + "user_rag_memory_id": state.get('user_rag_memory_id', ''), + "_intermediate": { + "type": "verification", + "title": "Data Verification", + "result": "failed", + "reason": f"验证过程出错: {str(e)}", + "query": state.get('data', ''), + "verified_count": 0, + "storage_type": state.get('storage_type', ''), + "user_rag_memory_id": state.get('user_rag_memory_id', '') + } + } + } \ No newline at end of file From 78559d98eb1ea8a41628956f90360f24a0b7f65b Mon Sep 17 00:00:00 2001 From: lixinyue <2569494688@qq.com> Date: Tue, 20 Jan 2026 19:11:40 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E8=AF=BB=E5=8F=96=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=86=85=E5=B1=82=E5=B5=8C=E5=A5=97BUG=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nodes/verification_nodes.py | 38 ++- .../agent/models/verification_models.py | 28 +- .../agent/services/optimized_llm_service.py | 33 +- .../utils/prompt/split_verify_prompt.jinja2 | 44 ++- .../core/memory/llm_tools/openai_client.py | 297 ++---------------- 5 files changed, 117 insertions(+), 323 deletions(-) diff --git a/api/app/core/memory/agent/langgraph_graph/nodes/verification_nodes.py b/api/app/core/memory/agent/langgraph_graph/nodes/verification_nodes.py index fbfbe86d..dac7ea14 100644 --- a/api/app/core/memory/agent/langgraph_graph/nodes/verification_nodes.py +++ b/api/app/core/memory/agent/langgraph_graph/nodes/verification_nodes.py @@ -26,22 +26,33 @@ class VerificationNodeService(LLMServiceMixin): # 创建全局服务实例 verification_service = VerificationNodeService() -async def Verify_prompt(state: ReadState,messages_deal): +async def Verify_prompt(state: ReadState, messages_deal: VerificationResult): + """处理验证结果并生成输出格式""" storage_type = state.get('storage_type', '') user_rag_memory_id = state.get('user_rag_memory_id', '') data = state.get('data', '') + + # 将 VerificationItem 对象转换为字典列表 + verified_data = [] + if messages_deal.expansion_issue: + for item in messages_deal.expansion_issue: + if hasattr(item, 'model_dump'): + verified_data.append(item.model_dump()) + elif isinstance(item, dict): + verified_data.append(item) + Verify_result = { "status": messages_deal.split_result, - "verified_data": messages_deal.expansion_issue, + "verified_data": verified_data, "storage_type": storage_type, "user_rag_memory_id": user_rag_memory_id, "_intermediate": { "type": "verification", "title": "Data Verification", "result": messages_deal.split_result, - "reason": messages_deal.reason, - "query": data, - "verified_count": len(messages_deal.expansion_issue), + "reason": messages_deal.reason or "验证完成", + "query": messages_deal.query, + "verified_count": len(verified_data), "storage_type": storage_type, "user_rag_memory_id": user_rag_memory_id } @@ -71,11 +82,16 @@ async def Verify(state: ReadState): } logger.info("Verify: 开始渲染模板") + + # 生成 JSON schema 以指导 LLM 输出正确格式 + json_schema = VerificationResult.model_json_schema() + system_prompt = await verification_service.template_service.render_template( template_name='split_verify_prompt.jinja2', operation_name='split_verify_prompt', history=history, - sentence=messages + sentence=messages, + json_schema=json_schema ) logger.info(f"Verify: 模板渲染完成,prompt length={len(system_prompt)}") @@ -92,10 +108,11 @@ async def Verify(state: ReadState): system_prompt=system_prompt, response_model=VerificationResult, fallback_value={ - "query": content, # 添加必填的 query 字段 - "split_result": "fail", + "query": content, + "history": history if isinstance(history, list) else [], "expansion_issue": [], - "reason": "验证失败" + "split_result": "failed", + "reason": "验证失败或超时" } ), timeout=150.0 # 150秒超时 @@ -105,8 +122,9 @@ async def Verify(state: ReadState): logger.error("Verify: LLM 调用超时(150秒),使用 fallback 值") structured = VerificationResult( query=content, - split_result="fail", + history=history if isinstance(history, list) else [], expansion_issue=[], + split_result="failed", reason="LLM调用超时" ) diff --git a/api/app/core/memory/agent/models/verification_models.py b/api/app/core/memory/agent/models/verification_models.py index bd8896b3..abdce040 100644 --- a/api/app/core/memory/agent/models/verification_models.py +++ b/api/app/core/memory/agent/models/verification_models.py @@ -4,11 +4,29 @@ from typing import List, Optional, Dict, Any from pydantic import BaseModel, Field +class VerificationItem(BaseModel): + """Individual verification item for a query-answer pair.""" + + query_small: str = Field(..., description="子问题") + answer_small: str = Field(..., description="子问题的回答") + status: str = Field(..., description="验证状态:True 或 False") + query_answer: str = Field(..., description="问题的答案(与 answer_small 相同)") + + class VerificationResult(BaseModel): """Result model for verification operation.""" - query: str - expansion_issue: List[Dict[str, Any]] - split_result: str - reason: Optional[str] = None - history: List[Dict[str, Any]] = Field(default_factory=list) + query: str = Field(..., description="原始查询问题") + history: List[Dict[str, Any]] = Field(default_factory=list, description="历史对话记录") + expansion_issue: List[VerificationItem] = Field( + default_factory=list, + description="验证后的数据列表,包含所有通过验证的问答对" + ) + split_result: str = Field( + ..., + description="验证结果状态:success(expansion_issue 非空)或 failed(expansion_issue 为空)" + ) + reason: Optional[str] = Field( + None, + description="验证结果的说明和分析" + ) diff --git a/api/app/core/memory/agent/services/optimized_llm_service.py b/api/app/core/memory/agent/services/optimized_llm_service.py index fce1cd76..68919c4a 100644 --- a/api/app/core/memory/agent/services/optimized_llm_service.py +++ b/api/app/core/memory/agent/services/optimized_llm_service.py @@ -162,35 +162,22 @@ class OptimizedLLMService: return fallback_value elif isinstance(fallback_value, dict): return response_model(**fallback_value) - elif isinstance(fallback_value, list): - # 对于 RootModel[List[...]] 类型,直接传入列表 - if hasattr(response_model, 'model_fields') and 'root' in response_model.model_fields: - return response_model(root=fallback_value) - # 或者尝试直接传入(Pydantic v2 的 RootModel 支持) - return response_model(fallback_value) - + # 尝试创建空的响应模型 - # 检查是否是 RootModel 类型(通过检查 __pydantic_root_model__ 属性) - if hasattr(response_model, '__pydantic_root_model__') and response_model.__pydantic_root_model__: - # RootModel类型 - 传入空列表 - logger.debug(f"创建 RootModel 类型的空响应: {response_model.__name__}") + if hasattr(response_model, 'root'): + # RootModel类型 return response_model([]) else: - # 普通BaseModel类型 - 尝试无参数构造 - logger.debug(f"创建普通 BaseModel 类型的空响应: {response_model.__name__}") + # 普通BaseModel类型 return response_model() - + except Exception as e: - logger.error(f"创建降级响应失败: {e}", exc_info=True) + logger.error(f"创建降级响应失败: {e}") # 最后的降级策略 - try: - if hasattr(response_model, '__pydantic_root_model__') and response_model.__pydantic_root_model__: - return response_model([]) - else: - return response_model() - except Exception as final_error: - logger.error(f"最终降级策略也失败: {final_error}") - raise + if hasattr(response_model, 'root'): + return response_model([]) + else: + return response_model() def clear_cache(self): """清理客户端缓存""" diff --git a/api/app/core/memory/agent/utils/prompt/split_verify_prompt.jinja2 b/api/app/core/memory/agent/utils/prompt/split_verify_prompt.jinja2 index d6ad8cab..5d10304a 100644 --- a/api/app/core/memory/agent/utils/prompt/split_verify_prompt.jinja2 +++ b/api/app/core/memory/agent/utils/prompt/split_verify_prompt.jinja2 @@ -42,19 +42,33 @@ 如果状态是TRUE保留这条数据,否则需不需要这条数据 ### 第五步 输出格式 按照json的形式输出 -{"data":"Query":原来Query的字段,"history":原来的history字段, -"expansion_issue":以为列表的形式存储验证之后的数据比如[ -{"query_small": query_small, - "answer_small": answer_small,, - "status": 回答的结果是否符合query_small,填写状态, - "query_answer": answer_small}, +{"query":"原来Query的字段", +"history":"原来的history字段", +"expansion_issue":以列表的形式存储验证之后的数据比如[ { - "query_small": "张曼婷生日是什么时候?", - "answer_small": "张曼婷喜欢绘画。", - "status": "True", - "query_answer": "张曼 婷喜欢绘画。" - },{}......] -, - "split_result":如果expansion_issue是空的列表返回failed,不是空列表返回success, - "reason": 为以上分析完之后的结果给一个说明 - } \ No newline at end of file + "query_small": "子问题", + "answer_small": "子问题的回答", + "status": "True或False,表示回答是否符合query_small", + "query_answer": "问题的答案(与answer_small相同)" +}, +{ + "query_small": "张曼婷生日是什么时候?", + "answer_small": "张曼婷喜欢绘画。", + "status": "False", + "query_answer": "张曼婷喜欢绘画。" +} +], +"split_result":"如果expansion_issue是空的列表返回failed,不是空列表返回success", +"reason": "为以上分析完之后的结果给一个说明" +} + +**输出格式要求** +**CRITICAL JSON FORMATTING REQUIREMENTS:** +1. Use only standard ASCII double quotes (") for JSON structure - never use Chinese quotation marks ("") or other Unicode quotes +2. If the extracted statement text contains quotation marks, escape them properly using backslashes (\") +3. Ensure all JSON strings are properly closed and comma-separated +4. Do not include line breaks within JSON string values +5. The output language should always be the same as the input language + +**JSON Schema:** +{{ json_schema }} \ No newline at end of file diff --git a/api/app/core/memory/llm_tools/openai_client.py b/api/app/core/memory/llm_tools/openai_client.py index 93c0efd6..dce7b495 100644 --- a/api/app/core/memory/llm_tools/openai_client.py +++ b/api/app/core/memory/llm_tools/openai_client.py @@ -100,41 +100,6 @@ class OpenAIClient(LLMClient): logger.error(f"LLM 调用失败: {e}") raise LLMClientException(f"LLM 调用失败: {e}") from e - async def response(self, messages: List[Dict[str, str]], **kwargs) -> str: - """ - 简单响应接口实现(用于fallback机制) - - Args: - messages: 消息列表 - **kwargs: 额外参数 - - Returns: - LLM 响应文本 - - Raises: - LLMClientException: LLM 调用失败 - """ - try: - template = """{messages}""" - prompt = ChatPromptTemplate.from_template(template) - chain = prompt | self.client - - # 添加 Langfuse 回调(如果可用) - config = {} - if self.langfuse_handler: - config["callbacks"] = [self.langfuse_handler] - - response = await chain.ainvoke({"messages": messages}, config=config) - - # 提取文本内容 - if hasattr(response, "content"): - return str(response.content) - return str(response) - - except Exception as e: - logger.error(f"LLM 调用失败: {e}") - raise LLMClientException(f"LLM 调用失败: {e}") from e - async def response_structured( self, messages: List[Dict[str, str]], @@ -166,206 +131,44 @@ class OpenAIClient(LLMClient): if self.langfuse_handler: config["callbacks"] = [self.langfuse_handler] - template = """{question}""" - prompt = ChatPromptTemplate.from_template(template) - - # 对于 DashScope 等不支持 with_structured_output 的模型,优先使用手动JSON解析 - # 这样可以避免不必要的尝试和错误 - if self.provider: #.lower() == "dashscope" - logger.info("DashScope 模型,直接使用手动JSON解析方法") - try: - # 获取原始响应,添加超时保护 - chain = prompt | self.client - response = await asyncio.wait_for( - chain.ainvoke({"question": question_text}, config=config), - timeout=self.timeout - ) - - # 提取响应文本 - response_text = "" - if hasattr(response, "content"): - response_text = str(response.content) - else: - response_text = str(response) - - logger.debug(f"LLM原始响应长度: {len(response_text)}") - - # 尝试提取JSON内容 - json_text = response_text.strip() - - # 如果响应包含markdown代码块,提取其中的JSON - if "```json" in json_text: - json_text = json_text.split("```json")[1].split("```")[0].strip() - elif "```" in json_text: - json_text = json_text.split("```")[1].split("```")[0].strip() - - # 尝试修复常见的JSON格式问题 - # 1. 移除可能的BOM标记 - json_text = json_text.lstrip('\ufeff') - - # 2. 如果JSON被截断(缺少结尾的 ] 或 }),尝试修复 - if json_text.startswith('[') and not json_text.rstrip().endswith(']'): - logger.warning("检测到JSON数组被截断,尝试修复") - # 找到最后一个完整的对象 - last_complete_brace = json_text.rfind('}') - if last_complete_brace > 0: - json_text = json_text[:last_complete_brace + 1] + ']' - logger.info(f"修复后的JSON长度: {len(json_text)}") - elif json_text.startswith('{') and not json_text.rstrip().endswith('}'): - logger.warning("检测到JSON对象被截断,尝试修复") - # 找到最后一个完整的字段 - last_complete_brace = json_text.rfind('}') - if last_complete_brace > 0: - json_text = json_text[:last_complete_brace + 1] - logger.info(f"修复后的JSON长度: {len(json_text)}") - - # 解析JSON - try: - parsed_dict = json.loads(json_text) - logger.debug(f"JSON解析成功,类型: {type(parsed_dict)}") - - # 如果是列表,记录第一个元素的结构 - if isinstance(parsed_dict, list) and len(parsed_dict) > 0: - logger.debug(f"第一个元素的键: {list(parsed_dict[0].keys()) if isinstance(parsed_dict[0], dict) else 'not a dict'}") - - # 尝试字段映射转换(处理LLM返回格式不匹配的情况) - if isinstance(parsed_dict, list): - transformed_list = [] - for item in parsed_dict: - if isinstance(item, dict): - transformed_item = {} - - # 常见的字段映射规则 - field_mappings = { - 'question': ['extended_question', 'question', 'query'], - 'original_question': ['original_question', 'original', 'source_question'], - 'extended_question': ['extended_question', 'question', 'query', 'extended'], - 'type': ['type', 'category', 'question_type'], - 'reason': ['reason', 'explanation', 'rationale'], - 'query': ['query', 'question', 'text'], - 'split_result': ['split_result', 'result', 'status'], - 'expansion_issue': ['expansion_issue', 'issues', 'expansions'], - } - - # 对于每个期望的字段,尝试从多个可能的源字段中获取 - for target_field, source_fields in field_mappings.items(): - for source_field in source_fields: - if source_field in item: - transformed_item[target_field] = item[source_field] - break - - # 特殊处理:如果只有 'question' 但缺少 'original_question' 和 'extended_question' - if 'question' in item and 'original_question' not in transformed_item: - transformed_item['original_question'] = item['question'] - if 'question' in item and 'extended_question' not in transformed_item: - transformed_item['extended_question'] = item['question'] - - # 保留原始字段(如果没有被映射) - for key, value in item.items(): - if key not in transformed_item: - transformed_item[key] = value - - transformed_list.append(transformed_item) - else: - transformed_list.append(item) - - logger.info(f"字段映射完成,尝试重新验证") - logger.debug(f"转换后的数据: {transformed_list}") - - try: - return response_model.model_validate(transformed_list) - except Exception as retry_error: - logger.error(f"字段映射后仍然验证失败: {retry_error}") - logger.error(f"完整的LLM响应: {response_text}") - logger.error(f"原始解析字典: {parsed_dict}") - logger.error(f"转换后的字典: {transformed_list}") - raise - else: - # 非列表类型,记录并抛出原始错误 - logger.error(f"完整的LLM响应: {response_text}") - logger.error(f"解析后的字典: {parsed_dict}") - raise - except json.JSONDecodeError as je: - logger.error(f"JSON解析失败: {je}") - logger.error(f"问题位置附近的文本: {json_text[max(0, je.pos-50):min(len(json_text), je.pos+50)]}") - - # 尝试更激进的修复:逐行解析,找到有效的JSON部分 - logger.info("尝试逐行解析JSON") - lines = json_text.split('\n') - for i in range(len(lines), 0, -1): - try: - partial_json = '\n'.join(lines[:i]) - if partial_json.startswith('['): - partial_json = partial_json.rstrip().rstrip(',') + ']' - elif partial_json.startswith('{'): - partial_json = partial_json.rstrip().rstrip(',') + '}' - - parsed_dict = json.loads(partial_json) - logger.info(f"成功解析部分JSON(前{i}行)") - return response_model.model_validate(parsed_dict) - except: - continue - - # 如果所有尝试都失败,抛出原始错误 - raise LLMClientException(f"JSON解析失败: {je}") from je - - except asyncio.TimeoutError: - logger.error(f"LLM调用超时({self.timeout}秒)") - raise LLMClientException(f"LLM调用超时({self.timeout}秒)") - except LLMClientException: - raise - except Exception as e: - logger.error(f"手动JSON解析失败: {e}", exc_info=True) - raise LLMClientException(f"手动JSON解析失败: {e}") from e - - - - - - # 方法 1: 使用 PydanticOutputParser(适用于支持的模型) + # 方法 1: 使用 PydanticOutputParser if PydanticOutputParser is not None: try: parser = PydanticOutputParser(pydantic_object=response_model) format_instructions = parser.get_format_instructions() - prompt_with_instructions = ChatPromptTemplate.from_template( + prompt = ChatPromptTemplate.from_template( "{question}\n{format_instructions}" ) - chain = prompt_with_instructions | self.client | parser + chain = prompt | self.client | parser - parsed = await asyncio.wait_for( - chain.ainvoke( - { - "question": question_text, - "format_instructions": format_instructions, - }, - config=config - ), - timeout=self.timeout + parsed = await chain.ainvoke( + { + "question": question_text, + "format_instructions": format_instructions, + }, + config=config ) logger.debug(f"使用 PydanticOutputParser 解析成功") return parsed - except asyncio.TimeoutError: - logger.error(f"PydanticOutputParser 调用超时({self.timeout}秒)") - raise LLMClientException(f"LLM调用超时({self.timeout}秒)") except Exception as e: logger.warning( f"PydanticOutputParser 解析失败,尝试其他方法: {e}" ) - # 方法 2: 使用 LangChain 的 with_structured_output (如果支持) - with_so = getattr(self.client, "with_structured_output", None) - - if callable(with_so): - try: + # 方法 2: 使用 LangChain 的 with_structured_output + template = """{question}""" + prompt = ChatPromptTemplate.from_template(template) + + try: + with_so = getattr(self.client, "with_structured_output", None) + + if callable(with_so): structured_chain = prompt | with_so(response_model, strict=True) - parsed = await asyncio.wait_for( - structured_chain.ainvoke( - {"question": question_text}, - config=config - ), - timeout=self.timeout + parsed = await structured_chain.ainvoke( + {"question": question_text}, + config=config ) # 验证并返回结果 @@ -378,60 +181,14 @@ class OpenAIClient(LLMClient): # 尝试从 JSON 解析 return response_model.model_validate_json(json.dumps(parsed)) - except asyncio.TimeoutError: - logger.error(f"with_structured_output 调用超时({self.timeout}秒)") - raise LLMClientException(f"LLM调用超时({self.timeout}秒)") - except NotImplementedError: - logger.warning( - f"模型 {self.model_name} 不支持 with_structured_output,使用手动JSON解析" - ) - except Exception as e: - logger.warning(f"with_structured_output 失败: {e},尝试手动解析") - - # 方法 3: 手动JSON解析(fallback方法) - logger.info("使用手动JSON解析方法(fallback)") - try: - # 获取原始响应 - chain = prompt | self.client - response = await asyncio.wait_for( - chain.ainvoke({"question": question_text}, config=config), - timeout=self.timeout - ) - - # 提取响应文本 - response_text = "" - if hasattr(response, "content"): - response_text = str(response.content) - else: - response_text = str(response) - - logger.debug(f"LLM原始响应: {response_text[:500]}...") - - # 尝试提取JSON内容 - json_text = response_text.strip() - - # 如果响应包含markdown代码块,提取其中的JSON - if "```json" in json_text: - json_text = json_text.split("```json")[1].split("```")[0].strip() - elif "```" in json_text: - json_text = json_text.split("```")[1].split("```")[0].strip() - - # 解析JSON - parsed_dict = json.loads(json_text) - logger.debug(f"JSON解析成功: {parsed_dict}") - - # 验证并创建Pydantic模型 - return response_model.model_validate(parsed_dict) - - except asyncio.TimeoutError: - logger.error(f"手动JSON解析调用超时({self.timeout}秒)") - raise LLMClientException(f"LLM调用超时({self.timeout}秒)") - except json.JSONDecodeError as je: - logger.error(f"JSON解析失败: {je}, 原始文本: {json_text[:200]}...") - raise LLMClientException(f"JSON解析失败: {je}") from je except Exception as e: - logger.error(f"手动JSON解析失败: {e}") - raise LLMClientException(f"手动JSON解析失败: {e}") from e + logger.error(f"结构化输出失败: {e}") + raise LLMClientException(f"结构化输出失败: {e}") from e + + # 如果所有方法都失败,抛出异常 + raise LLMClientException( + "无法生成结构化输出,所有解析方法均失败" + ) except LLMClientException: raise From 575190a96d8855503a31d6b576606e9a29fdc4c5 Mon Sep 17 00:00:00 2001 From: lixinyue <2569494688@qq.com> Date: Tue, 20 Jan 2026 19:14:32 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E8=AF=BB=E5=8F=96=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=86=85=E5=B1=82=E5=B5=8C=E5=A5=97BUG=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/app/core/memory/agent/langgraph_graph/routing/routers.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/api/app/core/memory/agent/langgraph_graph/routing/routers.py b/api/app/core/memory/agent/langgraph_graph/routing/routers.py index 151ce1c5..004e03b3 100644 --- a/api/app/core/memory/agent/langgraph_graph/routing/routers.py +++ b/api/app/core/memory/agent/langgraph_graph/routing/routers.py @@ -45,9 +45,6 @@ def Retrieve_continue(state) -> Literal["Verify", "Retrieve_Summary"]: return 'Retrieve_Summary' # Default based on business logic def Verify_continue(state: ReadState) -> Literal["Summary", "Summary_fails", "content_input"]: status=state.get('verify', '')['status'] - print(100*'-') - print(status) - print(100*'-') # loop_count = counter.get_total() if "success" in status: # counter.reset()