crewai介绍

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

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

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

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

在crewai中涵盖了Agents、Tasks、Crews、Flows、Knowledge、LLMs与Tools等这些核心概念。

接下来我将以一个具体的例子,介绍一下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. 使用 JsonSchema 校验 JSON数据

    有时候JSON 数据格式需要校验是否合法,我们可以使用 JsonSchema 来校验数据是否合法. 引入 pom.xml https://json-schema.org/ <dependency ...

  2. MiniTomcat 系列:第一章:解锁实现基础 HTTP 服务器的奥秘

    第一步:实现基础 HTTP 服务器 在这一章中,我们将从零开始编写一个简单的 HTTP 服务器.这个服务器的基本功能是监听一个端口,接收来自客户端的 HTTP 请求,并返回一个 HTTP 响应.我们将 ...

  3. 六步取消win11开机PIN密码登录

    0.前言 新买的电脑打开后首先要进行一系列的操作激活操作系统.在这些操作中最令人讨厌的是设置开机密码(pin). 也许有很多人的电脑需要保密,限制别人登录,这时使用登录pin是很有必要的.而还有很多人 ...

  4. QEMU CVE-2021-3947 和 CVE-2021-3929 漏洞利用分析

    QEMU CVE-2021-3947 和 CVE-2021-3929 漏洞利用分析 ‍ CVE-2021-3947 信息泄露漏洞 漏洞分析 漏洞点是 nvme_changed_nslist stati ...

  5. git 基础操作 && 在"develop"分支修改动但不想提交切换到"master"分支(最后)

    测试学习准备条件:一个目录,含不含有文件都可以,创建一个test.txt 1. 创建空仓库 git init 2. 修改过后,添加到本地仓库 添加指定的文件,如果一个以上,文件名空格隔开 git ad ...

  6. 浅聊web前端性能测试

    最近正好在做web前端的性能测试,这次就来聊聊关于这个的测试思路~ 首先从用户的思维去思考,关于web前端性能,用户最看重的是什么...... 其实就是下面三个点: 1. 加载性能(即页面加载时间+资 ...

  7. 【javaweb】【Session】记录用户访问时间

    效果 Servlet import jakarta.servlet.*; import jakarta.servlet.http.*; import jakarta.servlet.annotatio ...

  8. File and Code template

    /** * @author muzhi.zhong * @author <a href="mailto:muzhi.z@xxx.cn">muzhi.z</a> ...

  9. Qt/C++音视频开发48-推流到rtsp服务器

    一.前言 之前已经打通了rtmp的推流,理论上按照同样的代码,只要将rtmp推流地址换成rtsp推流地址,然后格式将flv换成rtsp就行,无奈直接遇到协议不支持的错误提示,网上说要换成rtp,换了也 ...

  10. Qt编写的项目作品4-输入法V2019

    一.功能特点 未采用Qt系统层输入法框架,独创输入切换机制. 纯QWidget编写,支持任何目标平台(亲测windows.linux.嵌入式linux等),支持任意Qt版本(亲测Qt4.6.0到Qt5 ...