125 lines
4.6 KiB
Python
125 lines
4.6 KiB
Python
from typing import List, Dict, Any
|
|
# from llm import llm as llm_model
|
|
from utils.llm import search_llm as llm_model
|
|
from utils.prompt import RESPONSE_TEMPLATE
|
|
import time
|
|
import logging
|
|
import sys
|
|
|
|
# 配置日志
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
handlers=[logging.StreamHandler(sys.stdout)]
|
|
)
|
|
logger = logging.getLogger("ResponseGenerator")
|
|
|
|
class ResponseGenerator:
|
|
def __init__(self):
|
|
"""初始化响应生成器,使用自定义的llm模型"""
|
|
logger.info("ResponseGenerator初始化完成")
|
|
|
|
def generate_response(self, query: str, retrieved_info: List[Dict[str, Any]], nlu_data: Dict = None) -> str:
|
|
"""
|
|
生成响应
|
|
|
|
参数:
|
|
query: 用户查询
|
|
retrieved_info: 检索到的信息
|
|
nlu_data: 意图识别和槽位提取的结果
|
|
|
|
返回:
|
|
生成的响应
|
|
"""
|
|
# 如果没有检索到信息,返回默认回答
|
|
if not retrieved_info:
|
|
logger.warning("没有检索到相关信息,返回默认回答")
|
|
return "抱歉,我没有找到与您问题相关的信息。请尝试使用其他关键词或更具体的问题。"
|
|
|
|
# 构建提示
|
|
logger.info("开始构建提示")
|
|
prompt = self._build_prompt(query, retrieved_info, nlu_data)
|
|
logger.info(f"提示构建完成,长度: {len(prompt)}")
|
|
|
|
# 调用自定义LLM模型生成回答
|
|
logger.info("开始调用LLM模型生成回答")
|
|
start_time = time.time()
|
|
|
|
try:
|
|
# 添加超时处理
|
|
response = llm_model.invoke(prompt)
|
|
logger.info(f"LLM响应完成,耗时: {time.time() - start_time:.2f}秒")
|
|
|
|
# 检查响应是否为空
|
|
if not response or not response.strip():
|
|
logger.error("LLM返回了空响应")
|
|
return "抱歉,生成回答时出现了问题。请稍后再试。"
|
|
|
|
return response
|
|
|
|
except Exception as e:
|
|
logger.error(f"调用LLM模型时出错: {str(e)}")
|
|
return f"抱歉,生成回答时出现了错误: {str(e)}"
|
|
|
|
def _build_prompt(self, query: str, retrieved_info: List[Dict[str, Any]], nlu_data: Dict = None) -> str:
|
|
"""
|
|
构建提示
|
|
|
|
参数:
|
|
query: 用户查询
|
|
retrieved_info: 检索到的信息
|
|
nlu_data: 意图识别和槽位提取的结果
|
|
|
|
返回:
|
|
构建的提示
|
|
"""
|
|
context_parts = []
|
|
|
|
for info in retrieved_info:
|
|
node = info.get("node", {})
|
|
text = info.get("text", "")
|
|
|
|
node_type = node.get("labels", [""])[0] if "labels" in node else ""
|
|
name = node.get("original_name", "") or node.get("display_name", "")
|
|
description = node.get("描述", "")
|
|
|
|
if node_type == "功能名称":
|
|
context_parts.append(f"功能: {name}\n描述: {description}")
|
|
else:
|
|
context_parts.append(f"{node_type}: {name}")
|
|
|
|
context = "\n\n".join(context_parts)
|
|
|
|
# 添加意图和槽位信息
|
|
intent_info = ""
|
|
if nlu_data and '意图' in nlu_data:
|
|
intent_data = nlu_data['意图']
|
|
|
|
# 获取一级意图
|
|
first_intent = "未知"
|
|
if '一级意图' in intent_data and 'name' in intent_data['一级意图']:
|
|
first_intent = intent_data['一级意图']['name']
|
|
|
|
# 获取二级意图
|
|
second_intent = "未知"
|
|
if '二级意图' in intent_data and 'name' in intent_data['二级意图']:
|
|
second_intent = intent_data['二级意图']['name']
|
|
|
|
intent_info = f"用户一级意图: {first_intent}\n用户二级意图: {second_intent}\n"
|
|
|
|
# 添加槽位信息
|
|
if '二级意图' in intent_data and 'slot_lv2' in intent_data['二级意图']:
|
|
slots = intent_data['二级意图']['slot_lv2']
|
|
if slots:
|
|
intent_info += "提取的槽位:\n"
|
|
for slot_name, slot_value in slots.items():
|
|
if slot_value and slot_value != '未知':
|
|
intent_info += f"- {slot_name}: {slot_value}\n"
|
|
|
|
prompt = RESPONSE_TEMPLATE.format(
|
|
intent_info=intent_info,
|
|
context=context,
|
|
query=query
|
|
)
|
|
|
|
return prompt |