mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-26 17:13:54 +08:00
Merge pull request #1250 from jwhna1/main
Update ollama.py 为本地ollama部署qwen3大语言模型添加适配!
This commit is contained in:
@@ -21,27 +21,67 @@ class LLMProvider(LLMProviderBase):
|
|||||||
api_key="ollama" # Ollama doesn't need an API key but OpenAI client requires one
|
api_key="ollama" # Ollama doesn't need an API key but OpenAI client requires one
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 检查是否是qwen3模型
|
||||||
|
self.is_qwen3 = self.model_name and self.model_name.lower().startswith("qwen3")
|
||||||
|
|
||||||
def response(self, session_id, dialogue):
|
def response(self, session_id, dialogue):
|
||||||
try:
|
try:
|
||||||
|
# 如果是qwen3模型,在用户最后一条消息中添加/no_think指令
|
||||||
|
if self.is_qwen3:
|
||||||
|
# 复制对话列表,避免修改原始对话
|
||||||
|
dialogue_copy = dialogue.copy()
|
||||||
|
|
||||||
|
# 找到最后一条用户消息
|
||||||
|
for i in range(len(dialogue_copy) - 1, -1, -1):
|
||||||
|
if dialogue_copy[i]["role"] == "user":
|
||||||
|
# 在用户消息前添加/no_think指令
|
||||||
|
dialogue_copy[i]["content"] = "/no_think " + dialogue_copy[i]["content"]
|
||||||
|
logger.bind(tag=TAG).debug(f"为qwen3模型添加/no_think指令")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 使用修改后的对话
|
||||||
|
dialogue = dialogue_copy
|
||||||
|
|
||||||
responses = self.client.chat.completions.create(
|
responses = self.client.chat.completions.create(
|
||||||
model=self.model_name,
|
model=self.model_name,
|
||||||
messages=dialogue,
|
messages=dialogue,
|
||||||
stream=True
|
stream=True
|
||||||
)
|
)
|
||||||
is_active=True
|
is_active = True
|
||||||
|
# 用于处理跨chunk的标签
|
||||||
|
buffer = ""
|
||||||
|
|
||||||
for chunk in responses:
|
for chunk in responses:
|
||||||
try:
|
try:
|
||||||
delta = chunk.choices[0].delta if getattr(chunk, 'choices', None) else None
|
delta = chunk.choices[0].delta if getattr(chunk, 'choices', None) else None
|
||||||
content = delta.content if hasattr(delta, 'content') else ''
|
content = delta.content if hasattr(delta, 'content') else ''
|
||||||
|
|
||||||
if content:
|
if content:
|
||||||
if '<think>' in content:
|
# 将内容添加到缓冲区
|
||||||
|
buffer += content
|
||||||
|
|
||||||
|
# 处理缓冲区中的标签
|
||||||
|
while '<think>' in buffer and '</think>' in buffer:
|
||||||
|
# 找到完整的<think></think>标签并移除
|
||||||
|
pre = buffer.split('<think>', 1)[0]
|
||||||
|
post = buffer.split('</think>', 1)[1]
|
||||||
|
buffer = pre + post
|
||||||
|
|
||||||
|
# 处理只有开始标签的情况
|
||||||
|
if '<think>' in buffer:
|
||||||
is_active = False
|
is_active = False
|
||||||
content = content.split('<think>')[0]
|
buffer = buffer.split('<think>', 1)[0]
|
||||||
if '</think>' in content:
|
|
||||||
|
# 处理只有结束标签的情况
|
||||||
|
if '</think>' in buffer:
|
||||||
is_active = True
|
is_active = True
|
||||||
content = content.split('</think>')[-1]
|
buffer = buffer.split('</think>', 1)[1]
|
||||||
if is_active:
|
|
||||||
yield content
|
# 如果当前处于活动状态且缓冲区有内容,则输出
|
||||||
|
if is_active and buffer:
|
||||||
|
yield buffer
|
||||||
|
buffer = "" # 清空缓冲区
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.bind(tag=TAG).error(f"Error processing chunk: {e}")
|
logger.bind(tag=TAG).error(f"Error processing chunk: {e}")
|
||||||
|
|
||||||
@@ -51,6 +91,22 @@ class LLMProvider(LLMProviderBase):
|
|||||||
|
|
||||||
def response_with_functions(self, session_id, dialogue, functions=None):
|
def response_with_functions(self, session_id, dialogue, functions=None):
|
||||||
try:
|
try:
|
||||||
|
# 如果是qwen3模型,在用户最后一条消息中添加/no_think指令
|
||||||
|
if self.is_qwen3:
|
||||||
|
# 复制对话列表,避免修改原始对话
|
||||||
|
dialogue_copy = dialogue.copy()
|
||||||
|
|
||||||
|
# 找到最后一条用户消息
|
||||||
|
for i in range(len(dialogue_copy) - 1, -1, -1):
|
||||||
|
if dialogue_copy[i]["role"] == "user":
|
||||||
|
# 在用户消息前添加/no_think指令
|
||||||
|
dialogue_copy[i]["content"] = "/no_think " + dialogue_copy[i]["content"]
|
||||||
|
logger.bind(tag=TAG).debug(f"为qwen3模型添加/no_think指令")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 使用修改后的对话
|
||||||
|
dialogue = dialogue_copy
|
||||||
|
|
||||||
stream = self.client.chat.completions.create(
|
stream = self.client.chat.completions.create(
|
||||||
model=self.model_name,
|
model=self.model_name,
|
||||||
messages=dialogue,
|
messages=dialogue,
|
||||||
@@ -58,8 +114,49 @@ class LLMProvider(LLMProviderBase):
|
|||||||
tools=functions,
|
tools=functions,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
is_active = True
|
||||||
|
buffer = ""
|
||||||
|
|
||||||
for chunk in stream:
|
for chunk in stream:
|
||||||
yield chunk.choices[0].delta.content, chunk.choices[0].delta.tool_calls
|
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
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 处理文本内容
|
||||||
|
if content:
|
||||||
|
# 将内容添加到缓冲区
|
||||||
|
buffer += content
|
||||||
|
|
||||||
|
# 处理缓冲区中的标签
|
||||||
|
while '<think>' in buffer and '</think>' in buffer:
|
||||||
|
# 找到完整的<think></think>标签并移除
|
||||||
|
pre = buffer.split('<think>', 1)[0]
|
||||||
|
post = buffer.split('</think>', 1)[1]
|
||||||
|
buffer = pre + post
|
||||||
|
|
||||||
|
# 处理只有开始标签的情况
|
||||||
|
if '<think>' in buffer:
|
||||||
|
is_active = False
|
||||||
|
buffer = buffer.split('<think>', 1)[0]
|
||||||
|
|
||||||
|
# 处理只有结束标签的情况
|
||||||
|
if '</think>' in buffer:
|
||||||
|
is_active = True
|
||||||
|
buffer = buffer.split('</think>', 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
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.bind(tag=TAG).error(f"Error in Ollama function call: {e}")
|
logger.bind(tag=TAG).error(f"Error in Ollama function call: {e}")
|
||||||
|
|||||||
Reference in New Issue
Block a user