Hanah

Hanah

wow-agent-day03 OpenAI實現閱卷智能體

參考: DataWhale wow agent day03
延用 day02 的環境配置和大模型設置。

定義函數#

提取大模型輸出內容中的 json 部分#

import re  
def extract_json_content(text):  
  text = text.replace()  

函數解析:
從文本中提取 JSON 內容並進行清理的函數

def extract_json_content(text):  
    text = text.replace("\n","")  
    pattern = r"```json(.*?)```"  
    matches = re.findall(pattern, text, re.DOTALL)  
    if matches:  
        return matches[0].strip()  
    return text  
參數:  
    text (str): 輸入的文本字符串,通常包含JSON代碼塊  
    
返回:  
    str: 提取並清理後的JSON字符串  
    
函數說明:  
1. text.replace("\n","") - 刪除文本中所有的換行符  
2. pattern = r"```json(.*?)```" - 定義正則表達式模式,匹配```json和```之間的內容  
3. re.findall() - 使用正則表達式查找所有匹配項,re.DOTALL允許.匹配換行符  
4. matches[0].strip() - 獲取第一個匹配結果並去除首尾空白  
5. 如果沒有匹配項則返回原文本  

把 json 字符串解析成 python 對象#

對函數進行了一些修改

class JsonOutputParser:  
    def parse(self, result):  
        # 首先嘗試直接解析  
        try:  
            return json.loads(result)  
        except json.JSONDecodeError:  
            pass  
            
        # 嘗試提取JSON內容  
        cleaned_result = extract_json_content(result)  
        try:  
            return json.loads(cleaned_result)  
        except json.JSONDecodeError:  
            pass  
            
        # 嘗試修復常見JSON錯誤  
        try:  
            # 處理單引號  
            fixed_result = cleaned_result.replace("'", '"')  
            # 處理末尾多餘的逗號  
            fixed_result = re.sub(r',\s*}', '}', fixed_result)  
            # 處理未閉合的引號  
            fixed_result = re.sub(r'([^"])"([^"])', r'\1"\2', fixed_result)  
            return json.loads(fixed_result)  
        except json.JSONDecodeError as e:  
            raise ValueError(f"無法解析JSON輸出。原始輸出: {result}\n錯誤信息: {str(e)}")  

函數解析:

    參數:  
        result (str): LLM生成的包含JSON的文本  
    返回:  
        dict: 解析後的JSON對象  
        
    優化說明:  
    1. 增加多種JSON提取方式,提高魯棒性  
    2. 添加JSON修復機制,處理常見錯誤  
    3. 增加重試機制,提高成功率  
    

定義 GradingOpenAI#

class GradingOpenAI:  
    def __init__(self):  
        self.model = "glm-4-flash"  
        self.output_parser = JsonOutputParser()  
        self.template = """你是一位中國專利代理師考試閱卷專家,  
擅長根據給定的題目和答案為考生生成符合要求的評分和中文評語,  
並按照特定的格式輸出。  
你的任務是,根據我輸入的考題和答案,針對考生的作答生成評分和中文的評語,並以JSON格式返回。  
閱卷標準適當寬鬆一些,只要考生回答出基本的意思就應當給分。  
答案如果有數字標注,含義是考生如果答出這個知識點,這道題就會得到幾分。  
生成的中文評語需要能夠被json.loads()這個函數正確解析。  
生成的整個中文評語需要用英文的雙引號包裹,在被包裹的字符串內部,請用中文的雙引號。  
中文評語中不可以出現換行符、轉義字符等等。  

輸出格式為JSON:  
{{  
  "llmgetscore": 0,  
  "llmcomments": "中文評語"  
}}  

比較學生的回答與正確答案,  
並給出滿分為10分的評分和中文評語。  
題目:{ques_title}  
答案:{answer}  
學生的回复:{reply}"""  

    def create_prompt(self, ques_title, answer, reply):  
        return self.template.format(  
            ques_title=ques_title,  
            answer=answer,  
            reply=reply  
        )  

    def grade_answer(self, ques_title, answer, reply):  
        success = False  
        while not success:  
            # 這裡是一個不得已的權宜之計  
            # 上面的json解析函數不是表現很差嗎,那就多生成幾遍,直到解析成功  
            # 對大模型生成的內容先解析一下,如果解析失敗,就再讓大模型生成一遍  
            try:  
                response = client.chat.completions.create(  
                    model=self.model,  
                    messages=[  
                        {"role": "system", "content": "你是一位專業的考試閱卷專家。"},  
                        {"role": "user", "content": self.create_prompt(ques_title, answer, reply)}  
                    ],  
                    temperature=0.7  
                )  

                result = self.output_parser.parse(response.choices[0].message.content)  
                success = True  
            except Exception as e:  
                print(f"Error occurred: {e}")  
                continue  

        return result['llmgetscore'], result['llmcomments']  

    def run(self, input_data):  
        output = []  
        for item in input_data:  
            score, comment = self.grade_answer(  
                item['ques_title'],  
                item['answer'],  
                item['reply']  
            )  
            item['llmgetscore'] = score  
            item['llmcomments'] = comment  
            output.append(item)  
        return output  
