使用crewai创建属于你自己的AI团队

crewai介绍

CrewAI 是一个用于协调自主 AI 代理的前沿框架。

CrewAI 允许你创建 AI 团队,其中每个代理都有特定的角色、工具和目标,协同工作以完成复杂任务。

把它想象成组建你的梦之队------每个成员(代理)都带来独特的技能和专业知识,无缝协作以实现你的目标。

最近使用了crewai这个框架,我觉得是一个比较好用的AI Agent框架,因此推荐给大家。

在crewai中涵盖了AgentsTasksCrewsFlowsKnowledgeLLMsTools等这些核心概念。

接下来我将以一个具体的例子,介绍一下crewai的使用。

crewai的GitHub地址为:github.com/crewAIInc/c...

使用crewai构建一个翻译代理

创建一个python虚拟环境,安装crewai与crewai-tools。

运行命令:

lua 复制代码
crewai create crew translation_agent

会出现一个模板项目。

在config目录下,使用yaml配置agent与task:

先来设置一下代理:

yaml 复制代码
file_reader:
  role: >
    读取文件代理
  goal: >
    根据文件路径,读取文件内容
  backstory: >
    你是一个文件读取代理,你的任务是根据文件路径,读取文件内容
​
translation_agent:
  role: >
    翻译代理
  goal: >
    根据用户需求翻译文本
  backstory: >
    你是一个翻译代理,你的任务是根据用户需求翻译文本
​
file_saver:
  role: >
    文件保存代理
  goal: >
    根据用户需求保存文件
  backstory: >
    你是一个文件保存代理,你的任务是根据用户需求保存文件

在这里设置了三个代理,分别是读取文件代理、翻译代理与文件保存代理。

再来配置一下task:

yaml 复制代码
file_read_task:
  description: >
    根据用户需求:{question}
    获取需要读取的文件路径
    使用工具读取文件内容
  expected_output: >
    返回文件内容
  agent: file_reader
​
translation_task:
  description: >
    根据file_reader获取的文件内容,将文本翻译成英文
  expected_output: >
    返回翻译后的文本内容
  agent: translation_agent
​
file_save_task:
  description: >
   根据用户需求:{question}提取出需要保存到的文件路径及相关信息
   将translation_agent的翻译内容,保存至指定文件
  expected_output: >
    返回保存结果
  agent: file_saver

设置了三个任务,分别是file_read_task、translation_task与file_save_task。

完成这些任务,需要代理能够使用读取文件与保存文件的工具。

在tools目录下可以写工具代码:

file_read_tool工具代码:

python 复制代码
from typing import Any, Optional, Type
​
from crewai.tools import BaseTool
from pydantic import BaseModel, Field
​
​
class FileReadToolSchema(BaseModel):
    """Input for FileReadTool."""
​
    # Mandatory file full path to read the file
    # 必须的文件全路径,以读取文件
    file_path: str = Field(..., description="Mandatory file full path to read the file")
​
​
class FileReadTool(BaseTool):
    """A tool for reading file contents.
​
    This tool inherits its schema handling from BaseTool to avoid recursive schema
    definition issues. The args_schema is set to FileReadToolSchema which defines
    the required file_path parameter. The schema should not be overridden in the
    constructor as it would break the inheritance chain and cause infinite loops.
​
    The tool supports two ways of specifying the file path:
    1. At construction time via the file_path parameter
    2. At runtime via the file_path parameter in the tool's input
​
    Args:
        file_path (Optional[str]): Path to the file to be read. If provided,
            this becomes the default file path for the tool.
        **kwargs: Additional keyword arguments passed to BaseTool.
​
    Example:
        >>> tool = FileReadTool(file_path="/path/to/file.txt")
        >>> content = tool.run()  # Reads /path/to/file.txt
        >>> content = tool.run(file_path="/path/to/other.txt")  # Reads other.txt
​
    用于读取文件内容的工具。
​
    该工具继承自 BaseTool 的 schema 处理,以避免递归 schema 定义问题。args_schema 设置为 FileReadToolSchema,定义了必需的 file_path 参数。构造函数中不应该覆盖 schema,否则会破坏继承链并导致无限循环。
​
    该工具支持两种指定文件路径的方法:
​
    在构造时通过 file_path 参数
    在运行时通过工具的输入参数 file_path
​
    参数:
    file_path (可选[str]): 要读取的文件路径。如果提供,则成为工具的默认文件路径。
    **kwargs: 传递给 BaseTool 的其他关键字参数。
​
    示例:
    >>> tool = FileReadTool(file_path="/path/to/file.txt")
    >>> content = tool.run()  # 读取 /path/to/file.txt
    >>> content = tool.run(file_path="/path/to/other.txt")  # 读取 other.txt
    """
