Phase 13: Tools & Protocols

Llamadas paralelas y transmisión con herramientas

Tres búsquedas de tiempo independientes en serie son tres viajes de ida y vuelta. ejecutarlos en paralelo y el tiempo total se desploma a la llamada única más lenta. Cada proveedor fronterizo ahora emite múltiples llamadas de herramienta en un solo giro. La recompensa es real; la tubería es sutil. Esta lección camina ambas mitades: el fan-out paralelo y el reensamblaje de argumentos transmitidos, con énfasis en la trampa de correlación de identidad.

Type: Build

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

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

Time: ~75 minutes

Objetivos de aprendizaje

  • ¿ Por qué ?parallel_tool_calls: trueexiste y cuándo desactivarlo.
  • Correlación de los trozos de argumento en streaming con la identificación de llamada de herramienta correcta durante el ventilador paralelo.
  • Reassemblar parcialmente argumentslas cadenas en JSON completo sin analizar temprano.
  • Ejecutar un indicador meteorológico de tres ciudades que demuestre latencia secuencial vs paralelo.

El problema

Sin llamadas paralelas, un agente respondiendo a "cuál es el tiempo en Bengaluru, Tokio y Zurich" hace esto:

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

Tres viajes de ida y vuelta de LLM, cada uno de los cuales también paga la latencia del ejecutor.

Con llamadas 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

Un viaje de ida y vuelta de LLM. El tiempo de ejecución es el máximo de los tres, no la suma. Los índices de producción en OpenAI, Anthropic y Gemini muestran una reducción del 60 a 70 por ciento en el reloj de pared en las cargas de trabajo de ventilador.

Cuando las tres llamadas terminan fuera de orden, sus resultados deben llevar la coincidencia tool_call_idCuando los resultados se transmiten, se debe reunir fragmentos de argumento parciales en JSON completo antes de ejecutar. Gemini 3 agregó ids únicos en parte para resolver un problema en el mundo real donde dos llamadas paralelas a la misma herramienta eran indistinguibles.

El concepto

Permitir el paralelo

  • OpenAI. parallel_tool_calls: trueen el por defecto.falsepara forzar a la serie.
  • Anthropic.Paralelamente a través de disable_parallel_tool_use: false(por defecto en Claude 3.5 y más).truepara la serie.
  • Gemini.Siempre paralela .tool_config.function_calling_config.mode = "AUTO"Deje que el modelo decida.

Deshabilitar el paralelo cuando las herramientas tengan dependencias de orden (create_fileEntonces ...write_file), cuando la salida de una llamada informa la entrada de otra, o cuando el limitador de velocidad no puede manejar el ventilador.

Correlación de identidad

Cada llamada que emite el modelo tiene unidCada resultado que devuelva el anfitrión debe incluir la misma identificación.

  • OpenAI. tool_call_iden cada mensaje de papel de herramienta.
  • Anthropic. tool_use_iden cada uno tool_resultEl bloque.
  • Gemini. iden cada uno functionResponse(Gemini 3 y arriba; Gemini 2 coincidió por nombre que rompió para llamadas paralelas del mismo nombre).

Ejecutar llamadas simultáneamente

El anfitrión ejecuta el ejecutor de cada llamada en su propio hilo, coroutine o trabajador remoto.asyncio.gatherEl orden de finalización es impredecible el id es el identificador.

Un error común: responder con resultados en orden de lista de llamadas en lugar de orden de finalización. Esto suele funcionar porque el modelo solo se preocupa por tool_call_id, pero si un resultado se deja caer o se duplica, la presentación fuera de orden hace que el descomposición sea más difícil.

Las llamadas de herramientas de transmisión

Cuando el modelo fluye,argumentsTres flujos separados de trozos para tres llamadas paralelas se interponen en el cable.

Forma por proveedor:

  • OpenAI.Cada pieza eschoices[0].delta.tool_calls[i].function.argumentsEl pedazo llevaindexSe acumula por índice, se lee idcuando aparece por primera vez, y analizar JSON cuando finish_reason = "tool_calls"¿ Qué ?
  • Anthropic.Los eventos de transmisión sonmessage_start, luego uno .content_block_startpor bloque con tipo tool_use(contiene identificación, nombre, entrada vacía). content_block_deltalos eventos llevan input_json_deltaLos trozos.content_block_stopcierra cada cuadra.
  • Gemini. streamFunctionCallArguments(Gemini 3 y arriba) emite trozos con un functionCallIdAntes de Gemini 3, la transmisión devolvió una llamada completa a la vez.