grading_openai = GradingOpenAI()  

演示#

input

# 示例輸入數據  
input_data = [  
 {'ques_title': '請解釋共有技術特徵、區別技術特徵、附加技術特徵、必要技術特徵的含義',  
  'answer': '共有技術特徵:與最接近的現有技術共有的技術特徵(2.5分); 區別技術特徵:區別於最接近的現有技術的技術特徵(2.5分); 附加技術特徵:對所引用的技術特徵進一步限定的技術特徵,增加的技術特徵(2.5分); 必要技術特徵:為解決其技術問題所不可缺少的技術特徵(2.5分)。',  
  'fullscore': 10,  
  'reply': '共有技術特徵:與所對比的技術方案相同的技術特徵\n區別技術特徵:與所對比的技術方案相區別的技術特徵\n附加技術特徵:對引用的技術特徵進一步限定的技術特徵\n必要技術特徵:解決技術問題必須可少的技術特徵'},  
 {'ques_title': '請解釋前序部分、特徵部分、引用部分、限定部分',  
  'answer': '前序部分:獨權中,主題+與最接近的現有技術共有的技術特徵,在其特徵在於之前(2.5分); 特徵部分:獨權中,與區別於最接近的現有技術的技術特徵,在其特徵在於之後(2.5分);引用部分:從權中引用的權利要求編號及主題 (2.5分);限定部分:從權中附加技術特徵(2.5分)。',  
  'fullscore': 10,  
  'reply': '前序部分:獨立權利要求中與現有技術相同的技術特徵\n特徵部分:獨立權利要求中區別於現有技術的技術特徵\n引用部分:從屬權利要求中引用其他權利要求的部分\n限定部分:對所引用的權利要求進一步限定的技術特徵'}]  

運行智能體

graded_data = grading_openai.run(input_data)  
print(graded_data)  

結果
[{'ques_title': ' 請解釋共有技術特徵、區別技術特徵、附加技術特徵、必要技術特徵的含義 ', 'answer': ' 共有技術特徵:與最接近的現有技術共有的技術特徵(2.5 分); 區別技術特徵:區別於最接近的現有技術的技術特徵(2.5 分); 附加技術特徵:對所引用的技術特徵進一步限定的技術特徵,增加的技術特徵(2.5 分); 必要技術特徵:為解決其技術問題所不可缺少的技術特徵(2.5 分)。', 'fullscore': 10, 'reply': ' 共有技術特徵:與所對比的技術方案相同的技術特徵 \n 區別技術特徵:與所對比的技術方案相區別的技術特徵 \n 附加技術特徵:對引用的技術特徵進一步限定的技術特徵 \n 必要技術特徵:解決技術問題必須可少的技術特徵 ', 'llmgetscore': 10, 'llmcomments': ' 考生對共有技術特徵、區別技術特徵、附加技術特徵、必要技術特徵的解釋基本正確,能夠準確表達這些概念的含義,故給予滿分。'}, {'ques_title': ' 請解釋前序部分、特徵部分、引用部分、限定部分 ', 'answer': ' 前序部分:獨權中,主題 + 與最接近的現有技術共有的技術特徵,在其特徵在於之前(2.5 分); 特徵部分:獨權中,與區別於最接近的現有技術的技術特徵,在其特徵在於之後(2.5 分);引用部分:從權中引用的權利要求編號及主題 (2.5 分);限定部分:從權中附加技術特徵(2.5 分)。', 'fullscore': 10, 'reply': ' 前序部分:獨立權利要求中與現有技術相同的技術特徵 \n 特徵部分:獨立權利要求中區別於現有技術的技術特徵 \n 引用部分:從屬權利要求中引用其他權利要求的部分 \n 限定部分:對所引用的權利要求進一步限定的技術特徵 ', 'llmgetscore': 8, 'llmcomments': ' 學生的回答基本正確,對前序部分和特徵部分的解釋與標準答案相符,對引用部分和限定部分的理解也正確,但未完全表述出標準答案中的具體技術特徵順序和位置,因此給予 8 分。'}]

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。