@@ -519,9 +519,6 @@ class LLMService:
"""
第二阶段调用:使用包含工具调用和结果的完整消息历史
注意: SiliconFlow 等平台不支持标准 tool 消息类型,
需要将工具结果转换为普通用户消息格式。
Args:
messages: 已包含assistant tool_calls和tool结果的完整消息历史
provider_config: LLM Provider配置
@@ -536,43 +533,8 @@ class LLMService:
max_tokens = provider_config . get ( ' max_tokens ' , 4096 )
temperature = agent_config . get ( ' temperature_override ' ) or provider_config . get ( ' temperature ' , 0.7 )
# 转换消息格式:将 tool 相关消息转为普通消息格式
# 因为很多 API 平台(如 SiliconFlow) 不支持 tool 消息类型
converted_messages = [ ]
tool_results_content = [ ]
for msg in messages :
role = msg . get ( ' role ' )
if role == ' system ' :
converted_messages . append ( msg )
elif role == ' user ' :
converted_messages . append ( msg )
elif role == ' assistant ' :
# 如果有 tool_calls, 跳过这个消息( 不发送给不支持的平台)
if msg . get ( ' tool_calls ' ) :
# 记录工具调用信息(可选)
pass
else :
converted_messages . append ( msg )
elif role == ' tool ' :
# 收集工具结果,后面合并成一个用户消息
tool_results_content . append ( msg . get ( ' content ' , ' ' ) )
# 如果有工具结果,添加为一个特殊的用户消息
if tool_results_content :
combined_results = " \n \n " . join ( [
f " 【搜索结果 { i + 1 } 】 \n { result } "
for i , result in enumerate ( tool_results_content )
] )
# 添加工具结果作为用户消息
converted_messages . append ( {
" role " : " user " ,
" content " : f " 以下是搜索工具返回的结果: \n \n { combined_results } \n \n 请根据以上搜索结果回答我之前的问题,不要再说 \" 让我搜索一下 \" ,直接给出回答。如果搜索结果不足以回答,请说明。 "
} )
final_messages = converted_messages
# 消息历史已经包含了assistant的tool_calls和tool结果, 直接使用
final_messages = messages . copy ( )
# 调用LLM生成最终回复
url = f " { api_base . rstrip ( ' / ' ) } /chat/completions "
@@ -588,16 +550,6 @@ class LLMService:
}
logger . info ( f " 工具结果返回LLM: url= { url } , model= { model } , 消息数= { len ( final_messages ) } " )
# 打印消息内容(调试)
for i , msg in enumerate ( final_messages ) :
role = msg . get ( ' role ' )
content_preview = str ( msg . get ( ' content ' , ' ' ) ) [ : 100 ] if msg . get ( ' content ' ) else ' None '
if role == ' tool ' :
logger . info ( f " 消息[ { i } ] role= { role } , tool_call_id= { msg . get ( ' tool_call_id ' ) } , content长度= { len ( msg . get ( ' content ' , ' ' ) ) } " )
elif role == ' assistant ' and msg . get ( ' tool_calls ' ) :
logger . info ( f " 消息[ { i } ] role= { role } , tool_calls= { len ( msg [ ' tool_calls ' ] ) } " )
else :
logger . info ( f " 消息[ { i } ] role= { role } , content= { content_preview } ... " )
try :
async with httpx . AsyncClient ( timeout = 60.0 ) as client :
@@ -610,27 +562,6 @@ class LLMService:
data = response . json ( )
content = data [ ' choices ' ] [ 0 ] [ ' message ' ] [ ' content ' ]
# 过滤掉伪工具调用格式( 某些模型如Kimi会输出这种内部格式)
# 模式:<|tool_calls_section_begin|>...<|tool_calls_section_end|>
import re
tool_pattern = r ' < \ |tool_calls_section_begin \ |>.*?< \ |tool_calls_section_end \ |> '
content = re . sub ( tool_pattern , ' ' , content , flags = re . DOTALL )
# 也过滤单个 tool_call 格式
tool_call_pattern = r ' < \ |tool_call_begin \ |>.*?< \ |tool_call_end \ |> '
content = re . sub ( tool_call_pattern , ' ' , content , flags = re . DOTALL )
# 清理可能残留的格式标记
content = content . replace ( ' <|tool_calls_section_begin|> ' , ' ' )
content = content . replace ( ' <|tool_calls_section_end|> ' , ' ' )
content = content . replace ( ' <|tool_call_begin|> ' , ' ' )
content = content . replace ( ' <|tool_call_end|> ' , ' ' )
content = content . replace ( ' <|tool_call_argument_begin|> ' , ' ' )
content = content . replace ( ' <|tool_call_argument_end|> ' , ' ' )
# 清理多余空行
content = re . sub ( r ' \ n { 3,} ' , ' \n \n ' , content ) . strip ( )
return content , None
except Exception as e :