​
    name: str = "Read a file's content"
    description: str = "A tool that reads the content of a file. To use this tool, provide a 'file_path' parameter with the path to the file you want to read."
    args_schema: Type[BaseModel] = FileReadToolSchema
    file_path: Optional[str] = None
​
    def __init__(self, file_path: Optional[str] = None, **kwargs: Any) -> None:
        """
        Initialize the FileReadTool.
​
        Args:
            file_path (Optional[str]): Path to the file to be read. If provided,
                this becomes the default file path for the tool.
            **kwargs: Additional keyword arguments passed to BaseTool.
​
        初始化 FileReadTool。
​
        参数:
        file_path(可选[str]):要读取的文件路径。如果提供,则此路径成为工具的默认文件路径。
        **kwargs:传递给 BaseTool 的其他关键字参数。
        """
​
        if file_path is not None:
            kwargs['description'] = f"A tool that reads file content. The default file is {file_path}, but you can provide a different 'file_path' parameter to read another file."
​
        super().__init__(**kwargs)
        self.file_path = file_path
​
    def _run(
        self,
        **kwargs: Any,
    ) -> str:
        file_path = kwargs.get("file_path", self.file_path)
        if file_path is None:
            return "Error: No file path provided. Please provide a file path either in the constructor or as an argument."
​
        try:
            with open(file_path, "r",encoding='utf-8') as file:
                return file.read()
        except FileNotFoundError:
            return f"Error: File not found at path: {file_path}"
        except PermissionError:
            return f"Error: Permission denied when trying to read file: {file_path}"
        except Exception as e:
            return f"Error: Failed to read file {file_path}. {str(e)}"

file_writer_tool工具代码:

python 复制代码
import os
from ast import literal_eval
from typing import Any, Optional, Type
​
from crewai.tools import BaseTool
from pydantic import BaseModel
​
​
class FileWriterToolInput(BaseModel):
    filename: str
    directory: Optional[str] = "./"
    overwrite: str = "False"
    content: str
​
​
class FileWriterTool(BaseTool):
    name: str = "File Writer Tool"
    description: str = "A tool to write content to a specified file. Accepts filename, content, and optionally a directory path and overwrite flag as input,overwrite flag is True or False."
    args_schema: Type[BaseModel] = FileWriterToolInput
​
    def _run(self, **kwargs: Any) -> str:
        try:
            # Create the directory if it doesn't exist
            if kwargs.get("directory") and not os.path.exists(kwargs["directory"]):
                os.makedirs(kwargs["directory"])
​
            # Construct the full path
            filepath = os.path.join(kwargs.get("directory") or "", kwargs["filename"])
​
            # Convert overwrite to boolean
            kwargs["overwrite"] = bool(literal_eval(kwargs["overwrite"]))
​
            # Check if file exists and overwrite is not allowed
            if os.path.exists(filepath) and not kwargs["overwrite"]:
                return f"File {filepath} already exists and overwrite option was not passed."
​
            # Write content to the file
            mode = "w" if kwargs["overwrite"] else "x"
            with open(filepath, mode) as file:
                content = kwargs["content"]
                file.write(content)
            return f"Content successfully written to {filepath}"
        except FileExistsError:
            return (
                f"File {filepath} already exists and overwrite option was not passed."
            )
        except KeyError as e:
            return f"An error occurred while accessing key: {str(e)}"
        except Exception as e:
            return f"An error occurred while writing to the file: {str(e)}"

现在需要构建一个团队。

构建团队的代码:

python 复制代码
from crewai import Agent, Crew, Process, Task,LLM
from crewai.project import CrewBase, agent, crew, task
from translation_agent.tools.file_read_tool import FileReadTool
from translation_agent.tools.file_writer_tool import FileWriterTool
import os
from dotenv import load_dotenv
load_dotenv()
​
file_read_tool = FileReadTool()
file_writer_tool = FileWriterTool()
​
api_key = os.getenv('OPENAI_API_KEY')
base_url = os.getenv('OPENAI_API_BASE')
model = os.getenv('OPENAI_MODEL_NAME', 'Qwen/Qwen2.5-72B-Instruct')  # Provide a default model if not set
agent_llm = LLM(
    model=model,
    base_url=base_url,
    api_key=api_key
    )
