EdgeOne Makers Agents 沙箱工具
Agent 不只是聊天,还能执行代码、调用工具。这篇讲怎么用沙箱环境安全地让 Agent 执行任务。
什么是沙箱
沙箱就是一个隔离的执行环境。Agent 在里面跑代码,不会影响外部系统。
| 场景 | 不用沙箱的风险 |
|---|---|
| Agent 执行用户提交的代码 | 可能删库、访问敏感数据 |
| Agent 调用外部 API | 可能泄露密钥、被滥用 |
| Agent 处理文件 | 可能覆盖系统文件 |
沙箱的作用就是让 Agent 能做事,但不会闯祸。
沙箱的能力
EdgeOne Makers 的沙箱提供这些能力
| 能力 | 说明 |
|---|---|
| 代码执行 | 运行 JavaScript、Python 等代码 |
| 文件操作 | 读写临时文件,有大小限制 |
| 网络请求 | 可以调用外部 API |
| 超时控制 | 自动终止长时间运行的任务 |
| 资源限制 | 内存、CPU 使用有上限 |
简单沙箱示例
用 eval 执行代码,但加上严格的限制。
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
if (url.pathname === '/execute') {
const { code, language } = await request.json();
// 简单的安全检查
const forbidden = ['process', 'require', 'import', 'fs'];
for (const keyword of forbidden) {
if (code.includes(keyword)) {
return Response.json({
error: `不允许使用 ${keyword}`
}, { status: 400 });
}
}
try {
// 设置超时(5秒)
const timeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error('执行超时')), 5000);
});
// 执行代码
const execute = new Promise((resolve) => {
const result = eval(code);
resolve(result);
});
const result = await Promise.race([execute, timeout]);
return Response.json({
success: true,
result: String(result)
});
} catch (error) {
return Response.json({
success: false,
error: error.message
});
}
}
}
};
这个例子很简单,只是演示思路。实际生产环境需要更严格的隔离。
工具调用
Agent 可以调用预定义的工具。用 JSON Schema 描述工具,模型 decides 什么时候调用。
定义工具
const tools = [
{
name: 'get_weather',
description: '获取指定城市的天气',
parameters: {
type: 'object',
properties: {
city: {
type: 'string',
description: '城市名称,比如"北京"'
}
},
required: ['city']
}
},
{
name: 'search_web',
description: '搜索网页信息',
parameters: {
type: 'object',
properties: {
query: {
type: 'string',
description: '搜索关键词'
}
},
required: ['query']
}
}
];
处理工具调用
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
if (request.method === 'POST') {
const { message } = await request.json();
// 调用模型,传入工具定义
const response = await env.AI.chat('deepseek-v3', {
messages: [
{ role: 'system', content: '你是一个助手,可以查询天气和搜索网页' },
{ role: 'user', content: message }
],
tools: tools
});
// 检查是否需要调用工具
if (response.tool_calls) {
const results = [];
for (const toolCall of response.tool_calls) {
const { name, arguments: args } = toolCall.function;
// 执行对应的工具
let result;
if (name === 'get_weather') {
result = await getWeather(args.city);
} else if (name === 'search_web') {
result = await searchWeb(args.query);
}
results.push({
tool_call_id: toolCall.id,
result
});
}
// 把工具结果传回模型,生成最终回复
const finalResponse = await env.AI.chat('deepseek-v3', {
messages: [
{ role: 'system', content: '你是一个助手' },
{ role: 'user', content: message },
{ role: 'assistant', content: null, tool_calls: response.tool_calls },
...results.map(r => ({
role: 'tool',
tool_call_id: r.tool_call_id,
content: JSON.stringify(r.result)
}))
]
});
return Response.json({
reply: finalResponse.message.content,
tools_used: response.tool_calls.map(t => t.function.name)
});
}
return Response.json({ reply: response.message.content });
}
}
};
// 工具实现
async function getWeather(city) {
// 调用天气 API
return {
city,
temperature: '22°C',
weather: '晴',
humidity: '45%'
};
}
async function searchWeb(query) {
// 调用搜索 API
return {
query,
results: [
{ title: '结果1', url: 'https://example.com/1' },
{ title: '结果2', url: 'https://example.com/2' }
]
};
}
工具调用流程
| 步骤 | 说明 |
|---|---|
| 1. 用户提问 | “北京今天天气怎么样” |
| 2. 模型判断 | 需要调用 get_weather 工具 |
| 3. 返回工具调用 | tool_calls 包含函数名和参数 |
| 4. 执行工具 | 调用 getWeather(‘北京’) |
| 5. 返回结果 | 把工具结果传回模型 |
| 6. 生成回复 | 模型根据结果生成自然语言回复 |
自定义工具开发
你可以封装任何能力成工具。比如查数据库、调 API、处理文件。
// 数据库查询工具
const dbTool = {
name: 'query_database',
description: '查询产品数据库',
parameters: {
type: 'object',
properties: {
table: { type: 'string' },
condition: { type: 'string' }
}
}
};
async function executeDbQuery(table, condition, env) {
// 简单的 SQL 构造(实际要用参数化查询防注入)
const sql = `SELECT * FROM ${table} WHERE ${condition}`;
// 调用数据库
const result = await env.DB.prepare(sql).all();
return {
table,
count: result.results.length,
data: result.results
};
}
// 文件处理工具
const fileTool = {
name: 'process_file',
description: '处理上传的文件',
parameters: {
type: 'object',
properties: {
action: {
type: 'string',
enum: ['analyze', 'convert']
},
format: { type: 'string' }
}
}
};
async function processFile(action, format, env) {
// 从存储读取文件
const fileData = await env.KV.get('uploaded_file', 'arrayBuffer');
if (action === 'analyze') {
return {
size: fileData.byteLength,
type: 'image',
metadata: { width: 800, height: 600 }
};
} else if (action === 'convert') {
// 转换格式(这里只是示例)
return {
original: 'png',
converted: format,
url: '/converted/file.jpg'
};
}
}
沙箱安全
沙箱不是万能的,还需要额外的安全措施。
| 措施 | 说明 |
|---|---|
| 输入校验 | 检查工具参数,防止注入 |
| 权限控制 | 限制工具能访问的资源 |
| 执行超时 | 自动终止长时间任务 |
| 资源限制 | 内存、CPU 使用上限 |
| 日志审计 | 记录所有工具调用 |
// 带权限检查的工具调用
async function callToolWithAuth(toolName, args, userId, env) {
// 检查用户权限
const userPerms = await env.KV.get(`user:${userId}:permissions`, 'json');
const toolPerms = {
'get_weather': 'public',
'query_database': 'admin',
'process_file': 'user'
};
const requiredPerm = toolPerms[toolName];
if (!userPerms.includes(requiredPerm)) {
throw new Error('没有权限执行此操作');
}
// 记录调用日志
await env.KV.put(`log:${Date.now()}`, JSON.stringify({
userId,
tool: toolName,
args,
timestamp: Date.now()
}));
// 执行工具
return await executeTool(toolName, args, env);
}
速查卡片
| 要点 | 说明 |
|---|---|
| 沙箱作用 | 隔离执行环境,防止 Agent 闯祸 |
| 沙箱能力 | 代码执行、文件操作、网络请求 |
| 工具定义 | 用 JSON Schema 描述工具参数 |
| 工具调用流程 | 模型判断 → 返回调用 → 执行 → 返回结果 → 生成回复 |
| 安全检查 | 输入校验、权限控制、超时、资源限制 |
| 自定义工具 | 可以封装任何能力成工具 |
| 日志审计 | 记录所有工具调用,便于追踪 |