mcpField
D
deep-agents-orchestration

deep-agents-orchestration

github.com/langchain-aiAgent 工作流1.3k16.2k 次安装3 天前更新
代码仓库

关于 deep-agents-orchestration

面向 Deep Agents 开发者,介绍通过子 Agent 委派任务、用待办列表跟踪多步骤工作,以及为敏感操作设置人工审批的编排模式。说明子 Agent 的状态限制和中断流程的检查点要求。

主要功能

  1. 01将任务委派给专用子 Agent
  2. 02用待办列表规划并跟踪任务
  3. 03为敏感工具调用设置人工审批
  4. 04配置子 Agent 的工具与模型
  5. 05通过检查点和 thread ID 恢复流程

适用场景

  1. 01将研究工作交给专用子 Agent
  2. 02跟踪复杂的多步骤开发任务
  3. 03审批部署或数据库写入操作

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/langchain-ai/langchain-skills --skill deep-agents-orchestration

安装后在 Claude Code 中输入/deep-agents-orchestration确认已加载。

详细介绍

Deep Agents 包含三种编排能力:
  1. SubAgentMiddleware:通过 task 工具将工作委派给专门的 Agent
  2. TodoListMiddleware:通过 write_todos 工具规划并跟踪任务
  3. HumanInTheLoopMiddleware:在执行敏感操作前要求审批

这三种能力都会自动包含在 create_deep_agent() 中。


子 Agent(任务委派)

适合使用子 Agent 的情况适合使用主 Agent 的情况
任务需要专门的工具通用工具已足够
希望隔离复杂工作单步操作
需要为主 Agent 提供干净的上下文可以接受上下文膨胀
主 Agent 拥有 `task` 工具 -> 创建新的子 Agent -> 子 Agent 自主执行 -> 返回最终报告。

默认子 Agent:“general-purpose”——自动提供,使用与主 Agent 相同的工具/配置。

创建一个自定义的“researcher”子 Agent,配备专门用于搜索学术论文的工具。
from deepagents import create_deep_agent
from langchain.tools import tool

@tool
def search_papers(query: str) -> str:
    """Search academic papers."""
    return f"Found 10 papers about {query}"

agent = create_deep_agent(
    subagents=[
        {
            "name": "researcher",
            "description": "Conduct web research and compile findings",
            "system_prompt": "Search thoroughly, return concise summary",
            "tools": [search_papers],
        }
    ]
)

# Main agent delegates: task(agent="researcher", instruction="Research AI trends")
创建一个自定义的“researcher”子 Agent,配备专门用于搜索学术论文的工具。
import { createDeepAgent } from "deepagents";
import { tool } from "@langchain/core/tools";
import { z } from "zod";

const searchPapers = tool(
  async ({ query }) => `Found 10 papers about ${query}`,
  { name: "search_papers", description: "Search papers", schema: z.object({ query: z.string() }) }
);

const agent = await createDeepAgent({
  subagents: [
    {
      name: "researcher",
      description: "Conduct web research and compile findings",
      systemPrompt: "Search thoroughly, return concise summary",
      tools: [searchPapers],
    }
  ]
});

// Main agent delegates: task(agent="researcher", instruction="Research AI trends")
为子 Agent 配置 HITL 审批,以便执行敏感操作。
from deepagents import create_deep_agent
from langgraph.checkpoint.memory import MemorySaver

agent = create_deep_agent(
    subagents=[
        {
            "name": "code-deployer",
            "description": "Deploy code to production",
            "system_prompt": "You deploy code after tests pass.",
            "tools": [run_tests, deploy_to_prod],
            "interrupt_on": {"deploy_to_prod": True},  # Require approval
        }
    ],
    checkpointer=MemorySaver()  # Required for interrupts
)
子 Agent 是无状态的——请在单次调用中提供完整指令。
# WRONG: Subagents don't remember previous calls
# task(agent='research', instruction='Find data')
# task(agent='research', instruction='What did you find?')  # Starts fresh!