​
# If you want to run a snippet of code before or after the crew starts, 
# you can use the @before_kickoff and @after_kickoff decorators
# https://docs.crewai.com/concepts/crews#example-crew-class-with-decorators
​
​
@CrewBase
class TranslationAgent():
    """TranslationAgent crew"""
​
    # Learn more about YAML configuration files here:
    # Agents: https://docs.crewai.com/concepts/agents#yaml-configuration-recommended
    # Tasks: https://docs.crewai.com/concepts/tasks#yaml-configuration-recommended
    agents_config = 'config/agents.yaml'
    tasks_config = 'config/tasks.yaml'
    
    # If you would like to add tools to your agents, you can learn more about it here:
    # https://docs.crewai.com/concepts/agents#agent-tools
    # @agent
    # def researcher(self) -> Agent:
    #   return Agent(
    #       config=self.agents_config['researcher'],
    #       verbose=True
    #   )
​
    # @agent
    # def reporting_analyst(self) -> Agent:
    #   return Agent(
    #       config=self.agents_config['reporting_analyst'],
    #       verbose=True
    #   )
    
    @agent
    def file_reader(self) -> Agent:     
        return Agent(
            config=self.agents_config['file_reader'],
            verbose=True,
            llm=agent_llm,
            tools=[file_read_tool],
        )
    
    @agent
    def translation_agent(self) -> Agent:       
        return Agent(
            config=self.agents_config['translation_agent'],
            verbose=True,
            llm=agent_llm,      
        )
    
    @agent
    def file_saver(self) -> Agent:      
        return Agent(
            config=self.agents_config['file_saver'],
            verbose=True,
            llm=agent_llm,
            tools=[file_writer_tool],
        )
    
    # To learn more about structured task outputs, 
    # task dependencies, and task callbacks, check out the documentation:
    # https://docs.crewai.com/concepts/tasks#overview-of-a-task
    @task
    def file_read_task(self) -> Task:
        return Task(
            config=self.tasks_config['file_read_task'],
        )
​
    @task
    def translation_task(self) -> Task:
        return Task(
            config=self.tasks_config['translation_task'],
        )
    
    @task
    def file_save_task(self) -> Task:
        return Task(
            config=self.tasks_config['file_save_task'],
        )
​
    @crew
    def crew(self) -> Crew:
        """Creates the TranslationAgent crew"""
        # To learn how to add knowledge sources to your crew, check out the documentation:
        # https://docs.crewai.com/concepts/knowledge#what-is-knowledge
​
        return Crew(
            agents=self.agents, # Automatically created by the @agent decorator
            tasks=self.tasks, # Automatically created by the @task decorator
            process=Process.sequential,
            verbose=True,
            # process=Process.hierarchical, # In case you wanna use that instead https://docs.crewai.com/how-to/Hierarchical/
        )

其中我想让代理使用硅基流动的模型可以这样写:

需要在模型名称前加上openai才行,不如会报错。

如果你还没注册的话,可以点击邀请链接进行注册:cloud.siliconflow.cn/i/Ia3zOSCU

这里我以具有工具调用能力的meta-llama/Llama-3.3-70B-Instruct为例。

然后可以这样使用:

ini 复制代码
import os
from dotenv import load_dotenv
load_dotenv()
​
file_read_tool = FileReadTool()
file_writer_tool = FileWriterTool()
​
api_key = os.getenv('OPENAI_API_KEY')
base_url = os.getenv('OPENAI_API_BASE')
model = os.getenv('OPENAI_MODEL_NAME', 'Qwen/Qwen2.5-72B-Instruct')  # Provide a default model if not set
agent_llm = LLM(
    model=model,
    base_url=base_url,
    api_key=api_key
    )

在创建代理时,记得使用这个大模型,并且记得使用工具:

ini 复制代码
@agent
def file_reader(self) -> Agent:     
        return Agent(
            config=self.agents_config['file_reader'],
            verbose=True,
            llm=agent_llm,
            tools=[file_read_tool],
        )

这样这个团队就构建成功了。

在main.py中这样写:

python 复制代码
#!/usr/bin/env python
import sys
import warnings
​
from datetime import datetime
​
from translation_agent.crew import TranslationAgent
​
warnings.filterwarnings("ignore", category=SyntaxWarning, module="pysbd")
​
# This main file is intended to be a way for you to run your
# crew locally, so refrain from adding unnecessary logic into this file.
# Replace with inputs you want to test with, it will automatically
# interpolate any tasks and agents information
​
def run():
    """
    Run the crew.
    """
    inputs = {
        'question': '读取test.txt文件内容,将其翻译为英文,然后写入test4.txt文件',
    }
    
    try:
        TranslationAgent().crew().kickoff(inputs=inputs)
    except Exception as e:
        raise Exception(f"An error occurred while running the crew: {e}")
​
​
def train():
    """
    Train the crew for a given number of iterations.
    """
    inputs = {
        "topic": "AI LLMs"
    }
    try:
        TranslationAgent().crew().train(n_iterations=int(sys.argv[1]), filename=sys.argv[2], inputs=inputs)
​
    except Exception as e:
        raise Exception(f"An error occurred while training the crew: {e}")
​
def replay():
    """
    Replay the crew execution from a specific task.
    """
    try:
        TranslationAgent().crew().replay(task_id=sys.argv[1])
​
    except Exception as e:
        raise Exception(f"An error occurred while replaying the crew: {e}")
​
def test():
    """
    Test the crew execution and returns the results.
    """
    inputs = {
        "topic": "AI LLMs"
    }
    try:
        TranslationAgent().crew().test(n_iterations=int(sys.argv[1]), openai_model_name=sys.argv[2], inputs=inputs)
​
    except Exception as e:
        raise Exception(f"An error occurred while testing the crew: {e}")

主要关注这里:

python 复制代码
def run():
    """
    Run the crew.
    """
    inputs = {
        'question': '读取test.txt文件内容,将其翻译为英文,然后写入test4.txt文件',
    }
    
    try:
        TranslationAgent().crew().kickoff(inputs=inputs)
    except Exception as e:
        raise Exception(f"An error occurred while running the crew: {e}")

在inputs中输入task中的question占位符的内容。

现在创建一个test.txt,输入内容为:

CrewAI:用于编排复杂 AI 代理系统的生产级框架。从简单的自动化到复杂的现实世界应用,CrewAI 提供精确控制和深度定制。通过灵活的、可投入生产的架构促进协作智能,CrewAI 使代理能够无缝协作,以可预测和一致的结果解决复杂的商业挑战。

现在输入crewai run,看看这个翻译代理的效果。

可以发现读取文件代理做的不够好的地方是多了一些内容。

需要进行改进。

改成这样再试试:

yaml 复制代码
file_reader:
  role: >
    读取文件代理
  goal: >
    根据文件路径,读取文件内容
  backstory: >
    你是一个文件读取代理,你的任务是根据文件路径,读取文件内容,只需返回文件内容即可

现在效果就很好了,如下所示:

翻译代理很好地进行翻译了,如下所示:

文件保存代理将翻译结果进行保存,如下所示:

最后

这就是使用crewai构建一个翻译代理的步骤与效果。在crewai中还有很多很有趣的工具值得探索,下期介绍代码解释器工具的使用。

相关推荐
青松@FasterAI6 分钟前
【Arxiv 大模型最新进展】PEAR: 零额外推理开销,提升RAG性能!(★AI最前线★)
人工智能
huoyingcg12 分钟前
武汉火影数字|VR沉浸式空间制作 VR大空间打造
人工智能·科技·vr·虚拟现实·增强现实
冷冷清清中的风风火火27 分钟前
本地部署DeepSeek的硬件配置建议
人工智能·ai
sauTCc36 分钟前
RAG实现大致流程
人工智能·知识图谱
lqqjuly1 小时前
人工智能驱动的自动驾驶:技术解析与发展趋势
人工智能·机器学习·自动驾驶
山东布谷科技官方1 小时前
AI大模型发展对语音直播交友系统源码开发搭建的影响
人工智能·实时音视频·交友
thinkMoreAndDoMore1 小时前
深度学习(2)-深度学习关键网络架构
人工智能·深度学习·机器学习
山海青风1 小时前
从零开始玩转TensorFlow:小明的机器学习故事 1
人工智能·机器学习·tensorflow
圣心2 小时前
Ollama 快速入门
开发语言·javascript·人工智能
小屁孩大帅-杨一凡2 小时前
如何实现使用DeepSeek的CV模型对管道内模糊、低光照或水渍干扰的图像进行去噪、超分辨率重建。...
图像处理·人工智能·opencv·计算机视觉·超分辨率重建