Which Task and Agent Attributes Can Be Put in the YAML File?

Hi everyone,

This solution I’m going to present aims to clarify how to use the tools and llm attributes in the YAML configuration files for agents.

Understanding the problem

When replicating the problem, you’ll basically encounter an error in a dictionary key, specifically in the crewai/project/crew_base.py file. Let’s look at the first lines of the method that raises the exception:

def map_agent_variables(
    self,
    agent_name: str,
    agent_info: Dict[str, Any],
    agents: Dict[str, Callable],
    llms: Dict[str, Callable],
    tool_functions: Dict[str, Callable],
    cache_handler_functions: Dict[str, Callable],
    callbacks: Dict[str, Callable],
) -> None:
    if llm := agent_info.get("llm"):
        try:
            self.agents_config[agent_name]["llm"] = llms[llm]()
        except KeyError:
            self.agents_config[agent_name]["llm"] = llm
    if tools := agent_info.get("tools"):
        self.agents_config[agent_name]["tools"] = [
            tool_functions[tool]() for tool in tools
        ]

Ok, let’s see what it does with the llm attribute from the YAML. It first searches for a key with the name you set to llm (a string). If it finds this key in the llms dict, then it runs the callable associated with that key. If the string you provided is not a key (which happens often since llms = {} by default), then it simply uses that string as the model parameter for a crewai.LLM object later. If you don’t believe me, go read the code yourself. :smiling_face:

And what about the tools parameter from the YAML, which is a list of strings? Well, it tests each string as a key in the tools dict then it runs the callable associated with that key.

Finding the solution

The llms and tools dicts are populated in a scan that’s done in a previous method named map_all_agent_variables, which I’ll omit. This method scans the decorators that are defined in crewai/project/__init__.py.

You’re certainly already used to saying from crewai.project import CrewBase, agent, task, crew, the new thing is that you can (and should) say from crewai.project import tool, llm. That’s the key insight.

Once you do this, the callables decorated with @tool will be automatically listed in the tools dict and so the callables decorated with @llm will be automatically listed in the llms dict. This is elegant.

Semi-functional example

File max_agents.yaml:

max_agent:
  role: >
    Max Role
  goal: >
    Max Goal
  backstory: >
    Max Backstory
  verbose: true
  llm: max_llm
  tools:
    - max_tool

File max_tasks.yaml:

max_task:
  description: >
    Max's question is: {user_question}
  expected_output: >
    Max answer
  agent: max_agent

File crew.py:

from crewai import Agent, Crew, Task, Process, LLM
from crewai.project import CrewBase, agent, task, crew, tool, llm
from crewai.tools import BaseTool
from crewai_tools import DirectoryReadTool
import os

os.environ['LLM_API_KEY'] = 'YOUR_KEY_NOT_MINE'

@CrewBase
class MaxCrew:
    agents_config = 'max_agents.yaml' 
    tasks_config = 'max_tasks.yaml'
    
    @agent
    def max_agent(self) -> Agent:
        return Agent(
            config=self.agents_config['max_agent'],
        )
    
    @task
    def max_task(self) -> Task:
        return Task(
            config=self.tasks_config['max_task'],
        )
    
    @tool
    def max_tool(self) -> BaseTool:
        return DirectoryReadTool(directory='./')
    
    @llm
    def max_llm(self) -> LLM:
        return LLM(
            model='max/maxgpt-999b-chat',
            temperature=0.7,
            timeout=90,
            max_tokens=512,
        )
    
    @crew
    def crew(self) -> Crew:
        return Crew(
            agents=self.agents,
            tasks=self.tasks,
            process=Process.sequential,
            verbose=True,
        )

Suggestions

I suggest that the CrewAI team enriches the documentation on this topic and perhaps even make the crewai create crew command add this import to the crew.py file, as this would encourage the use of this approach.

4 Likes