学习笔记 · Obsidian

Deep Agents Python:工具、后端、权限、沙箱与协议

LangChainPython

执行能力分层

一个生产 Agent 的“能做什么”至少分四层,不能只看模型工具列表:

层作用是否直接接触外部世界
工具调用业务函数、API、数据库或 MCP是,由工具实现决定
文件后端为内置文件工具提供统一命名空间取决于后端
解释器在 Agent 循环内用 JavaScript 编排工具和数据默认否,显式桥接后才是
沙箱隔离文件系统并执行 shell是,但应与宿主隔离

安全判断必须沿完整调用链进行:模型可见工具 → 中间件 → 后端或外部服务 → 凭证与网络。只在提示词中写“不要访问敏感信息”不构成隔离。

工具面

自定义与 MCP 工具

Deep Agents 接受普通可调用对象、LangChain Tool、供应商原生 tool dict 和 MCP 工具。函数签名与 docstring 会形成模型可见 schema,因此名称、何时使用、参数含义和返回约束应写得具体。

框架内置工具:

工具语义
ls列目录及元数据
read_file分页读文本,或返回多模态 content blocks
write_file创建或覆盖文件
edit_file精确字符串替换
delete删除文件或递归删除目录;需要 deepagents 0.7+
glob / grep路径匹配与内容检索
execute仅支持 shell 的后端可见
task启动同步子代理
write_todos仅加入 TodoListMiddleware 后可见

收窄工具优先于靠提示约束:只读 Agent 应使用 FilesystemMiddleware 的工具 allowlist;完全不需要的工具用 profile 的 excluded_tools 移除,既减少风险,也缩小每轮提示的 schema 体积。

后端选择

后端持久化/隔离范围适合主要风险
StateBackend同一 thread;由 checkpoint 延续草稿、结果卸载、临时文件大文件进入图状态会放大 checkpoint
StoreBackend跨 thread;namespace 决定隔离用户记忆、长期资料namespace 错误会造成跨用户泄漏
FilesystemBackend真实本地磁盘本地开发、受控 CI、挂载卷永久改盘、读取 secrets、路径逃逸
LocalShellBackend真实磁盘 + 宿主 shell可信的本地开发工具任意命令、资源耗尽、不可逆修改
ContextHubBackendLangSmith Hub repo有版本历史的持久上下文并发提交冲突、依赖远端服务
CompositeBackend按路径前缀路由临时区与持久区混合路由/权限作用域配置复杂
SandboxBackend隔离文件系统 + execute生产代码执行、数据分析上下文注入、网络外泄、资源成本

关键规则

  • 默认 StateBackend 在线程内持久,父子代理共享其中的文件。
  • 多用户 StoreBackend 必须显式用 user_id、tenant_id 或 assistant_id 构造 namespace;不要依赖旧的 assistant 默认命名空间。
  • FilesystemBackend 设置 root_dir 本身不是安全边界。需要路径约束时必须启用 virtual_mode;否则绝对路径、上级路径等仍可能越界。
  • LocalShellBackend 即使 virtual_mode 为真也不安全,因为 shell 命令仍可访问宿主任意可达路径。
  • 单独使用 FilesystemBackend 会把 /large_tool_results/、/conversation_history/ 等内部文件写进真实项目目录。通常用 CompositeBackend:项目路由到磁盘,默认路由仍用 StateBackend。
  • CompositeBackend 以最长前缀匹配;聚合 ls、glob、grep 时保留原始虚拟路径。
  • 自定义后端应返回带 error 的结构化结果而不是抛出异常;是否实现 delete / execute 决定对应工具是否向模型暴露。

文件权限

permissions 是面向内置文件工具的声明式规则:

  • operations:read 或 write。
  • paths:glob 路径。
  • mode:allow、deny 或 interrupt。
  • 从上到下匹配,第一个命中项生效。
  • 没有规则命中时默认允许。

因此“只允许工作区”的安全配置必须有末尾全局 deny;具体敏感文件 deny 要放在较宽工作区 allow 之前。

覆盖范围:

  • read 包含 ls、read_file、glob、grep。
  • write 包含 write_file、edit_file、delete。
  • 不覆盖自定义工具、MCP 工具。
  • 不覆盖沙箱中的 execute;shell 可以绕过路径级规则。
  • 子代理默认继承父权限;子代理声明 permissions 时是整体替换,不是追加。
  • interrupt 模式与 interrupt_on 合并,使用同一审批/恢复流程。

目录 delete 会保守检查目标和所有后代:任一路径拒绝,整次删除失败,不执行部分删除。对 CompositeBackend + sandbox 默认路由,权限路径必须落在明确的非沙箱路由下,否则路径规则无法约束 shell,应直接拒绝这种配置。

permissions 适合路径 allow/deny;内容审查、速率限制、审计日志等使用 backend policy hook 或包装器。

沙箱

为什么仍需要沙箱

Agent 生成的命令不可完全预测。沙箱将文件、进程和宿主隔离,并提供 execute。它保护宿主,但不自动解决两类问题:

  1. 间接提示注入仍可让 Agent 在沙箱内部执行任意动作。
  2. 如果网络开放,沙箱中的数据仍可通过 HTTP、DNS 等外传。

两种集成模式

模式Agent 在哪里优点成本
Agent in sandboxAgent 与工具都在容器/VM 内与本地运行相似、耦合紧密模型/API 凭证进入沙箱;更新镜像和通信层更重
Sandbox as toolAgent 在服务端,远程调用沙箱 backendAgent 状态和执行解耦;凭证留在外部;失败隔离好每次调用有网络延迟

