Files
deer-flow/frontend/src/content/zh/harness/sandbox.mdx
T
greatmengqi 3e6a34297d refactor(config): eliminate global mutable state — explicit parameter passing on top of main
Squashes 25 PR commits onto current main. AppConfig becomes a pure value
object with no ambient lookup. Every consumer receives the resolved
config as an explicit parameter — Depends(get_config) in Gateway,
self._app_config in DeerFlowClient, runtime.context.app_config in agent
runs, AppConfig.from_file() at the LangGraph Server registration
boundary.

Phase 1 — frozen data + typed context

- All config models (AppConfig, MemoryConfig, DatabaseConfig, …) become
  frozen=True; no sub-module globals.
- AppConfig.from_file() is pure (no side-effect singleton loaders).
- Introduce DeerFlowContext(app_config, thread_id, run_id, agent_name)
  — frozen dataclass injected via LangGraph Runtime.
- Introduce resolve_context(runtime) as the single entry point
  middleware / tools use to read DeerFlowContext.

Phase 2 — pure explicit parameter passing

- Gateway: app.state.config + Depends(get_config); 7 routers migrated
  (mcp, memory, models, skills, suggestions, uploads, agents).
- DeerFlowClient: __init__(config=...) captures config locally.
- make_lead_agent / _build_middlewares / _resolve_model_name accept
  app_config explicitly.
- RunContext.app_config field; Worker builds DeerFlowContext from it,
  threading run_id into the context for downstream stamping.
- Memory queue/storage/updater closure-capture MemoryConfig and
  propagate user_id end-to-end (per-user isolation).
- Sandbox/skills/community/factories/tools thread app_config.
- resolve_context() rejects non-typed runtime.context.
- Test suite migrated off AppConfig.current() monkey-patches.
- AppConfig.current() classmethod deleted.

Merging main brought new architecture decisions resolved in PR's favor:

- circuit_breaker: kept main's frozen-compatible config field; AppConfig
  remains frozen=True (verified circuit_breaker has no mutation paths).
- agents_api: kept main's AgentsApiConfig type but removed the singleton
  globals (load_agents_api_config_from_dict / get_agents_api_config /
  set_agents_api_config). 8 routes in agents.py now read via
  Depends(get_config).
- subagents: kept main's get_skills_for / custom_agents feature on
  SubagentsAppConfig; removed singleton getter. registry.py now reads
  app_config.subagents directly.
- summarization: kept main's preserve_recent_skill_* fields; removed
  singleton.
- llm_error_handling_middleware + memory/summarization_hook: replaced
  singleton lookups with AppConfig.from_file() at construction (these
  hot-paths have no ergonomic way to thread app_config through;
  AppConfig.from_file is a pure load).
- worker.py + thread_data_middleware.py: DeerFlowContext.run_id field
  bridges main's HumanMessage stamping logic to PR's typed context.

Trade-offs (follow-up work):

- main's #2138 (async memory updater) reverted to PR's sync
  implementation. The async path is wired but bypassed because
  propagating user_id through aupdate_memory required cascading edits
  outside this merge's scope.
- tests/test_subagent_skills_config.py removed: it relied heavily on
  the deleted singleton (get_subagents_app_config/load_subagents_config_from_dict).
  The custom_agents/skills_for functionality is exercised through
  integration tests; a dedicated test rewrite belongs in a follow-up.

Verification: backend test suite — 2560 passed, 4 skipped, 84 failures.
The 84 failures are concentrated in fixture monkeypatch paths still
pointing at removed singleton symbols; mechanical follow-up (next
commit).
2026-04-26 21:45:02 +08:00

