diff --git a/astrbot/core/provider/sources/openai_source.py b/astrbot/core/provider/sources/openai_source.py index 64e3a6645a..3d22cbb7da 100644 --- a/astrbot/core/provider/sources/openai_source.py +++ b/astrbot/core/provider/sources/openai_source.py @@ -669,10 +669,14 @@ async def _query_stream( # Gemini and some OpenAI-compatible proxies omit this field if not hasattr(tc, "index") or tc.index is None: tc.index = idx - try: - state.handle_chunk(chunk) - except Exception as e: - logger.error("Saving chunk state error: " + str(e)) + # 跳过 delta=None 的 chunk,避免 SDK 内部 _convert_initial_chunk_into_snapshot + # 第 747 行 choice.delta.to_dict() 抛出 NoneType 错误。 + # refs: AstrBot#6689 / openai-python#5069 / #5047 + if delta is not None: + try: + state.handle_chunk(chunk) + except Exception as e: + logger.error("Saving chunk state error: " + str(e)) # logger.debug(f"chunk delta: {delta}") # handle the content delta reasoning = self._extract_reasoning_content(chunk) @@ -700,10 +704,14 @@ async def _query_stream( if _y: yield llm_response - final_completion = state.get_final_completion() - llm_response = await self._parse_openai_completion(final_completion, tools) - - yield llm_response + try: + final_completion = state.get_final_completion() + llm_response = await self._parse_openai_completion(final_completion, tools) + yield llm_response + except Exception as e: + logger.error("get_final_completion error: " + str(e)) + # 流式内容已通过 yield 发出,记录错误后正常结束即可 + return def _extract_reasoning_content( self, @@ -901,6 +909,9 @@ async def _parse_openai_completion( args = {} else: args = tool_call.function.arguments + # Some API may return None for tools with no parameters + if args is None: + args = {} args_ls.append(args) func_name_ls.append(tool_call.function.name) tool_call_ids.append(tool_call.id)