学习笔记 · Obsidian
Deep Agents TypeScript:上下文、记忆、检索与子代理
把信息放到正确层
| 信息/工作类型 | 推荐机制 | 生命周期 |
|---|---|---|
| 每次都必须遵守的短规则 | AGENTS.md memory | 启动时总是进入系统提示 |
| 任务相关的详细流程与模板 | Skill | 先加载 name/description,命中后再读正文和资源 |
| 用户 ID、角色、连接、短期凭证 | Runtime context | 每次 invoke 传入,不自动给模型看 |
| 大工具结果与历史消息 | 自动 offloading / summarization | 接近上下文上限时压缩 |
| 跨会话事实与偏好 | Store-backed long-term memory | 由 namespace 决定用户/Agent/组织范围 |
| 输出密集或专门工作 | 子代理 | 独立上下文,只回传最终结果 |
核心原则是“常驻内容越短越好”。把所有知识塞入 system prompt 会降低相关性、增加缓存失效和成本;把需要每次遵守的安全规则藏进按需 Skill 又可能错过。
System prompt 与 runtime context
静态 systemPrompt 会与基础提示、memory、skills、文件系统说明、子代理说明、自定义 middleware 提示和 HITL 说明共同组装。需要根据用户角色动态改变提示时,用 dynamicSystemPromptMiddleware 读取 request.runtime.context 或 store;仅工具需要这些数据时,不必为此创建动态提示 middleware。
contextSchema 通常用 Zod 声明。invoke 时通过 options 的 context 传值;工具经 ToolRuntime 读取。Runtime context 自动传播到同步子代理,可用带子代理前缀的扁平键或独立字段表达专用配置。
上下文工程页的完整提示清单仍夹杂 system_prompt、interrupt_on 和 Python 源码链接。结构概念可用,但 TypeScript 字段名必须改为 camelCase。
自动上下文压缩
Offloading
默认阈值为约 20,000 文本 tokens:
- 大型文件写入/编辑输入已存在 backend 中;当整体上下文接近窗口的 85% 时,较旧调用会替换成文件指针。
- 大型工具结果会写入 backend,消息里保留路径与前 10 行预览。
模型可随后使用 read_file、grep 和分页读取恢复细节。非文本媒体不按二进制大小计入这套 token 规则。
Summarization
SummarizationMiddleware 在裸栈中默认存在:
- 通常在模型 profile 的输入窗口达到 85% 时触发。
- 保留最近约 10% tokens。
- 缺少 profile 时回退到约 170,000 tokens / 保留 6 条消息。
- 标准
ContextOverflowError可触发立即摘要并重试。 - 原消息会以文本形式保存在 backend,活动上下文只保留结构化摘要和最近消息。
摘要流生成的 token 可能混入普通 token stream,UI/日志要按 metadata 过滤。摘要是文本化压缩,不保存较早媒体 block。
Skills
Skill 是目录化能力包:SKILL.md 的 YAML frontmatter 至少有 name 和 description,正文写执行指令,可附 scripts/、references/ 与 assets/。
三层渐进披露:
- 启动加载所有技能的 name + description。
- 命中任务后读完整
SKILL.md。 - 指令要求时才读或运行支持文件。
写作建议:description 同时说明“做什么”和“何时使用”,减少近义技能;正文控制在单一工作流,长参考移到一层深的文件;给出决策条件、输入输出与边界情况。SKILL.md 超过 10 MB 会被跳过。
多 source 同名时后一个覆盖前一个。SDK 只加载显式传入的路径,不会自动扫描 Deep Agents Code 的用户/项目目录。一般 general-purpose 子代理继承主 Agent skills,自定义子代理不继承,需在规格中显式配置。
技能脚本能否执行取决于 backend:普通 backend 只能读,shell 运行需要 sandbox。技能文件在 sandbox 外时,需要 beforeAgent 上传、afterAgent 下载同步,否则模型看得到说明却运行不了脚本。
Skills 页的已知冲突
该页多个段落使用 Python 的 create_deep_agent、list[str]、interrupt_on 和 mode="interrupt"。其中路径级 interrupt 与 TypeScript permissions 专页冲突。可靠结论是:
- 可用 permissions 做只读技能库。
- TypeScript 工具级写入审批使用
interruptOn。 - 不能依据此页断言 permission 存在
interruptmode。
长期记忆
文件型记忆可按三个维度设计:
- 用户范围:用户偏好与私有上下文,推荐默认。
- Agent / assistant 范围:一个 Agent 的共享身份和经验。
- 组织范围:共享政策,通常必须只读。
语义事实可保存在 AGENTS.md 等文件;程序性知识放 Skills;会话过程属于 checkpointer 支持的 episodic memory。要检索历史会话,可把 thread search 封装成工具,并在服务端按 user/org metadata 过滤。
热路径写入立即可见但增加响应延迟;后台 consolidation 可定时读取近期对话并合并记忆,代价是下一次会话前才生效。cron 频率必须与搜索回看窗口一致,否则重复处理或漏掉会话。
共享记忆的最大风险是跨用户提示注入:
- 默认使用 user namespace。
- 组织政策由应用写、Agent 只读。
- 同一文件并发写是 last-write-wins;按主题拆文件或用 consolidation 串行化。
- 多 Agent 共用部署时把 assistant ID 纳入 namespace。
Retrieval 与 RAG
Retrieval 页给出三个架构:
| 架构 | 何时检索 | 特点 |
|---|---|---|
| 2-Step RAG | 生成前固定检索 | 可预测、低延迟、灵活性低 |
| Agentic RAG | Agent 自己决定 | 灵活但调用数与延迟波动 |
| Hybrid RAG | 查询改写、检索验证、答案验证 | 在控制与灵活性间折中 |
Deep Agent 只需获得能访问知识源的工具就可形成 Agentic RAG。大规模语料仍应建立 loader → splitter → embeddings → vector store 管线;已有 SQL、CRM 或文档库可直接包装为工具,不必为了 RAG 重新入库。
大结果适合“检索 → 写入 backend → 子代理分别分析 → 主 Agent 汇总”。这样主上下文只接收文件路径与短报告,而不是所有原文。
同步子代理
同步子代理由 task 调用;主 Agent 阻塞到完成,但一次模型响应可并行发出多个 task。适合多步骤调查、专门模型/工具以及上下文隔离,不适合简单单步动作或必须保留全部中间上下文的任务。
TypeScript 声明式规格的主要字段:name、description、systemPrompt、tools、model、middleware、interruptOn、skills、responseFormat、permissions。注意继承关系:
systemPrompt与 custom skills 不继承。model和工具默认继承;显式 tools 会整体覆盖。- custom middleware 追加到子代理栈,不继承主 Agent middleware。
- 子代理 permissions 若提供,会整体替换父规则。
- 结构化结果 JSON 序列化后通过 ToolMessage 返回父 Agent。
Compiled subagent 可接任意已编译 LangGraph,但 state 必须有 messages 键。
文档跨语言残留
Subagents 页同时出现正确的 camelCase 表格和 Python 的 general_purpose_subagent、excluded_middleware、ValueError、False。TypeScript 禁用或定制默认 general-purpose 的精确 profile 字段应以 profiles 页/API Reference 为准,不能复制 Python 参数。
Dynamic subagents
Dynamic subagents 是 QuickJS interpreter 内的 task() 桥:Agent 用 JavaScript 循环、分支和并发批次选择与调用子代理。适用模式包括:
- 分类后路由到不同专家。
- fan-out 后汇总。
- 两阶段对抗验证。
- 多候选生成与过滤。
- 淘汰赛式比较。
- 去重并循环直到没有新结果。
提示中使用“workflow”会触发内置解释器提示倾向动态编排,但它不是确定性的 API flag。文件发现等外部动作还需 PTC allowlist。task() 同样绕过普通工具审批路径;需要人审时 gate eval。
Async subagents
异步子代理是 deepagents 1.9.0 的 preview。它连接 Agent Protocol 服务,启动后立即返回 task ID,主 Agent 可继续对话,并用五个工具管理任务:start、check、update、cancel、list。
与同步子代理相比:
- 非阻塞,可中途更新和取消。
- 每个任务有独立 thread,跨交互保存状态。
- task metadata 存在主图的专用
asyncTaskschannel,不依赖可能被摘要掉的 ToolMessage。 - update 会中断上一 run,并在同一 thread 上携带完整历史重新启动。
同部署优先省去 URL,使用进程内 transport;跨部署 HTTP 适合独立扩缩容与不同资源配置。开发时 worker 数至少为“主 Agent 1 + 最大并行子代理数”,否则启动会排队。状态报告前必须实时 check/list,不能信任历史消息中的旧状态。
OpenWiki 的边界
/oss/javascript/deepagents/openwiki 当前 307 跳转到共享 /oss/openwiki/overview,且正文主要链接 Python Deep Agents。OpenWiki 是独立 CLI:生成仓库 Markdown wiki,并在根 AGENTS.md / CLAUDE.md 写入发现指针;它不是 TypeScript SDK API。其价值是把稳定仓库知识做成 Agent 可检索的持久上下文,而不是把全仓代码每次重读。