Hi all,
We are creating a crew whose job it is to assist with user queries. The crew consist of a coordinator agent (CA), an analyzer agent (AA), and five specialist agents (SA1-5). Each of these has one task, all of them described in a config YAML file.
The idea is for it to work as follows:
- The CA receives the user query. The agent’s task is defined as a sequence of steps that should be followed exactly, and that involves calling first the AA and then one of the SA.
- Knowing the user query, the CA first asks the AA, whose task is specified as to determine (1) the nature of the query, which can be one of two things (X or Y), and (2) the SA required for the query. It outputs this information.
- Once the CA knows (1) and (2) above, it asks the required SA, whose task is specified as to give give information about either X or Y (depending on the output of the AA) in its field of knowledge. It outputs this information.
- Once the SA has formulated its answer, the CA returns it to the user.
The problem we are encountering is with the execution of tasks. Debugging shows that:
- The CA is called and its task is executed properly
- The AA is called and its task is also executed properly
- The SA is called but it task is ignored - rather, it seems that the CA just decides to come up with its own task for the SA. This is not good: the task as defined should also be executed.
As far as we can see, in the code, the Tasks and Agents are set up correctly (see the code example below). Furthermore, the attributes role
, goal
, and backstory
for the Agent
s are defined in a YAML config file, as are the attributes description
and expected_output
for the Task
s. It’s important to note that a lot of time has gone into prompt engineering, i.e., wording these attributes as completely and clearly as possible.
Our assumption was that this setup - Agent
s are defined to have Task
s, and operate in a context
- is sufficient for an agent’s task to be executed whenever the agent is called. But this obviously is not the case - rather, it seems that we can’t fully hardcode it, and that the CA has the ‘last word’, in our case deciding not to execute the SA’s task.
Are we missing something, or are we approaching this completely wrong? How can we ensure that the SA’s task is always executed, and more specifically, that all tasks are always executed?
Minimal code example:
@CrewBase
class MyCrew:
agents_config = 'config/agents.yaml'
tasks_config = 'config/tasks.yaml'
@agent
def coordinator(self) -> Agent:
return Agent(
config=self.agents_config['coordinator'],
allow_delegation=True,
respect_context_window=True,
...
)
@task
def answer(self) -> Task:
return Task(
config=self.tasks_config['answer'],
agent=self.coordinator(),
context=[self.analyze()]
...
)
@agent
def analyzer(self) -> Agent:
return Agent(
config=self.agents_config['analyzer'],
allow_delegation=False,
respect_context_window=False,
...
)
@task
def analyze(self) -> Task:
return Task(
config=self.tasks_config['analyze'],
agent=self.analyzer(),
...
)
@agent
def specialist_1(self) -> Agent:
return Agent(
config=self.agents_config['specialist_1'],
allow_delegation=False,
respect_context_window=True,
...
)
@task
def provide_specialist_advice_1(self) -> Task:
return Task(
config=self.tasks_config['provide_specialist_advice_1'],
agent=self.specialist_1(),
context=[self.analyze()],
...
)
@crew
def build_crew(self) -> Crew:
coordinator_agent = self.coordinator()
agents = [
self.analyzer(),
self.specialist_1(),
self.specialist_2(),
self.specialist_3(),
self.specialist_4(),
self.specialist_5(),
]
tasks = [
self.answer()
]
crew = Crew(
agents=agents,
tasks=tasks,
process=Process.sequential,
manager_agent=coordinator_agent,
verbose=True
)
return crew