mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-26 17:13:54 +08:00
update:AliAppLLM流式接口改造
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
from config.logger import setup_logging
|
from config.logger import setup_logging
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
import dashscope
|
||||||
from dashscope import Application
|
from dashscope import Application
|
||||||
from core.providers.llm.base import LLMProviderBase
|
from core.providers.llm.base import LLMProviderBase
|
||||||
from core.utils.util import check_model_key
|
from core.utils.util import check_model_key
|
||||||
|
import time
|
||||||
|
|
||||||
TAG = __name__
|
TAG = __name__
|
||||||
logger = setup_logging()
|
logger = setup_logging()
|
||||||
@@ -15,6 +17,7 @@ class LLMProvider(LLMProviderBase):
|
|||||||
self.base_url = config.get("base_url")
|
self.base_url = config.get("base_url")
|
||||||
self.is_No_prompt = config.get("is_no_prompt")
|
self.is_No_prompt = config.get("is_no_prompt")
|
||||||
self.memory_id = config.get("ali_memory_id")
|
self.memory_id = config.get("ali_memory_id")
|
||||||
|
self.streaming_chunk_size = config.get("streaming_chunk_size", 3) # 每次流式返回的字符数
|
||||||
check_model_key("AliBLLLM", self.api_key)
|
check_model_key("AliBLLLM", self.api_key)
|
||||||
|
|
||||||
def response(self, session_id, dialogue):
|
def response(self, session_id, dialogue):
|
||||||
@@ -32,6 +35,8 @@ class LLMProvider(LLMProviderBase):
|
|||||||
"app_id": self.app_id,
|
"app_id": self.app_id,
|
||||||
"session_id": session_id,
|
"session_id": session_id,
|
||||||
"messages": dialogue,
|
"messages": dialogue,
|
||||||
|
# 开启SDK原生流式
|
||||||
|
"stream": True,
|
||||||
}
|
}
|
||||||
if self.memory_id != False:
|
if self.memory_id != False:
|
||||||
# 百练memory需要prompt参数
|
# 百练memory需要prompt参数
|
||||||
@@ -42,25 +47,63 @@ class LLMProvider(LLMProviderBase):
|
|||||||
f"【阿里百练API服务】处理后的prompt: {prompt}"
|
f"【阿里百练API服务】处理后的prompt: {prompt}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 可选地设置自定义API基地址(若配置为兼容模式URL则忽略)
|
||||||
|
if self.base_url and ("/api/" in self.base_url):
|
||||||
|
dashscope.base_http_api_url = self.base_url
|
||||||
|
|
||||||
responses = Application.call(**call_params)
|
responses = Application.call(**call_params)
|
||||||
if responses.status_code != HTTPStatus.OK:
|
|
||||||
logger.bind(tag=TAG).error(
|
# 流式处理(SDK在stream=True时返回可迭代对象;否则返回单次响应对象)
|
||||||
f"code={responses.status_code}, "
|
logger.bind(tag=TAG).debug(
|
||||||
f"message={responses.message}, "
|
f"【阿里百练API服务】构造参数: {dict(call_params, api_key='***')}"
|
||||||
f"请参考文档:https://help.aliyun.com/zh/model-studio/developer-reference/error-code"
|
)
|
||||||
)
|
|
||||||
yield "【阿里百练API服务响应异常】"
|
last_text = ""
|
||||||
else:
|
try:
|
||||||
logger.bind(tag=TAG).debug(
|
for resp in responses:
|
||||||
f"【阿里百练API服务】构造参数: {call_params}"
|
if resp.status_code != HTTPStatus.OK:
|
||||||
)
|
logger.bind(tag=TAG).error(
|
||||||
yield responses.output.text
|
f"code={resp.status_code}, message={resp.message}, 请参考文档:https://help.aliyun.com/zh/model-studio/developer-reference/error-code"
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
current_text = getattr(getattr(resp, "output", None), "text", None)
|
||||||
|
if current_text is None:
|
||||||
|
continue
|
||||||
|
# SDK流式为增量覆盖,计算差量输出
|
||||||
|
if len(current_text) >= len(last_text):
|
||||||
|
delta = current_text[len(last_text):]
|
||||||
|
else:
|
||||||
|
# 避免偶发回退
|
||||||
|
delta = current_text
|
||||||
|
if delta:
|
||||||
|
yield delta
|
||||||
|
last_text = current_text
|
||||||
|
except TypeError:
|
||||||
|
# 非流式回落(一次性返回)
|
||||||
|
if responses.status_code != HTTPStatus.OK:
|
||||||
|
logger.bind(tag=TAG).error(
|
||||||
|
f"code={responses.status_code}, message={responses.message}, 请参考文档:https://help.aliyun.com/zh/model-studio/developer-reference/error-code"
|
||||||
|
)
|
||||||
|
yield "【阿里百练API服务响应异常】"
|
||||||
|
else:
|
||||||
|
full_text = getattr(getattr(responses, "output", None), "text", "")
|
||||||
|
logger.bind(tag=TAG).info(
|
||||||
|
f"【阿里百练API服务】完整响应长度: {len(full_text)}"
|
||||||
|
)
|
||||||
|
for i in range(0, len(full_text), self.streaming_chunk_size):
|
||||||
|
chunk = full_text[i:i + self.streaming_chunk_size]
|
||||||
|
if chunk:
|
||||||
|
yield chunk
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.bind(tag=TAG).error(f"【阿里百练API服务】响应异常: {e}")
|
logger.bind(tag=TAG).error(f"【阿里百练API服务】响应异常: {e}")
|
||||||
yield "【LLM服务响应异常】"
|
yield "【LLM服务响应异常】"
|
||||||
|
|
||||||
def response_with_functions(self, session_id, dialogue, functions=None):
|
def response_with_functions(self, session_id, dialogue, functions=None):
|
||||||
logger.bind(tag=TAG).error(
|
# 阿里百练当前未支持原生的 function call。为保持兼容,这里回退到普通文本流式输出。
|
||||||
f"阿里百练暂未实现完整的工具调用(function call),建议使用其他意图识别"
|
# 上层会按 (content, tool_calls) 的形式消费,这里始终返回 (token, None)
|
||||||
|
logger.bind(tag=TAG).warning(
|
||||||
|
"阿里百练未实现原生 function call,已回退为纯文本流式输出"
|
||||||
)
|
)
|
||||||
|
for token in self.response(session_id, dialogue):
|
||||||
|
yield token, None
|
||||||
|
|||||||
Reference in New Issue
Block a user