主题
Daytona 沙箱工具
在隔离的 Daytona 沙箱中运行 shell 命令、执行 Python 以及管理文件。
Daytona 沙箱工具
描述
Daytona 沙箱工具让 CrewAI 智能体可以访问由 Daytona 提供支持的隔离、临时计算环境。共有三个工具可用,因此你可以精确地赋予智能体所需的能力:
DaytonaExecTool—— 在沙箱中运行任意 shell 命令。DaytonaPythonTool—— 在沙箱中执行一段 Python 源代码。DaytonaFileTool—— 在沙箱中读取、写入、追加、列出、删除和检查文件;还支持move、find(内容 grep)、search(文件名 glob)、chmod(权限)、replace(批量查找替换)以及exists。
这三个工具共享相同的沙箱生命周期控制,因此你可以混合搭配使用它们,同时将状态保存在单个持久化沙箱中。
安装
shell
uv add "crewai-tools[daytona]"
# or
pip install "crewai-tools[daytona]"设置你的 API key:
shell
export DAYTONA_API_KEY="your-api-key"如果设置了 DAYTONA_API_URL 和 DAYTONA_TARGET,它们也会被采用。
沙箱生命周期
这三个工具都从 DaytonaBaseTool 继承生命周期控制:
| 模式 | 启用方式 | 创建沙箱 | 删除沙箱 |
|---|---|---|---|
| 临时(默认) | persistent=False(默认) | 每次调用 _run 时 | 在同一次调用结束时 |
| 持久 | persistent=True | 首次使用时惰性创建 | 进程退出时(通过 atexit),或通过 tool.close() 手动删除 |
| 附加 | sandbox_id="<id>" | 从不创建 —— 附加到现有沙箱 | 从不删除 —— 工具不会删除非自己创建的沙箱 |
临时模式是安全的默认值:即使智能体忘记清理,也不会有任何残留。当你希望文件系统状态或已安装的包在多次工具调用之间保留时,请使用持久模式——这在将 DaytonaFileTool 与 DaytonaExecTool 搭配使用时很典型。
示例
一次性 Python 执行(临时)
python
from crewai_tools import DaytonaPythonTool
tool = DaytonaPythonTool()
result = tool.run(code="print(sum(range(10)))")
print(result)
# {"exit_code": 0, "result": "45\n", "artifacts": ExecutionArtifacts(stdout="45\n", charts=[])}多步骤 shell 会话(持久)
python
from crewai_tools import DaytonaExecTool, DaytonaFileTool
# Create the persistent sandbox via the first tool, then attach the second
# tool to it so both share state (installed packages, files, env vars).
exec_tool = DaytonaExecTool(persistent=True)
exec_tool.run(command="pip install httpx -q")
file_tool = DaytonaFileTool(sandbox_id=exec_tool.active_sandbox_id)
file_tool.run(
action="write",
path="workspace/script.py",
content="import httpx; print(f'httpx loaded, version {httpx.__version__}')",
)
exec_tool.run(command="python workspace/script.py")NOTE
默认情况下,每个设置了 persistent=True 的工具都会在首次使用时惰性创建它自己的沙箱。上面的模式通过在调用 .run() 后读取第一个工具的 active_sandbox_id,并通过 sandbox_id=... 将其传给其他工具,从而在多个工具之间共享同一个沙箱。当 persistent=False(默认值)时,每次 .run() 调用都会获得一个新的沙箱,并在该次调用结束时被删除。
附加到现有沙箱
python
from crewai_tools import DaytonaExecTool
tool = DaytonaExecTool(sandbox_id="my-long-lived-sandbox")
result = tool.run(command="ls workspace")自定义沙箱参数
通过 create_params 传入 Daytona 的 CreateSandboxFromSnapshotParams 关键字参数:
python
from crewai_tools import DaytonaExecTool
tool = DaytonaExecTool(
persistent=True,
create_params={
"language": "python",
"env_vars": {"MY_FLAG": "1"},
"labels": {"owner": "crewai-agent"},
},
)搜索、移动和修改文件
python
from crewai_tools import DaytonaFileTool
file_tool = DaytonaFileTool(persistent=True)
# Find every TODO in the source tree (grep file contents recursively)
file_tool.run(action="find", path="workspace/src", pattern="TODO:")
# Find all Python files (glob match on filenames)
file_tool.run(action="search", path="workspace", pattern="*.py")
# Make a script executable
file_tool.run(action="chmod", path="workspace/run.sh", mode="755")
# Rename or move a file
file_tool.run(
action="move",
path="workspace/draft.md",
destination="workspace/final.md",
)
# Bulk find-and-replace across multiple files
file_tool.run(
action="replace",
paths=["workspace/src/a.py", "workspace/src/b.py"],
pattern="old_function",
replacement="new_function",
)
# Quick existence check before a destructive op
file_tool.run(action="exists", path="workspace/cache.db")智能体集成
python
from crewai import Agent, Task, Crew
from crewai_tools import DaytonaExecTool, DaytonaPythonTool, DaytonaFileTool
exec_tool = DaytonaExecTool(persistent=True)
python_tool = DaytonaPythonTool(persistent=True)
file_tool = DaytonaFileTool(persistent=True)
coder = Agent(
role="Sandbox Engineer",
goal="Write and run code in an isolated environment",
backstory="An engineer who uses Daytona sandboxes to safely execute code and manage files.",
tools=[exec_tool, python_tool, file_tool],
verbose=True,
)
task = Task(
description="Write a Python script that prints the first 10 Fibonacci numbers, save it to workspace/fib.py, and run it.",
expected_output="The first 10 Fibonacci numbers printed to stdout.",
agent=coder,
)
crew = Crew(agents=[coder], tasks=[task])
result = crew.kickoff()参数
共享参数(DaytonaBaseTool)
这三个工具在初始化时都接受以下参数:
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
api_key | str | None | $DAYTONA_API_KEY | Daytona API 密钥。回退到 DAYTONA_API_KEY 环境变量。 |
api_url | str | None | $DAYTONA_API_URL | Daytona API URL 覆盖值。 |
target | str | None | $DAYTONA_TARGET | Daytona 目标区域。 |
persistent | bool | False | 在所有调用之间复用一个沙箱,并在进程退出时删除它。 |
sandbox_id | str | None | None | 通过 id 或名称附加到现有沙箱。 |
create_params | dict | None | None | 转发给 CreateSandboxFromSnapshotParams 的额外关键字参数(例如 language、env_vars、labels)。 |
sandbox_timeout | float | 60.0 | 沙箱创建/删除操作的超时时间(秒)。 |
DaytonaExecTool
| 参数 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
command | str | ✓ | 要执行的 shell 命令。 |
cwd | str | None | 沙箱内的工作目录。 | |
env | dict[str, str] | None | 该命令的额外环境变量。 | |
timeout | int | None | 等待该命令的最长秒数。 |
DaytonaPythonTool
| 参数 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
code | str | ✓ | 要执行的 Python 源代码。 |
argv | list[str] | None | 通过 CodeRunParams 转发的参数向量。 | |
env | dict[str, str] | None | 通过 CodeRunParams 转发的环境变量。 | |
timeout | int | None | 等待执行的最长秒数。 |
DaytonaFileTool
| 参数 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
action | str | ✓ | 以下之一:read、write、append、list、delete、mkdir、info、exists、move、find、search、chmod、replace。 |
path | str | None | 除 replace 外的所有操作必填 | 沙箱内的绝对路径。 |
content | str | None | append 时必填 | 要写入或追加的内容。 |
binary | bool | 若为 True,写入时 content 为 base64;读取时返回 base64。 | |
recursive | bool | 用于 delete:递归删除目录。 | |
mode | str | None | 用于 mkdir:新目录的八进制权限(默认为 "0755")。用于 chmod:应用于目标的八进制权限。 | |
destination | str | None | move 时必填 | move 的目标路径。 |
pattern | str | None | find、search、replace 时必填 | 用于 find:与文件内容匹配的子串。用于 search:与文件名匹配的 glob(例如 *.py)。用于 replace:在文件中要替换的文本。 |
replacement | str | None | replace 时必填 | pattern 的替换文本。 |
paths | list[str] | None | replace 时必填 | 要在其中替换文本的文件路径列表。 |
owner | str | None | 用于 chmod:新的文件所有者。 | |
group | str | None | 用于 chmod:新的文件组。 |
NOTE
对于 chmod,至少传入 mode、owner 或 group 之一——任何留为 None 的字段在目标上保持不变。
TIP
对于大于几 KB 的文件,先用 action="write" 和空内容创建文件,然后通过多次每次 ~4 KB 的 action="append" 调用发送正文,以保持在工具调用负载限制之内。