Skip to content
CrewAI 文档版本 跟随上游 源快照 617c118e 更新于 2026-10-18

工具

理解并运用 CrewAI 框架中的工具,实现智能体协作与任务执行。

概述

CrewAI 工具为智能体赋予了从网页搜索、数据分析到协作与在同事之间委派任务等多种能力。 本文档介绍如何在 CrewAI 框架中创建、集成和运用这些工具,并新增对协作工具的关注。

NOTE

工具为智能体提供可执行动作的 可调用函数。它们与 MCP(远程工具服务器)、Apps(平台集成)、技能(领域专业知识)和知识(检索到的事实)配合使用。请参阅智能体能力概览,了解何时使用哪一种。

什么是工具?

CrewAI 中的工具是一种技能或函数,智能体可以利用它来执行各种动作。 这包括来自 CrewAI Toolkit 和 LangChain Tools 的工具, 从简单搜索到复杂交互以及智能体之间高效协作,一切皆可实现。

NOTE

CrewAI AMP 提供全面的工具仓库,内含针对常见业务系统和 API 的预构建集成。几分钟(而非数天)即可部署具备企业级工具的智能体。

企业版工具仓库包括:

  • 针对主流企业系统的预构建连接器
  • 自定义工具创建界面
  • 版本控制与共享能力
  • 安全与合规特性

工具的关键特性

  • 实用性:为网页搜索、数据分析、内容生成和智能体协作等任务而打造。
  • 集成性:通过将工具无缝集成到工作流中,提升智能体能力。
  • 可定制性:可灵活开发自定义工具或使用现有工具,满足智能体的特定需求。
  • 错误处理:内置稳健的错误处理机制,确保平稳运行。
  • 缓存机制:具备智能缓存,以优化性能并减少重复操作。
  • 异步支持:同时支持同步和异步工具,实现非阻塞操作。
  • 类型化输出:使用可选的 Pydantic 模型为智能体提供清晰的 JSON 字段,而直接的 Python 调用仍会收到工具的正常返回值。

使用 CrewAI 工具

要借助 crewAI 工具增强智能体的能力,请先安装我们的额外工具包:

bash
pip install 'crewai[tools]'

以下示例演示了它们的使用方式:

python
import os
from crewai import Agent, Task, Crew
# Importing crewAI tools
from crewai_tools import (
    DirectoryReadTool,
    FileReadTool,
    SerperDevTool,
    WebsiteSearchTool
)

# Set up API keys
os.environ["SERPER_API_KEY"] = "Your Key" # serper.dev API key
os.environ["OPENAI_API_KEY"] = "Your Key"

# Instantiate tools
docs_tool = DirectoryReadTool(directory='./blog-posts')
file_tool = FileReadTool()
search_tool = SerperDevTool()
web_rag_tool = WebsiteSearchTool()

# Create agents
researcher = Agent(
    role='Market Research Analyst',
    goal='Provide up-to-date market analysis of the AI industry',
    backstory='An expert analyst with a keen eye for market trends.',
    tools=[search_tool, web_rag_tool],
    verbose=True
)

writer = Agent(
    role='Content Writer',
    goal='Craft engaging blog posts about the AI industry',
    backstory='A skilled writer with a passion for technology.',
    tools=[docs_tool, file_tool],
    verbose=True
)

# Define tasks
research = Task(
    description='Research the latest trends in the AI industry and provide a summary.',
    expected_output='A summary of the top 3 trending developments in the AI industry with a unique perspective on their significance.',
    agent=researcher
)

write = Task(
    description='Write an engaging blog post about the AI industry, based on the research analyst's summary. Draw inspiration from the latest blog posts in the directory.',
    expected_output='A 4-paragraph blog post formatted in markdown with engaging, informative, and accessible content, avoiding complex jargon.',
    agent=writer,
    output_file='blog-posts/new_post.md'  # The final blog post will be saved here
)

# Assemble a crew with planning enabled
crew = Crew(
    agents=[researcher, writer],
    tasks=[research, write],
    verbose=True,
    planning=True,  # Enable planning feature
)

# Execute tasks
crew.kickoff()

可用的 CrewAI 工具

  • 错误处理:所有工具都内置错误处理能力,使智能体能够优雅地处理异常并继续执行任务。
  • 缓存机制:所有工具都支持缓存,使智能体能够高效复用先前获得的结果,减轻外部资源负载并加快执行速度。你还可以使用工具上的 cache_function 属性对缓存机制进行更精细的控制。

