Assistants API가 오늘 종료된다: Responses API로 마이그레이션할 때 놓치기 쉬운 7가지

프로필 이미지
gwanhun1
7분 읽기조회 2
공유

Assistants API 종료 일정이 오늘, 2026년 8월 26일에 도착했습니다. 기존 API를 호출하는 애플리케이션이 당장 모두 멈춘다는 뜻으로만 받아들이면 대응이 늦습니다. 진짜 변화는 Assistant → Thread → Run으로 나뉘어 있던 실행 모델을 Response 중심으로 다시 설계해야 한다는 데 있습니다.

OpenAI는 새 프로젝트에 Responses API를 권장하고 있으며, 기존 Assistants API 사용자는 Responses API 마이그레이션 가이드를 따라 전환할 것을 안내합니다. Assistants API의 기존 실행 구조는 레거시 문서에서 확인할 수 있습니다.

이 글은 단순한 엔드포인트 치환 예제가 아닙니다. 운영 중인 AI 에이전트가 상태를 잃지 않고, 도구를 중복 실행하지 않으며, 문제가 생겼을 때 되돌릴 수 있도록 마이그레이션의 설계 포인트를 정리한 실전 가이드입니다.

먼저 확인할 것: 내 서비스가 정말 영향을 받는가

모든 OpenAI API 사용자가 같은 작업을 해야 하는 것은 아닙니다.

현재 사용 방식이번 종료와의 관계권장 대응
client.beta.assistants, Threads, Runs 사용직접 영향Responses API로 마이그레이션
Chat Completions만 사용직접 영향 없음새 기능은 Responses API도 검토
자체 에이전트 오케스트레이터 + 모델 호출간접 영향 가능도구·상태 계층을 점검
OpenAI SDK를 래핑한 사내 플랫폼확인 필요내부 래퍼가 Assistants 엔드포인트를 호출하는지 검색

저장소에서 beta.assistants, beta.threads, runs.create, createAndPoll 같은 문자열을 먼저 검색해 보세요. 직접 호출하지 않더라도 사내 SDK나 백엔드 작업 큐 안에 숨겨져 있을 수 있습니다.

구조가 어떻게 바뀌는가

Assistants API는 설정과 대화 상태, 실행을 서로 다른 리소스로 나눴습니다.

1 2 3 4 5 6 7 Assistant (instructions, model, tools) ↓ Thread (messages와 대화 상태) ↓ Run (실행) ↓ Run steps와 tool output

Responses API에서는 하나의 Response 요청 안에 지침, 입력, 도구, 출력 아이템이 함께 흐릅니다.

1 2 3 4 5 input + instructions + tools ↓ Response (텍스트, tool call, 상태 정보) ↓ previous_response_id 또는 애플리케이션 DB

중요한 점은 “리소스 이름이 줄었다”가 아닙니다. Thread와 Run에 기대던 상태 관리와 실행 제어를 애플리케이션이 더 명시적으로 소유해야 한다는 뜻입니다. Responses API는 웹 검색, 파일 검색, 코드 인터프리터, 컴퓨터 사용, 원격 MCP 같은 도구를 하나의 인터페이스에서 다룰 수 있고, 여러 도구를 한 요청의 에이전틱 루프에서 연결할 수 있도록 설계됐습니다. 다만 도구 권한, 재시도, 감사 로그까지 자동으로 해결해 주는 것은 아닙니다.

Assistants API에서 Responses API로 통합되는 흐름

개념 매핑: 검색·치환이 아니라 책임의 이동

다음 표는 1:1 API 변환표라기보다 설계 책임을 어디로 옮길지 보여주는 지도입니다. 세부 필드와 SDK 버전은 공식 마이그레이션 문서를 기준으로 확인해야 합니다.

Assistants API 개념Responses API에서의 방향개발자가 다시 결정할 것
Assistant의 지침·모델·도구instructions, model, tools기본 지침과 요청별 지침의 경계
Thread의 메시지input 메시지, previous_response_id, 외부 저장소보존 기간·삭제 정책·멀티테넌시
Run 생성·폴링responses.create와 스트리밍·백그라운드 처리타임아웃·취소·재시도·웹훅
Run stepresponse.output의 출력 아이템각 tool call의 추적 ID와 상태
Function callingResponses용 함수 도구 스키마중복 실행 방지와 권한 검사
File Search·Code InterpreterResponses의 내장 도구데이터 보존과 비용·권한 조건
외부 서비스 연동함수 도구 또는 원격 MCP서버 인증·허용 도구 목록·감사 로그

코드로 보는 최소 전환

아래 코드는 구조 차이를 보여주기 위한 축약 예제입니다. 실제 서비스에서는 모델 이름, SDK 버전, 함수 파라미터 스키마를 현재 공식 문서에 맞춰 검증해야 합니다.

이전: 리소스를 여러 단계로 생성

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 const assistant = await client.beta.assistants.create({ model: "gpt-5.6", instructions: "주문 상태를 확인하고 필요한 경우 담당자에게 넘겨라.", ![exec-22c35c64-75f1-47ed-8d23-f70cd3b9718d.png](https://res.cloudinary.com/dcfqahfbr/image/upload/v1787725071/cvlog/posts/r77afj9n6qf20ooymfln.png) tools: [{ ![exec-22c35c64-75f1-47ed-8d23-f70cd3b9718d.png](https://res.cloudinary.com/dcfqahfbr/image/upload/v1787725041/cvlog/posts/qekqzqyn7uslxv4warqj.png) type: "function", function: { name: "lookup_order", description: "주문 상태 조회", parameters: { type: "object", properties: { order_id: { type: "string" } }, required: ["order_id"] } } }] }); const thread = await client.beta.threads.create(); await client.beta.threads.messages.create(thread.id, { role: "user", ![exec-42ff978c-b4c5-40fd-8741-d4103f060376.png](https://res.cloudinary.com/dcfqahfbr/image/upload/v1787725126/cvlog/posts/bkcl9egcteus1vae8zzi.png) ![exec-42ff978c-b4c5-40fd-8741-d4103f060376.png](https://res.cloudinary.com/dcfqahfbr/image/upload/v1787725091/cvlog/posts/irorxsvdwy7evcwynguy.png) content: "주문 1234의 배송 상태를 알려줘." }); const run = await client.beta.threads.runs.createAndPoll(thread.id, { assistant_id: assistant.id });

이후: 하나의 Response와 명시적인 상태

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const response = await client.responses.create({ model: "gpt-5.6", instructions: "주문 상태를 확인하고 필요한 경우 담당자에게 넘겨라.", tools: [{ type: "function", name: "lookup_order", description: "주문 상태 조회", parameters: { type: "object", properties: { order_id: { type: "string" } }, required: ["order_id"], additionalProperties: false }, strict: true }], input: [{ role: "user", content: "주문 1234의 배송 상태를 알려줘." }], store: true }); console.log(response.output_text);

함수 호출이 반환되면 애플리케이션이 실제 함수를 실행한 뒤, 결과를 function_call_output 아이템으로 이어 보내야 합니다. 모델에게 같은 함수를 다시 호출해 달라고 프롬프트로 유도하는 방식보다, call_id를 기준으로 실행과 결과를 연결하는 편이 안전합니다.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const call = response.output.find(item => item.type === "function_call"); if (call) { const result = await lookupOrder(JSON.parse(call.arguments)); const finalResponse = await client.responses.create({ model: "gpt-5.6", previous_response_id: response.id, input: [{ type: "function_call_output", call_id: call.call_id, output: JSON.stringify(result) }] }); console.log(finalResponse.output_text); }

이 코드에서 previous_response_id를 쓸지, 대화 내용을 자체 DB에 저장해 매번 다시 보낼지는 제품 요구사항에 따라 달라집니다. 민감한 데이터를 다루거나 장기 보존이 필요한 서비스라면 저장·삭제·암호화 정책을 먼저 정하고 store 설정과 데이터 제어 문서를 함께 검토해야 합니다.

마이그레이션에서 자주 놓치는 7가지

1. Thread 상태를 어디에 둘지 정하지 않는다

기존에는 Thread가 대화 상태를 담는 그릇처럼 보였지만, Responses API에서는 상태를 previous_response_id로 이어갈지 외부 저장소가 소유할지 결정해야 합니다. 사용자별·조직별·업무별로 상태 키를 분리하고, 삭제 요청과 보존 기간을 데이터 모델에 넣으세요.

2. Run 폴링 코드를 그대로 복사한다

짧은 요청은 일반 응답이나 스트리밍으로 처리할 수 있지만, 오래 걸리는 도구 호출은 백그라운드 작업과 상태 조회가 필요할 수 있습니다. queued, in_progress, completed, failed, cancelled에 해당하는 애플리케이션 상태를 정의하고, 네트워크 재시도와 사용자 취소를 분리해 다뤄야 합니다.

3. 함수 호출의 중복 실행을 막지 않는다

모델 응답을 재수신하거나 작업 큐가 재시도하면 같은 결제·메일 발송·레코드 수정이 두 번 실행될 수 있습니다. call_id와 내부 idempotency key를 함께 기록하고, 읽기 작업과 쓰기 작업의 권한 정책을 다르게 두세요.

4. 내장 도구가 모든 기존 동작을 그대로 대체한다고 가정한다

Responses API에는 내장 도구가 많지만, 파일 검색 인덱스, 코드 실행 환경, 인증, 데이터 보존 조건은 기존 구현과 다를 수 있습니다. “호출된다”와 “운영 요구사항을 만족한다”를 구분해 샘플 데이터로 재검증해야 합니다.

5. 스트리밍 이벤트를 텍스트 한 덩어리로만 처리한다

Responses API의 출력에는 텍스트뿐 아니라 도구 호출, 도구 결과, 오류와 중단 상태가 포함될 수 있습니다. 프런트엔드가 텍스트 토큰만 그리는 구조라면 도구 실행 중 상태와 최종 결과를 사용자에게 잘못 표시할 수 있습니다. 이벤트 타입을 보존해 UI 상태를 설계하세요.

6. 평가 기준을 답변의 자연스러움으로만 둔다

마이그레이션 전후에 같은 테스트 세트를 돌리되, 정답 문장뿐 아니라 도구 선택, 권한 거부, 근거 누락, 실패 후 복구, 최종 시스템 기록까지 비교해야 합니다. 운영 로그에는 응답 ID, 도구 call ID, 모델, 지연시간, 입력·출력 토큰, 비용, 사용자 승인 여부를 남기는 편이 좋습니다.

7. 한 번에 전환하고 되돌릴 경로를 지운다

트래픽 일부만 Responses API로 보내는 카나리 배포부터 시작하세요. 모델 버전과 프롬프트를 고정하고, 성공률·지연시간·도구 오류·비용을 기존 경로와 비교한 뒤 점진적으로 비율을 올립니다. 이전 경로를 바로 삭제하지 말고, 데이터 계약과 롤백 절차가 검증될 때까지 읽기 전용 또는 제한된 트래픽으로 유지하세요.

Responses API를 새 프로젝트의 기본값으로 삼아도 될까

OpenAI의 공식 마이그레이션 문서는 Responses API의 장점으로 통합된 도구 인터페이스, 멀티턴 상호작용, 상태 유지, 향상된 캐시 활용을 설명합니다. 일부 내부 평가에서 성능과 비용 개선 수치를 제시하지만, 그 수치가 모든 모델·프롬프트·트래픽에 그대로 적용된다는 뜻은 아닙니다. 팀의 실제 워크로드로 다시 측정해야 합니다.

새 프로젝트라면 다음 순서가 현실적입니다.

  1. 제품의 대화 상태와 업무 상태를 분리한다.
  2. 읽기·쓰기 도구의 권한과 승인 규칙을 정의한다.
  3. Responses API로 최소 기능을 만들고 도구 호출 루프를 테스트한다.
  4. 스트리밍·실패·재시도·관찰성까지 포함한 평가를 돌린다.
  5. 데이터 보존 요구사항에 맞춰 store, previous_response_id, 자체 DB 전략을 확정한다.

반대로 현재 서비스가 Chat Completions만 사용한다면, 오늘 당장 긴급하게 코드를 바꿀 필요는 없습니다. 다만 웹 검색, 파일 검색, MCP 같은 에이전틱 도구를 새로 붙일 계획이라면 Responses API를 기준으로 설계하는 편이 미래의 재작업을 줄일 수 있습니다.

결론: API 종료가 아니라 에이전트 책임 모델의 변경이다

Assistants API 종료는 “베타 엔드포인트 이름이 바뀌는 이벤트”가 아닙니다. 서버가 나눠 관리하던 Assistant·Thread·Run의 책임을, 애플리케이션이 Response·도구·상태·권한 단위로 다시 조합하는 전환입니다.

오늘 확인할 최소 항목은 네 가지입니다.

  • 저장소와 사내 SDK에 Assistants 엔드포인트가 남아 있는가
  • 대화 상태와 업무 상태의 소유자가 누구인가
  • 함수 호출이 재시도돼도 부작용 없이 한 번만 실행되는가
  • 기존 경로로 되돌릴 수 있는 평가·롤백 지점이 있는가

이 네 가지에 답할 수 있다면 마이그레이션은 단순한 긴급 패치가 아니라, 다음 세대 AI 에이전트 아키텍처를 정리하는 기회가 됩니다.

출처

댓글을 작성하려면로그인이 필요합니다.