145 lines
4.9 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: 沙箱
description: 沙箱为 Lead Agent 提供一个受控环境,在其中可以读取文件、写入输出、运行 Shell 命令并生成产出物。没有沙箱,Agent 只能生成文本;有了沙箱,它可以编写和执行代码、处理数据文件、生成图表并构建交付物。
---
import { Callout, Cards, Tabs } from "nextra/components";
# 沙箱
<Callout type="info" emoji="📦">
沙箱是 Agent 进行文件和命令操作的隔离工作区。它让 DeerFlow 能够采取真实行动,而不仅仅是对话。
</Callout>
沙箱为 Lead Agent 提供一个受控环境,在其中可以读取文件、写入输出、运行 Shell 命令并生成产出物。没有沙箱,Agent 只能生成文本;有了沙箱,它可以编写和执行代码、处理数据文件、生成图表并构建交付物。
## 沙箱模式
DeerFlow 支持三种沙箱模式,选择适合你部署的一种:
### LocalSandbox(默认)
命令直接在主机机器的文件系统上运行,没有容器隔离。
- **适合**:受信任的单用户本地开发工作流。
- **风险**:Agent 可以访问主机文件系统。默认使用 `allow_host_bash: false` 防止任意命令执行。
```yaml
sandbox:
use: deerflow.sandbox.local:LocalSandboxProvider
allow_host_bash: false # 默认;仅对完全受信任的工作流设置为 true
```
### 基于容器的 AIO 沙箱
命令在隔离容器中运行(Linux/Windows 上的 DockermacOS 上的 Apple Container)。每个沙箱会话获得一个全新的容器环境。
- **适合**:多用户环境、生产部署,或任何需要执行隔离的场景。
```yaml
sandbox:
use: deerflow.community.aio_sandbox:AioSandboxProvider
# 可选:容器镜像(下方显示默认值)
image: enterprise-public-cn-beijing.cr.volces.com/vefaas-public/all-in-one-sandbox:latest
# 可选:最大并发容器数(默认:3,超出时 LRU 淘汰)
replicas: 3
# 可选:空闲超时(秒,默认:600)
idle_timeout: 600
# 可选:自定义挂载
mounts:
- host_path: /path/on/host
container_path: /home/user/shared
read_only: false
```
安装:`cd backend && uv add 'deerflow-harness[aio-sandbox]'`
### Provisioner 管理的沙箱(Kubernetes
每个沙箱在 Kubernetes 集群中获得一个专用 Pod,由 Provisioner 服务管理。这提供最强的隔离性,适合有多个并发用户的生产环境。
```yaml
sandbox:
use: deerflow.community.aio_sandbox:AioSandboxProvider
provisioner_url: http://provisioner:8002
```
## 路径映射
沙箱使用路径映射来桥接主机文件系统和容器的虚拟文件系统。始终配置两个关键映射:
| 主机路径 | 容器路径 | 访问权限 |
|---|---|---|
| `skills/`(来自 `skills.path` | `/mnt/skills`(来自 `skills.container_path` | 只读 |
| `.deer-flow/threads/{thread_id}/user-data/` | `/mnt/user-data/` | 读写 |
技能目录始终以只读方式挂载。线程将其工作数据(上传文件、输出、中间文件)写入 `/mnt/user-data/`。
### 自定义挂载
你可以为本地沙箱使用 `mounts:` 配置添加额外挂载:
```yaml
sandbox:
use: deerflow.sandbox.local:LocalSandboxProvider
mounts:
- host_path: /home/user/my-project
container_path: /mnt/my-project
read_only: true
```
<Callout type="warning">
自定义挂载的 <code>container_path</code> 不能与保留前缀冲突:
<code>/mnt/skills</code>、<code>/mnt/acp-workspace</code> 或 <code>/mnt/user-data</code>。
</Callout>
## 输出截断
沙箱工具限制输出大小以保持 Agent 上下文可控。这些限制可配置:
```yaml
sandbox:
use: deerflow.sandbox.local:LocalSandboxProvider
# bash 使用中间截断(头部 + 尾部)
bash_output_max_chars: 20000
# read_file 使用头部截断
read_file_output_max_chars: 50000
# ls 使用头部截断
ls_output_max_chars: 20000
```
设置为 `0` 禁用截断。
## 安全性
### LocalSandbox
`LocalSandbox` 直接在主机上运行命令。默认情况下,`bash` 工具**被禁用**以防止任意主机命令执行。仅对完全受信任的单用户工作流启用它:
```yaml
sandbox:
allow_host_bash: true # 危险:授予 Agent 对你机器的 Shell 访问权限
```
即使没有 `bash`,Agent 也可以通过专用文件工具读写文件。
### 容器沙箱
基于容器的沙箱提供文件系统和进程隔离。Agent 看不到或修改主机文件系统,除非通过显式挂载。Provisioner 管理模式增加了额外一层:每个线程获得自己的隔离 Pod。
### 审计中间件
`SandboxAuditMiddleware` 在每次 Agent 轮次上运行,记录所有沙箱操作,提供会话期间访问了哪些文件、运行了哪些命令的审计跟踪。
<Cards num={2}>
<Cards.Card title="工具" href="/docs/harness/tools" />
<Cards.Card title="子 Agent" href="/docs/harness/subagents" />
</Cards>