JSON parcial y la trampa de análisis precoz

No puedes analizar .argumentsJSON parcial como {"city": "BengLa puerta correcta es la señal de final de llamada del proveedor: OpenAI finish_reason = "tool_calls", Anthropic's content_block_stop, o el evento de la línea de salida de Géminis.json.loads. Un enfoque más robusto utiliza un parser JSON incremental que produce eventos a medida que se completa la estructura; la guía de transmisión de OpenAI lo recomienda para UX que muestra un indicador de "pensamiento" en vivo. La cuenta de correcciones es poco confiable como prueba de integridad (las correcciones dentro de las cadenas citadas o el contenido escapado causan falsos positivos) y solo debe usarse como una heurística de defecto informal.

Completado fuera de orden

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

La respuesta de la anfitriona deberá seguir citando las identidades siguientes:

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

El orden en la respuesta no importa para la corrección en OpenAI o Anthropic. Gemini acepta cualquier orden siempre que coincidan las identidades.

Indicador de referencia: secuencial vs paralelo

El arnés en code/main.pySe ejecuta en 1800 ms total. Se ejecuta en paralelo en max ((400, 600, 800) = 800 ms. La diferencia es constante, no proporcional, por lo que los ahorros crecen con el número de herramientas.

Advertencia en el mundo real: llamadas paralelas ponen en riesgo las APIs en el aguas abajo. Una ventaja de 10 vías a un servicio limitado de velocidad fallará. La fase 13 · 17 cubre la presión de retroceso a nivel de puerta de entrada; se planea volver a probar la semántica para una fase futura.

Reloj de pared de ventilador en streaming

Si el modelo en sí mismo transmite, puede comenzar a ejecutar tan pronto como los argumentos de una llamada estén completos, en lugar de esperar a que todas las llamadas se finalicen. Esta es una optimización de los documentos OpenAI pero no todos los SDK exponen. El arnés de esta lección lo hace: tan pronto como el flujo simulado produzca un objeto de argumento completo, el host inicia esa llamada.

Usalo

code/main.pyLa primera ejecuta tres llamadas meteorológicas simuladas secuencialmente y en paralelo utilizandoconcurrent.futures.ThreadPoolExecutorLa segunda mitad reproduce una respuesta de transmisión falsa trozos de argumentspara tres llamadas paralelas entrelazadas en una corriente y las reúne por identificación con StreamAccumulatorNo LLM, no red, sólo la lógica de reensamblaje.

Qué ver:

  • El temporizador secuencial alcanza 1,8 segundos y el temporizador paralelo alcanza 0,8 segundos en las mismas latencias falsas.
  • El acumulador maneja los trozos que llegan fuera de orden mediante el amortiguamiento por identificación y el análisis solo cuando el JSON de cada llamada esté completo.
  • El ejecutor comienza tan pronto como finalizan los argumentos de un ID, no después de que terminen todas las corrientes.

Envío

Esta lección produceoutputs/skill-parallel-call-safety-check.md. Dado un registro de herramientas, las auditorías de habilidades que son seguras para paralelar las herramientas, que tienen dependencias de orden y que abrumarían los límites de tasas a continuación devolver un registro revisado con herramienta por herramienta parallel_safelas banderas.

Los ejercicios

  1. - ¿ Qué ?code/main.pyConfirmar que la relación paralelo-secuencial es aproximadamente max/sum(las carreras reales se desvían ligeramente de la ideal debido a la programación de hilos, la serialización y el gasto superior del arnés).
  1. Extensión del acumulador para manejar un caso de "llamada fue cancelada en medio de la corriente" dejando caer su amortiguador y emitiendo un cancelled¿Qué proveedor documenta explícitamente este caso?content_block_stopLa semántica y OpenAI finish_reason: "length"el comportamiento.
  1. Remplaza el hilo de hilo con asyncio.gatherSe deberían ver pequeñas ganancias en async debido al menor costo de cambio de contexto, pero sólo si los ejecutores hacen I/O real.
  1. Elegir dos herramientas que NO deben estar en paralelo (por ejemplo create_fileEntonces ...write_fileAñadir unordering_dependencyEl sistema de programación de dependencias es el mínimo que una futura fase de ingeniería de agentes formaliza.
  1. Lea la sección de llamadas paralelas de funciones de OpenAI y la de Anthropic disable_parallel_tool_useDocuments. Identifique el tipo de herramienta en el mundo real en el que Anthropic recomienda desactivar el paralelismo.

Términos clave

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

Leer más

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.