Llamadas asíncronas a herramientas para agentes de IA: por qué start() supera a un run() bloqueante

Las llamadas asíncronas a herramientas para agentes de IA reemplazan una llamada bloqueante a run() por start(), status() y stop(): identificadores de tareas, eventos de finalización, procesamiento por lotes, cancelación y la API de tareas que hay detrás.

Medy Evrard

5 November 2026

Llamadas asíncronas a herramientas para agentes de IA: por qué start() supera a un run() bloqueante

Apidog para empresas

Despliegue local

SSO & RBAC

Conforme con SOC 2

Explorar Apidog Enterprise

Respuesta rápida: Las llamadas asíncronas a herramientas para agentes de IA dividen un run() bloqueante en un pequeño contrato: start() devuelve de inmediato un identificador de la tarea, status() informa del progreso, stop() cancela y el resultado regresa más tarde como un evento que el agente lee en su siguiente turno. El agente sigue conversando y recibiendo nuevas instrucciones mientras las tareas lentas se ejecutan en segundo plano.

La mayoría de los agentes actuales llaman a una herramienta y se quedan esperando. Si haces una segunda pregunta durante la ejecución de una suite de pruebas de 6 minutos, esta se queda en cola. Esto no supone un problema para una consulta de 200 ms, pero resulta frustrante en un despliegue o en un rastreo web.

Un artículo reciente del equipo de DeepSeek Harness, “Exploring Super-agent Design”, propone una solución denominada «full-duplex»: sustituir el run() bloqueante por start() y stop(). Esta guía aborda la perspectiva del bucle del agente: el contrato de las herramientas, cómo retornan los resultados, la cancelación y la API que requiere cada herramienta. Para conocer la gestión HTTP de una llamada individual de larga duración, consulta AI Agents and Long-Running API Calls: Polling vs Webhooks.

¿Qué son las llamadas asíncronas a herramientas en el bucle de un agente?

Una llamada asíncrona a una herramienta es una invocación que devuelve un identificador (handle) en lugar de un resultado inmediato. El bucle del agente registra dicho identificador, finaliza su turno y queda disponible para el usuario. Cuando el trabajo termina, el runtime inyecta un evento de finalización en la conversación y el modelo lo lee en su siguiente turno como cualquier otro mensaje.

La diferencia radica en quién espera: con run() espera el modelo; con start(), el runtime.

run() bloqueante start() asíncrono
Devuelve Resultado final Job id, “Started”
El agente durante el trabajo Bloqueado Conversando, planificando, iniciando más tareas
Nuevo mensaje del usuario En cola hasta que la herramienta responde Se procesa de inmediato
Cancelación Interrumpir todo el turno stop(job_id)

El artículo de DeepSeek describe esto como un enfoque arquitectónico, no como una función ya lista para producción. Señala que el modo full-duplex está implementado en DeepSeek Harness pero no habilitado por defecto, y que algunas partes forman parte de un plugin prototipo llamado dsh-superagent-prototype, el cual los autores aclaran que no es un producto oficial de DeepSeek. Conviene considerarlo como un patrón de diseño de referencia. Para más contexto, consulta qué es DeepSeek Harness y el artículo complementario sobre cómo crear un superagente.

El problema del bloqueo: una herramienta lenta paraliza al agente

Imagina un agente de programación al que se le pide ejecutar la suite de pruebas (5 minutos) y responder una duda sobre una importación fallida. Con llamadas bloqueantes, la pregunta queda a la espera detrás de las pruebas, a pesar de que no necesita nada de ellas. Surgen tres problemas principales:

  1. La latencia se acumula. Cada herramienta lenta suma toda su duración a todo lo que viene después.
  2. Las instrucciones quedan desfasadas. Si a los dos minutos dices «en realidad, salta las pruebas e2e», el agente no se enterará hasta que termine la ejecución.
  3. Aparecen problemas de timeout. Las pasarelas y proxies cierran conexiones que permanecen abiertas durante minutos, por lo que un run() prolongado puede fallar incluso cuando la tarea se completó correctamente.

El artículo califica la cualidad deseada como «productiva»: el agente acepta la siguiente instrucción antes de que termine la anterior. Las herramientas asíncronas son la forma de lograrlo.

Timeline comparing a blocking agent that waits idle for a 5-minute test run against an async agent that starts the run, answers two user messages, and reads the result when it lands

start, status y stop: el contrato de las herramientas asíncronas

Proporciona al modelo tres herramientas por cada capacidad de larga duración en lugar de una sola, con estructuras de respuesta muy concisas.

{
  "name": "start_test_run",
  "description": "Start the test suite. Returns immediately with a job_id. The result arrives later as a job_completed event; do not wait for it.",
  "input_schema": {
    "type": "object",
    "properties": {
      "suite": { "type": "string", "enum": ["unit", "e2e", "all"] },
      "idempotency_key": { "type": "string" }
    },
    "required": ["suite", "idempotency_key"]
  }
}

start_test_run devuelve {"job_id": "job_8f2", "status": "queued"} y nada más. get_job_status(job_id) devuelve queued, running, done o failed, junto con una breve nota de progreso. stop_job(job_id) solicita la cancelación y devuelve el estado alcanzado.

Dos reglas garantizan el comportamiento adecuado del modelo: incluye «do not wait» (no esperar) en la descripción, o de lo contrario sondeará get_job_status en un bucle continuo; y nunca devuelvas datos de resultado desde start, o el modelo tendrá que adivinar qué estructura recibió.

Cómo retornan los resultados al bucle

El sondeo (polling) por parte del modelo debe ser el plan de reserva, no el diseño principal. Un enfoque más sólido consiste en que el runtime supervise las tareas e inyecte un evento de finalización en la conversación como un nuevo mensaje:

[event] job_completed job_id=job_8f2 tool=start_test_run status=done
summary: 412 passed, 3 failed (auth/session.test.ts)
details: get_job_result(job_8f2)

Mantén el evento breve y deja la carga completa de datos detrás de una herramienta de consulta, evitando así que un registro de 40.000 líneas sature el contexto.

El siguiente paso es procesar por lotes (batching). El artículo de DeepSeek describe un enrutador que recopila los activadores (triggers) que llegan durante un turno y los combina en la siguiente llamada al modelo —entradas largas y salidas cortas, integradas en la fase de prefill—. En su experimento, los disparadores pasaron de 1 a 40 por minuto, el tamaño promedio del lote aumentó de 1,0 a 2,8 y el tiempo por decisión se redujo de 6,4 s a 1,6 s. Aunque son métricas propias de las pruebas del artículo y no una referencia generalizada, una llamada que procesa tres eventos resulta mucho más eficiente que tres llamadas individuales. Una regla práctica: mientras el modelo genera respuestas, pon en cola los eventos y los mensajes del usuario; cuando finalice el turno, envíalos juntos en orden de llegada.

Diagram of an agent runtime: tools return job ids to the model, a job watcher collects completion events and user messages into a queue, and a router batches them into the next model call

Orden de ejecución, cancelación y claves de idempotencia

Orden de ejecución. Las tareas pueden completarse en cualquier orden. Si la tarea B depende de la tarea A, haz explícita esa dependencia: inicia B solo tras recibir el evento de finalización de A, o configura la API para que acepte un parámetro depends_on.

Cancelación. stop es una solicitud, no una garantía. Devuelve el estado final real (cancelled, o done si concluyó antes) y permite que el modelo lo informe con precisión. La extensión Tasks de MCP adopta este mismo principio: su documentación describe la cancelación como cooperativa, por lo que una tarea aún puede alcanzar un estado terminal distinto de cancelled.

Claves de idempotencia. Los modelos realizan reintentos, por lo que una conexión interrumpida puede desencadenar un segundo start. Exige una idempotency_key en cada start y asegúrate de que la API devuelva la tarea existente si detecta la misma clave. De lo contrario, una instrucción como «ejecutar la migración» podría ejecutarse dos veces.

Resultados parciales. Expón los resultados preliminares (por ejemplo, las primeras 50 páginas rastreadas) mediante get_job_result(job_id, cursor) en lugar de esperar a que termine todo el proceso.

Crecimiento del contexto. Resume las tareas finalizadas en una sola línea una vez que el modelo haya actuado sobre ellas.

Tiempos de espera (timeouts). Asigna a cada tarea un límite de tiempo y emite job_timed_out si este se supera.

Cómo debe ser la API subyacente

Una herramienta asíncrona es tan eficaz como la API de tareas que la respalda: debe aceptar el trabajo, devolver un identificador y permitir que el cliente consulte su estado. El RFC 9110 define 202 Accepted indicando que «la solicitud ha sido aceptada para su procesamiento, pero este aún no se ha completado», y la referencia de MDN sobre el código 202 detalla su aplicación práctica.

Una API mínima de tareas para una herramienta start():

Llamada Respuesta Utilizado por
POST /jobs (con encabezado Idempotency-Key) 202 + {"job_id", "status":"queued"} + Location: /jobs/{id} start
GET /jobs/{id} 200 + queued, running, done o failed status, supervisor de tareas (job watcher)
GET /jobs/{id}/result 200 con la salida, o 409 si aún no termina herramienta de consulta (fetch tool)
DELETE /jobs/{id} 202 cancelación solicitada, luego 404 o 409 en llamadas posteriores stop
URL de callback opcional POST al emisor tras completarse supervisor de tareas (job watcher)