以下是可用工具及其描述列表:

工具描述
ApifyActorsTool将 Apify Actors 与你的工作流集成,用于网页抓取和自动化任务的工具。
BrowserbaseLoadTool用于与网页浏览器交互并从中提取数据的工具。
CodeDocsSearchTool针对代码文档及相关技术文档搜索而优化的 RAG 工具。
CodeInterpreterTool用于解释 python 代码的工具。
ComposioTool支持使用 Composio 工具。
CSVSearchTool专为在 CSV 文件内搜索而设计的 RAG 工具,适合处理结构化数据。
DALL-E Tool使用 DALL-E API 生成图像的工具。
DirectorySearchTool用于在目录内搜索的 RAG 工具,适合浏览文件系统。
DOCXSearchTool旨在在 DOCX 文档内搜索的 RAG 工具,非常适合处理 Word 文件。
DirectoryReadTool便于读取和处理目录结构及其内容。
ExaSearchTool使用 Exa 进行网页搜索,这是最快、最准确的网页搜索 API。支持 token 高效的 highlights 和整页内容。
FileReadTool支持从文件中读取和提取数据,兼容多种文件格式。
FirecrawlSearchTool使用 Firecrawl 搜索网页并返回结果的工具。
FirecrawlCrawlWebsiteTool使用 Firecrawl 抓取网页的工具。
FirecrawlScrapeWebsiteTool使用 Firecrawl 抓取网页 URL 并返回其内容的工具。
GithubSearchTool用于在 GitHub 仓库内搜索的 RAG 工具,适合代码和文档搜索。
SerperDevTool面向开发用途的专用工具,具备正在开发中的特定功能。
TXTSearchTool专注于在文本(.txt)文件内搜索的 RAG 工具,适用于非结构化数据。
JSONSearchTool专为在 JSON 文件内搜索而设计的 RAG 工具,适合处理结构化数据。
LlamaIndexTool支持使用 LlamaIndex 工具。
MDXSearchTool为在 Markdown(MDX)文件内搜索而定制的 RAG 工具,适合文档场景。
MongoDBVectorSearchTool用于在 MongoDB Atlas 集合上执行向量相似度搜索的 RAG 工具,并提供可选的辅助工具来创建和管理向量搜索索引。
PDFSearchTool旨在在 PDF 文档内搜索的 RAG 工具,非常适合处理扫描文档。
PGSearchTool针对在 PostgreSQL 数据库内搜索而优化的 RAG 工具,适合数据库查询。
Vision Tool使用 DALL-E API 生成图像的工具。
RagTool通用 RAG 工具,能够处理多种数据来源和类型。
ScrapeElementFromWebsiteTool支持从网站抓取特定元素,适合定向数据提取。
ScrapeWebsiteTool便于抓取整个网站,非常适合全面的数据收集。
WebsiteSearchTool用于搜索网站内容的 RAG 工具,针对网页数据提取进行了优化。
XMLSearchTool专为在 XML 文件内搜索而设计的 RAG 工具,适合结构化数据格式。
YoutubeChannelSearchTool用于在 YouTube 频道内搜索的 RAG 工具,适合视频内容分析。
YoutubeVideoSearchTool旨在在 YouTube 视频内搜索的 RAG 工具,非常适合视频数据提取。

创建你自己的工具

TIP

开发者可以打造契合智能体需求的 custom tools,也可以 使用预构建的选项。

创建 CrewAI 工具有两种主要方式:

子类化 BaseTool

python
from crewai.tools import BaseTool
from pydantic import BaseModel, Field

class MyToolInput(BaseModel):
    """Input schema for MyCustomTool."""
    argument: str = Field(..., description="Description of the argument.")

class MyCustomTool(BaseTool):
    name: str = "Name of my tool"
    description: str = "What this tool does. It's vital for effective utilization."
    args_schema: Type[BaseModel] = MyToolInput

    def _run(self, argument: str) -> str:
        # Your tool's logic here
        return "Tool's result"

类型化工具输出

当工具返回结构化数据时,定义一个 Pydantic 输出模型。这样智能体就能获得可信的字段名,例如 sku、quantity 或 needs_reorder。

