学习笔记 · Obsidian

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

LangChainTypeScript

执行能力不是一个开关

生产系统应把 Agent 的能力拆成四层:

层主要职责默认隔离
自定义 / MCP 工具调用 API、数据库和业务动作由工具自身决定
Backend为内置文件工具提供统一命名空间由具体后端决定
QuickJS interpreter在 Agent 循环内用 JavaScript 编排数据、工具和子代理默认无宿主文件、网络、shell、时钟
Sandbox隔离文件系统并提供 shell隔离宿主,但不防提示注入或网络外泄

安全审查必须沿“模型可见工具 → middleware → backend/外部系统 → 凭证和网络”追踪。提示词不是权限边界。

内置工具与 TypeScript 差异

TypeScript 当前公开的内置 harness 工具有:ls、read_file、write_file、edit_file、glob、grep、条件可见的 execute 与同步委派 task。任务计划的 write_todos 需要显式加入 TodoList middleware。

与 Python 页不同,TypeScript 的工具表没有 delete,write_file 文案是“创建新文件”。后端协议的 write() 又说明 create-only 语义;因此不要假定 TypeScript SDK 可覆盖或删除文件,修改现有文件应使用 edit_file,具体能力以当前 API 类型为准。

工具页 prose 中仍出现 create_deep_agent、tools= 和 Python LangChain 链接,是语言复制残留;TypeScript 实际入口是 createDeepAgent({ tools })。

后端选择

后端生命周期适用场景关键风险
StateBackend同一 thread,经 checkpoint 延续草稿、结果卸载、临时文件大文件会放大 graph state
StoreBackend跨 thread,namespace 决定隔离用户记忆、长期资料namespace 错误导致串租户
FilesystemBackend真实本地磁盘可信本地 CLI、受控 CIsecrets、永久修改、路径逃逸
LocalShellBackend真实磁盘 + 宿主 shell可信本地开发任意宿主命令,无资源隔离
ContextHubBackendLangSmith Hub repo有提交历史的共享上下文乐观并发冲突、远端依赖
CompositeBackend按最长路径前缀路由临时区与持久区混合路由与权限需要共同设计
Sandbox backend隔离文件系统 + execute生产代码执行、数据分析提示注入、网络外传、成本

重要实践:

  • 默认后端是线程内的 StateBackend,父子代理共享其中的文件。
  • 多租户 StoreBackend 必须显式从 runtime 构造 user / tenant / assistant namespace;不要依赖旧的 assistant 默认空间。
  • FilesystemBackend 的 root 目录只有在安全路径解析模式下才可能限制路径;文档此处夹杂 Python 的 virtual_mode=True 写法,TypeScript 实现需按 API Reference 核对真实字段。
  • LocalShellBackend 的 shell 可访问宿主其他路径,任何虚拟路径开关都不是安全边界。
  • 不要让真实项目目录承载 /large_tool_results/、/conversation_history/ 等内部文件。常见设计是 CompositeBackend 默认走 State,只把 /workspace/ 路由到磁盘。
  • ContextHubBackend 写入使用父提交进行乐观并发;冲突时重新拉取再重试,非 UTF-8 上传会按路径失败。

Backend Protocol V2

TypeScript V2 后端统一返回结构化 Result,不应通过抛异常表达“文件不存在”或无匹配:

  • ls(path)
  • read(filePath, offset?, limit?)
  • readRaw(filePath)
  • write(filePath, content)
  • edit(filePath, oldString, newString, replaceAll?)
  • glob(pattern, path?)
  • grep(pattern, path?, glob?)

实现 shell 时扩展 SandboxBackendProtocolV2.execute(),可选提供 uploadFiles() / downloadFiles() 作为应用侧跨边界传输 API。V1 会在运行时自动适配到 V2;迁移重点是查询方法改为 Result、lsInfo/globInfo/grepRaw 改名,以及二进制内容使用 Uint8Array + MIME type。

后端工厂模式在 1.9.0 起被标记弃用:新代码传入已构造的 backend 实例,运行时上下文由框架解析。文档的“更新到 V2”段落同时含 Python 与 TypeScript 版本,实际签名应以 camelCase TypeScript 表格为准。

文件权限

permissions 只拦截内置文件工具:

  • read 覆盖 ls、read_file、glob、grep。
  • write 覆盖 write_file、edit_file。
  • 规则按声明顺序,首个匹配项获胜。
  • 无匹配时默认 允许。
  • 路径必须绝对,禁止 .. 与 ~。
  • 子代理默认继承;子代理显式配置会整体替换父规则,空数组代表无约束。

