@@ -323,9 +323,9 @@ async def _yield_mcp_response(chat_model, message_list, mcp_servers, mcp_output_
323323 response = agent .astream ({"messages" : message_list }, config = {"recursion_limit" : recursion_limit },
324324 stream_mode = 'messages' )
325325
326- # 用于存储工具调用信息(按 tool_id)以及按 index 聚合分片
327- tool_calls_info = {}
328- _tool_fragments = {} # index -> {'id':..., 'name':..., 'arguments':...}
326+ # 用于存储工具调用信息
327+ tool_calls_info = {} # tool_id -> {'name': ..., 'input': ...}
328+ _tool_fragments = {} # index -> {'id': ..., 'name': ..., 'arguments': ...}
329329
330330 async for chunk in response :
331331 if isinstance (chunk [0 ], AIMessageChunk ):
@@ -334,21 +334,21 @@ async def _yield_mcp_response(chat_model, message_list, mcp_servers, mcp_output_
334334 idx = tool_call .get ('index' )
335335 if idx is None :
336336 continue
337+
337338 entry = _tool_fragments .setdefault (idx , {'id' : '' , 'name' : '' , 'arguments' : '' })
338339
339- # 更新 id 与 name(如果有)
340+ # 更新 id
340341 if tool_call .get ('id' ):
341342 entry ['id' ] = tool_call .get ('id' )
342343
344+ # 更新 name 和 arguments
343345 func = tool_call .get ('function' , {})
344- # arguments 可能在 function.arguments 或顶层 arguments
345- part_args = ''
346- if isinstance (func , dict ) and 'arguments' in func :
347- part_args = func .get ('arguments' ) or ''
346+ if isinstance (func , dict ):
348347 if func .get ('name' ):
349348 entry ['name' ] = func .get ('name' )
349+ part_args = func .get ('arguments' , '' )
350350 else :
351- part_args = tool_call .get ('arguments' , '' ) or ''
351+ part_args = tool_call .get ('arguments' , '' )
352352
353353 # 统一为字符串
354354 if not isinstance (part_args , str ):
@@ -359,27 +359,27 @@ async def _yield_mcp_response(chat_model, message_list, mcp_servers, mcp_output_
359359
360360 entry ['arguments' ] += part_args
361361
362- # 若 arguments 为空字符串,替换为 '{}'
363- if entry ['arguments' ] == '' :
364- entry ['arguments' ] = '{}'
365-
366- # 尝试判断 JSON 是否完整(若 arguments 是 JSON),完整则提交到 tool_calls_info
367- try :
368- json .loads (entry ['arguments' ])
369- if entry ['id' ]:
362+ # 尝试解析 JSON,判断是否完整
363+ if entry ['id' ] and entry ['arguments' ]:
364+ try :
365+ json .loads (entry ['arguments' ])
366+ # JSON 完整,保存到 tool_calls_info
370367 tool_calls_info [entry ['id' ]] = {
371- 'name' : entry . get ( 'name' , '' ) ,
368+ 'name' : entry [ 'name' ] ,
372369 'input' : entry ['arguments' ]
373370 }
374- _tool_fragments .pop (idx , None )
375- except Exception :
376- # 如果不是完整 JSON,继续等待后续片段
377- pass
371+ # 从 fragments 中移除
372+ del _tool_fragments [idx ]
373+ except (json .JSONDecodeError , ValueError ):
374+ # JSON 不完整,继续等待
375+ pass
378376
379377 yield chunk [0 ]
380378
381379 if mcp_output_enable and isinstance (chunk [0 ], ToolMessage ):
382- tool_id = _extract_tool_id (chunk [0 ].tool_call_id )
380+ # 直接使用 tool_call_id,不进行提取
381+ tool_id = chunk [0 ].tool_call_id
382+
383383 if tool_id in tool_calls_info :
384384 tool_info = tool_calls_info [tool_id ]
385385 content = generate_tool_message_complete (
@@ -388,10 +388,14 @@ async def _yield_mcp_response(chat_model, message_list, mcp_servers, mcp_output_
388388 chunk [0 ].content
389389 )
390390 chunk [0 ].content = content
391+ else :
392+ # 如果找不到对应的工具信息,记录日志
393+ maxkb_logger .warning (
394+ f"Tool ID { tool_id } not found in tool_calls_info. Available IDs: { list (tool_calls_info .keys ())} " )
395+
391396 yield chunk [0 ]
392397
393398 except ExceptionGroup as eg :
394-
395399 def get_real_error (exc ):
396400 if isinstance (exc , ExceptionGroup ):
397401 return get_real_error (exc .exceptions [0 ])
0 commit comments