CrewAI crewai-files 多模态文件输入全解:从文件自动识别到按 Provider 自适应上传
crewai-files 是 CrewAI 仓库中专门负责多模态文件处理的独立包,它让 Agent 可以直接接收图片、PDF、文本、音频和视频,并自动完成类型识别、体积校验、按需压缩/分片,以及向各 LLM Provider 的自适应投递(URL 引用、内联 Base64 或文件上传)。读完本文,你将掌握在 Crew 与 Task 层传入 input_files 的完整用法,并理解从 README.md 中的三行示例背后,整个“识别 → 处理 → 解析 → 上传”的源码级执行链路。
包定位与依赖
crewai-files 作为 monorepo 中 lib/ 下的独立分发包存在,其包元信息定义在 pyproject.toml:
- 包名
crewai-files,描述为 “File handling utilities for CrewAI multimodal inputs”; - Python 版本要求
>=3.10, <3.14; - 运行时依赖与文件处理能力一一对应:
Pillow~=12.3.0:图片读取、缩放与压缩;pypdf~=6.14.2:PDF 页数解析与按页分片;python-magic>=0.4.27:基于魔数(magic number)的 MIME 内容嗅探;aiocache~=0.12.3:上传结果缓存;aiofiles~=24.1.0:异步文件读写;tinytag~=2.2.1与av~=13.0.0:音频/视频元信息(时长)提取。
包的公开 API 集中在 src/crewai_files/init.py 中导出,包括五类文件类型、FileProcessor、FileResolver、各 Provider 约束常量与上传器,当前包版本为 1.15.18(版本值定义于同文件的 __version__)。
支持的文件类型与 File 类体系
README 给出的支持类型概览:
| 类型 | 支持格式(README 列举) |
|---|---|
ImageFile |
PNG、JPEG、GIF、WebP |
PDFFile |
PDF 文档 |
TextFile |
纯文本文件 |
AudioFile |
MP3、WAV、FLAC、OGG、M4A |
VideoFile |
MP4、WebM、MOV、AVI |
源码中每个类别的扩展名白名单比 README 更宽,定义在 core/types.py:
- 图片额外支持
.bmp、.tiff/.tif、.svg、.heic/.heif; - 文本扩展
.txt、.md、.rst、.csv、.json、.xml、.yaml/.yml、.html/.htm、.log、.ini、.cfg/.conf; - 音频扩展
.mp3、.wav、.ogg、.flac、.aac、.m4a、.wma、.aiff、.opus; - 视频扩展
.mp4、.avi、.mkv、.mov、.webm、.flv、.wmv、.m4v、.mpeg/.mpg。
所有具体类型都继承自抽象基类 BaseFile,它只有两个公开字段:
class BaseFile(ABC, BaseModel):
source: CoercedFileSource = Field(description="The underlying file source.")
mode: FileMode = Field(
default="auto",
description="How to handle if file exceeds limits: strict, auto, warn, chunk.",
)
source:底层文件来源,支持str(路径或 URL)、Path、bytes、二进制流等原始输入,Pydantic 校验时会被强制转换为内部的FileSource类型(见下一节);mode:该文件超出 Provider 限制时的处理策略,取值为Literal["strict", "auto", "warn", "chunk"],默认"auto"——这是逐文件(per-file)的开关,而非全局配置。
BaseFile 还提供两个实用能力(定义在 core/types.py):
- 内容读取:
read()返回字节、read_text()返回解码文本、aread()异步读取; - 字典解包:实现
keys()与__getitem__(),使{**ImageFile(source="./chart.png")}可以解包为{"chart": <ImageFile 实例>}——键名取文件名去掉扩展名的部分(stem),无文件名时回退为"file"。这正好对应 README 中input_files={"chart": ImageFile(...)}的写法。
File 是泛型入口,用于不想显式指定类型时的自动识别:
from crewai_files import File, ImageFile, PDFFile
# 自动识别文件类型
file = File(source="document.pdf") # 解析为 PDFFile
# 或者直接使用具体类型
image = ImageFile(source="chart.png")
pdf = PDFFile(source="report.pdf")
文件来源:五种 FileSource 与内容识别
source 字段接受 str | Path | bytes | IOBase | FileSource,由 _FileSourceCoercer(core/types.py)统一转换为五种内部来源类型,全部定义在 core/sources.py:
| 来源类型 | 触发条件 | 行为要点 |
|---|---|---|
FilePath |
str(非 URL)或 Path |
校验后读取磁盘文件,支持同步/异步/分块读取 |
FileBytes |
bytes |
内容已在内存,MIME 即时嗅探 |
FileStream |
具备 read()/seek() 的二进制流 |
首次读取时回卷到头部嗅探 MIME,读取结果缓存 |
AsyncFileStream |
具备 async read() 的对象 |
纯异步场景,需先 aread() 才能取 content_type |
FileUrl |
http:// / https:// 开头的字符串 |
延迟抓取;支持 URL 的 Provider 可直接引用 |
几个值得注意的实现细节:
MIME 检测策略。detect_content_type() 优先调用 python-magic 对前 2048 字节(MAGIC_BUFFER_SIZE)做内容嗅探;若 python-magic 不可用或返回 application/octet-stream,则回退到 _fallback_content_type():先按文件扩展名查 mimetypes 表(保证 text/csv 等精确类型不被降级为 text/plain),再尝试字节级嗅探(PNG/JPEG/PDF 魔数、JSON 结构、可解码 UTF-8 纯文本),最终兜底为 application/octet-stream。
FilePath 的安全校验。构造 FilePath 时的 @model_validator 会依次执行:
- 路径字符串含
..直接拒绝(防路径穿越); - 符号链接解析后必须落在当前工作目录之内,否则拒绝;
- 文件必须存在且是普通文件;
- 文件实际大小不得超过
max_size_bytes,默认值为DEFAULT_MAX_FILE_SIZE_BYTES = 524_288_000(500 MB,定义在 core/constants.py),超限抛出FileTooLargeError。
FileUrl 的延迟抓取。只有在不支持 URL 引用的 Provider 上,FileUrl.read()/aread() 才会通过 httpx 实际下载内容并采用响应头中的 Content-Type;支持 URL 引用的 Provider 可以直接把 URL 透传给模型侧。
实战:把文件传给 Crew 和 Task
README 给出了两个核心用法,它们与 crewai 主包的 Crew.kickoff() 和 Task 参数直接对接。
传给 Crew
crew.kickoff(
input_files={"chart": ImageFile(source="chart.png")}
)
kickoff 的 input_files 是「名称 → 文件对象」的字典。名称会成为提示词上下文中引用该文件的锚点。若不想手写键名,可利用 BaseFile 的 ** 解包能力:
crew.kickoff(input_files={**ImageFile(source="chart.png")})
# 等价于 input_files={"chart": ImageFile(source="chart.png")}
在主包 lib/crewai 中可以看到这些入口的真实消费方:Crew 的 A2A 委托层(lib/crewai/src/crewai/a2a/utils/delegation.py)会调用 _create_file_parts(input_files) 把每个 FileInput 转换为可发送给远端 Agent 的 Part 对象;lib/crewai/src/crewai/a2a/wrapper.py 中的 kickoff 包装函数同样贯穿 input_files 参数传递。
传给 Task
task = Task(
description="Analyze the chart",
expected_output="Analysis",
agent=agent,
input_files=[ImageFile(source="chart.png")],
)
Task 层的 input_files 接收文件对象列表,仅对该任务可见,适合多任务 Crew 中按任务分发不同材料的场景;Crew 层的 input_files 则是整次 kickoff 的共享材料。
仓库测试目录中的 fixtures 覆盖了五类文件的真实样例:revenue_chart.png、agents.pdf、review_guidelines.txt、sample_audio.wav、sample_video.mp4 与 quarterly_report.csv,可作为本地联调的输入素材。
处理模式 mode:strict / auto / warn / chunk
每个文件携带的 mode 字段决定了它超出 Provider 限制时的行为,核心调度逻辑在 processing/processor.py 的 FileProcessor.process():
if not errors:
return file # 校验通过,原样返回
if mode == FileHandling.STRICT: # 严格:直接抛 FileValidationError
raise FileValidationError(...)
if mode == FileHandling.WARN: # 警告:记录 warning 后原样返回
for error in errors:
logger.warning(error)
return file
if mode == FileHandling.AUTO: # 自动:尝试缩放/压缩
return self._auto_process(file)
if mode == FileHandling.CHUNK: # 分片:拆成多个文件
return self._chunk_process(file)
四种模式的语义:
strict:任何校验失败立即抛错(FileValidationError),适合对输入质量有硬性要求的离线批处理;auto(默认):对图片尝试自动缩放(超过max_width/max_height时调用resize_image)与压缩(超过max_size_bytes时调用optimize_image);对 PDF 仅记录 warning 建议改用 CHUNK 模式(源码注释明确 “Cannot auto-compress PDF”);对音视频不处理并记录 warning;warn:只记日志、原样放行,交给 Provider 自行拒绝或容忍;chunk:PDF 超过max_pages时按页拆分为多个文件;TextFile超过体积上限时按字符数拆分。分片后的文件在process_files()中会被展开为原名_chunk_0、原名_chunk_1… 的多个字典条目。
FileProcessor 接受 ProviderConstraints 实例或 Provider 名字符串(经 get_constraints_for_provider() 解析);传入未知 Provider 名时仅记录 warning 并关闭校验,不会中断运行。批量场景还有 aprocess_files() 异步版本,内部用信号量限制并发(默认 10)。
Provider 约束:内置的各家上限表
processing/constraints.py 内置了六套 Provider 约束,这是本包与具体 LLM 服务商之间的契约层:
| Provider | 图片上限 | PDF 上限 | 音频上限 | 视频上限 | 文件上传 API | URL 引用 |
|---|---|---|---|---|---|---|
anthropic |
5 MB/张,≤8000×8000 像素,≤100 张 | 32 MB、≤100 页 | — | — | 支持(阈值 5 MB) | 支持 |
openai(completions) |
20 MB/张、≤10 张 | — | — | — | 支持(阈值 5 MB) | 支持 |
openai_responses |
20 MB/张、≤10 张 | 32 MB、≤100 页 | 25 MB、≤25 分钟 | — | 支持(阈值 5 MB) | 支持 |
gemini |
100 MB(含 HEIC/HEIF) | 50 MB | 100 MB、≤9.5 小时 | 2 GB、≤1 小时 | 支持(阈值 20 MB) | 支持 |
bedrock |
4.5 MB,≤8000×8000 像素 | 3.67 MB、≤100 页 | — | — | 不支持 | 支持(S3 URI) |
azure |
20 MB/张、≤10 张 | — | 25 MB、≤25 分钟 | — | 不支持 | 支持 |
(表中“—”表示该 Provider 未配置对应类别约束,即不做该类校验。)
get_constraints_for_provider() 支持大小写不敏感的模糊匹配,并内置别名映射:claude → anthropic、gpt → openai、google → gemini、aws → bedrock(结果带 lru_cache 缓存)。另有 uses_openai_responses_api() 判定是否走 Responses API 的文件能力集,get_supported_content_types() 可按 Provider 返回其接受的 MIME 前缀列表(如 ["image/", "application/pdf"]),供上层做前置过滤。
约束类本身是 frozen dataclass,字段含义清晰:ImageConstraints(体积/宽高/单请求图片数/格式白名单)、PDFConstraints(体积/页数)、AudioConstraints 与 VideoConstraints(体积/时长/格式)、TextConstraints(体积/格式),以及顶层 ProviderConstraints 的 supports_file_upload、file_upload_threshold_bytes、supports_url_references 三个能力位。
文件解析与上传:FileResolver 的三级投递决策
处理完之后,文件还要以 Provider 能接受的形式投出去。resolution/resolver.py 中的 FileResolver.resolve(file, provider) 按以下决策树执行:
- URL 引用:来源本身是
FileUrl且 Providersupports_url_references=True(且非 Bedrock/AWS 系)时,直接返回UrlReference,零下载、零编码; - 文件上传:Provider 支持 File API 且满足
_should_upload()条件时走上传。判定逻辑:prefer_upload=True一律上传;否则文件体积超过「该类型约束的max_size_bytes」或超过「配置/Provider 默认的file_upload_threshold_bytes」时上传; - 内联:其余情况返回
InlineBase64(Base64 编码内容);Bedrock 在use_bytes_for_bedrock=True(默认)时返回InlineBytes原始字节。
上传链路有三个可靠性设计:
- 内容寻址缓存:
UploadCache以「SHA-256 内容哈希 + Provider」为键缓存file_id(缓存 TTL 默认 86400 秒、最多 1000 条,见 core/constants.py),同一文件在同一次运行中对同一 Provider 只上传一次; - 指数退避重试:
_upload_with_retry()最多UPLOAD_MAX_RETRIES=3次,重试间隔为2**attempt秒;PermanentUploadError(如文件超限)立即放弃,TransientUploadError(网络抖动)才进入重试; - 工厂化上传器:
get_uploader(provider)返回对应实现(OpenAI Files API、Gemini Files API、Anthropic、Bedrock 等),均继承自 uploaders/base.py 的FileUploader抽象基类,统一提供upload/aupload、delete/adelete、get_file_info、list_files接口,返回值为UploadResult(file_id, provider, content_type, file_uri?, expires_at?)。
create_resolver() 工厂函数把以上能力装配起来:传入 provider 名即可自动带上该 Provider 的默认上传阈值,prefer_upload、upload_threshold_bytes、enable_cache 均可覆盖。
测试覆盖与延伸阅读
crewai-files 的测试位于 lib/crewai-files/tests,按模块划分:
- test_resolver.py:解析决策树各分支(URL 引用、上传命中缓存、内联回退);
- test_file_url.py:URL 来源的校验与抓取行为;
- test_resolved.py:四种
ResolvedFile形态(FileReference/InlineBase64/InlineBytes/UrlReference); - test_upload_cache.py:上传缓存的读写与过期;
- tests/processing/:
test_processor.py、test_constraints.py、test_transformers.py、test_validators.py,覆盖模式调度、各 Provider 约束、图片缩放/压缩与 PDF/文本分片。
小结
crewai-files 的抽象层次可以概括为一句话:File 家族负责“装得进”(来源与类型),FileProcessor 负责“变得合规”(校验与变换),FileResolver 负责“送得出去”(URL/上传/内联三级投递)。在 Crew 层用 kickoff(input_files=...)、在 Task 层用 input_files=[...] 即可接入;而当你需要自定义 Provider 行为时,正确姿势是构造一份 ProviderConstraints 传给 FileProcessor 与 FileResolver,而不是自行绕过该包重写文件编码逻辑。所有阈值、常量与默认值均可在 core/constants.py 与 processing/constraints.py 中查证,本文数据以当前仓库版本(crewai-files 1.15.18)为准。
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 StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00