权限不覆盖自定义工具、MCP 工具,也不覆盖 sandbox 内的 shell。CompositeBackend 默认路由到 sandbox 时,permission 路径必须落在已知非 sandbox 路由前缀,否则构造时拒绝。

TypeScript 权限页只定义 allow / deny,没有 Python 的路径级 interrupt。技能页中出现 mode="interrupt" 属于跨语言残留;TypeScript 人工审批应通过工具级 interruptOn,不能据此实现按路径中断。

Interpreter:循环内编排,不是操作系统

Interpreter 使用 WASM 隔离的 QuickJS,增加 eval 工具,适合:

  • 循环、分支、重试和确定性数据转换。
  • 在变量中保留中间结果,避免全部进入模型上下文。
  • Programmatic Tool Calling(PTC)批量调用显式 allowlist 中的工具。
  • 通过 task() 动态扇出子代理。

默认没有网络、宿主文件、shell、包管理器或墙上时钟。PTC 工具名会转换为 camelCase,但参数对象仍遵循原工具 schema。关键配置包括 64 MB 默认堆上限、5 秒单次执行超时、4000 字符结果上限、每次 eval 默认最多 256 个 PTC 调用。

安全边界:PTC 与 task() 从解释器桥接调用,不经过普通 tool-call 路径,所以父 Agent 的 interruptOn 不会逐次执行。需要审批时应 gate eval 本身,并收窄 PTC allowlist;对敏感系统、付费动作和任意网络工具尤其如此。

Sandbox:宿主隔离与数据边界

TypeScript 文档列出的当前集成包括 LangSmith、Deno、Daytona、Leap0、Modal 与 Node VFS;具体可用性、计费和生命周期仍要以各提供方文档为准。

两种架构模式:

  1. Agent 在 sandbox 内:接近本地运行,但密钥与 Agent 进程都进入容器,升级需重建镜像。
  2. Sandbox as tool:Agent 在服务端运行,经远程 API 调用 sandbox。密钥可留在外部、Agent 状态不随 sandbox 故障丢失,代价是每次操作的网络延迟。

生产通常使用第二种。应用侧 uploadFiles/downloadFiles 负责播种与回收;模型侧文件工具负责任务过程。两条通道不能混为一谈。

Sandbox 只隔离宿主,不自动解决:

  • 间接提示注入。
  • sandbox 内敏感文件读取。
  • 允许出网时的 HTTP/DNS 外传。
  • 资源生命周期与持续费用。

不要把长期密钥放进 sandbox 环境变量或文件。优先把认证封装在宿主工具中,或使用出站代理注入凭证。确实需要注入时仍不能把 HITL 和出网限制视为绝对防护。

多模态文件

Backend V2 的 read_file 可按 MIME 返回图片、音频、视频和文档 content blocks。大媒体应存储在 backend 或对象存储,只把路径/URL和短说明放入消息。

压缩有两个局限:

  • offloading 主要按文本 token 计数,纯图片不会因二进制大小自动卸载。
  • summarization 把较早消息变成文本摘要;其中媒体 block 不会原样保留。

因此长时间多模态任务应保留可重新读取的原始文件,并让专门子代理做媒体检查后返回短文本结论。

ACP、MCP 与 A2A 的边界

协议方向主要用途
ACP编辑器 ↔ Agent server把 Deep Agent 暴露给 Zed、JetBrains、VS Code、Neovim
MCPAgent client → 工具服务器加载外部工具和多模态工具结果
A2AAgent server ↔ Agent server标准化跨 Agent 请求、流式与任务状态

ACP 是 TypeScript 独有的强项之一:deepagents-acp 支持 stdio CLI、程序化服务器、多 Agent、slash commands、skills、memory 与 IDE 内 HITL。客户端能力不一;例如部分编辑器没有多 Agent 选择 UI。

/oss/javascript/deepagents/mcp 当前 307 跳转到通用 /oss/javascript/langchain/mcp。该页只覆盖工具加载、HTTP/stdio、认证和多模态工具内容;TypeScript adapter 遇到 MCP isError 会抛 ToolException,不像 Python adapter 那样直接给模型失败 ToolMessage。

/oss/javascript/deepagents/a2a 当前 307 跳转到 /langsmith/server-a2a,是 Agent Server 能力而非 Deep Agents SDK 专属 API。服务端支持 message/send、message/stream 与 tasks/get,要求消息型 state;contextId 映射到 LangSmith thread_id 用于跨 Agent 追踪。可在 langgraph.json 中关闭 A2A 端点。