Pular para o conteúdo principal
Use este padrão quando um único modelo realizando toda a pesquisa em uma única resposta começar a atingir os limites de contexto. Em vez de permitir que uma resposta consuma diretamente cada resultado de web_search, use uma resposta pai para delegar tarefas de pesquisa focadas a respostas filhas. Cada filho realiza suas próprias buscas e retorna um memo compacto. O pai consome apenas esses memos, o que permite que o fluxo de trabalho geral pesquise de forma muito mais agressiva sem sobrecarregar o contexto do pai. Este é uma versão especializada do padrão geral de subagentes. Aqui, o pai é um orquestrador de pesquisa e os filhos são pesquisadores. Fluxo de pesquisa profunda -> resposta pai planeja a pesquisa -> pai chama spawn_subagent várias vezes -> seu app executa respostas filhas com web_search -> filhos retornam memos de pesquisa compactos -> seu app envia todos os memos filhos de volta como function_call_output -> pai retoma, decide se faz outra rodada, então responde

Por que usar subagentes para pesquisa profunda

Em um loop clássico de pesquisa profunda com agente único, uma resposta continua chamando web_search. Isso funciona até que a resposta tenha visto muitos resultados de busca e comece a ficar sem orçamento de contexto útil. Subagentes resolvem isso dividindo o trabalho:
  • O pai mantém o plano global e a síntese final.
  • Cada filho lida com uma tarefa de pesquisa focada e pode realizar várias buscas próprias.
  • O pai vê apenas o memo do filho, não cada resultado bruto de busca.
  • O pai pode delegar uma segunda ou terceira rodada se a primeira for fraca ou conflitante.

Projete o pai e o filho de forma diferente

O pai não deve pesquisar diretamente. Seu trabalho é decompor o pedido, lançar múltiplos subagentes em paralelo e decidir se outra rodada é necessária. Os filhos devem pesquisar diretamente. Seu trabalho é realizar o trabalho focado, superar resultados iniciais fracos e retornar evidências compactas para o pai. Uma boa divisão se parece com isto:
  • Pai: planejamento, decomposição de tarefas, resolução de conflitos, resposta final.
  • Filho: refinamento de consulta, busca repetida, avaliação de fontes, redação do memo.

Defina a ferramenta de delegação

Mantenha o esquema da ferramenta pequeno. Passe apenas a tarefa do filho, instruções opcionais e uma possível substituição de modelo.
const spawnSubagentTool = {
  type: "function" as const,
  name: "spawn_subagent",
  description: "Delegue uma tarefa de pesquisa focada a uma resposta filha e retorne um memo compacto.",
  strict: true,
  parameters: {
    type: "object",
    properties: {
      task: { type: "string" },
      instructions: { type: "string" },
      model: { type: "string" },
    },
    required: ["task"],
    additionalProperties: false,
  },
};

type SpawnSubagentArgs = {
  task: string;
  instructions?: string;
  model?: string;
};

Dê ao pai um prompt de orquestração

O prompt do pai deve forçar a decomposição e a abrangência. Para pesquisa profunda, diga ao pai para usar vários subagentes por padrão e lançar outra rodada quando a primeira for fraca.
const DEEP_RESEARCH_PARENT_INSTRUCTIONS = `
Você é um orquestrador de pesquisa profunda.

Você não pesquisa diretamente.
Use a ferramenta spawn_subagent para delegar tarefas de pesquisa focadas a respostas filhas.

Regras de delegação:
- Para buscas factuais diretas, lance pelo menos 3 subagentes antes de responder.
- Para a maioria das tarefas de pesquisa, lance pelo menos 4 subagentes antes de responder.
- Para pesquisas amplas, ambíguas ou de alto impacto, lance de 5 a 8 subagentes em rodadas.
- Lance múltiplos subagentes no mesmo turno sempre que o trabalho deles puder prosseguir independentemente.
- Se a primeira rodada for incompleta, repetitiva, fraca ou conflitante, lance outra rodada em vez de adivinhar.

Exemplos de delegação:
- Um subagente para o caminho de resposta mais direto.
- Um subagente focado em fontes primárias ou oficiais.
- Um subagente focado em corroboração ou contradições.
- Subagentes adicionais para linha do tempo, geografia, perspectiva de partes interessadas, detalhe técnico ou desenvolvimentos recentes.

Depois que todos os resultados das ferramentas retornarem, sintetize as evidências em uma resposta para o usuário.
`;

Dê ao filho um prompt de pesquisa mais rigoroso

O prompt do filho deve restaurar a intensidade de busca que a pesquisa profunda de agente único geralmente tem naturalmente. Sem isso, um filho pode parar após uma busca fraca e retornar um memo dizendo o que faria a seguir.
const DEEP_RESEARCH_CHILD_INSTRUCTIONS = `
Você é um subagente especialista em pesquisa profunda.

Você tem a ferramenta web_search e deve usá-la de forma agressiva.
Foque apenas na tarefa delegada.

Disciplina de busca:
- Para tarefas não triviais, faça pelo menos 3 buscas web distintas antes de retornar.
- Se a primeira busca for fraca, vazia, genérica ou composta principalmente por diretórios, continue buscando.
- Não retorne "próximos passos". Execute essas buscas você mesmo antes de retornar.
- Prefira fontes primárias, oficiais e de autoridade.
- Trate diretórios e sites de perfil como pistas para corroborar, não como prova única quando uma fonte mais forte deveria existir.

Retorne um memo compacto para outro modelo:
1. Principais descobertas
2. Evidências e fontes
3. Questões em aberto ou ressalvas
`;
Cada filho é apenas outra requisição de Responses. Forneça a tarefa delegada como entrada e a ferramenta web_search.
import { SDK } from "@meetkai/mka1";

const sdk = new SDK({
  bearerAuth: process.env.MKA1_API_KEY!,
});

async function runResearchChild(args: SpawnSubagentArgs) {
  const child = await sdk.llm.responses.create({
    model: args.model ?? "auto",
    instructions: args.instructions ?? DEEP_RESEARCH_CHILD_INSTRUCTIONS,
    input: args.task,
    tools: [
      {
        type: "web_search",
        userLocation: { country: "pakistan" },
        searchContextSize: "medium",
      },
    ],
    tool_choice: "auto",
    parallel_tool_calls: true,
    max_tool_calls: 60,
    store: true,
  });

  return {
    response_id: child.id,
    output_text: child.outputText,
  };
}

Continue filhos fracos em vez de aceitá-los

Para pesquisa profunda, não aceite um resultado de filho apenas porque ele retornou texto. Se o filho fez apenas uma busca, produziu um memo curto ou disse coisas como “próximos passos” ou “preciso pesquisar mais”, continue esse mesmo filho com previous_response_id.
const MIN_CHILD_SEARCHES = 3;
const MAX_CHILD_PASSES = 3;
const WEAK_MEMO_PATTERNS = [
  /next steps/i,
  /let me try/i,
  /need to search/i,
  /should check/i,
  /didn't find/i,
  /no direct results/i,
];

function isWeakMemo(outputText: string) {
  const trimmed = outputText.trim();
  if (!trimmed) return true;
  if (trimmed.length < 250) return true;
  return WEAK_MEMO_PATTERNS.some((pattern) => pattern.test(trimmed));
}

function buildChildContinuationPrompt(args: {
  task: string;
  searchCount: number;
  previousOutput: string;
}) {
  return [
    `Continue a tarefa de pesquisa delegada: ${args.task}`,
    `Você completou apenas ${args.searchCount} buscas web até agora.`,
    `Faça pelo menos ${MIN_CHILD_SEARCHES} buscas web distintas antes de retornar, a menos que já tenha uma resposta direta de evidência autoritativa.`,
    `Não retorne "próximos passos" nem diga que mais buscas são necessárias. Execute as buscas adicionais você mesmo.`,
    `Priorize fontes primárias, oficiais e de autoridade. Use diretórios apenas como pistas para corroborar.`,
    ``,
    `Memo anterior:`,
    args.previousOutput,
  ].join("\n");
}

async function runResearchChildWithContinuation(args: SpawnSubagentArgs) {
  let previous_response_id: string | undefined;
  let nextInput = args.task;
  let totalSearchCount = 0;

  for (let pass = 0; pass < MAX_CHILD_PASSES; pass += 1) {
    const child = await sdk.llm.responses.create({
      model: args.model ?? "auto",
      instructions: args.instructions ?? DEEP_RESEARCH_CHILD_INSTRUCTIONS,
      ...(previous_response_id
        ? { previous_response_id, input: nextInput }
        : { input: nextInput }),
      tools: [
        {
          type: "web_search",
          userLocation: { country: "pakistan" },
          searchContextSize: "medium",
        },
      ],
      tool_choice: "auto",
      parallel_tool_calls: true,
      max_tool_calls: 60,
      store: true,
    });

    const passSearchCount = countCompletedWebSearches(child.output);
    totalSearchCount += passSearchCount;

    if (totalSearchCount >= MIN_CHILD_SEARCHES && !isWeakMemo(child.outputText)) {
      return {
        response_id: child.id,
        output_text: child.outputText,
        search_count: totalSearchCount,
      };
    }

    previous_response_id = child.id;
    nextInput = buildChildContinuationPrompt({
      task: args.task,
      searchCount: totalSearchCount,
      previousOutput: child.outputText,
    });
  }

  throw new Error("A resposta do filho permaneceu muito fraca após múltiplas rodadas de pesquisa");
}
O helper exato countCompletedWebSearches depende se você está usando eventos transmitidos ou itens de saída armazenados. A ideia importante é contar operações de busca realmente concluídas, não apenas turnos.

