Files
deepdata/runtime/ops/llms/qa_condition_evaluator/process.py
T

99 lines
4.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -- encoding: utf-8 --
"""
Description: 基于LLM通过用户设置维度和相应描述进行QA对评估
Create: 2023/11/7 9:26
"""
import json
import re
import time
from pathlib import Path
from typing import List, Dict, Any
from loguru import logger
from deepdata.core.base_op import LLM
class QAConditionEvaluator(LLM):
def __init__(self, *args, **kwargs):
super(QAConditionEvaluator, self).__init__(*args, **kwargs)
self.pattern = r'结果[::] ?[YN]'
self.template_path = Path(__file__).parent / "resources/template.txt"
self.examples_path = Path(__file__).parent / "resources/examples.json"
self.task_id = kwargs.get("taskId", "default_id")
self.dimensions = kwargs.get("dimension", [
{
"dimension": "回答是否有针对性",
"description": "回答应对问题中的所有疑问点提供正面、直接的回答,"
"不应引起疑惑。同时,答案不应有任何内容的遗漏,需构成一个完整的陈述。"
},
{
"dimension": "问题是否独立",
"description": "仅分析问题,问题的主体和客体都比较明确,即使有省略,也符合语言习惯。"
"在不需要补充其他信息的情况下不会引起疑惑。"
},
{
"dimension": "语法是否错误",
"description": "问题为疑问句,答案为陈述句; 不存在词语搭配不当的情况;连接词和标点符号不存在错用情况;"
"逻辑混乱的情况不存在;语法结构都正确且完整;"
}
])
self.llm = self.get_llm(*args, **kwargs)
self.prompts = self.build_llm_prompt(*args, **kwargs)
@staticmethod
def _process_examples(dimension_example: List) -> str:
if not dimension_example:
return "\n"
res = "\n以下是一些案例供你参考:"
for single_example in dimension_example:
res += (f"\n问题:{single_example['question']}"
f"\n回答:{single_example['answer']}"
f"\n分析思路:{single_example['evaluate']}"
f"\n结果:{single_example['result']}\n")
return res
def execute(self, sample: Dict[str, Any]) -> Dict[str, Any]:
start = time.time()
qas = json.loads(sample[self.text_key])
single_content_res = []
for qa in qas:
single_qa_res = []
for dimension, prompt in self.prompts.items():
local_result = self._llm_call_parse(qa, prompt, retry=2)
single_qa_res.append({"dimension": dimension, "result": local_result})
qa_response = {"qaId": qa["qaId"], "result": single_qa_res}
single_content_res.append(qa_response)
sample[self.text_key] = "Sucess"
self.save_sample(single_content_res, sample)
cost_time = time.time() - start
logger.info(f"task id: {self.task_id}, method: QAConditionEvaluator costs {cost_time:.6f} s")
return sample
def build_llm_prompt(self, *args, **kwargs) -> Dict:
templates = self.template_path.read_text(encoding="utf-8")
examples_dict = json.loads(self.examples_path.read_text(encoding="utf-8"))
prompts_dict = {}
for dimension in self.dimensions:
name, des = dimension["dimension"], dimension["description"]
dimension_example = self._process_examples(examples_dict.get(name))
dimension_prompt = templates.format(criterion=des, examples=dimension_example, question="{question}",
answer="{answer}")
prompts_dict[name] = dimension_prompt
return prompts_dict
def _llm_call_parse(self, data: Dict, prompt: str, retry: int = 2):
try:
for _ in range(retry):
response = self.llm(prompt.format(question=data["question"], answer=data["answer"]))
result = re.findall(self.pattern, response)
if result:
return "Y" in result[0]
except RuntimeError as e:
logger.error(f"method: QAConditionEvaluator execution error, cause by {e}")
return False