mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-24 08:03:53 +08:00
update:使用intent_llm中的LLM进行工具内容回复
This commit is contained in:
@@ -157,7 +157,7 @@ selected_module:
|
|||||||
Memory: nomem
|
Memory: nomem
|
||||||
# 意图识别模块开启后,可以播放音乐、控制音量、识别退出指令。
|
# 意图识别模块开启后,可以播放音乐、控制音量、识别退出指令。
|
||||||
# 不想开通意图识别,就设置成:nointent
|
# 不想开通意图识别,就设置成:nointent
|
||||||
# 意图识别可使用intent_llm。优点:通用性强,缺点:增加串行前置意图识别模块,会增加处理时间,这个意图识别暂时不支持控制音量大小等iot操作
|
# 意图识别可使用intent_llm。优点:通用性强,缺点:增加串行前置意图识别模块,会增加处理时间,支持控制音量大小等iot操作
|
||||||
# 意图识别可使用function_call,缺点:需要所选择的LLM支持function_call,优点:按需调用工具、速度快,理论上能全部操作所有iot指令
|
# 意图识别可使用function_call,缺点:需要所选择的LLM支持function_call,优点:按需调用工具、速度快,理论上能全部操作所有iot指令
|
||||||
# 默认免费的ChatGLMLLM就已经支持function_call,但是如果像追求稳定建议把LLM设置成:DoubaoLLM,使用的具体model_name是:doubao-1-5-pro-32k-250115
|
# 默认免费的ChatGLMLLM就已经支持function_call,但是如果像追求稳定建议把LLM设置成:DoubaoLLM,使用的具体model_name是:doubao-1-5-pro-32k-250115
|
||||||
Intent: function_call
|
Intent: function_call
|
||||||
|
|||||||
@@ -108,43 +108,21 @@ async def process_intent_result(conn, intent_result, original_text):
|
|||||||
if result.action == Action.RESPONSE: # 直接回复前端
|
if result.action == Action.RESPONSE: # 直接回复前端
|
||||||
text = result.response
|
text = result.response
|
||||||
if text is not None:
|
if text is not None:
|
||||||
text_index = (
|
speak_and_play(conn, text)
|
||||||
conn.tts_last_text_index + 1
|
|
||||||
if hasattr(conn, "tts_last_text_index")
|
|
||||||
else 0
|
|
||||||
)
|
|
||||||
conn.recode_first_last_text(text, text_index)
|
|
||||||
future = conn.executor.submit(
|
|
||||||
conn.speak_and_play, text, text_index
|
|
||||||
)
|
|
||||||
conn.llm_finish_task = True
|
|
||||||
conn.tts_queue.put((future, text_index))
|
|
||||||
conn.dialogue.put(Message(role="assistant", content=text))
|
|
||||||
elif result.action == Action.REQLLM: # 调用函数后再请求llm生成回复
|
elif result.action == Action.REQLLM: # 调用函数后再请求llm生成回复
|
||||||
text = result.result
|
text = result.result
|
||||||
if text is not None and len(text) > 0:
|
conn.dialogue.put(Message(role="tool", content=text))
|
||||||
conn.dialogue.put(Message(role="tool", content=text))
|
llm_result = conn.intent.replyResult(text)
|
||||||
conn.executor.submit(
|
if llm_result is None:
|
||||||
conn.chat_with_function_calling, text, True
|
llm_result = text
|
||||||
)
|
speak_and_play(conn, llm_result)
|
||||||
elif (
|
elif (
|
||||||
result.action == Action.NOTFOUND
|
result.action == Action.NOTFOUND
|
||||||
or result.action == Action.ERROR
|
or result.action == Action.ERROR
|
||||||
):
|
):
|
||||||
text = result.result
|
text = result.result
|
||||||
if text is not None:
|
if text is not None:
|
||||||
text_index = (
|
speak_and_play(conn, text)
|
||||||
conn.tts_last_text_index + 1
|
|
||||||
if hasattr(conn, "tts_last_text_index")
|
|
||||||
else 0
|
|
||||||
)
|
|
||||||
conn.recode_first_last_text(text, text_index)
|
|
||||||
future = conn.executor.submit(
|
|
||||||
conn.speak_and_play, text, text_index
|
|
||||||
)
|
|
||||||
conn.llm_finish_task = True
|
|
||||||
conn.tts_queue.put((future, text_index))
|
|
||||||
conn.dialogue.put(Message(role="assistant", content=text))
|
|
||||||
elif function_name != "play_music":
|
elif function_name != "play_music":
|
||||||
# For backward compatibility with original code
|
# For backward compatibility with original code
|
||||||
# 获取当前最新的文本索引
|
# 获取当前最新的文本索引
|
||||||
@@ -152,18 +130,7 @@ async def process_intent_result(conn, intent_result, original_text):
|
|||||||
if text is None:
|
if text is None:
|
||||||
text = result.result
|
text = result.result
|
||||||
if text is not None:
|
if text is not None:
|
||||||
text_index = (
|
speak_and_play(conn, text)
|
||||||
conn.tts_last_text_index + 1
|
|
||||||
if hasattr(conn, "tts_last_text_index")
|
|
||||||
else 0
|
|
||||||
)
|
|
||||||
conn.recode_first_last_text(text, text_index)
|
|
||||||
future = conn.executor.submit(
|
|
||||||
conn.speak_and_play, text, text_index
|
|
||||||
)
|
|
||||||
conn.llm_finish_task = True
|
|
||||||
conn.tts_queue.put((future, text_index))
|
|
||||||
conn.dialogue.put(Message(role="assistant", content=text))
|
|
||||||
|
|
||||||
# 将函数执行放在线程池中
|
# 将函数执行放在线程池中
|
||||||
conn.executor.submit(process_function_call)
|
conn.executor.submit(process_function_call)
|
||||||
@@ -174,21 +141,12 @@ async def process_intent_result(conn, intent_result, original_text):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def extract_text_in_brackets(s):
|
def speak_and_play(conn, text):
|
||||||
"""
|
text_index = (
|
||||||
从字符串中提取中括号内的文字
|
conn.tts_last_text_index + 1 if hasattr(conn, "tts_last_text_index") else 0
|
||||||
|
)
|
||||||
:param s: 输入字符串
|
conn.recode_first_last_text(text, text_index)
|
||||||
:return: 中括号内的文字,如果不存在则返回空字符串
|
future = conn.executor.submit(conn.speak_and_play, text, text_index)
|
||||||
"""
|
conn.llm_finish_task = True
|
||||||
left_bracket_index = s.find("[")
|
conn.tts_queue.put((future, text_index))
|
||||||
right_bracket_index = s.find("]")
|
conn.dialogue.put(Message(role="assistant", content=text))
|
||||||
|
|
||||||
if (
|
|
||||||
left_bracket_index != -1
|
|
||||||
and right_bracket_index != -1
|
|
||||||
and left_bracket_index < right_bracket_index
|
|
||||||
):
|
|
||||||
return s[left_bracket_index + 1 : right_bracket_index]
|
|
||||||
else:
|
|
||||||
return ""
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ class IntentProvider(IntentProviderBase):
|
|||||||
self.intent_cache = {} # 缓存意图识别结果
|
self.intent_cache = {} # 缓存意图识别结果
|
||||||
self.cache_expiry = 600 # 缓存有效期10分钟
|
self.cache_expiry = 600 # 缓存有效期10分钟
|
||||||
self.cache_max_size = 100 # 最多缓存100个意图
|
self.cache_max_size = 100 # 最多缓存100个意图
|
||||||
|
self.history_count = 4 # 默认使用最近4条对话记录
|
||||||
|
|
||||||
def get_intent_system_prompt(self, functions_list: str) -> str:
|
def get_intent_system_prompt(self, functions_list: str) -> str:
|
||||||
"""
|
"""
|
||||||
@@ -104,6 +105,13 @@ class IntentProvider(IntentProviderBase):
|
|||||||
for key, _ in sorted_items[: len(sorted_items) - self.cache_max_size]:
|
for key, _ in sorted_items[: len(sorted_items) - self.cache_max_size]:
|
||||||
del self.intent_cache[key]
|
del self.intent_cache[key]
|
||||||
|
|
||||||
|
def replyResult(self, text: str):
|
||||||
|
llm_result = self.llm.response_no_stream(
|
||||||
|
system_prompt=text,
|
||||||
|
user_prompt="请总结以上内容,像人类一样说话的口吻回复用户,要求简洁,请直接返回结果。",
|
||||||
|
)
|
||||||
|
return llm_result
|
||||||
|
|
||||||
async def detect_intent(self, conn, dialogue_history: List[Dict], text: str) -> str:
|
async def detect_intent(self, conn, dialogue_history: List[Dict], text: str) -> str:
|
||||||
if not self.llm:
|
if not self.llm:
|
||||||
raise ValueError("LLM provider not set")
|
raise ValueError("LLM provider not set")
|
||||||
@@ -150,14 +158,13 @@ class IntentProvider(IntentProviderBase):
|
|||||||
|
|
||||||
logger.bind(tag=TAG).debug(f"User prompt: {prompt_music}")
|
logger.bind(tag=TAG).debug(f"User prompt: {prompt_music}")
|
||||||
|
|
||||||
# 构建用户最后一句话的提示
|
# 构建用户对话历史的提示
|
||||||
msgStr = ""
|
msgStr = ""
|
||||||
|
|
||||||
# 只使用最后两句即可
|
# 获取最近的对话历史
|
||||||
if len(dialogue_history) >= 2:
|
start_idx = max(0, len(dialogue_history) - self.history_count)
|
||||||
# 保证最少有两句话的时候处理
|
for i in range(start_idx, len(dialogue_history)):
|
||||||
msgStr += f"{dialogue_history[-2].role}: {dialogue_history[-2].content}\n"
|
msgStr += f"{dialogue_history[i].role}: {dialogue_history[i].content}\n"
|
||||||
msgStr += f"{dialogue_history[-1].role}: {dialogue_history[-1].content}\n"
|
|
||||||
|
|
||||||
msgStr += f"User: {text}\n"
|
msgStr += f"User: {text}\n"
|
||||||
user_prompt = f"current dialogue:\n{msgStr}"
|
user_prompt = f"current dialogue:\n{msgStr}"
|
||||||
|
|||||||
Reference in New Issue
Block a user