Skip to content
This page has been auto-translated and may contain errors.View in English

Chat Completions y Responses

Abre el playground de la lección y encontrarás dos botones, uno para cada una de las dos estructuras de API de OpenAI: Chat Completions y Responses. Volverás a encontrar ambos nombres en código de otras personas y en la propia documentación del proveedor, casi siempre sin ninguna explicación de por qué existen dos.

Ambas hacen lo mismo. Las dos envían instrucciones y un mensaje del usuario a un modelo y reciben una respuesta. Lo que cambia es dónde ubicas cada parte de la solicitud y dónde aparece el texto de la respuesta después, y esa segunda diferencia es la que te complica la vida cuando copias un fragmento de código de algún lugar.

Esos botones del playground llaman a rutas del servidor Express, el pequeño programa de Node que el proyecto del curso ejecuta junto con la página, para que las solicitudes al modelo ocurran fuera del código del navegador y tu clave de API nunca quede expuesta. En Scrimba, la salida de esas rutas del servidor aparece en la pestaña Runner en lugar de la pestaña Console.

Los dos ejemplos siguientes usan el mismo cliente, creado una sola vez a partir de los valores que guardaste en Configuración del proveedor:

js
import OpenAI from "openai"

const client = new OpenAI({
  apiKey: process.env.AI_KEY,
  baseURL: process.env.AI_URL,
})

Chat Completions

Chat Completions coloca el prompt del sistema y la entrada del usuario juntos en messages:

js
const response = await client.chat.completions.create({
  model: process.env.AI_MODEL,
  messages: [
    { role: "system", content: "You are a helpful assistant." },
    {
      role: "user",
      content: "Give me a short explanation of why open-source tools matter.",
    },
  ],
});

El texto de la respuesta queda anidado bajo la primera opción:

js
response.choices[0].message.content
JunoChat Completions Todo va en una sola lista messages: primero el prompt del sistema, luego tu pregunta. La respuesta vuelve enterrada en response.choices[0].message.content.

Esa ruta parece complicada las primeras veces que la escribes. Vale la pena leerla despacio una vez, ¡porque la vas a ver en casi todos los ejemplos de código que encuentres en línea!

JunoChat Completions Un solo arreglo lleva toda la solicitud, y role decide para qué sirve cada elemento. La respuesta está bajo choices[0] porque la API puede devolver varias respuestas alternativas en una sola llamada.

Básicamente siempre vas a querer la primera, así que choices[0].message.content se convierte en algo casi automático. Reconocer esa ruta es útil incluso aquí, porque te dice de inmediato que un fragmento que encontraste es de Chat Completions y no de Responses.

JunoChat Completionschoices es un plural que casi nunca lo es. Viene del parámetro n de la API de completions, que pedía varias muestras independientes en una sola solicitud, y sobrevive en la forma de la respuesta mucho después de que casi nadie lo siguiera usando.

Vale la pena saberlo porque explica la comodidad que estás a punto de sacrificar. Cada lectura te cuesta un índice de arreglo que no aporta ninguna información, y cada turno con llamadas a herramientas que agregues tienes que reconstruirlo a mano dentro de esa misma lista plana.

Responses

Responses le da al prompt del sistema su propio campo instructions. Para una solicitud simple, input puede ser directamente un string:

js
const response = await client.responses.create({
  model: process.env.AI_MODEL,
  instructions: "You are a helpful assistant.",
  input: "Give me a short explanation of why open-source tools matter.",
});

Ese mismo string directo se puede convertir en un objeto de mensaje con role/content cuando necesitas esa forma:

js
input: [
  {
    role: "user",
    content: "Give me a short explanation of why open-source tools matter.",
  },
],

Responses expone el texto de la respuesta directamente:

js
response.output_text

También conserva la estructura completa de la respuesta en response.output. Una respuesta de texto básica suele contener un elemento de mensaje cuyo content incluye ese mismo texto de salida.

JunoResponses El prompt del sistema tiene su propio campo instructions en lugar de compartir la lista, y input puede ser un string simple cuando solo estás preguntando una cosa.

La mejor parte: la respuesta está en response.output_text. Un solo paso en lugar de tres.

JunoResponses Hay dos diferencias prácticas. instructions separa el prompt del sistema de la conversación, así que no tienes que reconstruir un arreglo en cada turno para mantenerlo al principio. Y output_text te da el texto directamente.

input igual acepta la forma de arreglo de mensajes cuando la necesitas, que es lo que se usa más adelante en el curso para el historial de la conversación y los resultados de herramientas. La forma en string es un atajo para el caso simple, no una API distinta.

JunoResponsesoutput_text es una comodidad sobre output, que es el verdadero valor de retorno: una lista de elementos tipados en lugar de un solo mensaje. Esa estructura es justamente el punto, porque un turno que llama herramientas devuelve elementos de llamada a herramientas junto con cualquier texto, y un string plano de contenido no tiene dónde ponerlos.

Así que lee output_text cuando quieras una respuesta final y output cuando necesites saber qué hizo realmente el modelo. En el momento en que agregues tu primera herramienta, será ahí donde vas a estar mirando.

Por qué el curso usa Responses

Chat Completions sigue siendo una API válida, y la funcionalidad de agentes de este curso podría construirse con ella.

El curso usa Responses por la diferencia que ya puedes ver en los dos bloques de código anteriores. Leer una respuesta es response.output_text en lugar de response.choices[0].message.content, y el prompt del sistema tiene un lugar propio en vez de ser el primer elemento de un arreglo al que también le vas agregando los turnos del usuario. Una vez que empiezan a acumularse las llamadas a herramientas y el historial de la conversación, esa estructura significa menos código para mantener todas las piezas juntas.

Usa la salida completa cuando necesites la estructura

output_text es la forma cómoda de leer una respuesta final en texto. Usa output cuando necesites inspeccionar el conjunto completo de elementos de la respuesta.

JunoPor qué el curso usa Responses Ambas APIs pueden hacer todo lo que este curso necesita. Responses es la que requiere escribir menos: la respuesta está a un paso en lugar de tres, y el prompt del sistema tiene su propio campo.

No necesitas memorizar las diferencias. Usa Responses aquí, y reconoce Chat Completions cuando te la encuentres en otro lado.

JunoPor qué el curso usa Responses La elección tiene que ver con cuánto código de conexión tienes que escribir alrededor de la llamada. Con Responses, el prompt del sistema tiene un lugar propio, así que deja de ser un elemento del arreglo que tienes que mantener en la posición cero, y la respuesta está a solo una propiedad de distancia.

Chat Completions no está obsoleta y mucho código en producción la usa. Si heredas una base de código construida con ella, no necesitas reescribir nada de esto.

JunoPor qué el curso usa Responses La diferencia se acumula en lugar de notarse desde la primera solicitud. En un ciclo con llamadas a herramientas agregas el turno del modelo, luego los resultados de las herramientas, y vuelves a llamar, y Chat Completions te obliga a reconstruir a mano todo ese arreglo plano cada vez, manteniendo además el mensaje del sistema fijo al principio.

Responses representa un turno como una serie de elementos, que es la estructura que realmente tiene el ciclo. Ese es el argumento de fondo, y es invisible en los dos ejemplos sencillos de arriba, por eso vale la pena mencionarlo antes de que te topes con él.

Hacia dónde va esto ahora

Ejecutar el código de forma local explica cómo se conectan el navegador y el servidor Express después de que descargas una lección desde Scrimba. Si todavía no has elegido un modelo, Modelos recomendados explica qué necesita el trabajo con agentes.