diff --git a/astrbot/core/provider/sources/anthropic_source.py b/astrbot/core/provider/sources/anthropic_source.py index 203d0610ff..ca4eabb627 100644 --- a/astrbot/core/provider/sources/anthropic_source.py +++ b/astrbot/core/provider/sources/anthropic_source.py @@ -418,19 +418,40 @@ async def _query_stream( if event.index in tool_use_buffer: # 解析完整的工具调用 tool_info = tool_use_buffer[event.index] + parsed_ok = False + try: if "input_json" in tool_info: tool_info["input"] = json.loads(tool_info["input_json"]) - - # 添加到最终结果 - final_tool_calls.append( - { - "id": tool_info["id"], - "name": tool_info["name"], - "input": tool_info["input"], - }, + else: + tool_info["input"] = {} + parsed_ok = True + + except json.JSONDecodeError as e: + raw_json = tool_info.get("input_json", "") + logger.warning( + f"工具调用参数 JSON 解析失败: {e}。" + f"len={len(raw_json)}; head={raw_json[:120]!r}; tail={raw_json[-120:]!r}" ) - + # Fallback:尝试补全可能截断的尾部 + for suffix in ["}", "]", '"}', '"]']: + if raw_json and not raw_json.rstrip().endswith(suffix): + try: + tool_info["input"] = json.loads(raw_json + suffix) + parsed_ok = True + logger.info( + f"工具调用参数 JSON 解析成功 (fallback,修复后缀 '{suffix}')" + ) + break + except json.JSONDecodeError: + pass + + if parsed_ok: + final_tool_calls.append({ + "id": tool_info["id"], + "name": tool_info["name"], + "input": tool_info["input"], + }) yield LLMResponse( role="tool", completion_text="", @@ -441,12 +462,12 @@ async def _query_stream( usage=usage, id=id, ) - except json.JSONDecodeError: - # JSON 解析失败,跳过这个工具调用 - logger.warning(f"工具调用参数 JSON 解析失败: {tool_info}") + else: + logger.warning( + f"工具调用参数 JSON 解析最终失败,跳过工具调用: {tool_info['name']}" + ) - # 清理缓冲区 - del tool_use_buffer[event.index] + tool_use_buffer.pop(event.index, None) elif event.type == "message_delta": if event.usage: