Hanah

Hanah

wow-agent-day03 OpenAIによる採点AIの実現

Reference: 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"エラーが発生しました: {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 点を与えます。'}]

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。