El callback permite que el runtime envíe eventos en lugar de recurrir al sondeo. Si necesitas ayuda para elegir entre ambas opciones, consulta el análisis comparativo en webhooks vs polling; la perspectiva de las API orientadas a eventos se explica en qué es AsyncAPI.

Si tus herramientas son compatibles con MCP, ya existe un estándar para esto. La especificación de MCP (versión 2026-07-28) incluye Tasks como una extensión opcional: el servidor puede responder a tools/call con un CreateTaskResult que contiene un taskId, el cliente sondea tasks/get (o escucha notifications/tasks) y tasks/cancel solicita la detención. Los estados son working, input_required, completed, failed y cancelled. Tanto el cliente como el servidor deben habilitarlo expresamente, y el soporte en los hosts puede variar, por lo que conviene verificar tu cliente antes de depender de esta función.

Crea y prueba la API de tareas con tu agente de programación y Apidog CLI

La API de tareas es el componente que puedes verificar antes de que cualquier agente interactúe con él. Entrega el diseño y las pruebas a tu agente de desarrollo y haz que opere con Apidog CLI. Tú solo redactas un prompt; el agente se encarga de generar la especificación, los casos de prueba y ejecutarlos.

La configuración solo requiere tres comandos:

npm install -g apidog-cli@latest
apidog auth login --with-token <YOUR_TOKEN>
npx -y skills add https://apidog.com   # pick your agent when prompted

A continuación, proporciona un único prompt a tu agente:

In Apidog project <projectId>, design the job API a start() tool needs:
POST /jobs returns 202 with job_id, GET /jobs/{id} returns queued|running|done|failed,
DELETE /jobs/{id} cancels. Create the endpoints, then create test cases that assert:
202 and a job_id on create, a status that reaches done within 60 seconds,
the same job_id when the Idempotency-Key repeats, and 409 or 404 on GET result after cancel.
Run them against the staging environment <envId> and summarize failures.

El agente lee la estructura de cada payload desde la CLI, la valida y luego genera y ejecuta los comandos:

apidog cli-schema get endpoint-create
apidog cli-schema validate endpoint-create --file post-jobs.json
apidog endpoint create --project <projectId> --file post-jobs.json
apidog cli-schema get test-case-create
apidog cli-schema validate test-case-create --file case-create-202.json
apidog test-case create --project <projectId> --file case-create-202.json
apidog run --test-case <caseId> --project <projectId> -e <envId> -r cli,json

El reporter cli muestra en la terminal si cada aserción pasó o falló, y el informe en formato json proporciona al agente datos estructurados para interpretarlos y explicarlos. Ejecuta el mismo comando en CI con -r junit una vez que las pruebas sean exitosas; la guía de flujo de trabajo del agente con Apidog CLI explica ese ciclo en detalle, y Apidog CLI en Claude Code aborda la configuración del agente. El plan gratuito de Apidog admite hasta 4 usuarios.

Cuándo conviene usar herramientas asíncronas y cuándo no

Cuándo usar el modelo asíncrono:

Cuándo mantener el modelo bloqueante:

Una división práctica: mantén las lecturas bloqueantes y convierte en asíncronas las escrituras lentas y los cómputos pesados.

Preguntas frecuentes

¿Cuál es la diferencia entre las llamadas a herramientas asíncronas y las paralelas? Las llamadas paralelas ejecutan varias herramientas simultáneamente dentro de un mismo turno, y el modelo sigue esperando a que todas concluyan. Las llamadas asíncronas devuelven el control de inmediato y se completan en turnos posteriores, lo que permite al modelo seguir interactuando mientras se ejecutan.

¿Se necesita MCP para crear herramientas asíncronas? No. Cualquier herramienta que devuelva un job id y un runtime que inyecte eventos de finalización funcionará. La extensión opcional Tasks de MCP estandariza el identificador, el sondeo y las llamadas de cancelación si tanto el cliente como el servidor la admiten.

¿Cómo sabe el agente cuándo termina una tarea? El runtime se lo comunica. Un supervisor de tareas (job watcher) sondea la API de tareas o recibe un callback, e incorpora un breve evento de finalización en la conversación. El modelo lo procesa en su siguiente turno.

¿Qué ocurre si el usuario cancela en mitad de una tarea? El agente invoca stop(job_id), la API registra la petición y la tarea reporta su estado final real. Si el trabajo terminó antes de que se procesara la cancelación, el agente debe comunicarlo con total transparencia en lugar de afirmar que se detuvo.

¿Se puede activar el modo full-duplex de DeepSeek con un simple interruptor? No como una función de producto lista para usar. El artículo explica que está implementado en DeepSeek Harness pero desactivado por defecto, y el plugin asociado es un prototipo que, según los propios autores, no constituye un producto oficial de DeepSeek. Conviene utilizarlo como un diseño de referencia.

Practica el diseño de API en Apidog

Descubre una forma más fácil de construir y usar APIs