官方示例以“沙箱作为工具”为主。生产通常也更容易做凭证隔离和多沙箱并发。

生命周期

  • thread-scoped:每个会话一个沙箱;同一 thread 重用,TTL 后回收。默认隔离更强。
  • assistant-scoped:同一 assistant 的多个 thread 共用;适合复用已克隆仓库和依赖,但状态会持续累积,必须设置 TTL、快照或清理。

沙箱是计费资源,创建、查找、过期与销毁都要可观测;不要把“对话结束”当作一定会触发清理。

两个文件平面

  • Agent 文件工具:模型在任务中读写、搜索、执行。
  • upload_files / download_files:应用在边界外播种输入与取回产物。

两者用途不同。应用上传项目、技能脚本和输入数据;Agent 在容器内工作;应用最后下载报告、构建产物或需要回写的记忆。

凭证

不要把 API key、token、数据库凭证放进沙箱环境变量、挂载文件或 secrets。Agent 能读到的秘密,提示注入者也有机会读取并外传。

首选:

  1. 把认证动作封装为沙箱外的窄工具。
  2. 使用网络代理在出站请求处注入凭证,沙箱只看到普通 URL。
  3. 不需要网络时直接阻断网络;需要时做目标白名单。
  4. 把沙箱产物视为不可信输入,输出进入业务系统前再校验。

解释器

解释器是 QuickJS 内存运行时,为模型增加 eval 工具。它适合循环、分支、重试、聚合和批量编排,不等于操作系统沙箱。

需求推荐
一两个简单外部调用普通工具调用
纯 JavaScript 计算、循环、聚合解释器
大量工具调用,先处理再只返回摘要解释器 + PTC
大量独立语言任务或多视角验证解释器 + 动态子代理
shell、安装依赖、测试、真实文件系统沙箱

默认 QuickJS 没有文件、网络、shell、包管理器和时钟。外部能力来自两个显式桥:

  • PTC:将 allowlist 工具以 tools.* 暴露给 JavaScript。
  • task:配置子代理后,在解释器中动态调度。

重要边界:

  • PTC 调用不走常规模型工具调用路径,因此 interrupt_on 不会逐次审批。
  • 动态 task 调度同样不会让父 Agent 对每次派发执行常规审批;如需审批,应闸住 eval。
  • 解释器与 Python 进程同进程,不是宿主内存隔离边界;不可信代码仍应放入独立 worker 或容器。
  • thread / turn / call 三种持久模式只保存可序列化内存;恢复快照不会回滚外部工具已产生的副作用。
  • 默认有内存、单次执行超时、返回字符数和最大 PTC 调用数限制,应保留并按风险收紧。

多模态

read_file 可把图片、音频、视频、PDF/PPT 等转为标准 content blocks,但最终可用性由模型的 MIME/模态能力决定。

上下文压缩以文本为主:

  • 卸载只计算文本 token;不会按图片体积自动压缩图片。
  • 摘要会把旧消息压成纯文本,旧媒体块不会保留,只剩摘要模型写出的描述。

长任务应把媒体放入后端或对象存储,以路径/URL 引用;大二进制工具结果返回简短说明和引用;图像密集分析可交给子代理,只将文字结论返回主上下文。

ACP、MCP 与 A2A

协议连接对象在 Deep Agents 中的用途
ACP代码编辑器 ↔ Agent通过 stdio 把自定义编码 Agent 接入 Zed、JetBrains、VS Code、Neovim 等
MCPAgent/客户端 ↔ 工具与上下文服务器加载外部 tools、resources、prompts;支持 HTTP/stdio、认证和会话
A2AAgent ↔ AgentAgent Server 的标准 JSON-RPC 通信、SSE 流和 Agent Card

MCP 要点

  • MultiServerMCPClient 默认无状态:每次工具调用建立新 session;真正有状态的服务需显式 client.session。
  • stdio 进程本身可持续,但未显式管理时工具调用仍按无状态会话处理。
  • 工具业务错误默认转成 status=error 的 ToolMessage,模型可据此调整;传输、session、内容转换错误仍抛异常。
  • structuredContent 进入 artifact;需要让模型看到时再通过 interceptor 有选择地加入消息,避免无谓膨胀。
  • interceptor 可读取 runtime context、state 和 store,动态加 header、重试或短路;多个 interceptor 按洋葱顺序执行。
  • elicitation 允许 MCP 服务在执行中向用户请求输入,结果区分 accept、decline、cancel。

A2A 要点

Agent Server 暴露 /a2a/{assistant_id},支持 message/send、message/stream、tasks/get,并自动提供 Agent Card。兼容 Agent 的 state 必须有 messages。

contextId 表示对话连续性,taskId 表示单个请求。首轮省略,由服务端生成;后续携带。Agent Server 会把 contextId 映射成 LangSmith thread_id。跨框架 Agent 要显式传播同一 thread_id 才能在一条分布式 trace 中观察完整链路。

生产安全基线

  1. Web/API 服务不直接使用 FilesystemBackend 或 LocalShellBackend。
  2. 生产代码执行使用独立沙箱,默认 thread 级隔离、TTL 和网络限制。
  3. 内置工具做 allowlist,路径规则采用“具体 deny → 具体 allow → 全局 deny”。
  4. 自定义/MCP 工具单独做授权、输入校验、审计和幂等,不能误以为 permissions 已覆盖。
  5. PTC 与动态子代理视为独立能力桥,审批策略必须覆盖 eval。
  6. StoreBackend namespace 必须从已认证 runtime 身份生成,不接受模型或用户消息直接提供。
  7. 所有下载产物、MCP structured content 和沙箱输出在进入下游系统前视为不可信数据。

延伸阅读