# CORRECT: Complete instructions upfront
# task(agent='research', instruction='Find data on AI, save to /research/, return summary')
子 Agent 是无状态的——请在单次调用中提供完整指令。
// WRONG: Subagents don't remember previous calls
// task research: Find data
// task research: What did you find?  // Starts fresh!

// CORRECT: Complete instructions upfront
// task research: Find data on AI, save to /research/, return summary
自定义子 Agent 不会继承主 Agent 的技能。
# WRONG: Custom subagent won't have main agent's skills
agent = create_deep_agent(
    skills=["/main-skills/"],
    subagents=[{"name": "helper", ...}]  # No skills inherited
)

# CORRECT: Provide skills explicitly (general-purpose subagent DOES inherit)
agent = create_deep_agent(
    skills=["/main-skills/"],
    subagents=[{"name": "helper", "skills": ["/helper-skills/"], ...}]
)

TodoList(任务规划)

适合使用 TodoList 的情况适合跳过 TodoList 的情况
复杂的多步骤任务简单的单操作任务
长时间运行的操作快速操作(< 3 步)
write_todos(todos: list[dict]) -> None

每个待办事项包含:

  • content:任务描述
  • status:以下状态之一:"pending"、"in_progress"、"completed"
调用一个会自动为多步骤任务创建待办列表的 Agent。
from deepagents import create_deep_agent

agent = create_deep_agent()  # TodoListMiddleware included by default

result = agent.invoke({
    "messages": [{"role": "user", "content": "Create a REST API: design models, implement CRUD, add auth, write tests"}]
}, config={"configurable": {"thread_id": "session-1"}})

# Agent's planning via write_todos:
# [
#   {"content": "Design data models", "status": "in_progress"},
#   {"content": "Implement CRUD endpoints", "status": "pending"},
#   {"content": "Add authentication", "status": "pending"},
#   {"content": "Write tests", "status": "pending"}
# ]
调用一个会自动为多步骤任务创建待办列表的 Agent。
import { createDeepAgent } from "deepagents";

const agent = await createDeepAgent();  // TodoListMiddleware included

const result = await agent.invoke({
  messages: [{ role: "user", content: "Create a REST API: design models, implement CRUD, add auth, write tests" }]
}, { configurable: { thread_id: "session-1" } });
调用完成后,从 Agent 的最终状态中获取待办列表。
result = agent.invoke({...}, config={"configurable": {"thread_id": "session-1"}})

# Access todo list from final state
todos = result.get("todos", [])
for todo in todos:
    print(f"[{todo['status']}] {todo['content']}")
待办列表状态需要 `thread_id`,才能在多次调用之间持久保存。
# WRONG: Fresh state each time without thread_id
agent.invoke({"messages": [...]})

# CORRECT: Use thread_id
config = {"configurable": {"thread_id": "user-session"}}
agent.invoke({"messages": [...]}, config=config)  # Todos preserved

人机协作(审批工作流)

适用 HITL 的情况不适用 HITL 的情况
高风险操作(数据库写入、部署)只读操作
合规要求人工监督全自动工作流
配置执行前需要人工审批的工具。
from deepagents import create_deep_agent
from langgraph.checkpoint.memory import MemorySaver

agent = create_deep_agent(
    interrupt_on={
        "write_file": True,  # All decisions allowed
        "execute_sql": {"allowed_decisions": ["approve", "reject"]},
        "read_file": False,  # No interrupts
    },
    checkpointer=MemorySaver()  # REQUIRED for interrupts
)
配置执行前需要人工审批的工具。
import { createDeepAgent } from "deepagents";
import { MemorySaver } from "@langchain/langgraph";

const agent = await createDeepAgent({
  interruptOn: {
    write_file: true,
    execute_sql: { allowedDecisions: ["approve", "reject"] },
    read_file: false,
  },
  checkpointer: new MemorySaver()  // REQUIRED
});
完整工作流:触发中断、检查状态、批准操作并恢复执行。
from deepagents import create_deep_agent
from langgraph.checkpoint.memory import MemorySaver
from langgraph.types import Command

agent = create_deep_agent(
    interrupt_on={"write_file": True},
    checkpointer=MemorySaver()
)

config = {"configurable": {"thread_id": "session-1"}}