直接的 Python 调用仍会收到工具返回的值。当智能体使用该工具时,CrewAI 会基于输出模型向智能体发送一个 JSON 字符串。

python
from crewai.tools import BaseTool
from pydantic import BaseModel

class InventoryResult(BaseModel):
    sku: str
    quantity: int
    needs_reorder: bool

class InventoryTool(BaseTool):
    name: str = "Inventory Check"
    description: str = "Checks current stock for a product SKU."

    def _run(self, sku: str) -> InventoryResult:
        quantity = {"SKU-123": 14, "SKU-456": 0}.get(sku, 0)
        return InventoryResult(sku=sku, quantity=quantity, needs_reorder=quantity < 5)

tool = InventoryTool()

# Direct calls receive the raw Pydantic object.
result = tool.run(sku="SKU-123")
print(result.quantity)

若要向智能体发送 Markdown 或其他简短文本格式,请重写 format_output_for_agent。直接调用 tool.run(...) 仍会返回正常的 Python 值。

python
class InventoryTool(BaseTool):
    name: str = "Inventory Check"
    description: str = "Checks current stock for a product SKU."

    def _run(self, sku: str) -> InventoryResult:
        quantity = {"SKU-123": 14, "SKU-456": 0}.get(sku, 0)
        return InventoryResult(sku=sku, quantity=quantity, needs_reorder=quantity < 5)

    def format_output_for_agent(self, raw_result: object) -> str:
        result = InventoryResult.model_validate(raw_result)
        status = "reorder needed" if result.needs_reorder else "stock is healthy"
        return f"{result.sku}: {result.quantity} units. {status}."

如果你不重写 format_output_for_agent,类型化输出会以 JSON 形式发送给智能体。纯字符串结果的行为与之前相同。

异步工具支持

CrewAI 支持异步工具,允许你实现执行非阻塞操作的工具,例如网络请求、文件 I/O 或其他异步操作,而不会阻塞主执行线程。

创建异步工具

你可以通过两种方式创建异步工具:

1. 将 tool 装饰器与异步函数配合使用

python
from crewai.tools import tool

@tool("fetch_data_async")
async def fetch_data_async(query: str) -> str:
    """Asynchronously fetch data based on the query."""
    # Simulate async operation
    await asyncio.sleep(1)
    return f"Data retrieved for {query}"

2. 在自定义工具类中实现异步方法

python
from crewai.tools import BaseTool

class AsyncCustomTool(BaseTool):
    name: str = "async_custom_tool"
    description: str = "An asynchronous custom tool"

    async def _run(self, query: str = "") -> str:
        """Asynchronously run the tool"""
        # Your async implementation here
        await asyncio.sleep(1)
        return f"Processed {query} asynchronously"

使用异步工具

异步工具在标准 Crew 工作流和基于 Flow 的工作流中都能无缝运行:

python
# In standard Crew
agent = Agent(role="researcher", tools=[async_custom_tool])

# In Flow
class MyFlow(Flow):
    @start()
    async def begin(self):
        crew = Crew(agents=[agent])
        result = await crew.kickoff_async()
        return result

CrewAI 框架会自动处理同步工具和异步工具的执行,因此你无需担心如何以不同方式调用它们。

使用 tool 装饰器

python
from crewai.tools import tool
@tool("Name of my tool")
def my_tool(question: str) -> str:
    """Clear description for what this tool is useful for, your agent will need this information to use it."""
    # Function logic here
    return "Result from your custom tool"

自定义缓存机制

TIP

工具可以选择实现 cache_function,以微调缓存 行为。该函数根据特定条件决定何时缓存结果, 让你可以细粒度地控制缓存逻辑。

python
from crewai.tools import tool

@tool
def multiplication_tool(first_number: int, second_number: int) -> str:
    """Useful for when you need to multiply two numbers together."""
    return first_number * second_number

def cache_func(args, result):
    # In this case, we only cache the result if it's a multiple of 2
    cache = result % 2 == 0
    return cache

multiplication_tool.cache_function = cache_func

writer1 = Agent(
        role="Writer",
        goal="You write lessons of math for kids.",
        backstory="You're an expert in writing and you love to teach kids but you know nothing of math.",
        tools=[multiplication_tool],
        allow_delegation=False,
    )
    #...

报告工具失败

