Skip to content

实战:安全的编码 Agent

本实战为一个虚构仓库组装编码流程:读取任务、规划、检查文件、生成补丁、在 remote sandbox 中验证、 根据失败修复,再把高风险动作交给人工审批。示例只描述 SandboxBackendProtocol 边界,不创建真实 sandbox,不在宿主运行命令。

威胁模型先于 Prompt

假设任务描述、仓库源码、依赖脚本、测试输出和 MCP 结果都可能包含恶意指令。需要保护的资产包括 宿主文件、SSH/cloud 凭据、内网、其他租户 workspace、代码仓库写权限和构建制品。

前端类比

这类似在 CI 的隔离 runner 中构建不可信 Pull Request:即使 PR 作者写了“这是安全脚本”,平台仍要 用权限、网络、secret 和审批策略限制执行。

Deep Agents 原生语义:实现 SandboxBackendProtocol 的 backend 会让 FilesystemMiddleware 暴露 execute。内置 filesystem permissions 不约束 shell,因此安全边界必须由 remote sandbox、 命令/网络策略、业务工具授权和 HITL 共同建立。

目标流程

  1. 读取只读任务说明,使用 write_todos 建立计划。
  2. lsglobgrepread_file 获取最小上下文。
  3. 只在 /workspace/ 生成补丁,不直接推送或发布。
  4. 在 sandbox 运行批准的 formatter、lint 和 test。
  5. 测试失败时读取有限输出,修改后重新验证。
  6. 安装依赖、网络访问、删除、git push 等高风险动作必须审批或直接禁用。
  7. 最终返回验证命令、exit code、变更摘要与未解决风险。

1. 从可信应用注入 Sandbox

python
import os

from deepagents import create_deep_agent
from deepagents.backends import SandboxBackendProtocol
from langgraph.checkpoint.base import BaseCheckpointSaver


def build_coding_agent(
    backend: SandboxBackendProtocol,
    checkpointer: BaseCheckpointSaver,
):
    return create_deep_agent(
        model=os.environ["DEEPAGENTS_MODEL"],
        backend=backend,
        permissions=[
            {
                "operations": ["read", "write"],
                "paths": ["/workspace/**"],
                "mode": "allow",
            },
            {
                "operations": ["read", "write"],
                "paths": ["/**"],
                "mode": "deny",
            },
        ],
        checkpointer=checkpointer,
        interrupt_on={
            "execute": {"allowed_decisions": ["approve", "reject"]},
            "delete": {"allowed_decisions": ["approve", "reject"]},
        },
        system_prompt="""
        先规划,再读取最小文件集。所有改动仅限 /workspace。
        修改后运行应用提供的验证命令;不要访问网络、安装依赖、推送或发布。
        结束时报告文件 diff、验证命令、exit code 与未解决问题。
        """,
    )

backend 必须由认证后的应用根据 thread/tenant 创建,不能由模型选择 sandbox id。生产实现应配置 TTL、CPU/内存/磁盘/进程、网络 egress 和并发配额,并在 finally 或平台回收机制中销毁资源。

2. 在 Sandbox 层强制命令策略

HITL 适合让人看见 action,但不是强制 allowlist。Sandbox provider、代理或 backend wrapper 仍要 拒绝不在策略内的命令。虚构仓库的最小策略可以是:

python
ALLOWED_COMMANDS = {
    "python -m pytest -q",
    "python -m ruff check .",
    "python -m ruff format --check .",
}


def validate_command(command: str) -> None:
    if command not in ALLOWED_COMMANDS:
        raise PermissionError(f"Command is not allowed: {command}")

真实实现必须在 backend.execute() 进入 provider 之前调用策略,而不是让模型先执行后检查。 禁止通过 bash -c、重定向、管道、命令替换或解释器参数绕过 allowlist;复杂场景优先暴露 run_testsrun_lint 等结构化业务工具,而不是任意 shell 字符串。

3. 运行与恢复

HITL 依赖 checkpointer 和稳定 thread_id。应用层调用形状为:

python
# 本文不创建 backend,也不执行模型或命令。
agent = build_coding_agent(trusted_remote_backend, persistent_checkpointer)
config = {"configurable": {"thread_id": trusted_thread_id}}

result = agent.invoke(
    {
        "messages": [
            {
                "role": "user",
                "content": "修复 /workspace/tests 中描述的日期格式化失败。",
            }
        ]
    },
    config=config,
    version="v2",
)

如果返回 interrupt,审批 UI 应展示完整命令、cwd、预期文件/网络影响、subagent 来源和可替代操作。 恢复时沿用同一 thread_id,使用 Command(resume={"decisions": [...]})。审批后的参数仍要再次经过 sandbox policy。

4. 失败修复与完成证据

模型说“测试通过”不算证据。应用应从 tool result 记录:

  • 完整命令的规范化标识和 policy 版本。
  • Exit code、受限 stdout/stderr、timeout 与 sandbox id。
  • 修改前后文件 hash 或统一 diff。
  • 重试次数、失败分类和最终未通过项。
  • 审批人、decision、编辑后的 action 和时间。

测试失败时只把相关片段返回 Agent,完整日志留作 artifact。达到 turn、时间或费用上限后应停止并报告, 不能无限进入“修改—重试”循环。

不可越过的边界

  • 不对不可信任务使用宿主 LocalShellBackend
  • 不把 .env、SSH key、cloud token 或 package registry 凭据放进 sandbox。
  • 不给 Agent 直接 git push、merge、发布或生产写权限。
  • 不让 filesystem permission 的“允许 /workspace/**”掩盖 execute 可访问整个 sandbox 的事实。
  • 不把 HITL auto-approve 当成 CI 的默认配置。
  • 不直接信任生成 diff、测试输出或 artifact;它们仍是 sandbox 中的不可信数据。

TypeScript 迁移表

PythonTypeScript
create_deep_agentcreateDeepAgent
SandboxBackendProtocolprovider 对应的 sandbox backend type
interrupt_oninterruptOn
allowed_decisionsallowedDecisions
system_promptsystemPrompt
Command(resume=...)new Command({ resume: ... })

两个语言版本必须共享同一命令策略、sandbox template、网络规则和验收 fixture;只有 SDK adapter 层 使用各自命名习惯。

先修

下一步

官方参考

学习文档整合站点