feat: 优化LLM服务的错误处理和模型配置逻辑
- 增强LLMService中的base_url和模型名称处理,确保兼容SiliconFlow格式 - 改进错误处理,详细记录异常信息并提供可能的原因 - 更新WorkflowEngine以使用LLMService的详细错误信息,避免重复信息
This commit is contained in:
parent
6724b38c18
commit
db8cc75ff5
Binary file not shown.
Binary file not shown.
|
|
@ -22,12 +22,34 @@ class LLMService:
|
||||||
max_tokens: Optional[int] = None
|
max_tokens: Optional[int] = None
|
||||||
) -> str:
|
) -> str:
|
||||||
"""调用大模型进行对话完成"""
|
"""调用大模型进行对话完成"""
|
||||||
|
# 处理 base_url:如果包含 /chat/completions,需要移除
|
||||||
|
base_url = model_config.base_url
|
||||||
|
if base_url and '/chat/completions' in base_url:
|
||||||
|
# 移除 /chat/completions 后缀,ChatOpenAI 会自动添加
|
||||||
|
base_url = base_url.replace('/chat/completions', '').rstrip('/')
|
||||||
|
logger.debug(f"调整 base_url: {model_config.base_url} -> {base_url}")
|
||||||
|
|
||||||
|
# 处理 SiliconFlow 的模型名称格式
|
||||||
|
model_name = model_config.model_name
|
||||||
|
if 'siliconflow' in (base_url or '').lower() and '/' not in model_name:
|
||||||
|
# SiliconFlow 需要 org/model 格式,尝试自动转换
|
||||||
|
model_name_lower = model_name.lower()
|
||||||
|
if 'deepseek' in model_name_lower or 'r1' in model_name_lower:
|
||||||
|
# 尝试常见的 DeepSeek 模型格式
|
||||||
|
if 'r1' in model_name_lower:
|
||||||
|
model_name = 'deepseek-ai/DeepSeek-R1'
|
||||||
|
elif 'v3' in model_name_lower:
|
||||||
|
model_name = 'deepseek-ai/DeepSeek-V3'
|
||||||
|
else:
|
||||||
|
model_name = f'deepseek-ai/{model_name}'
|
||||||
|
logger.debug(f"调整 SiliconFlow 模型名称: {model_config.model_name} -> {model_name}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 创建LangChain ChatOpenAI实例
|
# 创建LangChain ChatOpenAI实例
|
||||||
llm = ChatOpenAI(
|
llm = ChatOpenAI(
|
||||||
model=model_config.model_name,
|
model=model_name,
|
||||||
api_key=model_config.api_key,
|
api_key=model_config.api_key,
|
||||||
base_url=model_config.base_url,
|
base_url=base_url,
|
||||||
temperature=temperature or model_config.temperature,
|
temperature=temperature or model_config.temperature,
|
||||||
max_tokens=max_tokens or model_config.max_tokens,
|
max_tokens=max_tokens or model_config.max_tokens,
|
||||||
streaming=False
|
streaming=False
|
||||||
|
|
@ -53,8 +75,41 @@ class LLMService:
|
||||||
return response.content
|
return response.content
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"LLM调用失败: {str(e)}")
|
# 提取详细的错误信息
|
||||||
raise Exception(f"LLM调用失败: {str(e)}")
|
error_detail = str(e)
|
||||||
|
|
||||||
|
# 尝试从异常对象中提取更多信息
|
||||||
|
if hasattr(e, 'response'):
|
||||||
|
# HTTP 响应错误
|
||||||
|
if hasattr(e.response, 'status_code'):
|
||||||
|
error_detail = f"HTTP {e.response.status_code}: {error_detail}"
|
||||||
|
if hasattr(e.response, 'text'):
|
||||||
|
try:
|
||||||
|
import json
|
||||||
|
error_body = json.loads(e.response.text)
|
||||||
|
if isinstance(error_body, dict):
|
||||||
|
if 'message' in error_body:
|
||||||
|
error_detail = f"{error_detail} - {error_body['message']}"
|
||||||
|
if 'error' in error_body:
|
||||||
|
error_info = error_body['error']
|
||||||
|
if isinstance(error_info, dict) and 'message' in error_info:
|
||||||
|
error_detail = f"{error_detail} - {error_info['message']}"
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 添加模型配置信息到错误消息中(使用处理后的配置)
|
||||||
|
model_info = f"模型: {model_name}, base_url: {base_url}"
|
||||||
|
if 'Not Found' in error_detail or '404' in error_detail:
|
||||||
|
error_detail = f"{error_detail} ({model_info})。可能的原因:1) 模型名称格式不正确(SiliconFlow需要org/model格式,如deepseek-ai/DeepSeek-R1);2) base_url配置错误;3) API端点不存在"
|
||||||
|
elif '403' in error_detail or 'account balance' in error_detail.lower() or 'insufficient' in error_detail.lower():
|
||||||
|
error_detail = f"{error_detail} ({model_info})。可能的原因:账户余额不足或API密钥权限不足"
|
||||||
|
elif '401' in error_detail or 'authentication' in error_detail.lower():
|
||||||
|
error_detail = f"{error_detail} ({model_info})。可能的原因:API密钥无效或已过期"
|
||||||
|
else:
|
||||||
|
error_detail = f"{error_detail} ({model_info})"
|
||||||
|
|
||||||
|
logger.error(f"LLM调用失败: {error_detail}")
|
||||||
|
raise Exception(f"LLM调用失败: {error_detail}")
|
||||||
|
|
||||||
async def chat_completion_stream(
|
async def chat_completion_stream(
|
||||||
self,
|
self,
|
||||||
|
|
|
||||||
|
|
@ -831,7 +831,23 @@ class WorkflowEngine:
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_msg = str(e)
|
error_msg = str(e)
|
||||||
logger.error(f"LLM调用失败: {error_msg}")
|
# LLMService 已经添加了详细的错误信息(包括处理后的模型名称和base_url),直接使用
|
||||||
|
# 如果错误信息中已经包含了模型信息,就不再重复添加
|
||||||
|
detailed_error = error_msg
|
||||||
|
|
||||||
|
# 如果错误信息中还没有包含模型配置信息,则添加(使用原始配置作为补充)
|
||||||
|
if "使用的模型:" not in error_msg and "模型:" not in error_msg:
|
||||||
|
model_info = f"使用的模型: {llm_config.model_name} (ID: {llm_config.id}), base_url: {llm_config.base_url}"
|
||||||
|
if "Not Found" in error_msg or "404" in error_msg:
|
||||||
|
detailed_error = f"{detailed_error}。{model_info}。可能的原因:1) 模型名称格式不正确(SiliconFlow需要org/model格式);2) base_url配置错误;3) API端点不存在"
|
||||||
|
elif "403" in error_msg or "account balance" in error_msg.lower() or "insufficient" in error_msg.lower():
|
||||||
|
detailed_error = f"{detailed_error}。{model_info}。可能的原因:账户余额不足或API密钥权限不足"
|
||||||
|
elif "401" in error_msg or "authentication" in error_msg.lower():
|
||||||
|
detailed_error = f"{detailed_error}。{model_info}。可能的原因:API密钥无效或已过期"
|
||||||
|
else:
|
||||||
|
detailed_error = f"{detailed_error}。{model_info}"
|
||||||
|
|
||||||
|
logger.error(f"LLM调用失败: {detailed_error}")
|
||||||
|
|
||||||
# 如果当前使用的不是默认模型,并且错误包含 Not Found / 404,则尝试回退到默认模型再调用一次
|
# 如果当前使用的不是默认模型,并且错误包含 Not Found / 404,则尝试回退到默认模型再调用一次
|
||||||
if (not used_default_model) and ("Not Found" in error_msg or "404" in error_msg):
|
if (not used_default_model) and ("Not Found" in error_msg or "404" in error_msg):
|
||||||
|
|
@ -863,7 +879,7 @@ class WorkflowEngine:
|
||||||
logger.error(f"使用默认模型重试LLM调用失败: {str(fallback_error)}")
|
logger.error(f"使用默认模型重试LLM调用失败: {str(fallback_error)}")
|
||||||
# 继续向下抛出原始错误
|
# 继续向下抛出原始错误
|
||||||
|
|
||||||
raise ValueError(f"LLM调用失败: {error_msg}")
|
raise ValueError(f"LLM调用失败: {detailed_error}")
|
||||||
|
|
||||||
def _substitute_variables(self, template: str, input_data: Dict[str, Any]) -> str:
|
def _substitute_variables(self, template: str, input_data: Dict[str, Any]) -> str:
|
||||||
"""变量替换函数"""
|
"""变量替换函数"""
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue