OpenAI의 Assistants API가 8월 26일에 종료되지만, 실제 문제는 훨씬 이전에 발생하는 '조용한 실패'에 있습니다
요약
OpenAI의 Assistants API가 종료됨에 따라 Responses API로의 마이그레이션이 필요하지만, 이 과정에서 발생하는 '조용한 실패'를 경계해야 합니다. Assistants API가 자동으로 관리하던 대화 상태와 컨텍스트 유지가 Responses API에서는 개발자의 명시적 구현 영역으로 넘어가면서, 오류 없이 동작이 저하되는 문제가 발생할 수 있습니다.
핵심 포인트
- Assistants API 종료에 따른 Responses API 마이그레이션 주의 필요
- 상태 관리(Thread)가 자동에서 명시적 방식으로 변경됨
- 컨텍스트 누락 시 에러 없이 모델 성능만 저하되는 '조용한 실패' 위험
- Conversations API와 response_id 체이닝의 혼용 금지
2026년 8월 26일, OpenAI는 Assistants API를 제거합니다. /v1/assistants, /v1/threads, 그리고 /v1/threads/runs로의 호출은 오류를 반환하기 시작할 것입니다. 이 날짜는 개발자들의 달력에 일 년 동안 표시되어 왔으며, 이것은 쉬운 부분입니다. 즉, 하드 커트오프(hard cutoff)는 눈앞에서 크게 실패합니다. 계획을 세울 수 있는 날에 말이죠.
실제로 사람들에게 비용이 드는 부분은 Responses API로의 마이그레이션이며, 이 API는 8월 26일을 기다려주지 않고, 또한 크게 실패하지도 않습니다.
Assistants 기반 앱을 Responses로 포팅할 때, 엔드포인트들은 200 OK로 응답합니다. 아무것도 오류를 일으키지 않습니다. 하지만 Assistants API가 사용자를 위해 관리해주던 세 가지 요소는 이제 사용자의 몫이 되었고, 이 중 어느 하나라도 잘못 연결하면 실패는 **오류(error)가 아닌 저하된 동작(degraded behavior)**으로 나타납니다. 컨텍스트를 잊어버리는 모델, 조용히 누락되는 Grounding, 빈 화면을 렌더링하는 스트림과 같습니다. 앱을 배포하고 스모크 테스트에서는 괜찮아 보이지만, 실제 운영 환경에서는 잘못된 것입니다.
왜 이것이 위험한 종류의 변경인가
Assistants API는 상태를 유지하고(stateful) 의견이 강했습니다(opinionated). Thread는 대화 기록을 지속적으로 유지하고, 컨텍스트 창에 맞게 이를 잘라내며(truncated), 도구 실행(tool runs)을 오케스트레이션해 주었습니다. — 이 모든 것이 사용자의 코드 없이 암묵적으로 이루어졌습니다. Responses API는 의도적으로 더 단순합니다. 입력 항목들을 보내면, 출력 항목들을 받기만 하면 됩니다. Thread가 거의 모든 것을 대신 해주던 것들이 이제 명시적인 결정이 되었습니다.
바로 이 역전(inversion)이 함정입니다.
응답(Responses)에서는 지속적인 대화 상태(persistent conversation state)가 명시적입니다. 마지막 응답에서 previous_response_id를 다음 요청으로 전달하여 턴(turn)을 체이닝(chaining)하거나, Conversations API를 사용하여 히스토리를 유지해야 합니다. 여기서 두 가지 문제가 발생하는데, 둘 다 조용히 일어납니다.
- 체이닝을 완전히 잊어버리는 경우: 각 요청은 사실상 상태가 없는(stateless) 상태가 됩니다. 첫 번째 턴은 완벽해 보입니다. 하지만 두 번째 턴인 "더 짧게 만들어줘"라는 요청은 "그것"이 무엇인지 알 수 없습니다. 이전 턴의 컨텍스트와 앞서 설정한 시스템 제약 조건(system constraints)이 함께 전달되지 않았기 때문입니다. API는
200상태 코드와 함께 유창하고 자신감 넘치지만 컨텍스트가 없는 답변을 반환합니다. 잡아낼 수 있는 에러는 없습니다. 모델은 그저 기억상실증에 걸린 것처럼 행동할 뿐입니다. - 두 메커니즘을 혼용하는 경우: OpenAI의 가이드는 명확합니다. 워크로드당 하나의 상태 모델(
previous_response_id또는 Conversations)을 선택하고, 이를 임의로(ad hoc) 섞어서 사용하지 마십시오. Conversations를 절반만 채택하면서 여전히 응답 ID(response IDs)를 전달하는 앱들은 요청이 거치는 경로에 따라 일관성 없는 히스토리를 갖게 됩니다. 세션 초기에 설정된 제약 조건들이 턴 사이에 나타났다 사라졌다를 반복하며, 이는 상태 버그(state bug)라기보다 모델이 불안정한(flaky) 것처럼 보이게 만듭니다.
Assistants 버전의 코드는 이런 버그가 발생할 수 없었습니다. Thread가 상태를 놓치지 않도록 관리해주었기 때문입니다. 하지만 Responses 버전은 상태를 놓칠 수 있으며, 그 사실을 당신에게 알려주지도 않습니다.
2. 검색 퇴보(Retrieval regression) — 에러 없이 발생하는 RAG 근거(grounding) 저하
Assistants의 file_search는 관대했습니다. 실행(run) 시 어시스턴트 레벨과 스레드 레벨의 벡터 스토어(vector stores)를 모두 검색할 수 있었고, 실행 흐름이 검색(retrieval) 과정을 자동으로 연결해 주었습니다. 파일을 첨부하고 질문을 던지면 근거가 확실한(grounded) 답변을 얻을 수 있었습니다.
Responses에서는 파일 검색(file search)이 도구(tool) 상에서 명시적으로(explicitly) 구성됩니다. 즉, 검색하고자 하는 vector_store_ids를 직접 전달하며, 검색(retrieval) 동작은 사용자가 직접 조정해야 합니다. 이 실패 모드는 사후에 보면 명확하지만 실행 시점에는 보이지 않습니다. 목록에서 벡터 스토어(vector store) 하나를 누락하면, 해당 지식은 근거(grounding) 데이터에서 조용히 사라집니다. 요청은 성공합니다. 모델은 여전히 답변을 합니다. 다만 컨텍스트가 부족하거나 아예 없는 상태에서 답변하며, 모델의 파라미터 메모리(parametric memory)에 의존하게 될 뿐입니다.
검색 누락은 404 에러처럼 나타나지 않습니다. 누락된 스토어에 의존했던 특정 질문들에 대해 약간 품질이 떨어지는 답변, 혹은 자신 있게 틀린 답변으로 나타납니다. 아무도 호출(page)을 받지 않습니다. 평가 스위트(eval suite)가 있다면 이를 잡아내겠지만, 200 응답 여부만 확인하는 통합 테스트는 잡아내지 못합니다.
3. 스트리밍 중단 — SSE 이벤트 분류 체계(taxonomy)의 변경
만약 응답을 스트리밍(stream)한다면, 이것이 실제 사용자에게 오류가 포함된 채 배포될 가능성이 가장 높은 부분입니다.
Assistants API는 실행(run) 중심의 서버 전송 이벤트(SSE, server-sent events)를 방출했습니다. 즉, 실행(run), 실행 단계(run step), 메시지(message)와 연결된 델타(delta) 값들이었습니다 (thread.run.step.delta, thread.message.delta 등).
하위 소비자(downstream consumers)들은 이러한 이벤트 유형을 패턴 매칭하여 출력을 조립하도록 작성되었습니다.
Responses API는 **전혀 다른 이벤트 분류 체계(taxonomy)**를 방출합니다. response.output_text.delta나 response.completed와 같이 응답(response) 중심의 이벤트들입니다. 기존의 thread.* 이벤트를 기다리던 소비자는 크래시(crash)보다 더 나쁜 상황을 맞이하게 됩니다. 연결은 되고, 스트림은 열리며, 이벤트는 흐르고, 스트림도 완료되지만, 찾고 있는 핸들러(handler)와 일치하는 이벤트가 단 하나도 없게 됩니다. 결과적으로 모든 상태 체크상으로는 성공한 연결임에도 불구하고, 화면에는 빈 화면이 출력되거나 잘린 렌더링이 나타납니다. 200 응답, 깨끗한 SSE, 하지만 빈 UI가 나타나는 것입니다.
이것이 바로 리뷰를 통과하고(요청은 작동하니까요!) 사용자에게서 발견되는 전형적인 오류 유형입니다. 실패의 원인이 HTTP 상태 코드가 아닌 이벤트 이름 문자열에 들어있기 때문입니다.
로그가 아닌 청구서에 타격을 주는 보너스
내장 도구(Built-in tools)도 변경되었습니다. Responses에서는 웹 검색(web search) 및 파일 검색(file search)과 같은 호스팅 도구에 대해 Assistants API에서는 존재하지 않았던 **호출당 비용(per-call fees)**이 발생합니다. 이러한 도구에 의존하던 트래픽이 높은 어시스턴트를 마이그레이션했을 때, 기능은 동일하고 에러율은 0인데 코드 변경 없이 인보이스(invoice) 금액만 올라간다면, 이를 지목할 곳이 없게 됩니다. 조용한 비용 회귀(Silent cost regression) 또한 엄연한 회귀입니다.
그리고 당신을 구해줄 지름길은 없습니다. OpenAI는 기존의 스레드(Threads)를 컨버세이션(Conversations)으로 마이그레이션하는 자동화 도구를 제공하지 않을 것이라고 밝혔습니다. 권장되는 경로는 새 모델에서 새로운 세션을 시작하고 이전 기록을 직접 백필(backfill)하는 것입니다. 8월에 클릭 한 번으로 마이그레이션이 가능할 것이라 기대하는 사람은, 8월이 되어서야 그것이 불가능하다는 사실을 깨닫게 될 것입니다.
8월 26일 이전에 실제로 해야 할 일
- 마이그레이션을 단순한 엔드포인트 교체가 아닌 아키텍처 변경으로 취급하세요. 위의 세 가지 회귀 현상은 모두 Responses가 Thread가 암묵적으로 수행하던 작업을 수행할 것이라고 가정하는 데서 비롯됩니다. 그렇지 않습니다. 상태(state), 검색(retrieval), 스트리밍(streaming)을 명시적으로 매핑하세요.
- 하나의 상태 모델을 선택하고 이를 확정하세요.
previous_response_id또는 Conversations 중 하나만 사용해야 하며, 둘 다 사용해서는 안 됩니다. 멀티 턴(multi-turn) 대화를 실행하고 N번째 턴이 실제로 1번째 턴에서 설정된 제약 조건을 준수하는지 확인하는 테스트를 추가하세요. 이 단일 테스트가 조용한 기억 상실(silent amnesia) 버그를 잡아낼 수 있습니다. - 벡터 스토어(vector store) ID와 평가 근거(eval grounding)를 고정하세요. 기존 어시스턴트가 접근할 수 있었던 스토어와 Responses에 전달하는
vector_store_ids를 비교(diff)하세요. 그런 다음 단순히200상태 코드를 확인하는 것이 아니라, 검색 평가(retrieval eval)를 실행하세요. 근거 데이터가 비어 있는 상태로 성공적으로 반환되는 요청이 바로 당신이 찾아야 할 실패 사례입니다. - 새로운 이벤트에 맞춰 스트림 컨슈머(stream consumer)를 다시 작성하고 엔드 투 엔드(end-to-end)로 테스트하세요. 연결이 열린다고 해서 SSE 파서(parser)가 "여전히 작동할 것"이라고 가정하지 마세요.
thread.*이벤트가 아닌response.*이벤트로부터 실제 출력을 제대로 조립하는지 확인하세요. - 상태 코드뿐만 아니라 응답 형태(response shape)를 주시하세요. 이러한 실패 사례는 모두
200을 반환합니다.
상태 저하(state drop), 근거 누락(grounding miss), 또는 처리되지 않은 이벤트(unhandled event)를 포착할 수 있는 유일한 방법은 호출이 성공했는지 여부가 아니라, 응답에 실제로 무엇이 들어있는지를 검사하는 것입니다.
종료 날짜는 요란하게 잘 광고되는 부분이며, 여러분이 틀릴 가능성이 가장 낮은 부분입니다. 마이그레이션(migration)은 조용한 부분입니다. 여러분의 컨텍스트(context), 근거(grounding), 또는 출력(output)이 누락된 200 응답은 8월 26일에 발생하는 정직한 오류보다 훨씬 알아차리기 어렵습니다.
FlareCanary는 바로 이러한 현상을 감시합니다: 타입이 변하는 필드, null이 되는 값, 드리프트(drift)가 발생하는 이벤트 형태(event shape), 그리고 이전과 같은 의미를 조용히 잃어버리는 계약(contract). Assistants → Responses와 같은 마이그레이션은 응답 형태(response shape)가 조용히 변하는 지점입니다. 잘못된 형태를 가진 200 응답은 로그에 도달하기 전에 사용자에게 먼저 도달하는 실패입니다. 여러분이 의존하는 계약이 변경된다면, 저희를 통해 가장 먼저 알게 될 것입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기