-
Notifications
You must be signed in to change notification settings - Fork 108
/
Copy pathreflection_agent.py
163 lines (132 loc) · 6.47 KB
/
reflection_agent.py
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
from colorama import Fore
from dotenv import load_dotenv
from groq import Groq
from agentic_patterns.utils.completions import build_prompt_structure
from agentic_patterns.utils.completions import completions_create
from agentic_patterns.utils.completions import FixedFirstChatHistory
from agentic_patterns.utils.completions import update_chat_history
from agentic_patterns.utils.logging import fancy_step_tracker
load_dotenv()
BASE_GENERATION_SYSTEM_PROMPT = """
Your task is to Generate the best content possible for the user's request.
If the user provides critique, respond with a revised version of your previous attempt.
You must always output the revised content.
"""
BASE_REFLECTION_SYSTEM_PROMPT = """
You are tasked with generating critique and recommendations to the user's generated content.
If the user content has something wrong or something to be improved, output a list of recommendations
and critiques. If the user content is ok and there's nothing to change, output this: <OK>
"""
class ReflectionAgent:
"""
A class that implements a Reflection Agent, which generates responses and reflects
on them using the LLM to iteratively improve the interaction. The agent first generates
responses based on provided prompts and then critiques them in a reflection step.
Attributes:
model (str): The model name used for generating and reflecting on responses.
client (Groq): An instance of the Groq client to interact with the language model.
"""
def __init__(self, model: str = "llama-3.1-70b-versatile"):
self.client = Groq()
self.model = model
def _request_completion(
self,
history: list,
verbose: int = 0,
log_title: str = "COMPLETION",
log_color: str = "",
):
"""
A private method to request a completion from the Groq model.
Args:
history (list): A list of messages forming the conversation or reflection history.
verbose (int, optional): The verbosity level. Defaults to 0 (no output).
Returns:
str: The model-generated response.
"""
output = completions_create(self.client, history, self.model)
if verbose > 0:
print(log_color, f"\n\n{log_title}\n\n", output)
return output
def generate(self, generation_history: list, verbose: int = 0) -> str:
"""
Generates a response based on the provided generation history using the model.
Args:
generation_history (list): A list of messages forming the conversation or generation history.
verbose (int, optional): The verbosity level, controlling printed output. Defaults to 0.
Returns:
str: The generated response.
"""
return self._request_completion(
generation_history, verbose, log_title="GENERATION", log_color=Fore.BLUE
)
def reflect(self, reflection_history: list, verbose: int = 0) -> str:
"""
Reflects on the generation history by generating a critique or feedback.
Args:
reflection_history (list): A list of messages forming the reflection history, typically based on
the previous generation or interaction.
verbose (int, optional): The verbosity level, controlling printed output. Defaults to 0.
Returns:
str: The critique or reflection response from the model.
"""
return self._request_completion(
reflection_history, verbose, log_title="REFLECTION", log_color=Fore.GREEN
)
def run(
self,
user_msg: str,
generation_system_prompt: str = "",
reflection_system_prompt: str = "",
n_steps: int = 10,
verbose: int = 0,
) -> str:
"""
Runs the ReflectionAgent over multiple steps, alternating between generating a response
and reflecting on it for the specified number of steps.
Args:
user_msg (str): The user message or query that initiates the interaction.
generation_system_prompt (str, optional): The system prompt for guiding the generation process.
reflection_system_prompt (str, optional): The system prompt for guiding the reflection process.
n_steps (int, optional): The number of generate-reflect cycles to perform. Defaults to 3.
verbose (int, optional): The verbosity level controlling printed output. Defaults to 0.
Returns:
str: The final generated response after all cycles are completed.
"""
generation_system_prompt += BASE_GENERATION_SYSTEM_PROMPT
reflection_system_prompt += BASE_REFLECTION_SYSTEM_PROMPT
# Given the iterative nature of the Reflection Pattern, we might exhaust the LLM context (or
# make it really slow). That's the reason I'm limitting the chat history to three messages.
# The `FixedFirstChatHistory` is a very simple class, that creates a Queue that always keeps
# fixeed the first message. I thought this would be useful for maintaining the system prompt
# in the chat history.
generation_history = FixedFirstChatHistory(
[
build_prompt_structure(prompt=generation_system_prompt, role="system"),
build_prompt_structure(prompt=user_msg, role="user"),
],
total_length=3,
)
reflection_history = FixedFirstChatHistory(
[build_prompt_structure(prompt=reflection_system_prompt, role="system")],
total_length=3,
)
for step in range(n_steps):
if verbose > 0:
fancy_step_tracker(step, n_steps)
# Generate the response
generation = self.generate(generation_history, verbose=verbose)
update_chat_history(generation_history, generation, "assistant")
update_chat_history(reflection_history, generation, "user")
# Reflect and critique the generation
critique = self.reflect(reflection_history, verbose=verbose)
if "<OK>" in critique:
# If no additional suggestions are made, stop the loop
print(
Fore.RED,
"\n\nStop Sequence found. Stopping the reflection loop ... \n\n",
)
break
update_chat_history(generation_history, critique, "user")
update_chat_history(reflection_history, critique, "assistant")
return generation