crewai介绍

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

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

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

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

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

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

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

使用crewai构建一个翻译代理

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

运行命令:

crewai create crew translation_agent

会出现一个模板项目。

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

先来设置一下代理:

file_reader:
role: >
  读取文件代理
goal: >
  根据文件路径,读取文件内容
backstory: >
  你是一个文件读取代理,你的任务是根据文件路径,读取文件内容

translation_agent:
role: >
  翻译代理
goal: >
  根据用户需求翻译文本
backstory: >
  你是一个翻译代理,你的任务是根据用户需求翻译文本

file_saver:
role: >
  文件保存代理
goal: >
  根据用户需求保存文件
backstory: >
  你是一个文件保存代理,你的任务是根据用户需求保存文件

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

再来配置一下task:

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工具代码:

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工具代码:

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)}"

现在需要构建一个团队。

构建团队的代码:

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才行,不如会报错。

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

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

然后可以这样使用:

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
)

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

@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中这样写:

#!/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}")

主要关注这里:

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,看看这个翻译代理的效果。

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

需要进行改进。

改成这样再试试:

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

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

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

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

最后

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

使用crewai创建属于你自己的AI团队的更多相关文章

  1. 技术解密 |阿里云多媒体 AI 团队拿下 CVPR2021 5 冠 1 亚成绩的技术分享

    6 月 19-25 日,备受全球瞩目的国际顶级视觉会议 CVPR2021(Computer Vision and Pattern Recognition,即国际机器视觉与模式识别)在线上举行,但依然人 ...

  2. 创建第一个简单的AI分类器

    from sklearn import tree# 第一个简单的分类器features = [[140, 1], [130, 1], [150, 0], [170, 0]] #列表左边的变量代表水果的 ...

  3. 使用Recast.AI创建具有人工智能的聊天机器人

    很多SAP顾问朋友们对于人工智能/机器学习这个话题非常感兴趣,也在不断思考如何将这种新技术和SAP传统产品相结合.Jerry之前的微信公众号文章C4C和微信集成系列教程曾经介绍了Partner如何利用 ...

  4. GAME AI Pro 1 第1章

    和钱康来合作翻译的AI PRO 1和2 系列,计划是一周一篇,先捡着有意思的翻,对那篇有兴趣也可以留言给我优先翻译,希望都翻译好后有机会成书吧,有兴趣一起翻译的也可以联系我. 游戏人工智能是什么( W ...

  5. 最近整理AI相关感想

    前言 目前笔者致力于 在AI 开发研究,四大平台里,百度AI 提供 的开发者资料是最全,开发的友好度也是最高的,很多都已经集成在SDK中,支持许多语言体系. 其实 作为公司层面的考虑,针对技术的研究出 ...

  6. Unity Rain Ai 插件基本使用(一)

    1.下载安装Rain 插件 原先可以在unity的Asset Stroe 下载到,但是现在Rain 的开发公司因为人工智能的发展,公司得到投资,所以下架了rain插件. 所以我给出网盘链接 链接:ht ...

  7. 2018 AI产业界大盘点

    2018  AI产业界大盘点 大事件盘点 “ 1.24——Facebook人工智能部门负责人Yann LeCun宣布卸任 Facebook人工智能研究部门(FAIR)的负责人Yann LeCun宣布卸 ...

  8. 吴恩达《AI For Everyone》_练习英语翻译_待更新

    AI For Everyone https://www.coursera.org/learn/ai-for-everyone 讲师: Andrew Ng (吴恩达) CEO/Founder Landi ...

  9. Unreal Engine 4 系列教程 Part 9:AI教程

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  10. AI 开发路漫漫,什么才是真正的极客精神?

    摘要:AI开发看上去很美,实践起来却不是一件容易的事.一个聪明的开发者知道借助工具提升开发效率,一个智能的平台则会站在开发者的立场,为用户提供贴心服务. 前言 “理想很丰满,现实很骨感.”如果用一句话 ...

随机推荐

  1. Java基础 —— 集合(一)

    集合(一) 数组和集合的区别 数组是固定长度的数据结构,而集合是动态的数据结构 数组可以包含基本数据类型和对象,集合只能包含对象 数组只能存放同一类型的数据,而集合可以蹲房不同类型的 数组可以直接访问 ...

  2. 《JavaScript 模式》读书笔记(7)— 设计模式3

    这一篇,我们学习本篇中最为复杂的三个设计模式,代理模式.中介者模式以及观察者模式.这三个模式很重要!! 七.代理模式 在代理设计模式中,一个对象充当另一个对象的接口.它与外观模式的区别之处在于,外观模 ...

  3. 前端每日一知之opcity/visiblity/display隐藏元素对比

    脑图在线链接 本文内容依据CSDN博主FEWY精彩文章总结而来原文链接

  4. 小程序,用户授权手机号,node需要检验和解析

    1. 第一步需要先在小程序api文档中下载对应语言的解密算法,解压之后就可以看到 https://developers.weixin.qq.com/miniprogram/dev/framework/ ...

  5. 《Visual Studio Code 权威指南》登上京东科技IT新书榜第一名!

    自 6 月 30 日开启预售以来,<Visual Studio Code 权威指南>受到了许多读者朋友的青睐.感谢大家的支持! 仅仅三天时间,<Visual Studio Code ...

  6. jdk安装-windows和linux

    下载:见此博客https://www.cnblogs.com/zn19961006/p/12857930.html 一.windows安装 1.很简单,运行exe,然后一直下一步 选安装路径. 注意: ...

  7. 哪里有 class 告诉我?

    说明 本文中的 JVM 参数和代码在 JDK 8 版本生效. 哪里有用户类? 用户类是由开发者和第三方定义的类,它是由应用程序类加载器加载的. Java 程序可以通过CLASSPATH 环境变量,JV ...

  8. Qt音视频开发23-视频绘制QPainter方式(占用CPU)

    一.前言 采集到的图片,用painter绘制是最基础的方式,初学者可能第一次尝试显示图片用的qlabel的setpixmap,用下来会发现卡成屎,第二次尝试用样式表设置背景图,依然卡成屎,最终选用pa ...

  9. 做一个windos服务和api搭配,获取电脑的mac地址

    创建webapi项目,只是搭配服务用,什么三层mvc都不弄了,默认的模板直接用就好. 简单分析下,采用signalr通信来传递mac地址,所以先安装个signalr的包(如果简单操作的话可以不装最新的 ...

  10. C#使用Tesseract C++ API过程记录

    Tesseract Tesseract 是一个开源的光学字符识别(OCR)引擎,最初由 Hewlett-Packard(惠普)实验室开发,后来由 Google 收购并继续维护和开源贡献.Tessera ...