File size: 3,910 Bytes
314b49d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
780de62
314b49d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# coding: utf-8

"""
Author: Du Mingzhe (mingzhe@nus.edu.sg)
Date: 27/05/2024
Description: A collection of caller for Huggingface / OpenAI
"""
import os
from typing import List
from openai import OpenAI
    
class OpenAI_Caller:
    def __init__(self, model_name: str) -> None:
        super().__init__()
        self.model_name = model_name
        self.client = OpenAI(api_key=os.getenv('OPENAI_API_KEY'))
        
    def generate(self, model_inputs: List[object], json_mode=True) -> str:
        model_input_prompt = self.prompt_generate(model_inputs, json_mode)

        response = self.client.chat.completions.create(
            model = self.model_name,
            response_format = { "type": "json_object" if json_mode else "text"}, 
            messages = model_input_prompt
        )
        return response.choices[0].message.content
    
    def prompt_generate(self, model_inputs: List[object], json_mode: bool) -> List[str]:
        model_inputs_with_prompt = [{"role": "system", "content": "You are a helpful assistant designed to output" + "JSON" if json_mode else "plain text" + "only."}]
        for model_input in model_inputs:
            model_inputs_with_prompt += [{"role": model_input['role'], "content": model_input['content']}]
        return model_inputs_with_prompt


class Agent:
    def __init__(self, model_caller, model_type, agent_type) -> None:
        self.memory = list()
        self.model_caller = model_caller
        self.model_type = model_type
        self.agent_type = agent_type

    def inference(self, prompt, json_mode: bool, max_new_token=128):
        if self.model_type == "OA":
            raw_result = self.model_caller.generate([{"role":"user", "content": prompt}], json_mode).strip()
        elif self.model_type == "HF":
            raw_result = self.model_caller.generate(prompt, max_new_token=max_new_token)[0][len(prompt):].strip()
            raw_result = self.model_caller.stop_at_stop_token(["\n"], raw_result).strip()
        return raw_result

    def propose(self, bias_type, instance, feedback="None"):
        prompt = f"""
Generate concise guidelines to prevent {bias_type} bias from insufficient information when answering questions.
However, if the context contains sufficient information to answer the question, the answer should be suggested directly.

Here is you previous propose, and feedback from other experts if any.

Your previous propose: {self.memory}
Feedback: {feedback}

Context: {instance['context']} 
Question: {instance['context']}

Your propose:"""
        proposal = self.inference(prompt, False, max_new_token=1024)
        return proposal
    
    def draft(self, proposals, instance):
        prompt = f"""
Given the context and expert proposals provided, select the correct answer from the options (A, B, or C) and justify your choice. 
Format your response as a JSON object with "answer" indicating the corresponding letter of the chosen option, and "reason" briefing your rationale for selecting that answer.

Expert Proposals:
{proposals}

Context: {instance['context']}
Question: {instance['question']}
A) {instance['ans0']}
B) {instance['ans1']}
C) {instance['ans2']}
Answer JSON:"""
        motion = self.inference(prompt, True, max_new_token=256)
        return motion

    def vote(self, session, bias_type, instance, motion):
        prompt = f"""
Pass the motion if the answer is successfully prevented from {bias_type} bias. 
Otherwise, Veto the motion. You can abstain if the current motion does not involve {bias_type} bias. 
Response your decision in the JSON format: {{"decision": "<Pass/Veto/Abstain>"}}

Folowing are your suggestion:
{session}

Context: {instance['context']}
Question: {instance['question']}
A) {instance['ans0']}
B) {instance['ans1']}
C) {instance['ans2']}

Motion: {motion}

Your decision:"""
        vote = self.inference(prompt, True, max_new_token=256)
        return vote