软错误不计入总错误数

This commit is contained in:
xunbu
2025-09-04 16:55:46 +08:00
parent 9c05661496
commit c964eb0da6
3 changed files with 30 additions and 18 deletions

View File

@@ -23,8 +23,15 @@ MAX_REQUESTS_PER_ERROR = 15
ThinkingMode = Literal["enable", "disable", "default"] ThinkingMode = Literal["enable", "disable", "default"]
class PartialTranslationError(ValueError): class AgentResultError(ValueError):
"""一个特殊的异常,用于表示结果不完整但包含了部分成功的数据,以便触发重试。""" """一个特殊的异常,用于表示结果由AI正常返回但返回的结果有问题。该错误不计入总错误数"""
def __init__(self, message):
super().__init__(message)
class PartialAgentResultError(ValueError):
"""一个特殊的异常,用于表示结果不完整但包含了部分成功的数据,以便触发重试。该错误不计入总错误数"""
def __init__(self, message, partial_result: dict): def __init__(self, message, partial_result: dict):
super().__init__(message) super().__init__(message)
@@ -177,9 +184,12 @@ class Agent:
# print(f"result:=============================================================\n{result}\n================\n") # print(f"result:=============================================================\n{result}\n================\n")
return result if result_handler is None else result_handler(result, prompt, self.logger) return result if result_handler is None else result_handler(result, prompt, self.logger)
except AgentResultError as e:
self.logger.error(f"AI返回结果有误: {e}")
should_retry = True
# 专门捕获部分翻译错误(软错误) # 专门捕获部分翻译错误(软错误)
except PartialTranslationError as e: except PartialAgentResultError as e:
self.logger.error(f"收到部分翻译结果,将尝试重试: {e}") self.logger.error(f"收到部分返回结果,将尝试重试: {e}")
current_partial_result = e.partial_result current_partial_result = e.partial_result
should_retry = True should_retry = True
# is_hard_error 保持 False # is_hard_error 保持 False
@@ -285,7 +295,7 @@ class Agent:
headers, data = self._prepare_request_data(prompt, system_prompt) headers, data = self._prepare_request_data(prompt, system_prompt)
should_retry = False should_retry = False
is_hard_error = False # 新增标志,用于区分是否为硬错误 is_hard_error = False # 新增标志,用于区分是否为硬错误
current_partial_result = None current_partial_result = None
try: try:
@@ -302,9 +312,11 @@ class Agent:
self.logger.info(f"重试成功 (第 {retry_count + 1}/{MAX_RETRY_COUNT + 1} 次尝试)。") self.logger.info(f"重试成功 (第 {retry_count + 1}/{MAX_RETRY_COUNT + 1} 次尝试)。")
return result if result_handler is None else result_handler(result, prompt, self.logger) return result if result_handler is None else result_handler(result, prompt, self.logger)
except AgentResultError as e:
self.logger.error(f"AI返回结果有误: {e}")
should_retry = True
# 专门捕获部分翻译错误(软错误) # 专门捕获部分翻译错误(软错误)
except PartialTranslationError as e: except PartialAgentResultError as e:
self.logger.error(f"收到部分翻译结果,将尝试重试: {e}") self.logger.error(f"收到部分翻译结果,将尝试重试: {e}")
current_partial_result = e.partial_result current_partial_result = e.partial_result
should_retry = True should_retry = True

View File

