From 2a4dbdb69b26388741e740b6e5099e2a8070d11a Mon Sep 17 00:00:00 2001 From: Sakura-RanChen <1908198662@qq.com> Date: Wed, 22 Apr 2026 11:24:43 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=A2=91=E7=B9=81?= =?UTF-8?q?=E6=89=93=E6=96=AD=E4=B8=8B=E7=94=9F=E6=88=90=E5=99=A8=E4=B8=8D?= =?UTF-8?q?=E4=BC=9A=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../llm/homeassistant/homeassistant.py | 11 +- .../core/providers/llm/ollama/ollama.py | 156 +++++++++--------- .../core/providers/llm/openai/openai.py | 62 +++---- .../providers/llm/xinference/xinference.py | 19 ++- 4 files changed, 131 insertions(+), 117 deletions(-) diff --git a/main/xiaozhi-server/core/providers/llm/homeassistant/homeassistant.py b/main/xiaozhi-server/core/providers/llm/homeassistant/homeassistant.py index d875d0d0..1fe8a0d2 100644 --- a/main/xiaozhi-server/core/providers/llm/homeassistant/homeassistant.py +++ b/main/xiaozhi-server/core/providers/llm/homeassistant/homeassistant.py @@ -39,13 +39,12 @@ class LLMProvider(LLMProviderBase): } # 发起 POST 请求 - response = requests.post(self.api_url, json=payload, headers=headers) + with requests.post(self.api_url, json=payload, headers=headers) as response: + # 检查请求是否成功 + response.raise_for_status() - # 检查请求是否成功 - response.raise_for_status() - - # 解析返回数据 - data = response.json() + # 解析返回数据 + data = response.json() speech = ( data.get("response", {}) .get("speech", {}) diff --git a/main/xiaozhi-server/core/providers/llm/ollama/ollama.py b/main/xiaozhi-server/core/providers/llm/ollama/ollama.py index c62a432d..ba7ceef8 100644 --- a/main/xiaozhi-server/core/providers/llm/ollama/ollama.py +++ b/main/xiaozhi-server/core/providers/llm/ollama/ollama.py @@ -50,43 +50,46 @@ class LLMProvider(LLMProviderBase): # 用于处理跨chunk的标签 buffer = "" - for chunk in responses: - try: - delta = ( - chunk.choices[0].delta - if getattr(chunk, "choices", None) - else None - ) - content = delta.content if hasattr(delta, "content") else "" + try: + for chunk in responses: + try: + delta = ( + chunk.choices[0].delta + if getattr(chunk, "choices", None) + else None + ) + content = delta.content if hasattr(delta, "content") else "" - if content: - # 将内容添加到缓冲区 - buffer += content + if content: + # 将内容添加到缓冲区 + buffer += content - # 处理缓冲区中的标签 - while "" in buffer and "" in buffer: - # 找到完整的标签并移除 - pre = buffer.split("", 1)[0] - post = buffer.split("", 1)[1] - buffer = pre + post + # 处理缓冲区中的标签 + while "" in buffer and "" in buffer: + # 找到完整的标签并移除 + pre = buffer.split("", 1)[0] + post = buffer.split("", 1)[1] + buffer = pre + post - # 处理只有开始标签的情况 - if "" in buffer: - is_active = False - buffer = buffer.split("", 1)[0] + # 处理只有开始标签的情况 + if "" in buffer: + is_active = False + buffer = buffer.split("", 1)[0] - # 处理只有结束标签的情况 - if "" in buffer: - is_active = True - buffer = buffer.split("", 1)[1] + # 处理只有结束标签的情况 + if "" in buffer: + is_active = True + buffer = buffer.split("", 1)[1] - # 如果当前处于活动状态且缓冲区有内容,则输出 - if is_active and buffer: - yield buffer - buffer = "" # 清空缓冲区 + # 如果当前处于活动状态且缓冲区有内容,则输出 + if is_active and buffer: + yield buffer + buffer = "" # 清空缓冲区 - except Exception as e: - logger.bind(tag=TAG).error(f"Error processing chunk: {e}") + except Exception as e: + logger.bind(tag=TAG).error(f"Error processing chunk: {e}") + finally: + responses.close() def response_with_functions(self, session_id, dialogue, functions=None): # 如果是qwen3模型,在用户最后一条消息中添加/no_think指令 @@ -117,49 +120,52 @@ class LLMProvider(LLMProviderBase): is_active = True buffer = "" - for chunk in stream: - try: - delta = ( - chunk.choices[0].delta - if getattr(chunk, "choices", None) - else None - ) - content = delta.content if hasattr(delta, "content") else None - tool_calls = ( - delta.tool_calls if hasattr(delta, "tool_calls") else None - ) + try: + for chunk in stream: + try: + delta = ( + chunk.choices[0].delta + if getattr(chunk, "choices", None) + else None + ) + content = delta.content if hasattr(delta, "content") else None + tool_calls = ( + delta.tool_calls if hasattr(delta, "tool_calls") else None + ) - # 如果是工具调用,直接传递 - if tool_calls: - yield None, tool_calls + # 如果是工具调用,直接传递 + if tool_calls: + yield None, tool_calls + continue + + # 处理文本内容 + if content: + # 将内容添加到缓冲区 + buffer += content + + # 处理缓冲区中的标签 + while "" in buffer and "" in buffer: + # 找到完整的标签并移除 + pre = buffer.split("", 1)[0] + post = buffer.split("", 1)[1] + buffer = pre + post + + # 处理只有开始标签的情况 + if "" in buffer: + is_active = False + buffer = buffer.split("", 1)[0] + + # 处理只有结束标签的情况 + if "" in buffer: + is_active = True + buffer = buffer.split("", 1)[1] + + # 如果当前处于活动状态且缓冲区有内容,则输出 + if is_active and buffer: + yield buffer, None + buffer = "" # 清空缓冲区 + except Exception as e: + logger.bind(tag=TAG).error(f"Error processing function chunk: {e}") continue - - # 处理文本内容 - if content: - # 将内容添加到缓冲区 - buffer += content - - # 处理缓冲区中的标签 - while "" in buffer and "" in buffer: - # 找到完整的标签并移除 - pre = buffer.split("", 1)[0] - post = buffer.split("", 1)[1] - buffer = pre + post - - # 处理只有开始标签的情况 - if "" in buffer: - is_active = False - buffer = buffer.split("", 1)[0] - - # 处理只有结束标签的情况 - if "" in buffer: - is_active = True - buffer = buffer.split("", 1)[1] - - # 如果当前处于活动状态且缓冲区有内容,则输出 - if is_active and buffer: - yield buffer, None - buffer = "" # 清空缓冲区 - except Exception as e: - logger.bind(tag=TAG).error(f"Error processing function chunk: {e}") - continue + finally: + stream.close() diff --git a/main/xiaozhi-server/core/providers/llm/openai/openai.py b/main/xiaozhi-server/core/providers/llm/openai/openai.py index ba0498e5..ed0b5e97 100644 --- a/main/xiaozhi-server/core/providers/llm/openai/openai.py +++ b/main/xiaozhi-server/core/providers/llm/openai/openai.py @@ -115,21 +115,24 @@ class LLMProvider(LLMProviderBase): responses = self.client.chat.completions.create(**request_params) is_active = True - for chunk in responses: - try: - delta = chunk.choices[0].delta if getattr(chunk, "choices", None) else None - content = getattr(delta, "content", "") if delta else "" - except IndexError: - content = "" - if content: - if "" in content: - is_active = False - content = content.split("")[0] - if "" in content: - is_active = True - content = content.split("")[-1] - if is_active: - yield content + try: + for chunk in responses: + try: + delta = chunk.choices[0].delta if getattr(chunk, "choices", None) else None + content = getattr(delta, "content", "") if delta else "" + except IndexError: + content = "" + if content: + if "" in content: + is_active = False + content = content.split("")[0] + if "" in content: + is_active = True + content = content.split("")[-1] + if is_active: + yield content + finally: + responses.close() def response_with_functions(self, session_id, dialogue, functions=None, **kwargs): dialogue = self.normalize_dialogue(dialogue) @@ -157,16 +160,19 @@ class LLMProvider(LLMProviderBase): stream = self.client.chat.completions.create(**request_params) - for chunk in stream: - if getattr(chunk, "choices", None): - delta = chunk.choices[0].delta - content = getattr(delta, "content", "") - tool_calls = getattr(delta, "tool_calls", None) - yield content, tool_calls - elif isinstance(getattr(chunk, "usage", None), CompletionUsage): - usage_info = getattr(chunk, "usage", None) - logger.bind(tag=TAG).info( - f"Token 消耗:输入 {getattr(usage_info, 'prompt_tokens', '未知')}," - f"输出 {getattr(usage_info, 'completion_tokens', '未知')}," - f"共计 {getattr(usage_info, 'total_tokens', '未知')}" - ) + try: + for chunk in stream: + if getattr(chunk, "choices", None): + delta = chunk.choices[0].delta + content = getattr(delta, "content", "") + tool_calls = getattr(delta, "tool_calls", None) + yield content, tool_calls + elif isinstance(getattr(chunk, "usage", None), CompletionUsage): + usage_info = getattr(chunk, "usage", None) + logger.bind(tag=TAG).info( + f"Token 消耗:输入 {getattr(usage_info, 'prompt_tokens', '未知')}," + f"输出 {getattr(usage_info, 'completion_tokens', '未知')}," + f"共计 {getattr(usage_info, 'total_tokens', '未知')}" + ) + finally: + stream.close() diff --git a/main/xiaozhi-server/core/providers/llm/xinference/xinference.py b/main/xiaozhi-server/core/providers/llm/xinference/xinference.py index f6f71455..b44ce023 100644 --- a/main/xiaozhi-server/core/providers/llm/xinference/xinference.py +++ b/main/xiaozhi-server/core/providers/llm/xinference/xinference.py @@ -74,12 +74,15 @@ class LLMProvider(LLMProviderBase): tools=functions, ) - for chunk in stream: - delta = chunk.choices[0].delta - content = delta.content - tool_calls = delta.tool_calls + try: + for chunk in stream: + delta = chunk.choices[0].delta + content = delta.content + tool_calls = delta.tool_calls - if content: - yield content, tool_calls - elif tool_calls: - yield None, tool_calls + if content: + yield content, tool_calls + elif tool_calls: + yield None, tool_calls + finally: + stream.close()