Phase 13: Tools & Protocols

Chamadas paralelas e transmissão com ferramentas

Três pesquisas meteorológicas independentes são três viagens de ida e volta. Execute-as em paralelo e o tempo total desabre para a chamada única mais lenta. Cada fornecedor de fronteira agora emite várias chamadas de ferramentas em uma única volta. O pagamento é real; a canalização é sutil. Esta lição percorre ambas as metades: o fan-out paralelo e a reensembleia de argumentos transmitidos, com ênfase na armadilha de correlação de id.

Type: Build

Languages: Python (stdlib, thread pool + streaming harness)

Prerequisites: Phase 13 · 02 (function calling deep dive)

Time: ~75 minutes

Objetivos de aprendizagem

  • Explique por que .parallel_tool_calls: trueExiste e quando desativar.
  • Correlação de blocos de argumento fluídos para a identificação de chamada de ferramenta certa durante o fan-out paralelo.
  • Reassemblar parcial argumentsAs cadeias em JSON completo sem análise precoce.
  • Execute um índice meteorológico de três cidades que demonstre latência sequencial vs paralela.

O problema

Sem chamadas paralelas, um agente respondendo a "o que é o tempo em Bengaluru, Tóquio e Zurique" faz o seguinte:

user -> LLM
LLM -> call get_weather(Bengaluru)
host -> run executor, reply with result
LLM -> call get_weather(Tokyo)
host -> run executor, reply with result
LLM -> call get_weather(Zurich)
host -> run executor, reply with result
LLM -> final text answer

Três viagens de ida e volta para o LLM, cada uma das quais também paga a latência do executor.

Com chamadas paralelas:

user -> LLM
LLM -> call get_weather(Bengaluru); call get_weather(Tokyo); call get_weather(Zurich)
host -> run all three executors concurrently, reply with three results
LLM -> final text answer

Uma viagem de ida e volta de LLM. O tempo de execução é o máximo dos três, não a soma. Os índices de produção em OpenAI, Anthropic e Gemini mostram uma redução de 60 a 70 por cento no relógio de parede nas cargas de trabalho de ventilador.

Quando as três chamadas forem completas, os resultados devem ser iguais.tool_call_idO modelo pode alinhá-los. Quando os resultados são transmitidos, você deve montar fragmentos de argumento parciais em JSON completo antes de executar. Gemini 3 adicionou ids únicos em parte para resolver um problema do mundo real onde duas chamadas paralelas para a mesma ferramenta eram indistinguíveis.

O conceito

Atividade paralela

  • OpenAI. parallel_tool_calls: trueligado por padrão.falsePara forçar a série.
  • Anthropic.Paralelamente através dedisable_parallel_tool_use: false(por defeito em Claude 3.5 e superior).truePara série.
  • Gemini.Sempre paralelas .tool_config.function_calling_config.mode = "AUTO"Deixa o modelo decidir.

Desativar o paralelo quando as ferramentas têm dependências de ordem (create_fileEntão ...write_file), quando a saída de uma chamada informa a entrada de outra, ou quando o limitador de taxa não pode lidar com o ventilador.

Correlação Id

Cada chamada que o modelo emite tem umidCada resultado que o anfitrião retorna deve incluir a mesma identificação.

  • OpenAI. tool_call_idem cada mensagem de papel de ferramenta.
  • Anthropic. tool_use_idem cada umtool_resultBloco.
  • Gemini. idem cada umfunctionResponse(Gêmeos 3 e acima; Gêmeos 2 correspondido pelo nome que rompeu para chamadas paralelas do mesmo nome).

A execução de chamadas simultâneas

O host executa o executor de cada chamada em seu próprio fio, coroutine ou operador remoto.asyncio.gatherO número de identificação é o número de identificação.

Um erro comum: responder com resultados na ordem da lista de chamadas em vez de ordem de conclusão.tool_call_id, mas se um resultado for deixado de lado ou duplicado, a submissão fora de ordem torna o depuração mais difícil.

Chamadas de ferramentas de streaming

Quando o modelo fluir,argumentsTrês fluxos separados de pedaços para três chamadas paralelas se interceptam no fio.

Forma por fornecedor:

  • OpenAI.Cada pedaço échoices[0].delta.tool_calls[i].function.argumentsO pedaço carrega .index(posição na lista de chamadas).idquando aparece pela primeira vez, e analisar JSON quando finish_reason = "tool_calls"- Não .
  • Anthropic.Os eventos de streaming sãomessage_start, depois um .content_block_startpor bloco com tipo tool_use(conteendo identificação, nome, entrada vazia). content_block_deltaeventos de transporte input_json_deltapedaços.content_block_stopfecha cada quarteirão.
  • Gemini. streamFunctionCallArguments(Gêmeos 3 e acima) emite pedaços com um functionCallIdAntes do Gemini 3, o streaming devolvia uma chamada completa de cada vez.

JSON parcial e a armadilha de análise precoce

