Skip to content

SubAgent 模式 ​

使用标准 Halo 工具将任务委托给专门的子 Agent。无需新包 — 子 Agent 就是 ToolDefinition,其 execute 内部创建短生命周期 HaloAgent。

核心模式 ​

ts
const codeReviewer: ToolDefinition<{ code: string }> = {
  description: "审查代码中的 bug 和安全漏洞",
  parameters: {
    type: "object",
    properties: { code: { type: "string" } },
    required: ["code"],
  },
  execute: async ({ code }) => {
    // 创建短生命周期 agent — 每次调用独立的上下文
    const agent = halo.agent({
      messages: [
        { role: "system", content: "你是资深代码审查员。找出 bug、安全隐患并给出改进建议。" },
      ],
      model: { temperature: 0.1 },
    });
    const result = await agent.generateText(code);
    return result.content;
  },
};

像普通工具一样喂给父 Agent:

ts
const mainAgent = halo.agent({
  messages: [{ role: "system", content: "你是技术主管。将代码审查委托给 reviewer 工具。" }],
  tools: { code_reviewer: codeReviewer },
});

何时使用 SubAgent ​

使用 SubAgent:

  • 任务可以并行执行(三个分析同时进行)
  • 子任务需要不同的工具集(搜索 agent 需要 Puppeteer,分析 agent 不需要)
  • 中间产出太大,会撑爆父 Agent 的 MessageLog
  • 子任务需要不同的模型参数(搜索: temp 0.1,创意: temp 0.9)

不使用 SubAgent:

  • 任务在一个轮次内就能完成,不造成上下文压力
  • 子任务需要父 Agent 的完整对话上下文
  • 只是一次简单的查表

模式 ​

并行派发 ​

模型返回多个独立的工具调用时,并发执行:

ts
// 在 onToolCall 中:
const results = await Promise.all(
  toolCalls.map(call => {
    const executor = toolExecutors.get(call.function.name);
    return executor?.(JSON.parse(call.function.arguments));
  })
);

流水线 (Chain) ​

每一步的输出喂入下一步:

ts
const search = await searcherAgent.generateText(topic);
const analysis = await analystAgent.generateText(search.content);
const report = await writerAgent.generateText(analysis.content);

路由器 (Router) ​

调度器选择调用哪个专家:

ts
const router: ToolDefinition<{ task: string }> = {
  description: "将任务路由到合适的专家",
  parameters: { ... },
  execute: async ({ task }) => {
    const decision = await routerAgent.generateText(
      `为以下任务选择: 前端、后端还是运维?${task}`
    );
    const agent = { 前端: feAgent, 后端: beAgent, 运维: opsAgent }[decision.content.trim()];
    return (await agent.generateText(task)).content;
  },
};

输出格式 ​

子 Agent 的结果是父 Agent MessageLog 中的一条工具结果消息。将其结构化以便父 Agent 高效消费:

ts
execute: async (args) => {
  const result = await subAgent.generateText(JSON.stringify(args));
  return JSON.stringify({
    content: result.content,
    sources: extractSources(result.content),
    confidence: "high",
  });
}

上下文预算 ​

每次委托子 Agent 都会在父 Agent 的 MessageLog 中产生一条工具结果消息。一个返回 3000 token 散文的冗长子 Agent 会消耗父 Agent 3000 token 上下文。对于机械性任务,在 system prompt 中指示子 Agent 返回压缩输出。

模块级复用(缓存命中优化) ​

对于配置固定的子 Agent,复用单个实例:

ts
const _reviewer = halo.agent({
  messages: [{ role: "system", content: "你是代码审查员。" }],
  model: { temperature: 0.1 },
});

const codeReviewer: ToolDefinition<{ code: string }> = {
  description: "审查代码",
  parameters: { ... },
  execute: async ({ code }) => {
    const result = await _reviewer.generateText(code);
    _reviewer.clearLog(); // 重置对话,保留前缀缓存
    return result.content;
  },
};

权衡:复用 agent 会跨调用共享 StablePrefix(首次后缓存命中),但需要在调用间执行 clearLog() 防止上下文泄漏。

基于 MIT 许可证发布