@@ -10,6 +10,7 @@ from logging import Logger
import json_repair import json_repair
from docutranslate.agents import AgentConfig, Agent from docutranslate.agents import AgentConfig, Agent
from docutranslate.agents.agent import AgentResultError
from docutranslate.utils.json_utils import segments2json_chunks from docutranslate.utils.json_utils import segments2json_chunks
@@ -52,16 +53,16 @@ The output format should be plain JSON text in a list format
if result == "": if result == "":
if origin_prompt.strip()!="": if origin_prompt.strip()!="":
logger.error("result为空值但原文不为空") logger.error("result为空值但原文不为空")
raise ValueError("result为空值但原文不为空") raise AgentResultError("result为空值但原文不为空")
return [] return []
try: try:
repaired_result = json_repair.loads(result) repaired_result = json_repair.loads(result)
if not isinstance(repaired_result, list): if not isinstance(repaired_result, list):
raise ValueError(f"GlossaryAgent返回结果不是list的json形式, result: {result}") raise AgentResultError(f"GlossaryAgent返回结果不是list的json形式, result: {result}")
return repaired_result return repaired_result
except (RuntimeError, JSONDecodeError) as e: except (RuntimeError, JSONDecodeError) as e:
# 将解析错误包装成 ValueError 以便被 send 方法捕获并重试 # 将解析错误包装成 ValueError 以便被 send 方法捕获并重试
raise ValueError(f"结果不能正确解析: {e.__repr__()}") raise AgentResultError(f"结果不能正确解析: {e.__repr__()}")
def _error_result_handler(self, origin_prompt: str, logger: Logger): def _error_result_handler(self, origin_prompt: str, logger: Logger):
if origin_prompt == "": if origin_prompt == "":

View File

@@ -10,7 +10,7 @@ from logging import Logger
from json_repair import json_repair from json_repair import json_repair
from docutranslate.agents import AgentConfig, Agent from docutranslate.agents import AgentConfig, Agent
from docutranslate.agents.agent import PartialTranslationError from docutranslate.agents.agent import PartialAgentResultError, AgentResultError
from docutranslate.glossary.glossary import Glossary from docutranslate.glossary.glossary import Glossary
from docutranslate.utils.json_utils import segments2json_chunks from docutranslate.utils.json_utils import segments2json_chunks
@@ -70,18 +70,17 @@ class SegmentsTranslateAgent(Agent):
""" """
if result == "": if result == "":
if origin_prompt.strip() != "": if origin_prompt.strip() != "":
logger.error("result为空值但原文不为空") raise AgentResultError("result为空值但原文不为空")
raise ValueError("result为空值但原文不为空")
return {} return {}
try: try:
original_chunk = json.loads(origin_prompt) original_chunk = json.loads(origin_prompt)
repaired_result = json_repair.loads(result) repaired_result = json_repair.loads(result)
if not isinstance(repaired_result, dict): if not isinstance(repaired_result, dict):
raise ValueError(f"Agent返回结果不是dict的json形式, result: {result}") raise AgentResultError(f"Agent返回结果不是dict的json形式, result: {result}")
if repaired_result == original_chunk: if repaired_result == original_chunk:
raise ValueError("翻译结果与原文完全相同,判定为翻译失败,将进行重试。") raise AgentResultError("翻译结果与原文完全相同,疑似翻译失败,将进行重试。")
original_keys = set(original_chunk.keys()) original_keys = set(original_chunk.keys())
result_keys = set(repaired_result.keys()) result_keys = set(repaired_result.keys())
@@ -104,7 +103,7 @@ class SegmentsTranslateAgent(Agent):
final_chunk[key] = str(original_chunk[key]) final_chunk[key] = str(original_chunk[key])
# 抛出自定义异常,将部分结果和错误信息一起传递出去 # 抛出自定义异常,将部分结果和错误信息一起传递出去
raise PartialTranslationError("键不匹配,触发重试", partial_result=final_chunk) raise PartialAgentResultError("键不匹配,触发重试", partial_result=final_chunk)
# 如果键完全匹配(理想情况),正常返回 # 如果键完全匹配(理想情况),正常返回
for key, value in repaired_result.items(): for key, value in repaired_result.items():
@@ -114,7 +113,7 @@ class SegmentsTranslateAgent(Agent):
except (RuntimeError, JSONDecodeError) as e: except (RuntimeError, JSONDecodeError) as e:
# 对于JSON解析等硬性错误继续抛出普通ValueError # 对于JSON解析等硬性错误继续抛出普通ValueError
raise ValueError(f"结果处理失败: {e.__repr__()}") raise AgentResultError(f"结果处理失败: {e.__repr__()}")
def _error_result_handler(self, origin_prompt: str, logger: Logger): def _error_result_handler(self, origin_prompt: str, logger: Logger):
""" """