# Cómo migrar de Assistants API a Responses API tras el cierre

> Assistants API ya cerró. Para continuar el servicio con Responses API necesitas reconstruir la configuración, convertir el historial conservado y completar la ejecución de herramientas; la recuperación debe apoyarse en un entorno que siga funcionando.

- URL: https://blog.laozhang.ai/es/posts/openai-assistants-api-to-responses-api
- Published: 2026-07-28
- Updated: 2026-10-06
- Author: LaoZhang AI Team (https://blog.laozhang.ai/es/about)
- Topic: Guías de API
- Tags: OpenAI Assistants API, Responses API, Conversations API, function calling, migración API

---
**Assistants API dejó de estar disponible el 26 de agosto de 2026.** Si tu aplicación aún utiliza `beta.assistants` o `beta.threads`, la solución es reconstruir ese flujo sobre Responses API con la configuración y los mensajes que ya conserves. No puedes mantener Assistants como respaldo ni consultar ahora sus Threads para exportar el historial: la [guía oficial confirma que esa llamada ya no funciona](https://developers.openai.com/api/docs/assistants/migration).

Empieza por un flujo concreto: recupera sus instrucciones y herramientas, decide dónde guardar las conversaciones, devuelve cada resultado de función con su `call_id` y valida las respuestas contra casos conservados. Después activa esa implementación para sesiones nuevas. Si falla, deriva la sesión a una versión de Responses ya validada o a atención manual; volver al endpoint retirado no recupera el servicio.

Esta guía trata la API directa de OpenAI. Si tu integración pasa por Azure, una plataforma de automatización o un proveedor compatible, comprueba también su contrato. Que acepte el formato de OpenAI no demuestra que implemente Conversations, File Search o los mismos eventos. Para resolver un problema de direccionamiento, consulta [qué ajuste de `base_url` tiene prioridad y qué ruta debes poner](https://blog.laozhang.ai/es/posts/openai-base-url-override).

## Qué recuperar antes de escribir la nueva integración

Busca en el repositorio, la base de datos de tu aplicación y las copias que conservaste antes del cierre. Un `asst_…` permite reconocer qué configuración falta; por sí solo no contiene las instrucciones. Un `thread_…` tampoco es un historial recuperable.

| Material conservado | Uso en Responses | Si falta |
|---|---|---|
| Instrucciones, modelo, parámetros y versión | Configuración explícita de cada petición | Reconstruye las reglas con el responsable del servicio antes de automatizar |
| Esquemas de funciones y su implementación | `tools` y código ejecutor de la aplicación | Recupera también permisos, errores y efectos de cada operación |
| Mensajes completos, orden y propietario de la sesión | Historial propio o Items de una Conversation | Abre una conversación nueva y pide los datos necesarios; no inventes turnos |
| Documentos originales, archivos y referencia al vector store | Búsqueda sobre recursos accesibles y autorizados | Recupera los documentos y prepara la búsqueda en tu entorno autorizado |
| Resultados anteriores de tareas y registros de errores | Casos de comparación | Define ejemplos con resultado esperado, incluidos los que deben rechazarse |

Mantén las copias originales sin modificarlas. Trabaja sobre una conversión separada y registra qué sesión antigua corresponde a la nueva. Esa relación debe incluir el usuario y la organización autenticados, la versión de configuración y la estrategia de estado. No aceptes un identificador recibido del navegador como permiso para continuar cualquier conversación.

Hay una segunda retirada que afecta a la configuración: **los objetos Prompt reutilizables y `v1/prompts` tienen previsto cerrar el 30 de noviembre de 2026**. No es la fecha de cierre de Assistants. Aunque la guía de Assistants todavía muestre la transición `Assistant → Prompt`, la [guía para abandonar los objetos Prompt](https://developers.openai.com/api/docs/guides/prompting/migrate-from-prompt-object) indica que debes llevar su contenido al código de la aplicación. Conserva allí instrucciones, modelo, herramientas y esquema de salida, con una versión que puedas desplegar y recuperar conjuntamente.

## Convierte el historial guardado sin perder contenido en silencio

La conversión parte de una exportación que **ya exista**, no de una consulta nueva a Threads. Separa las conversaciones que deben continuar de las que solo necesitan consulta histórica. Una conversación cerrada puede permanecer en un archivo de lectura si tu política de conservación lo permite; no hace falta enviarla entera al modelo.

![Opciones para aprovechar el historial conservado: convertir el texto compatible, revisar adjuntos y citas o iniciar una conversación nueva cuando solo queda el ID](https://blog.laozhang.ai/posts/es/openai-assistants-api-to-responses-api/img/historial-conservado.webp)

El siguiente conversor procesa un archivo JSON local con mensajes de texto. Se niega a convertir adjuntos, citas, bloques desconocidos o una sesión con una operación pendiente. Así evita producir un historial aparentemente válido que haya perdido el dato necesario para responder. Es un ejemplo deliberadamente limitado: las imágenes, archivos y estados de herramientas necesitan una conversión específica, recursos todavía accesibles y comprobaciones propias.

Guarda este código como `convertir_historial.py`. El archivo de entrada debe tener `messages` en orden cronológico y declarar `order: "asc"` y `pending_action: false`; esos dos campos son el formato local de este ejemplo, no campos nuevos de la API de OpenAI.

```python
import json
import sys
from pathlib import Path

def convertir(archivo):
    if archivo.get("order") != "asc":
        raise ValueError("Falta un orden cronológico confirmado")
    if archivo.get("pending_action") is not False:
        raise ValueError("Hay una operación pendiente o su estado es desconocido")
    mensajes = archivo.get("messages")
    if not isinstance(mensajes, list) or not mensajes:
        raise ValueError("No hay mensajes completos para continuar")
    items = []
    for numero, mensaje in enumerate(mensajes):
        role = mensaje.get("role")
        if role not in {"user", "assistant"}:
            raise ValueError(f"Mensaje {numero}: role no compatible")
        if mensaje.get("attachments"):
            raise ValueError(f"Mensaje {numero}: revisa los adjuntos")
        bloques = mensaje.get("content")
        if not isinstance(bloques, list) or not bloques:
            raise ValueError(f"Mensaje {numero}: contenido ausente")
        textos = []
        for bloque in bloques:
            texto = bloque.get("text", {})
            if bloque.get("type") != "text" or not isinstance(texto, dict):
                raise ValueError(f"Mensaje {numero}: bloque no compatible")
            if texto.get("annotations"):
                raise ValueError(f"Mensaje {numero}: conserva y revisa las citas")
            valor = texto.get("value")
            if not isinstance(valor, str) or not valor.strip():
                raise ValueError(f"Mensaje {numero}: texto vacío")
            textos.append(valor)
        items.append({"role": role, "content": "\n\n".join(textos)})
    return items

if __name__ == "__main__":
    if len(sys.argv) != 3:
        raise SystemExit("Uso: python convertir_historial.py origen.json items.json")
    entrada = Path(sys.argv[1])
    salida = Path(sys.argv[2])
    if entrada.resolve() == salida.resolve() or salida.exists():
        raise SystemExit("La salida debe ser un archivo nuevo")
    archivo = json.loads(entrada.read_text(encoding="utf-8"))
    items = convertir(archivo)
    with salida.open("x", encoding="utf-8") as destino:
        json.dump(items, destino, ensure_ascii=False, indent=2)
```

Puedes comprobarlo sin red con una copia sintética como esta:

```json
{
  "order": "asc",
  "pending_action": false,
  "messages": [
    {"role": "user", "content": [{"type": "text", "text": {"value": "Mi incidencia es T-81.", "annotations": []}}]},
    {"role": "assistant", "content": [{"type": "text", "text": {"value": "Voy a consultar su estado.", "annotations": []}}]}
  ]
}
```

Ejecuta `python convertir_historial.py origen.json items.json` y revisa el orden y el contenido del resultado. Después prueba un adjunto y una anotación: ambos deben detener la conversión. Antes de continuar una sesión real, comprueba sus registros de herramientas, aunque el último mensaje parezca normal. Si hubo una modificación de negocio, consulta el estado actual del backend en lugar de ejecutarla otra vez.

La [migración oficial de historial](https://developers.openai.com/api/docs/assistants/migration) también transforma mensajes en Items, pero su ejemplo de lectura desde Threads es histórico. No supone una conversión completa de citas, adjuntos ni operaciones pendientes. Cuando no puedas convertir una parte, conserva el original para consulta y bloquea la continuación automática de esa sesión hasta resolverla.

## Elige cómo continuar las conversaciones

Responses permite gestionar el historial en tu aplicación, usar `previous_response_id` o crear una Conversation. Elige una estrategia para cada flujo y mantenla estable durante la primera validación.

| Estrategia | Cuándo resulta práctica | Responsabilidad que conservas |
|---|---|---|
| Historial propio | Necesitas decidir qué se persiste y qué contexto se envía | Guardar y reproducir todos los Items necesarios, controlar tamaño y acceso |
| `previous_response_id` | Una secuencia breve continúa desde una respuesta disponible | Guardar el ID correcto y volver a enviar las instrucciones |
| Conversation | La conversación debe continuar entre dispositivos o trabajos | Asociar su ID al usuario, serializar turnos y gestionar conservación y borrado |

Con historial propio, carga los `items.json` de la sesión autorizada como `input`. En adelante, conserva las entradas, las llamadas, los resultados y **todos los Items reproducibles de `response.output`**, no solo `output_text`. La [documentación de estado](https://developers.openai.com/api/docs/guides/conversation-state) muestra que esto conserva el razonamiento cifrado y el campo `phase` de los mensajes del asistente. En Python, sus ejemplos añaden el `response.output` completo; en JavaScript utilizan `toResponseInputItems` del SDK para preparar los Items de entrada. No reconstruyas razonamientos ausentes a partir de una respuesta antigua.

Con Conversation, crea el objeto con los Items ya convertidos y guarda su nuevo ID en tu base de datos. Las peticiones posteriores llevan `conversation` y únicamente la entrada nueva: el [contrato de creación de Responses](https://developers.openai.com/api/reference/resources/responses/methods/create) incorpora el contexto guardado y añade la entrada y la salida al terminar. No reenvíes también todo el historial, porque duplicarías el contexto. Protege cada sesión con un bloqueo o una cola por conversación para que dos workers no alteren el orden.

`previous_response_id` no se puede combinar con `conversation`. Además, las `instructions` de la respuesta previa no se trasladan a la siguiente: envía la configuración aplicable en cada petición. Un ID de Response depende de que ese estado siga disponible; conserva un historial propio si necesitas recuperarte cuando deje de estarlo. Los IDs antiguos `thread_`, `run_` o `asst_` no se convierten cambiándoles el prefijo.

### Conservación y coste: decide antes de elegir el estado

Los objetos Response se guardan normalmente durante 30 días; con `store=true`, la documentación de datos señala al menos 30 días, salvo sus excepciones. Las Conversations y sus Items no tienen ese vencimiento y se conservan hasta borrarlos; esos endpoints no son aptos para Zero Data Retention (ZDR). Tampoco `store=false` elimina por sí solo los registros de supervisión de abuso, cuyo plazo predeterminado puede llegar a 30 días. Consulta las [condiciones de conservación de OpenAI](https://developers.openai.com/api/docs/guides/your-data) para tu organización y modelo.

El historial propio necesita también una política local de conservación y borrado. Y mandar solo `previous_response_id` reduce el cuerpo de la petición, pero **no evita facturar como entrada los tokens previos de la cadena**. La ventana de contexto incluye entrada, salida y razonamiento. Define cuánto historial necesita la tarea y comprueba que cualquier resumen conserve sus hechos críticos; no asumas que resumir es una transformación sin pérdidas. Estas condiciones están recogidas en la [guía de estado de conversación](https://developers.openai.com/api/docs/guides/conversation-state).

## Implementa la función y devuelve el resultado al modelo

Una función declarada en `tools` no ejecuta tu backend. Responses devuelve un Item `function_call` con nombre, argumentos JSON y `call_id`; tu aplicación valida, autoriza y ejecuta la consulta, y devuelve un `function_call_output` con **ese mismo `call_id`**. El ID del Item, que puede empezar por `fc_`, no sirve para unir el resultado con la llamada. Después hace falta otra petición para obtener la respuesta final o nuevas llamadas. La [guía de function calling](https://developers.openai.com/api/docs/guides/function-calling) describe este ciclo.

![Intercambio de una llamada de función entre Responses y la aplicación, con validación, ejecución y devolución del resultado mediante el mismo call_id](https://blog.laozhang.ai/posts/es/openai-assistants-api-to-responses-api/img/ciclo-funciones.webp)

El ejemplo siguiente implementa una consulta de incidencias de solo lectura. Es una función de integración: recibe un cliente de OpenAI ya configurado, un modelo admitido por tu proyecto y el historial autorizado. No incluye credenciales ni crea un cliente. Los datos `CASOS` son sintéticos; en producción, sustituye esa consulta por tu backend autenticado y con tiempo máximo de ejecución.

```python
import json
import re

TOOLS = [{
    "type": "function",
    "name": "consultar_incidencia",
    "description": "Consulta el estado actual de una incidencia autorizada.",
    "strict": True,
    "parameters": {
        "type": "object",
        "properties": {"numero": {"type": "string"}},
        "required": ["numero"],
        "additionalProperties": False,
    },
}]
INSTRUCTIONS = (
    "Responde en español. Consulta el estado actual con consultar_incidencia. "
    "No inventes datos ni afirmes que has modificado una incidencia."
)
CASOS = {("empresa-demo", "T-81"): {"estado": "en_revision"}}

def ejecutar_llamada(llamada, empresa, permitidos):
    if llamada.name != "consultar_incidencia":
        raise ValueError("Función no permitida")
    args = json.loads(llamada.arguments)
    if not isinstance(args, dict) or set(args) != {"numero"}:
        raise ValueError("Argumentos no válidos")
    numero = args["numero"]
    if not isinstance(numero, str) or not re.fullmatch(r"T-\d+", numero):
        raise ValueError("Número de incidencia no válido")
    if numero not in permitidos:
        raise PermissionError("Incidencia no autorizada")
    resultado = CASOS.get((empresa, numero), {"estado": "no_encontrada"})
    return {
        "type": "function_call_output",
        "call_id": llamada.call_id,
        "output": json.dumps(resultado, ensure_ascii=False),
    }

def resolver(client, model, historial, empresa, permitidos):
    items = list(historial)
    vistas = set()
    for ronda in range(5):
        respuesta = client.responses.create(
            model=model,
            instructions=INSTRUCTIONS,
            tools=TOOLS,
            input=items,
            store=False,
        )
        if respuesta.status != "completed":
            raise RuntimeError(f"Generación no completada: {respuesta.status}")
        items.extend(respuesta.output)
        llamadas = [x for x in respuesta.output if x.type == "function_call"]
        if not llamadas:
            texto = respuesta.output_text.strip()
            if not texto:
                raise RuntimeError("No hay una respuesta final de texto")
            return {"texto": texto, "items": items, "response_id": respuesta.id}
        if ronda == 4:
            raise RuntimeError("Límite de rondas; no se ejecutan más funciones")
        for llamada in llamadas:
            if not llamada.call_id or llamada.call_id in vistas:
                raise RuntimeError("call_id ausente o repetido")
            salida = ejecutar_llamada(llamada, empresa, permitidos)
            vistas.add(llamada.call_id)
            items.append(salida)
    raise RuntimeError("No se obtuvo una respuesta final")
```

En tu controlador autenticado, carga el historial, añade la pregunta nueva y llama a `resolver(client, model, historial, empresa, permitidos)`. `empresa` y `permitidos` deben proceder de la sesión autenticada y de tu autorización, nunca del modelo. Guarda los `items` devueltos bajo esa misma sesión antes de entregar `texto` al usuario. Este código corresponde a **historial propio**: no añadas `conversation` ni `previous_response_id` sin adaptar cómo se conserva y se envía el estado.

La ausencia de llamadas es un resultado válido del modelo; solo se acepta aquí si hay texto final. También se procesan varias llamadas en una respuesta y llamadas en rondas posteriores. Un JSON inválido, una función desconocida, un permiso denegado o una respuesta `failed` o `incomplete` interrumpen este ejemplo. El controlador debe registrar el motivo sin exponer datos de otros usuarios y devolver un estado de error o derivar a la alternativa definida, en vez de presentar una consulta pendiente como resuelta.

`strict: true` requiere `additionalProperties: false` en cada objeto y todos sus campos en `required`; los opcionales se representan admitiendo `null`. Si omites `strict`, Responses intenta normalizar el esquema, pero puede recurrir a llamadas de mejor esfuerzo con `strict: false` si no consigue hacerlo compatible. Por eso no basta con suponer que “Responses valida por defecto”. Las [condiciones de strict mode](https://developers.openai.com/api/docs/guides/function-calling#strict-mode) tampoco sustituyen la autorización de negocio. `parallel_tool_calls: false` limita a cero o una llamada por turno; no obliga a que exista una.

Si añades escrituras, un `call_id` sirve para correlacionar una llamada, **no para impedir que un reintento repita un cobro o una modificación**. Usa una clave de operación duradera en tu backend, ligada a la acción y al usuario, y registra su resultado antes de reintentar. La cancelación de una generación no deshace una acción ya confirmada.

## Recupera File Search con los documentos correctos

`file_search` sí lo ejecuta OpenAI: realiza búsqueda semántica y por palabras clave sobre los `vector_store_ids` indicados. Una referencia antigua a un vector store es una pista para localizarlo, no una prueba de que siga disponible o autorizado. Comprueba proyecto, acceso, documentos previstos y estado `completed` de los archivos antes de usarlo. Si necesitas reconstruirlo, parte de documentos originales cuya subida esté autorizada.

Para observar la recuperación, prepara una petición como esta en tu integración. Sustituye `MODEL` y `VECTOR_STORE_ID` por valores ya verificados de tu entorno; este bloque es el cuerpo de una petición, no un programa independiente:

```json
{
  "model": "MODEL",
  "instructions": "Responde solo con la política documentada y cita su archivo. Si no hay evidencia, indícalo.",
  "input": "¿Qué plazo tiene una incidencia antes de escalarse?",
  "tools": [{"type": "file_search", "vector_store_ids": ["VECTOR_STORE_ID"]}],
  "include": ["file_search_call.results"]
}
```

Los resultados de búsqueda no vienen incluidos por defecto; `include` permite inspeccionarlos. Comprueba el Item `file_search_call`, los documentos recuperados y las anotaciones `file_citation` de los mensajes. Una respuesta plausible con una cita cualquiera no pasa la prueba: la cita debe pertenecer al documento que respalda el plazo. La [guía de File Search](https://developers.openai.com/api/docs/guides/tools-file-search) explica estos resultados y los filtros por metadatos.

En un servicio con varias organizaciones, el backend debe elegir los stores y filtros a partir de los permisos del usuario. No dejes esa selección en manos del texto de la pregunta. Prueba una consulta con fuente conocida, otra sin respuesta documental y otra que intente acceder a documentos de una organización distinta. Si cambias el corpus, repite las preguntas afectadas: haber recuperado bien el corpus anterior no valida el nuevo.

## Adapta la salida, los eventos y los trabajos largos

Sustituye los consumidores de mensajes y Run steps por lectores de Items tipados. `response.output` puede contener mensajes, razonamiento y llamadas; `output_text` es útil para mostrar texto, pero no es una copia completa de la ejecución. Si tu aplicación exige JSON estructurado, traslada el esquema de `response_format` a `text.format`, por ejemplo con `type: "json_schema"`, `name`, `schema` y `strict`. La [guía de Responses](https://developers.openai.com/api/docs/guides/migrate-to-responses) muestra el formato correspondiente.

| Evento o estado | Qué debe hacer tu aplicación |
|---|---|
| `response.created` | Asociar la nueva Response al trabajo y a la sesión |
| `response.output_text.delta` | Actualizar el texto provisional, sin declarar éxito todavía |
| `response.function_call_arguments.delta` | Acumular argumentos por Item, sin ejecutar JSON parcial |
| `response.function_call_arguments.done` | Recibir argumentos completos y aplicar el control de ejecución |
| `response.completed` | Comprobar el resultado final y si quedan funciones por resolver |
| Error, fallo, cancelación o resultado incompleto | Mostrar el estado correspondiente y decidir recuperación |

No conviertas automáticamente todo Run en `background=true`. Para una interacción breve, una respuesta normal o streaming puede bastar. Background encaja cuando el trabajo debe continuar aunque el cliente deje de esperar: consulta la Response mientras esté `queued` o `in_progress`, y al salir de esos estados revisa **cuál** es el terminal. Terminar no implica éxito. La cancelación de un trabajo background usa `responses.cancel`; para una generación síncrona, se termina la conexión.

Si necesitas reanudar streaming de background, la petición inicial debe tener también `stream=true`. Guarda el `sequence_number` y reanuda con `starting_after`. Conserva el ID del trabajo y el cursor antes de depender de una reconexión; no crees automáticamente otra generación cuando solo se ha cortado el stream. Estos comportamientos están documentados en [background mode](https://developers.openai.com/api/docs/guides/background).

La documentación actual permite background con `store=false`, incluidos proyectos ZDR, **pero guarda temporalmente datos en disco durante unos diez minutos** para la ejecución y la consulta de estado. En proyectos con Modified Abuse Monitoring (MAM), background solo conserva la respuesta tras ese periodo cuando se proporciona expresamente `store=true`; si se omite o es `false`, se elimina tras el periodo temporal. No confundas esto con ausencia de almacenamiento ni con una autorización general para cualquier política de datos. Si tu contrato prohíbe ese almacenamiento temporal, elige un flujo compatible con él. Consulta tanto la [guía de background](https://developers.openai.com/api/docs/guides/background) como las [condiciones de `/v1/responses`](https://developers.openai.com/api/docs/guides/your-data#v1responses).

## Pon Responses en producción con una recuperación que funcione

Después del cierre, la comparación se hace con **resultados guardados de tareas** o con una **versión operativa de Responses**. No ejecutes una supuesta prueba A/B contra Assistants. Para cada caso, anota el resultado esperado y la condición que obligaría a detener el cambio.

| Caso | Resultado que necesitas observar | Si no se cumple |
|---|---|---|
| Continuar una incidencia del historial convertido | Conserva el número y consulta su estado actual | Mantén esa sesión en consulta histórica o atención manual |
| Solicitar una incidencia ajena | La autorización la rechaza sin mostrar sus datos | Detén la ampliación de tráfico y corrige el aislamiento |
| Función con llamadas sucesivas | Cada resultado conserva `call_id` y llega una respuesta final | Corrige la orquestación antes de aceptar el flujo |
| Pregunta documental con fuente conocida | Recupera el archivo previsto y una cita pertinente | Corrige corpus, filtros o respuesta |
| Pregunta sin documento | Explica que falta evidencia | Corrige las instrucciones y el criterio de aceptación |
| Fallo, desconexión o cancelación | Trabajo y pantalla muestran el estado real | Recupera por ID o deriva sin repetir efectos |

Define también tus límites de latencia y coste por tarea completada. Mide tokens, herramientas y almacenamiento aplicables; cambiar de endpoint no demuestra por sí mismo ahorro ni mejor calidad. Mantén inicialmente modelo, instrucciones, corpus y permisos estables para poder localizar la causa de una diferencia.

Para activar el cambio, prepara una versión identificable de la aplicación y su configuración, y verifica la alternativa antes de enviarle tráfico. Puedes usar una versión anterior de Responses ya validada, una respuesta determinista para tareas acotadas o una cola de atención manual. La alternativa debe tener acceso autorizado al estado que necesita; un flag que cambia de ruta pero pierde el historial no es una recuperación operativa.

Empieza con sesiones nuevas y un flujo de solo lectura. Amplía la cohorte cuando los casos críticos, los errores y los límites se cumplan; continúa después las conversaciones archivadas que hayan pasado su conversión. Vincula cada sesión a su estrategia y versión, y protege el cambio con una actualización atómica para que dos workers no creen historiales distintos. Para comparar una operación con efectos, utiliza resultados registrados o una simulación: no hagas que dos implementaciones modifiquen el mismo recurso.

Si aparece una filtración de datos, una escritura duplicada o una pérdida de contexto crítica, detén la ampliación inmediatamente. Envía las sesiones nuevas a la alternativa comprobada y conserva los trabajos afectados con su último estado para conciliarlos. Las operaciones ya ejecutadas requieren revisar el backend; no se solucionan regenerando el mensaje. Puedes retirar la dependencia del código de Assistants cuando el nuevo servicio y su recuperación cumplan esos criterios, conservando los archivos históricos según tu política.

Los ejemplos de esta guía se comprobaron mediante sintaxis y casos sintéticos sin red. No se realizaron llamadas al SDK o a la API, pruebas de modelos, subidas de documentos ni una comparación de producción. Antes de desplegar en tu entorno, valida la versión del SDK, el modelo, los permisos y los recursos reales con los casos anteriores.

## Preguntas frecuentes sobre la migración

### ¿Puedo recuperar una conversación solo con su `thread_id`?

No puedes reconstruir sus mensajes a partir del ID. La [guía oficial de migración](https://developers.openai.com/api/docs/assistants/migration) confirma que la llamada antigua para listar mensajes de Threads ya no funciona. Busca mensajes completos en tu aplicación o en copias anteriores. Si solo conservas el identificador, abre una sesión nueva y solicita los datos necesarios; no presentes una recuperación que no has realizado.

### ¿Tengo que crear un objeto Prompt para sustituir al Assistant?

No. Para una integración duradera, lleva la configuración al código versionado. Los objetos Prompt reutilizables y `v1/prompts` tienen prevista su retirada el 30 de noviembre de 2026, según la [guía de migración de Prompt objects](https://developers.openai.com/api/docs/guides/prompting/migrate-from-prompt-object). Su fecha es distinta del cierre ya ocurrido de Assistants.

### ¿Por qué aparece una llamada de función pero no una respuesta final?

Porque el modelo ha solicitado datos y tu aplicación aún debe ejecutar la función y enviar su resultado como `function_call_output`, con el `call_id` original. Después realiza otra petición; puede devolver texto o más llamadas. Conserva los Items completos y controla rondas, errores y autorización, como indica la [guía de function calling](https://developers.openai.com/api/docs/guides/function-calling).

### ¿`store=false` evita todo almacenamiento en OpenAI?

No. Es una opción relativa al almacenamiento de la Response; no elimina automáticamente los registros de abuso, el estado de Conversations o el de archivos y otras herramientas. Background conserva temporalmente datos en disco durante unos diez minutos incluso cuando usa `store=false`. Revisa el alcance de tu organización, modelo y funcionalidad en las [condiciones de datos](https://developers.openai.com/api/docs/guides/your-data#v1responses) y la [guía de background](https://developers.openai.com/api/docs/guides/background).

### ¿Puedo volver a Assistants si la migración falla?

No: Assistants dejó de estar disponible el 26 de agosto de 2026. Prepara una versión validada de Responses, un modo seguro acotado o atención manual, y comprueba que pueda continuar las sesiones autorizadas. La [confirmación oficial del cierre](https://developers.openai.com/api/docs/assistants/migration) invalida los planes antiguos que dependían de volver al endpoint retirado.

## Fuentes

Páginas externas que cita esta guía, en el orden en que aparecen. Última actualización: 2026-10-06.

- [guía oficial confirma que esa llamada ya no funciona](https://developers.openai.com/api/docs/assistants/migration) (developers.openai.com)
- [guía para abandonar los objetos Prompt](https://developers.openai.com/api/docs/guides/prompting/migrate-from-prompt-object) (developers.openai.com)
- [documentación de estado](https://developers.openai.com/api/docs/guides/conversation-state) (developers.openai.com)
- [contrato de creación de Responses](https://developers.openai.com/api/reference/resources/responses/methods/create) (developers.openai.com)
- [condiciones de conservación de OpenAI](https://developers.openai.com/api/docs/guides/your-data) (developers.openai.com)
- [guía de function calling](https://developers.openai.com/api/docs/guides/function-calling) (developers.openai.com)
- [guía de File Search](https://developers.openai.com/api/docs/guides/tools-file-search) (developers.openai.com)
- [guía de Responses](https://developers.openai.com/api/docs/guides/migrate-to-responses) (developers.openai.com)
- [background mode](https://developers.openai.com/api/docs/guides/background) (developers.openai.com)