工具可以在不抛出异常的情况下结束,却仍然没有完成它被要求做的事。Slack 会返回 HTTP 200 和 {"ok": false, "error": "channel_not_found"};MCP 服务器会设置 isError;平台操作会返回错误负载。工具调用 “成功了”,于是错误文本作为普通结果传给智能体——智能体 在最终答案中叙述该问题,而这次运行被记录为成功。

返回 ToolFailure 而不是错误字符串,框架就能分辨出 两者的差别:

python
from typing import Any

from crewai.tools import BaseTool
from crewai.tools.tool_failure import ToolFailure

class SendSlackMessage(BaseTool):
    name: str = "send_slack_message"
    description: str = "Post a message to a Slack channel."

    def _run(self, channel: str, text: str) -> Any:
        payload = slack.post(channel=channel, text=text)
        if not payload["ok"]:
            return ToolFailure(
                message=f"Slack rejected the message: {payload['error']}",
                code=payload["error"],
                retryable=payload["error"] == "rate_limited",
            )
        return payload

智能体读到的仍然是纯文本——ToolFailure.as_agent_message() 会渲染该 消息——因此模型行为没有变化。改变的是,这个失败现在 对下游的所有环节都可见。

检测严格是声明式的。CrewAI 从不猜测某个字符串是否“看起来 像”错误,因此一个合法返回错误相关文本的工具永远不会 被误读为失败。以下情况会记录失败:工具返回 ToolFailure、工具抛出异常、MCP 服务器设置 isError、工具的 max_usage_count 用完,或智能体调用了不存在的工具。

选择失败策略

tool_failure_policy 控制接下来发生什么:

策略行为
ignore不记录、不发出事件,也不采取任何动作。
warn (默认)记录失败,发出 ToolFailureDetectedEvent,然后继续执行。
raise记录并发出事件,然后以 ToolExecutionFailedError 中止。
python
from crewai import Agent, Crew, Task
from crewai.tools.tool_failure import ToolFailurePolicy

agent = Agent(
    role="Slack Messenger",
    goal="Post the report to Slack",
    backstory="...",
    tools=[SendSlackMessage()],
    tool_failure_policy=ToolFailurePolicy.WARN,
)

# Tighten a single high-stakes task without changing the agent.
task = Task(
    description="Post the final report to #engineering",
    expected_output="Confirmation the message was posted",
    agent=agent,
    tool_failure_policy=ToolFailurePolicy.RAISE,
)

# Or set a baseline once for every agent in the crew.
crew = Crew(
    agents=[agent],
    tasks=[task],
    tool_failure_policy=ToolFailurePolicy.WARN,
)

最具体的设置优先:tool → task → agent → crew → warn。每一 层默认都是 None,表示“从外一层继承”,因此在任何地方都 未配置时,实际生效的默认值是 warn。

检查失败

记录下来的失败是结构化的,因此下游无需解析字符串:

python
result = crew.kickoff()

if result.has_tool_failures:
    for record in result.tool_failures:
        print(record.tool_name)          # "send_slack_message"
        print(record.failure.code)       # "channel_not_found"
        print(record.failure.reason)     # ToolFailureReason.TOOL_REPORTED
        print(record.summary())

tool_failures 可在 TaskOutput、CrewOutput 和 LiteAgentOutput 上获取。团队可能带着非空列表成功结束——在 把 raw 当作完整结果之前请先检查它。

要在失败发生时做出反应,请订阅该事件:

python
from crewai.events import ToolFailureDetectedEvent
from crewai.events.event_bus import crewai_event_bus

@crewai_event_bus.on(ToolFailureDetectedEvent)
def on_tool_failure(source, event):
    print(f"{event.tool_name} failed: {event.failure.message} ({event.policy})")

事件会在 raise 策略中止之前发出,因此订阅者总能 观察到该失败。ToolUsageFinishedEvent 还带有一个 failure 字段,让 追踪 UI 无需关联两个事件就能把该调用标记为失败。

结论

工具在扩展 CrewAI 智能体的能力方面至关重要,使它们能够承担广泛的任务并有效协作。 在使用 CrewAI 构建解决方案时,请同时利用自定义工具和现有工具来增强你的智能体并改善 AI 生态。可以考虑使用错误处理、 缓存机制以及工具参数的灵活性,来优化智能体的性能和能力。

BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。