# Step 1: Agent proposes write_file - execution pauses
result = agent.invoke({
    "messages": [{"role": "user", "content": "Write config to /prod.yaml"}]
}, config=config)

# Step 2: Check for interrupts
state = agent.get_state(config)
if state.next:
    print(f"Pending action")

# Step 3: Approve and resume
result = agent.invoke(Command(resume={"decisions": [{"type": "approve"}]}), config=config)
完整工作流:触发中断、检查状态、批准操作并恢复执行。
import { createDeepAgent } from "deepagents";
import { MemorySaver, Command } from "@langchain/langgraph";

const agent = await createDeepAgent({
  interruptOn: { write_file: true },
  checkpointer: new MemorySaver()
});

const config = { configurable: { thread_id: "session-1" } };

// Step 1: Agent proposes write_file - execution pauses
let result = await agent.invoke({
  messages: [{ role: "user", content: "Write config to /prod.yaml" }]
}, config);

// Step 2: Check for interrupts
const state = await agent.getState(config);
if (state.next) {
  console.log("Pending action");
}

// Step 3: Approve and resume
result = await agent.invoke(
  new Command({ resume: { decisions: [{ type: "approve" }] } }), config
);
拒绝待处理的操作并提供反馈,提示 Agent 尝试其他方法。
result = agent.invoke(
    Command(resume={"decisions": [{"type": "reject", "message": "Run tests first"}]}),
    config=config,
)
拒绝待处理的操作并提供反馈,提示 Agent 尝试其他方法。
const result = await agent.invoke(
  new Command({ resume: { decisions: [{ type: "reject", message: "Run tests first" }] } }),
  config,
);
修改提议操作的参数后再允许执行。
result = agent.invoke(
    Command(resume={"decisions": [{
        "type": "edit",
        "edited_action": {
            "name": "execute_sql",
            "args": {"query": "DELETE FROM users WHERE last_login < '2020-01-01' LIMIT 100"},
        },
    }]}),
    config=config,
)
### Agent 可以配置的内容
  • 子 Agent 的名称、工具、模型和系统提示词
  • 哪些工具需要审批
  • 每种工具允许的决策类型
  • TodoList 的内容和结构
Agent 不能配置的内容
  • 工具名称(task、write_todos)
  • HITL 协议(批准/编辑/拒绝结构)
  • 跳过中断所需的检查点保存器要求
  • 让子 Agent 保持有状态(它们是临时的)
使用 interrupt_on 进行 HITL 工作流时,必须配置检查点保存器。
# WRONG
agent = create_deep_agent(interrupt_on={"write_file": True})

# CORRECT
agent = create_deep_agent(interrupt_on={"write_file": True}, checkpointer=MemorySaver())
使用 interruptOn 进行 HITL 工作流时,必须配置检查点保存器。
// WRONG
const agent = await createDeepAgent({ interruptOn: { write_file: true } });

// CORRECT
const agent = await createDeepAgent({ interruptOn: { write_file: true }, checkpointer: new MemorySaver() });
恢复中断的工作流需要使用一致的 thread_id。
# WRONG: Can't resume without thread_id
agent.invoke({"messages": [...]})

# CORRECT
config = {"configurable": {"thread_id": "session-1"}}
agent.invoke({...}, config=config)
# Resume with Command using same config
agent.invoke(Command(resume={"decisions": [{"type": "approve"}]}), config=config)
恢复中断的工作流需要使用一致的 thread_id。
// WRONG: Can't resume without thread_id
await agent.invoke({ messages: [...] });

// CORRECT
const config = { configurable: { thread_id: "session-1" } };
await agent.invoke({ messages: [...] }, config);
// Resume with Command using same config
await agent.invoke(new Command({ resume: { decisions: [{ type: "approve" }] } }), config);
中断发生在 invoke() 调用之间,而非执行过程中。
result = agent.invoke({...}, config=config)       # Step 1: triggers interrupt
if "__interrupt__" in result:                      # Step 2: check for interrupt
    result = agent.invoke(                         # Step 3: resume
        Command(resume={"decisions": [{"type": "approve"}]}),
        config=config,
    )

评论

支持 Markdown