全栈应用服务器

  • 全栈应用服务器 > 使用指南 > 沙箱服务概述 > AI Agents > Claude Code

    Claude Code

    最近更新时间: 2026-04-30 16:22:05

    概述

    claude 是预构建的 AI Agents 运行环境,已内置 Claude Code CLI 和官方 MCP server,可在隔离的沙箱环境中以无头方式运行 Anthropic 的智能编码代理,具备完整的文件系统、终端和 git 访问能力。

    模板预装 Node.js、git、ripgrep、vim、GitHub CLI 等常用工具,以及 pnpm/tsx/vite 前端脚手架。镜像内不内置任何 API key,认证信息通过沙箱创建时的 envs 注入或通过密钥注入规则下发。

    模板内容

    组件 说明
    claude Claude Code CLI
    MCP servers @modelcontextprotocol/server-filesystem / server-github / server-memory / server-sequential-thinking
    /home/user/.claude.json 预置 onboarding 状态,避免首次交互卡在官方服务连通性检查
    基础工具 Node.js 24.x、git、ripgrep、vim、GitHub CLI、pnpm/tsx/vite 等

    创建沙箱

    通过 envs 传入 ANTHROPIC_API_KEY

    import { Sandbox } from 'e2b'
    
    const sandbox = await Sandbox.create('claude', {
      envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY },
    })
    

    如需指向第三方 Anthropic 兼容网关,额外注入 ANTHROPIC_BASE_URL

    const sandbox = await Sandbox.create('claude', {
      envs: {
        ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY,
        ANTHROPIC_BASE_URL: 'https://api.qnaigc.com',
      },
    })
    

    常用 CLI flag

    Flag 说明
    -p "<prompt>" 无头(非交互)模式,将 prompt 直接传给 CLI
    --dangerously-skip-permissions 跳过工具调用审批,沙箱隔离环境下可用
    --output-format json 一次性返回 JSON 响应
    --output-format stream-json 实时输出 JSONL 事件流
    --resume <sessionId> 继续之前的会话
    --system-prompt <text> 注入任务级系统提示

    无头执行

    import { Sandbox } from 'e2b'
    
    const sandbox = await Sandbox.create('claude', {
      envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY },
    })
    
    const result = await sandbox.commands.run(
      `claude --dangerously-skip-permissions -p "Create a hello world HTTP server in Go"`,
    )
    
    console.log(result.stdout)
    await sandbox.kill()
    

    Git 仓库集成

    在沙箱中克隆仓库后,让 Claude Code 直接对代码做改动并查看 diff:

    import { Sandbox } from 'e2b'
    
    const sandbox = await Sandbox.create('claude', {
      envs: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY },
      timeoutMs: 600_000,
    })
    
    await sandbox.git.clone('https://github.com/your-org/your-repo.git', {
      path: '/home/user/repo',
      username: 'x-access-token',
      password: process.env.GITHUB_TOKEN,
      depth: 1,
    })
    
    const result = await sandbox.commands.run(
      `cd /home/user/repo && claude --dangerously-skip-permissions -p "Add error handling to all API endpoints"`,
      { onStdout: (data) => process.stdout.write(data) },
    )
    
    const diff = await sandbox.commands.run('cd /home/user/repo && git diff')
    console.log(diff.stdout)
    
    await sandbox.kill()
    

    结构化 JSON 输出

    const result = await sandbox.commands.run(
      `claude --dangerously-skip-permissions --output-format json -p "Review this codebase and list all security issues as JSON"`,
    )
    
    const response = JSON.parse(result.stdout)
    console.log(response)
    

    流式事件处理

    const result = await sandbox.commands.run(
      `cd /home/user/repo && claude --dangerously-skip-permissions --output-format stream-json -p "Find and fix all TODO comments"`,
      {
        onStdout: (data) => {
          for (const line of data.split('\n').filter(Boolean)) {
            const event = JSON.parse(line)
            if (event.type === 'assistant') {
              console.log(`[assistant] tokens: ${event.message.usage?.output_tokens}`)
            } else if (event.type === 'result') {
              console.log(`[done] ${event.subtype} in ${event.duration_ms}ms`)
            }
          }
        },
      },
    )
    

    会话恢复

    --output-format json 返回的 session_id 可用于后续 --resume,把多步任务拆成多次调用:

    const initial = await sandbox.commands.run(
      `cd /home/user/repo && claude --dangerously-skip-permissions --output-format json -p "Analyze the codebase and create a refactoring plan"`,
    )
    
    const sessionId = JSON.parse(initial.stdout).session_id
    
    const followUp = await sandbox.commands.run(
      `cd /home/user/repo && claude --dangerously-skip-permissions --resume ${sessionId} -p "Now implement step 1 of the plan"`,
      { onStdout: (data) => process.stdout.write(data) },
    )
    

    自定义系统提示(CLAUDE.md)

    将项目级约定写入 CLAUDE.md,Claude Code 会自动读取:

    await sandbox.files.write('/home/user/repo/CLAUDE.md', `
    You are working on a Go microservice.
    Always use structured logging with slog.
    Follow the project's error handling conventions in pkg/errors.
    `)
    
    const result = await sandbox.commands.run(
      `cd /home/user/repo && claude --dangerously-skip-permissions -p "Add a /healthz endpoint"`,
    )
    

    配合密钥注入使用

    直接通过 envs 注入 ANTHROPIC_API_KEY 时,真实密钥会落到沙箱进程的环境变量里。如果希望让真实 key 完全留在平台侧,沙箱内代码无法读取,可使用密钥注入:CLI 仍然向 api.anthropic.com(或自定义 ANTHROPIC_BASE_URL)发请求,平台在出站链路上把 x-api-key 改写为真实密钥再转发到上游。

    工作原理

    Sandbox (claude CLI) ──► 平台 MITM ──► api.anthropic.com / 兼容网关
       x-api-key=placeholder  注入真实 key
    

    要让 Claude Code CLI 命中注入规则,必须同时满足两个条件:

    1. ANTHROPIC_BASE_URL 必须等于规则的 base_url(host 部分):平台按 SNI 主机名匹配,CLI 默认访问 api.anthropic.com,与规则不一致时不会被拦截,请求会直连官方 Anthropic。
    2. ANTHROPIC_API_KEY 设为任意非空占位符:CLI 在本地预检阶段需要 key 字段才会发起请求;真实 key 由平台在出站时写入 header,本地的占位符值不会被外发。

    方式一:引用已保存的注入规则

    先用 qshell 创建一条 anthropic 类型的规则:

    qshell sandbox injection-rule create \
      --name claude-anthropic \
      --type anthropic \
      --api-key sk-ant-real-xxx
    

    或针对 Anthropic 兼容网关(需指定 --base-url):

    qshell sandbox injection-rule create \
      --name claude-via-qnaigc \
      --type anthropic \
      --api-key sk-real-xxx \
      --base-url https://api.qnaigc.com
    

    创建沙箱时引用 <rule-id>,并把 CLI 的 ANTHROPIC_API_KEY 设为任意占位符:

    qshell sbx cr claude \
      --injection-rule <rule-id> \
      -e ANTHROPIC_API_KEY=placeholder \
      -e ANTHROPIC_BASE_URL=https://api.qnaigc.com   # 仅当规则指定了 base-url 时
    
    import { Sandbox } from 'e2b'
    
    const sandbox = await Sandbox.create('claude', {
      envs: {
        ANTHROPIC_API_KEY: 'placeholder',
        // 仅当规则指定了 base_url 时才需要设置
        ANTHROPIC_BASE_URL: 'https://api.qnaigc.com',
      },
      injections: [{ id: '<rule-id>' }],
    })
    
    const result = await sandbox.commands.run(
      `claude --dangerously-skip-permissions -p "Create a hello world HTTP server in Go"`,
    )
    console.log(result.stdout)
    

    方式二:内联注入(无需提前创建规则)

    适合临时验证,沙箱销毁后规则不会保留:

    qshell sbx cr claude \
      --inline-injection 'type=anthropic,api-key=sk-ant-real-xxx' \
      -e ANTHROPIC_API_KEY=placeholder
    

    如果同时使用兼容网关,需要 base-urlANTHROPIC_BASE_URL 三处保持一致:

    qshell sbx cr claude \
      --inline-injection 'type=anthropic,api-key=sk-real-xxx,base-url=https://api.qnaigc.com' \
      -e ANTHROPIC_API_KEY=placeholder \
      -e ANTHROPIC_BASE_URL=https://api.qnaigc.com
    

    注意事项

    • 同 host 规则首匹配生效:若有多条规则的 base_url 主机名相同,平台只会按列表顺序应用第一条。同一沙箱内 CLI 也只能指向一个 ANTHROPIC_BASE_URL,因此实际只会触发该 host 对应的那条规则。
    • 占位符不能为空ANTHROPIC_API_KEY="" 会让 CLI 在本地直接报错;任意非空字符串(如 placeholder)即可。
    • --dangerously-skip-permissions 不影响注入:注入发生在网络出站阶段,与 CLI 是否跳过工具审批无关。
    • 生产场景建议使用持久规则:内联注入便于临时调试,但密钥会出现在 qshell 命令历史里;多人协作或长期使用建议改用 --injection-rule 引用持久规则,便于审计、轮换和回收。

    参考

    以上内容是否对您有帮助?