Skip to content
15 changes: 15 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

# mac
.DS_Store

# python
__pycache__/
*.pyc

# IDE
.vscode/



# Environment
.env
22 changes: 22 additions & 0 deletions core/action.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from pydantic import BaseModel
from typing import Any


class Action(BaseModel):
thought:str
action:str
action_input:str
oberservation:str=""

def to_string(self,keep_thought_prefix=True):

if keep_thought_prefix:
thought_str="Thought: "+self.thought+"\n"
else:
thought_str=self.thought+"\n"

return thought_str+ \
"Action: "+self.action+"\n"+ \
"Action Input: "+self.action_input+"\n"+ \
"Observation: "+self.oberservation

9 changes: 7 additions & 2 deletions core/config.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import os
from dotenv import load_dotenv



class Config:

OPENAI_MODEL_BASIC = 'gpt-4o-mini'
OPENAI_MODEL_ADVANCED = 'gpt-4o'
OPENAI_MODEL_EXPERT = 'o1-preview'
os.environ['OPENAI_API_BASE'] = 'https://api.ohmygpt.com/v1/'
os.environ['OPENAI_API_KEY'] = ''
#os.environ['OPENAI_API_BASE'] = 'https://api.ohmygpt.com/v1/'
#os.environ['OPENAI_API_KEY'] = ''

load_dotenv()
4 changes: 2 additions & 2 deletions core/context_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class ContextManager:

def __init__(self):
self.context = {}

def get_context(self):
return self.context

Expand Down Expand Up @@ -30,4 +30,4 @@ def context_to_str(self):

def print_context(self):
print(f"Here is the context:")
print(self.contextToString())
print(self.context_to_str())
24 changes: 17 additions & 7 deletions core/llm_chat.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
from typing import Dict, Any
from typing import Dict, Any,List,Union
import re

from langchain_core.documents import Document
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
Expand All @@ -11,6 +12,7 @@
from langchain.globals import set_debug
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage

from core.config import Config
from core.pydantic_validator import PydanticValidator
Expand All @@ -20,9 +22,10 @@

set_debug(True)


class LLMChat:

def __init__(self, model_type = 'BASIC'):
def __init__(self, model_type = 'BASIC',validator=None):

if model_type == 'ADVANCED':
model = Config.OPENAI_MODEL_ADVANCED
Expand All @@ -31,9 +34,18 @@ def __init__(self, model_type = 'BASIC'):
else:
model = Config.OPENAI_MODEL_BASIC

self.chat = ChatOpenAI(model=model, temperature=0.1, verbose=True)
self.chat = ChatOpenAI(model=model, temperature=0.1,verbose=True)
self.chat_history_for_chain = ChatMessageHistory()

self.validator=validator

def one_time_respond_str(self, prompt):

output_parser = StrOutputParser()
chain = self.chat | output_parser
response = chain.invoke(prompt)
return response

def one_time_respond(self, request):
prompt = ChatPromptTemplate.from_messages(
[
Expand Down Expand Up @@ -200,7 +212,6 @@ def context_respond_with_tools(self, context_str, tools, messages_str):
"messages": messages,
}
)
validator = Validator()
try:
try:
answer_data = json.loads(result['answer'])
Expand All @@ -218,7 +229,7 @@ def context_respond_with_tools(self, context_str, tools, messages_str):
input_args = arguments
print(f"arg_definition: {arg_definition}")
print(f"input_args: {input_args}")
# validator.validate(input_args, arg_definition, validator.ARGUMENTS_NOT_MATCH) #TODO
# self.validator.validate(input_args, arg_definition, validator.ARGUMENTS_NOT_MATCH) #TODO
if not self._validate_arguments(input_args,arg_definition):
message_str = messages[0]
input_args_str = json.dumps(input_args)
Expand Down Expand Up @@ -272,9 +283,8 @@ def one_time_respond_with_validation(self, request):
],
}
)
validator = Validator()
try:
validator.validate(request, response, validator.CHECK_UNCERTAINTY)
self.validator.validate(request, response, self.validator.CHECK_UNCERTAINTY)
return response
except ValueError as error:
attempt += 1
Expand Down
44 changes: 31 additions & 13 deletions core/llm_validator.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import json
from typing import List,Union
import re

from typing_extensions import Annotated
from pydantic import BaseModel, ValidationError, AfterValidator, ValidationInfo

class LLMValidator:
from core.llm_chat import LLMChat

def create_validator_prompt(self, request, response):

prompt = f"""

class Validator(object):

def __init__(self,model_type = 'BASIC',tools=[]):

self.chat = LLMChat(model_type)


def create_validator_prompt(self,request,response):
prompt=f"""
You are an expert validator of AI-generated outputs. Evaluate the provided subtask output based on the following criteria:

1. **Accuracy** (Score 1-5): The output fulfills the requirements of the subtask accurately.
Expand All @@ -24,15 +32,20 @@ def create_validator_prompt(self, request, response):
- **Score (1-5)**
- **Justification:** A brief explanation for your score.

in following example:
1. **Accuracy (Score 5)**: The output correctly completed the task.

At the end:

- Calculate the **Total Score**.
- Provide a final recommendation:
- Provide a **Final Recommendation:**

- **Accept Output** if the total score is above 35 and no criterion scored below 3.
- **Rerun Subtask** if the total score is 35 or below, or if any criterion scored below 3.

- If recommending a rerun, provide suggestions on how to improve the output.
- If recommending a rerun, in **Suggestions** provide suggestions on how to improve the output.

You must follow the output format! Don't add additional symbol in section keys.

---

Expand All @@ -57,6 +70,7 @@ def parse_validation_response(self, validation_response):
else:
return "Undetermined"


def parse_scored_validation_response(self, validation_response):
scores = []
total_score = 0
Expand All @@ -82,18 +96,22 @@ def parse_scored_validation_response(self, validation_response):
else:
decision = "Rerun Subtask"

return decision, total_score, scores
# Final Recommendation
m=re.search(r"\*\*suggestions\*\*:?",validation_response.lower())
if m:
suggestions=validation_response[m.start():]
else:
suggestions=""

return decision, total_score, scores,suggestions

def validate(self, request, response):
prompt = self.create_validator_prompt(request, response)

from core.llm_chat import LLMChat
chat = LLMChat()

validation_response = chat.one_time_respond(prompt)
validation_response = self.chat.one_time_respond(prompt)

# validation_response = check_result['choices'][0]['message']['content']
return validation_response


# Example usage
if __name__ == "__main__":
Expand Down
88 changes: 69 additions & 19 deletions core/planner.py
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feel free to add new function in the planner, but please do not change the existing plan function because all the existing experiments are broken.

Original file line number Diff line number Diff line change
@@ -1,36 +1,86 @@
import json, re

from core.llm_chat import LLMChat
from core.step_manager import Step

from prompt.plan import PLAN_FORMAT
from prompt.plan import PLAN_FORMAT,RE_PLAN_FORMAT,LOW_LEVEL_PLANNER_FORMAT,REVIEW_FORMAT
from core.llm_chat import LLMChat


class Planner:

def __init__(self):
def __init__(self,model_type=None):
self.history_steps=[]
self.steps = []
self.chat = LLMChat(model_type)

def plan_with_template_format(self, request, background="",knowledge=""):

if knowledge:
knowledge=f"<knowledge>\n{knowledge}\n</knowledge>\n"

sys_prompt=PLAN_FORMAT.format(background=background,knowledge=knowledge)

response = self.chat.prompt_respond(request, sys_prompt).replace("```json", '').replace("```", '')
steps_data = json.loads(response)["steps"]
for i,step_data in enumerate(steps_data):
step = Step(i+1,step_data["step_name"], step_data["step_description"])
self.steps.append(step)
return self.steps[:]

def replan(self,request, completed_steps:list[Step], background="",knowledge=""):


if knowledge:
knowledge=f"<knowledge>\n{knowledge}\n</knowledge>\n"

original_plan_str="\n".join(str(step) for step in self.steps)
completed_steps_str="\n".join([step.get_context_str() for step in completed_steps])

def plan(self, request, **kwargs):

plan_content = ""
background = ""
if 'background' in kwargs:
background = kwargs['background']
plan_content += f"<background>\n{background}\n</background>\n"
knowledge = ""
if 'knowledge' in kwargs:
knowledge = kwargs['knowledge']
plan_content += f"<knowledge>\n{knowledge}\n</knowledge>\n"
plan_content += PLAN_FORMAT
critiqe_prompt=REVIEW_FORMAT.format(request=request,
original_plan=original_plan_str,completed_steps=completed_steps_str)
critique_response=self.chat.one_time_respond(critiqe_prompt)

chat = LLMChat()


prompt=RE_PLAN_FORMAT.format(background=background,knowledge=knowledge,request=request,
original_plan=original_plan_str,completed_steps=completed_steps_str,criteque=critique_response)



response = chat.prompt_respond(request, plan_content).replace("```json", '').replace("```", '')
response = self.chat.one_time_respond(prompt).replace("```json", '').replace("```", '')
steps_data = json.loads(response)["steps"]

self.history_steps.append(self.steps)

remaining_steps=[]

for i,step_data in enumerate(steps_data):
step = Step(len(completed_steps)+i+1,step_data["step_name"], step_data["step_description"])
remaining_steps.append(step)

self.steps=completed_steps+remaining_steps

return remaining_steps


def low_level_plan(self,request, step:Step,tools):
tool_descriptions="\n".join([f"{tool.name}: {tool.description}" for tool in tools])
prompt=LOW_LEVEL_PLANNER_FORMAT.format(request=request,step=step,tools=tool_descriptions)


response = self.chat.one_time_respond(prompt).replace("```json", '').replace("```", '')
steps_data = json.loads(response)["steps"]

sub_steps=[]

for step_data in steps_data:
step = Step(step_data["step_name"], step_data["step_description"])
self.steps.append(step)
return self.steps
sub_step = Step(step_data["step_name"], step_data["step_description"])
sub_steps.append(sub_step)

step.add_sub_steps(sub_steps)
return step


def extract_steps(plan_string):
# Define an empty list to store the steps
Expand Down
Loading