DeepSeek Harness: 沙箱与审批
最后更新:2026-08-31
Agent 的强大在于它能执行操作,但"能执行"不等于"应该执行"。审批策略是 Agent 行为的刹车,沙箱是 Agent 行为的围栏。两者结合,让 Agent 在安全边界内自由行动。
💡 提示:审批策略是"什么时候问用户",沙箱是"在哪执行"。审批决定决策权归属,沙箱决定执行环境边界。两者独立但互补。
📋 前置知识:已完成 13-effect.md 和 22-capability.md
1. 你将学到
- 审批策略(approval policy)
- 权限预设(permission presets)
- 危险操作审批弹窗
- 沙箱后端注册
- ctx.sandbox 与 ctx.shell
- 远程沙箱配置
2. 审批策略(approval policy)
(1) 策略模式
DSH 提供四种审批模式:
| 模式 | 行为 | 适用 |
|---|---|---|
always |
始终允许,不弹窗 | 安全操作(read、search) |
ask |
需要审批,弹窗确认 | 危险操作(create、edit、shell) |
ask_with_confirm |
二次确认弹窗 | 极危险操作(delete、sudo) |
deny |
自动拒绝 | 绝不允许的操作(rm -rf /) |
(2) ▶ 示例 2
YAML
# dsh.config.yaml
approval:
default: ask
tools:
file_edit:
read: always
create: ask
edit: ask
delete: ask_with_confirm
shell:
safe: always
moderate: ask
dangerous: ask_with_confirm
forbidden: deny
search:
default: always
sandbox:
default: ask
(3) ▶ 示例 3
YAML
approval:
tools:
file_edit:
# 路径白名单自动允许
auto_allow_paths:
- /tmp/**
- /workspace/**
# 路径黑名单自动拒绝
auto_deny_paths:
- /etc/**
- /var/**
shell:
# 命令白名单
auto_allow_commands:
- ls
- cat
- grep
- head
- wc
- git status
- git log
# 命令黑名单
auto_deny_commands:
- rm -rf /*
- mkfs
- dd if=*
(4) ▶ 示例 4
TYPESCRIPT
import { defineTool } from '@deepseek-ai/dsh'
export default defineTool({
name: 'db_query',
description: 'Execute SQL query',
parameters: { /* ... */ },
approval: {
level: 'ask',
rules: [
{ match: { query: /^SELECT/i }, level: 'always' },
{ match: { query: /^DROP/i }, level: 'deny' },
{ match: { query: /^INSERT|^UPDATE|^DELETE/i }, level: 'ask_with_confirm' }
]
},
async execute({ query }, ctx) {
return await ctx.database.query(query)
}
})
3. 权限预设(permission presets)
(1) 内置预设
DSH 提供三个权限预设:
| 预设 | 说明 | 典型操作 |
|---|---|---|
| trusted | 信任模式,大部分自动允许 | 个人开发环境 |
| standard | 标准模式,危险操作需审批 | 默认配置 |
| restricted | 受限模式,严格审批 | 生产环境 |
(2) 预设对比
YAML
# trusted — 信任模式
approval:
tools:
file_edit: always
shell: always
search: always
# standard — 标准模式
approval:
tools:
file_edit:
read: always
create: ask
edit: ask
delete: ask_with_confirm
shell: ask
# restricted — 受限模式
approval:
tools:
file_edit: ask_with_confirm
shell: deny
search: ask
(3) 选择预设
BASH
# 启动时选择预设
pnpm dsh web --preset trusted
pnpm dsh web --preset standard
pnpm dsh web --preset restricted
(4) 自定义预设
YAML
# dsh.config.yaml
approval:
presets:
my-team:
tools:
file_edit:
read: always
create: ask
edit: ask
delete: deny
shell: ask
4. 危险操作审批弹窗
(1) 弹窗机制
当工具调用需要审批时,DSH 暂停执行,弹出审批弹窗:
TEXT
📖 仅展示
⚠️ Approval Required: Execute shell command
Command: npm install bcryptjs
Working directory: /home/alice/project
Risk level: MODERATE
[Allow] [Always for npm] [Deny]
(2) 审批选项
| 选项 | 说明 |
|---|---|
| Allow | 允许本次操作 |
| Always | 允许此类操作(不再弹窗) |
| Always for X | 允许特定规则的操作 |
| Deny | 拒绝本次操作 |
(3) 批量审批
多个操作可以批量审批:
TEXT
📖 仅展示
⚠️ Batch Approval Required: 3 operations
1. file_edit: create src/utils.ts
2. file_edit: edit src/app.ts
3. shell: npm install bcryptjs
[Allow All] [Review Each] [Deny All]
(4) 审批日志
所有审批决策记录到日志:
TEXT
📖 仅展示
[approval] ALLOWED: file_edit(read, src/config.ts) — policy: always
[approval] ASKED: file_edit(create, src/utils.ts) — user: allowed
[approval] DENIED: shell(rm -rf /tmp/test) — policy: deny
5. 沙箱后端注册
(1) 沙箱概念
沙箱是工具执行的隔离环境——Agent 的操作在沙箱内执行,不影响宿主系统:
graph LR
AGENT[Agent] -->|调用工具| SANDBOX[沙箱环境]
SANDBOX -->|隔离执行| FS[沙箱文件系统]
SANDBOX -->|隔离执行| SHELL[沙箱 Shell]
SANDBOX -->|隔离网络| NET[沙箱网络]
SANDBOX -.->|不允许| HOST[宿主系统]
(2) 沙箱后端接口
TYPESCRIPT
interface SandboxBackend {
name: string
execute(command: string, options: ShellOptions): Promise<ShellResult>
readFile(path: string): Promise<string>
writeFile(path: string, content: string): Promise<void>
stat(path: string): Promise<FileStat>
readdir(path: string): Promise<DirEntry[]>
}
(3) 注册沙箱后端
TYPESCRIPT
import { Service, Context } from '@deepseek-ai/cordis'
export default class DockerSandboxBackend extends Service {
constructor(ctx: Context) {
super(ctx, 'sandbox')
ctx.implement(SandboxCapability, {
name: 'docker-sandbox',
async execute(command, options) {
const container = await this.getContainer()
const result = await container.exec(command, options)
return result
},
async readFile(path) {
const container = await this.getContainer()
return await container.readFile(path)
},
async writeFile(path, content) {
const container = await this.getContainer()
await container.writeFile(path, content)
},
// ...
})
}
}
(4) 配置沙箱
YAML
# dsh.config.yaml
sandbox:
backend: docker
config:
image: dsh-sandbox:latest
workdir: /workspace
memory: 512m
cpus: 1
timeout: 30000
network: none
6. ctx.sandbox 与 ctx.shell
(1) ctx.sandbox
ctx.sandbox 提供沙箱化的文件操作:
TYPESCRIPT
export const inject = ['sandbox']
export function apply(ctx: Context) {
ctx.tools.register(defineTool({
name: 'sandbox_read',
description: 'Read file in sandbox',
parameters: {
type: 'object',
properties: {
path: { type: 'string', description: 'File path in sandbox' }
},
required: ['path']
},
async execute({ path }, ctx) {
const content = await ctx.sandbox.readFile(path)
return { content }
}
}))
}
(2) ctx.shell
ctx.shell 在沙箱内执行命令:
TYPESCRIPT
export const inject = ['shell']
export function apply(ctx: Context) {
ctx.tools.register(defineTool({
name: 'sandbox_exec',
description: 'Execute command in sandbox',
parameters: {
type: 'object',
properties: {
command: { type: 'string', description: 'Command to execute' }
},
required: ['command']
},
async execute({ command }, ctx) {
const result = await ctx.shell.execute(command, {
cwd: '/workspace',
timeout: 30000
})
return {
stdout: result.stdout,
stderr: result.stderr,
exitCode: result.exitCode
}
}
}))
}
(3) sandbox vs 直接 fs
| 操作 | 直接 fs | ctx.sandbox |
|---|---|---|
| 文件路径 | 宿主系统路径 | 沙箱内路径 |
| 权限 | 宿主用户权限 | 沙箱用户权限 |
| 隔离 | 无 | 完全隔离 |
| 性能 | 快 | 稍慢(经过沙箱层) |
(4) 安全使用原则
TYPESCRIPT
// ❌ 直接操作宿主文件系统
import { readFileSync } from 'fs'
const content = readFileSync('/etc/passwd')
// ✅ 通过沙箱操作
const content = await ctx.sandbox.readFile('/etc/passwd')
// → 如果沙箱配置了文件系统隔离,这个调用会被限制
7. 远程沙箱配置
(1) 远程沙箱架构
graph TB
DSH[DSH Agent] -->|HTTP API| API[Sandbox API Server]
API -->|管理| CONTAINER1[容器 1<br/>Agent A]
API -->|管理| CONTAINER2[容器 2<br/>Agent B]
CONTAINER1 --> FS1[隔离文件系统 1]
CONTAINER2 --> FS2[隔离文件系统 2]
(2) 配置远程沙箱
YAML
# dsh.config.yaml
sandbox:
backend: remote
config:
endpoint: http://sandbox-server:8080
apiKey: sk-sandbox-xxx
defaultImage: dsh-sandbox:latest
maxContainers: 10
containerTimeout: 3600
allowedImages:
- dsh-sandbox:latest
- dsh-sandbox-python:latest
(3) 远程沙箱后端实现
TYPESCRIPT
export default class RemoteSandboxBackend extends Service {
private endpoint: string
private apiKey: string
constructor(ctx: Context) {
super(ctx, 'sandbox')
this.endpoint = ctx.config.endpoint
this.apiKey = ctx.config.apiKey
}
async execute(command: string, options: ShellOptions): Promise<ShellResult> {
const response = await fetch(`${this.endpoint}/execute`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiKey}`
},
body: JSON.stringify({ command, ...options })
})
return await response.json()
}
async readFile(path: string): Promise<string> {
const response = await fetch(`${this.endpoint}/read`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${this.apiKey}` },
body: JSON.stringify({ path })
})
const data = await response.json()
return data.content
}
// ...
}
(4) 沙箱生命周期
TEXT
📖 仅展示
1. Agent 会话创建 → 请求沙箱容器
2. 沙箱 API 创建容器 → 返回容器 ID
3. Agent 操作在容器内执行
4. Agent 会话销毁 → 请求销毁容器
5. 沙箱 API 销毁容器 → 释放资源
❓ 常见问题
Q 审批弹窗会阻塞 Agent 吗?
A 会。Agent 等待用户审批后才会继续执行。这是有意设计——防止 Agent 在用户不知情时执行危险操作。
Q 可以跳过审批弹窗吗?
A 使用
--preset trusted 可以自动允许大部分操作。但不建议在生产环境使用。Q 沙箱和 Docker 是什么关系?
A Docker 是沙箱的一种实现方式。DSH 的沙箱后端接口是通用的,可以用 Docker、gVisor、远程服务器等任何实现。
Q 没有配置沙箱时会怎样?
A 工具直接在宿主系统上执行。相当于"无沙箱"模式——Agent 有完整的宿主权限。
Q 远程沙箱的延迟大吗?
A 取决于网络和沙箱实现。通常文件操作 10-50ms,命令执行 100-500ms(含启动开销)。
Q 如何审计审批决策?
A 查看审批日志(approval log),记录了每次审批决策的时间、操作、策略和用户选择。 ---
📖 小节
- 审批策略四种模式:always/ask/ask_with_confirm/deny
- 权限预设:trusted(自动允许)、standard(需审批)、restricted(严格审批)
- 审批弹窗暂停 Agent 执行,等待用户决策
- 沙箱后端通过 SandboxCapability 接口注册,支持 Docker/远程/自定义实现
- ctx.sandbox 和 ctx.shell 在沙箱内执行操作,隔离宿主系统
- 远程沙箱通过 HTTP API 管理,支持多容器隔离
📝 作业
1. ⭐ 基础题:配置 DSH 使用 standard 预设,尝试让 Agent 执行 ls(自动允许)和 rm(需审批),观察审批弹窗行为。
2. ⭐⭐ 进阶题:为自定义工具添加审批规则——SELECT 查询自动允许,INSERT/UPDATE/DELETE 需审批,DROP 自动拒绝。测试每种 SQL 类型的审批行为。
3. ⭐⭐⭐ 挑战题:实现一个简单的沙箱后端(用子进程隔离),注册到 DSH 中。让 Agent 在沙箱内执行命令,验证:1) 文件操作限制在沙箱目录内;2) 网络请求被阻断;3) 沙箱销毁后文件被清理。