CrewAI FirecrawlSearchTool 实战:为 AI Agent 接入 Firecrawl 网页搜索能力
本文围绕 CrewAI 工具库中的 FirecrawlSearchTool 展开:它如何把 Firecrawl 平台的网页搜索与 Markdown 抓取能力封装成 Agent 可直接调用的标准工具。读完本文,你将掌握该工具的完整安装配置、全部参数与默认值,以及其在 CrewAI 工具基类上的源码级实现细节,能够将网页搜索结果作为 LLM 上下文接入你的 Crew 或 Flow 应用。
工具定位:Agent 的网页搜索入口
Firecrawl 工具说明文档 对它的定义是:Firecrawl 是一个把任意网站爬取并转换为干净 Markdown 或结构化数据的平台,而 FirecrawlSearchTool 就是让 CrewAI Agent 具备"加载网页"能力的具体实现。
从源码结构看,该工具以独立子模块形式组织在 lib/crewai-tools/src/crewai_tools/tools/firecrawl_search_tool/ 目录下,包含 README.md 与 firecrawl_search_tool.py 两个核心文件,并通过 crewai_tools 包入口 的 __all__ 列表导出,因此可以直接 from crewai_tools import FirecrawlSearchTool 使用,无需关心内部模块路径。工具对外的 name 与 description 均为英文固定值("Firecrawl web search tool" / "Search webpages using Firecrawl and return the results"),这也是 LLM 在 Function Calling 时看到的工具签名。
安装与环境准备
根据工具文档,使用前需要完成两件事:
- 在 Firecrawl 官方平台申请 API Key,并写入环境变量
FIRECRAWL_API_KEY; - 安装 Firecrawl Python SDK 与 CrewAI 工具包:
pip install firecrawl-py 'crewai[tools]'
源码层面有两条对应的硬性约束,值得注意:
- firecrawl_search_tool.py#L66-L74 中通过
env_vars声明了FIRECRAWL_API_KEY且标记为required=True。这意味着该 key 会被纳入 CrewAI 的环境变量校验体系,在未配置时运行 Crew 会在启动检查阶段被提示缺失,而不是等到调用时才失败; package_dependencies字段声明了["firecrawl-py"](见 源码第 65 行),供上层工具校验逻辑确认依赖是否齐备。
此外,源码在模块顶部对 from firecrawl import FirecrawlApp 做了 try/except ImportError 兜底并记录 FIRECRAWL_AVAILABLE 标志(源码第 9-14 行)。也就是说 crewai[tools] 本体并不强制安装 firecrawl-py,属于可选重依赖——这正是工具采用延迟导入设计的原因。
基本用法
文档给出的最小示例如下,创建工具实例后调用 run(query=...) 发起搜索:
from crewai_tools import FirecrawlSearchTool
tool = FirecrawlSearchTool(config={"limit": 5})
tool.run(query="firecrawl web scraping")
tool.run() 是 CrewAI BaseTool 的统一执行入口。从 源码第 106-116 行 可以看到,run 背后的 _run(self, query: str) 实现非常薄——它先校验 FirecrawlApp 已完成初始化(否则抛出 RuntimeError("FirecrawlApp not properly initialized")),随后把 self.config 整个展开透传给 SDK:
return self._firecrawl.search(
query=query,
**self.config,
)
这意味着 config 字典里出现的每个键都会原样成为 FirecrawlApp.search() 的命名参数。工具的参数模型由 FirecrawlSearchToolSchema(源码第 17-18 行)定义,LLM 在调用该工具时只需要填写一个 query: str 字段,其余参数全部由开发者在实例化时通过 config 固定,这一设计把搜索策略的控制权交给了编排者而非模型。
实际使用时,通常把工具实例交给 Agent 的 tools 参数,即可让角色自主决定何时搜索:
from crewai import Agent
from crewai_tools import FirecrawlSearchTool
agent = Agent(
role="Researcher",
goal="Gather up-to-date information from the web",
tools=[FirecrawlSearchTool(config={"limit": 5})],
llm="gpt-4o",
)
参数详解:api_key 与 config
工具说明文档(README 的 Arguments 小节)声明了两个实例化参数:
| 参数 | 必填 | 说明 |
|---|---|---|
api_key |
可选 | 指定 Firecrawl API Key;缺省时回退到 FIRECRAWL_API_KEY 环境变量 |
config |
可选 | 包含传给 Firecrawl API 的全部搜索参数 |
文档中给出的默认配置块为:
{
"limit": 5,
"tbs": None,
"lang": "en",
"country": "us",
"location": None,
"timeout": 60000,
}
需要提示的是:以当前仓库源码为准,config 字段真实的 default_factory(源码第 49-63 行)对齐的是 Firecrawl v2 API,实际默认为:
{
"limit": 5, # 返回的最大搜索结果数,默认 5
"tbs": None, # 时间过滤,如 "qdr:d" 限定最近一天
"location": None, # 搜索结果的地域偏好
"timeout": None, # 请求超时(毫秒)
"scrape_options": { # 对搜索结果页面的抓取选项
"formats": ["markdown"], # 返回内容格式,默认 Markdown
"only_main_content": True, # 只保留正文,过滤导航/页脚
"include_tags": [],
"exclude_tags": [],
"wait_for": 0, # 抓取前等待的毫秒数,用于 JS 渲染页面
},
}
源码中的类 docstring(源码第 22-40 行)对这些参数逐项做了说明:limit 控制返回条数,tbs 支持类似 "qdr:d" 的时间窗口过滤,scrape_options.formats 控制内容格式,only_main_content 决定是否剥离页面头尾噪声,wait_for 则用于应对需要等待前端渲染的动态页面。
这里可以看出工具文档与源码存在一点演进差异:文档默认配置块中的 lang / country 字段未出现在当前源码的默认工厂里,而 scrape_options 子配置则是文档尚未覆盖的新能力。以当前仓库源码结构看,config 应围绕 v2 API 的键名来配置;如果你传入文档中列出的 lang / country,它们会经由 **self.config 透传给 SDK,是否生效取决于所用 firecrawl-py 版本的 API 契约,建议以所装 SDK 版本行为为准。
初始化链路:懒加载 SDK 与交互式依赖安装
FirecrawlSearchTool 的构造函数(源码第 76-79 行)先完成 Pydantic 字段初始化,再调用 _initialize_firecrawl()。该私有方法(源码第 81-104 行)实现了一条完整的"缺依赖自愈"链路:
- 尝试
from firecrawl import FirecrawlApp,成功则用当前api_key构造FirecrawlApp实例存入私有属性_firecrawl; - 若导入失败,用
click.confirm询问用户"是否安装 firecrawl-py"; - 确认后执行
subprocess.run(["uv", "add", "firecrawl-py"])自动安装并重新导入,安装失败则包装为ImportError抛出; - 若用户拒绝安装,抛出提示信息
`firecrawl-py` package not found, please run `uv add firecrawl-py`的ImportError。
这条链路解释了为什么文档要求预先 pip install firecrawl-py:预装可以跳过交互式询问,在 CI 或 Agent 等无人值守环境下避免卡在 click.confirm 上。此外,模块底部还有一段 model_rebuild() 保护逻辑(源码第 119-126 行),仅在 firecrawl-py 可用时重建 Pydantic 模型并打上 _model_rebuilt 防重入标记,保证类型引用在 SDK 存在与否两种状态下都稳定。
返回值形态与测试验证
工具的运行测试位于 firecrawl_search_tool_test.py,采用 pytest-vcr 录制回放的方式(@pytest.mark.vcr)固定外部调用,断言搜索返回对象非空且带有 web、news 或 images 属性之一:
tool = FirecrawlSearchTool()
result = tool.run(query="firecrawl")
assert result is not None
assert hasattr(result, 'web') or hasattr(result, 'news') or hasattr(result, 'images')
从测试用例可以推断,tool.run() 的返回值不是裸字符串,而是 Firecrawl v2 API 的搜索结果响应对象,按结果类型分列在 web / news / images 字段下;结合 scrape_options 默认的 formats: ["markdown"],每条结果正文即为可直接投喂给 LLM 的 Markdown 文本。在 Agent 场景下,整个响应体会被序列化为工具结果字符串回传给模型,因此 limit 的大小直接影响注入上下文的 token 量,按需调小 limit 或开启 only_main_content 是控制成本的有效手段。
小结与延伸阅读
FirecrawlSearchTool 的设计可以概括为"薄封装、厚透传":工具本身只承担 API Key 管理、依赖校验与参数默认值三件事,真正的搜索与抓取行为全部委托给 firecrawl-py 的 FirecrawlApp.search()。想进一步了解的读者可以阅读 工具说明文档、实现源码 与 集成测试;同一平台下的网页抓取工具(如 FirecrawlScrapeWebsiteTool、FirecrawlCrawlWebsiteTool)可在官方文档目录 docs/edge/en/tools/web-scraping/ 中对照参考,与搜索工具组合使用可覆盖"先搜后抓"的完整网页情报链路。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00