My implementation is a Flask app where the user can drive the UI through natural language. My agents are the top-level “decider” agent, and sub-agents that are meant to handle different UI interactions (think panning and zooming vs. editing a feature in the view in some kind of graphics program, for example).
All prompts from a user are sent to an /ask
route, which calls the listen()
function of the decider agent. This agent class holds a reference to an OpenAI client and has tools
and a system_message
defined as I mentioned in my earlier post. This agent sends a request to OpenAI to choose the agent by returning the agent name.
For each possible agent response, I have other “agent” Flask routes defined. Client side (i.e. in JavaScript), I take the agent name response from the /ask
route and based on what it returns, send it to the appropriate agent route. These routes call their respective listen()
functions of the agent classes, which have thier own reference to the OpenAI client, system messages, and tools defined that take the appropriate action the user requested. I then take the JSON response (every agent defined uses function calling) and act on it in the UI.
Here’s an example decider agent class as described:
import json
import logging
logger = logging.getLogger(__name__)
class DeciderAgent:
"""A Decider agent that has function descriptions for choosing the appropriate agent for a specified task."""
def __init__(self, client, model_version):
self.model_version = model_version
self.client = client
self.tools = [
{
"type": "function",
"function": {
"name": "choose_agent",
"description": """Chooses an appropriate agent for a given task.""",
"parameters": {
"type": "object",
"properties": {
"agent_name": {
"type": "string",
"description": "The name of the agent to choose. One of 'NavigationAgent', 'EditAgent'.",
},
},
"required": ["agent_name"],
},
},
},
]
self.system_message = """You are a helpful assistant that decides which agent to use for a specified task related to navigating a graphics program and editing objects in the program.
For tasks related to navigating the program, such as panning, zooming, or rotating the view, you will use the NavigationAgent.
Example NavigationAgent prompts include 'pan left some', 'zoom in', 'pan up 5 units', 'zoom in two times', 'rotate the view 23 degrees clockwise', and 'tilt the view 45 degrees'
For tasks that edit an object, such as changing the opacity, color, or size of an object, you will use the EditAgent.
Example EditAgent prompts include 'make the object harder to see', 'change color to green', 'opacity 45%', and 'move the selected object 4 units to the left'.
"""
#initialize the messages queue with the system message
self.messages = [{"role": "system", "content": self.system_message}]
self.available_functions = {
"choose_agent": self.choose_agent,
}
def choose_agent(self, agent_name):
return {"name": "choose_agent", "agent_name": agent_name}
def listen(self, message):
logger.info(f"In DeciderAgent.listen()...message is: {message}")
"""Listen to a message from the user."""
self.messages.append({
"role": "user",
"content": message,
})
# this will be the function the model will choose if it
# determines that the user wants to call a function
function_response = None
try:
response = self.client.chat.completions.create(
model=self.model_version,
messages=self.messages,
tools=self.tools,
tool_choice={"type": "function", "function": {"name": "choose_agent"}},
)
response_message = response.choices[0].message
tool_calls = response_message.tool_calls
if tool_calls:
available_functions = self.available_functions
self.messages.append(response_message)
for tool_call in tool_calls:
function_name = tool_call.function.name
function_to_call = available_functions[function_name]
function_args = json.loads(tool_call.function.arguments)
function_response = function_to_call(**function_args)
self.messages.append(
{
"tool_call_id": tool_call.id,
"role": "tool",
"name": function_name,
"content": json.dumps(function_response),
}
)
logger.info(f"Sucessful DeciderAgent task completion: {function_response}")
return {"response": function_response}
except Exception as e:
return {"error": "Failed to get response from OpenAI in DeciderAgent: " + str(e)}, 500
return {"response": function_response}
Let me know if you have any questions. I’ll do my best to answer with the time I have.