Execute uma rodada do pai, depois reúna todos os memos filhos

O pai deve poder emitir várias chamadas spawn_subagent em um turno. Trate essas chamadas de ferramenta como um lote. Inicie todos os filhos, espere todos terminarem e então retome o pai uma vez com todas as saídas dos filhos.
export async function runDeepResearch(input: string) {
  let response = await sdk.llm.responses.create({
    model: "meetkai:functionary-urdu-large",
    instructions: DEEP_RESEARCH_PARENT_INSTRUCTIONS,
    input,
    tools: [spawnSubagentTool],
    tool_choice: "auto",
    parallel_tool_calls: true,
    max_tool_calls: 18,
    store: true,
  });

  while (true) {
    const toolCalls = response.output.filter(
      (item): item is {
        type: "function_call";
        name: string;
        call_id: string;
        arguments: string;
      } => item.type === "function_call" && item.name === "spawn_subagent",
    );

    if (toolCalls.length === 0) {
      return response.outputText;
    }

    const toolOutputs = await Promise.all(
      toolCalls.map(async (toolCall) => {
        const args = JSON.parse(toolCall.arguments) as SpawnSubagentArgs;
        const childResult = await runResearchChildWithContinuation(args);

        return {
          type: "function_call_output" as const,
          call_id: toolCall.call_id,
          output: JSON.stringify(childResult),
        };
      }),
    );

    response = await sdk.llm.responses.create({
      model: response.model,
      previous_response_id: response.id,
      input: toolOutputs,
      tools: [spawnSubagentTool],
      parallel_tool_calls: true,
      max_tool_calls: 18,
      store: true,
    });
  }
}
Este é o núcleo do loop de pesquisa profunda:
  1. O pai cria um plano de pesquisa.
  2. O pai emite um lote de chamadas spawn_subagent.
  3. Seu app executa todos os filhos em paralelo.
  4. Filhos fracos continuam para outra rodada.
  5. Seu app envia todos os memos finais dos filhos juntos.
  6. O pai lança outra rodada ou responde.

Transmita e registre o processo de pesquisa

A pesquisa profunda é muito mais fácil de depurar se você registrar o ciclo de vida das buscas dos filhos. Logs úteis incluem:
  • resposta pai criada
  • cada tarefa delegada
  • cada consulta de busca do filho
  • cada lote de resultados de busca do filho
  • cada prévia de memo do filho
  • quando um filho fraco é continuado para outra rodada
  • retomada do pai com o lote final de filhos
Isso permite distinguir falhas de orquestração de falhas de qualidade de pesquisa. Por exemplo, se o sistema responde mal, mas os logs mostram apenas um filho com uma busca, isso é um problema de prompt ou continuação, não de transporte.

Regras práticas para pesquisa profunda

  • Use parallel_tool_calls: true no pai para que ele possa lançar vários subagentes em um turno.
  • Mantenha as saídas dos filhos compactas. O pai deve receber resumos de evidências, não dumps brutos de pesquisa.
  • Prefira várias tarefas filhas focadas a uma tarefa filha vaga.
  • Se um filho encontrar principalmente diretórios ou páginas genéricas, continue insistindo nesse filho em vez de aceitar o primeiro memo.
  • Não retome o pai cedo com apenas parte de um lote de filhos.
  • Mantenha store: true ativado durante o desenvolvimento para poder inspecionar as respostas de pais e filhos depois.
  • Se você estiver agindo em nome de um usuário final, envie o mesmo valor de X-On-Behalf-Of nas requisições de pai e filho.

Armadilhas comuns

  • Poucos subagentes: o pai sintetiza antes que a pesquisa tenha real abrangência.
  • Filhos fracos: um filho retorna após uma busca fraca com “próximos passos” em vez de fazer mais buscas.
  • Memos de filhos muito grandes: o pai ganha pouco porque o filho passa contexto bruto demais.
  • Fan-in precoce: retomar o pai antes de todos os filhos de um lote terminarem torna o fluxo de trabalho menos previsível.
  • Deriva de qualidade de fonte: filhos podem usar demais diretórios, sites de perfil e agregadores, a menos que o prompt diga explicitamente para priorizar fontes primárias.

Veja também

Revise spawn subagents using the Responses API para o padrão geral de delegação pai/filho. Revise generate a response para o formato básico de requisição de Responses.