Não consegues analisar .argumentsAté que seja completo.{"city": "BengO portão correto é o sinal de final de chamada do prestador: o OpenAI finish_reason = "tool_calls", Anthropic's content_block_stopSó depois tentamos.json.loads. Uma abordagem mais robusta usa um parser JSON incremental que produz eventos à medida que a estrutura completa; o guia de streaming da OpenAI recomenda isso para UX que mostra um indicador de "pensamento" ao vivo. A contagem de braces não é confiável como um teste de integridade (braces dentro de strings citadas ou conteúdo escapado causam falsos positivos) e só deve ser usada como uma heurística de defeito informal.

Conclusão fora de ordem

call_A: fast API, returns first
call_B: slow API, returns second
call_C: median API, returns third

A resposta do anfitrião deve ainda citar os ids:

[{role: "tool", tool_call_id: "call_A", content: ...},
 {role: "tool", tool_call_id: "call_B", content: ...},
 {role: "tool", tool_call_id: "call_C", content: ...}]

A ordem na resposta não importa para a corretão na OpenAI ou na Anthropic.

Indicador de referência: sequencial vs paralelo

O arame está dentro .code/main.pySimula três executores com latência de 400, 600 e 800 ms. Sequencial executa em 1800 ms total. Paralelamente executa em max ((400, 600, 800) = 800 ms. A diferença é constante, não proporcional, então as economias crescem com a contagem de ferramentas.

A advertência do mundo real: chamadas paralelas estressam APIs para baixo. Um ventilador de 10 vias para um serviço limitado de taxa falhará. Fase 13 · 17 cobre a pressão de volta ao nível do gateway; semântica de retest é planejada para uma fase futura.

O relógio de parede de ventilador em streaming

Se o modelo em si transmite, você pode começar a executar assim que os argumentos de uma chamada estiverem completos, em vez de esperar que todas as chamadas sejam finalizadas. Este é um documento de otimização OpenAI, mas nem todos os SDKs expõem. O arsenal desta lição o faz: assim que o fluxo simulado produz um objeto de argumento completo, o host inicia essa chamada.

Usá-lo

code/main.pyA primeira opera três chamadas meteorológicas simuladas sequencialmente e em paralelo usandoconcurrent.futures.ThreadPoolExecutorA segunda metade reproduz uma resposta de streaming falsa pedaços de argumentspara três chamadas paralelas intercaladas em um fluxo e reassemble-las por id com StreamAccumulatorSem LLM, sem rede, apenas a lógica de reensamblagem.

O que ver:

  • O temporizador sequencial atinge 1,8 segundos. O temporizador paralelo atinge 0,8 segundos nas mesmas latências falsas.
  • O acumulador lida com pedaços que chegam fora de ordem, tampando por ID e analisando apenas quando o JSON de cada chamada está completo.
  • O executor começa assim que os argumentos de um ID terminam, não depois de todos os fluxos acabarem.

Envia-o

Esta lição produzoutputs/skill-parallel-call-safety-check.md. Tendo em conta um registo de ferramentas, as auditorias de competências que permitem parallelizar as ferramentas, que têm dependências de ordem e que ultrapassam os limites de taxas a jusante devolver um registo revisto com ferramentas parallel_safe- As bandeiras.

Exercícios

  1. Corra .code/main.pyConfirme que a relação paralelo-sequencial é aproximadamente max/sum(as corridas reais desviam ligeiramente do ideal devido à programação de fios, serialização e sobrecarga de arremesso).
  1. Extender o acumulador para lidar com um caso de "chamada foi cancelada no meio do fluxo" deixando cair o seu tampão e emitindo um cancelledQual fornecedor documenta este caso explicitamente?content_block_stopSemântica e OpenAI finish_reason: "length"- Comportamento.
  1. Substitua a piscina de fios por asyncio.gatherVocê deve ver pequenas vitórias em async por causa do menor custo de comutação de contexto, mas apenas se os executores fazem I / O real.
  1. Escolha duas ferramentas que NÃO devem ser paralelas (por exemplo create_fileEntão ...write_file ordering_dependencyO sistema de programação de dependência é o mínimo que uma futura fase de engenharia de agentes formaliza.
  1. Leia a seção de chamadas para funções paralelas da OpenAI e a Anthropic disable_parallel_tool_useDocs. Identificar o tipo de ferramenta do mundo real em que a Anthropic recomenda desativar o paralelismo.

Termos-chave

TermWhat people sayWhat it actually means
Parallel tool calls"Fan-out in one turn"Model emits multiple tool calls in a single assistant message
parallel_tool_calls"OpenAI's flag"Enable or disable multi-call emission
disable_parallel_tool_use"Anthropic's inverse"Opt-out flag; default is parallel enabled
Tool call id"Correlation handle"Per-call identifier the result message must echo
Accumulator"Stream buffer"Per-id string buffer for partial arguments chunks
Out-of-order completion"Fastest first"Parallel calls finish in unpredictable order; ids are the glue
Dependency graph"Ordering constraints"Tools whose outputs feed into inputs of other tools; cannot parallelize
Parse-early trap"JSON.parse exploded"Attempting to parse an incomplete arguments string
streamFunctionCallArguments"Gemini 3 feature"Streamed argument chunks with unique id per call
Completion-order reply"Don't wait for all"Reply with results as they arrive, keyed by id

Mais leitura

This free lesson is part of the AI Engineering from Scratch curriculum. Read the full explanation, run the lesson code, and verify the result in the interactive reader or from the repository source.

Browse the complete course catalog or open this lesson on GitHub.