
GPT-5.1 API 변경사항, 모델 ID만 바꾸면 추론이 꺼집니다
GPT-5가 나온 지 얼마 지나지 않아 GPT-5.1이 공개되었습니다. 기능 추가보다 API 쪽 변경이 더 눈에 띄는 릴리스입니다. Chat Completions API를 쓰고 있거나 reasoning effort를 minimal로 두고 있었다면, 모델 ID만 올렸을 때 동작이 달라집니다.
이 글은 2025년 11월 GPT-5.1 공개 시점을 기준으로 정리했습니다. reasoning effort의 허용값은 모델마다 다르고 뒤에 나온 모델에서 단계가 더 늘기도 하므로, 다른 모델에 옮겨 쓸 때는 그 모델의 문서에서 허용값을 확인해야 합니다.
사고량을 스스로 조절하는 adaptive reasoning
GPT-5.1은 문제의 난이도에 따라 사고 시간을 다르게 씁니다. 쉬운 요청에는 토큰을 덜 쓰고, 어려운 요청에는 더 오래 붙잡습니다. OpenAI는 이 동작을 adaptive reasoning이라고 부릅니다.
전역 설치된 npm 패키지를 나열하는 명령어를 묻는 같은 질문에서, GPT-5는 medium 설정으로 사고 토큰 약 250개를 쓰고 10초가 걸렸습니다. GPT-5.1은 같은 medium에서 약 50개로 2초 만에 답했습니다.
reasoning effort와 새로 생긴 none
reasoning effort는 사고량을 개발자가 직접 지정하는 파라미터입니다. o3 같은 이전 추론 모델은 low, medium, high 세 단계였고, GPT-5에서 minimal이 더해져 네 단계가 되었습니다.
GPT-5.1은 이 목록에서 minimal을 빼고 none을 넣었습니다. none은 추론 토큰을 아예 만들지 않아서, GPT-4.1 같은 비추론 모델처럼 동작하면서 GPT-5.1의 지능을 씁니다. 그리고 기본값이 medium에서 none으로 내려갔습니다.
from openai import OpenAI
client = OpenAI()
# 빠른 응답이 필요한 경우
result = client.responses.create(
model="gpt-5.1",
input="Write a haiku about code.",
reasoning={"effort": "none"},
text={"verbosity": "low"}
)minimal은 GPT-5.1 이후 모델에서 받지 않는 값입니다. GPT-5에서 reasoning={"effort": "minimal"}을 쓰던 코드를 모델 ID만 바꿔 옮기면 이 줄에서 에러가 납니다. none이나 low 중 하나를 골라야 합니다.
모델 ID만 바꾸면 추론이 조용히 꺼집니다
GPT-5에서 reasoning_effort를 명시하지 않고 기본값 medium에 기대고 있었다면, 모델 ID를 gpt-5.1로 바꾸는 순간 기본값이 none이 되어 추론이 사라집니다. 이쪽은 에러가 나지 않고 응답도 정상으로 오기 때문에, 품질이 떨어진 뒤에야 알아차리게 됩니다. 기존 동작을 유지하려면 reasoning={"effort": "medium"}을 명시적으로 넘기면 됩니다.
GPT-4.1에서 넘어오는 경우는 사정이 반대입니다. 추론이 필요 없던 저지연 용도라면 none이 그대로 대체 지점입니다.
추론 모델에서 막히는 파라미터
GPT-5 계열은 추론이 켜진 요청에서 다음 세 파라미터를 받지 않습니다.
temperaturetop_plogprobs
GPT-5.1에 reasoning effort를 none 이외의 값으로 주면서 이 필드를 함께 넣으면 에러가 납니다. GPT-5, GPT-5-mini, GPT-5-nano는 effort와 무관하게 막혀 있습니다.
GPT-5.1에서 새로 생긴 제약은 아닙니다
GPT-5 세대부터 적용된 규칙입니다. 다만 GPT-4.1이나 o 시리즈에서 곧바로 넘어오면 이 시점에 처음 마주치게 되므로 함께 정리합니다.
대신 GPT-5 계열은 reasoning effort와 verbosity로 출력을 조절합니다. verbosity는 모델이 출력 토큰을 얼마나 쓸지 정하는 값입니다. 낮추면 지연과 비용이 함께 줄지만, 답변이 짧아지는 만큼 빠지는 내용도 생깁니다.
response = client.responses.create(
model="gpt-5.1",
input="Your prompt here",
reasoning={"effort": "none"}, # none | low | medium | high
text={"verbosity": "medium"}, # low | medium | high
max_output_tokens=1000
)Chat Completions에서 Responses API로
OpenAI의 생성 API는 두 갈래입니다. Responses가 현재 권장 경로이고, Chat Completions는 계속 지원되지만 신규 프로젝트에는 권장되지 않습니다. GPT-5.1 사용 가이드도 Responses를 기준으로 쓰여 있습니다.
Responses로 옮겼을 때 달라지는 것은 네 가지입니다.
- 성능: 추론 모델을 같은 프롬프트와 설정으로 돌렸을 때 내부 평가에서 SWE-bench 점수 3% 향상
- 비용: 캐시 활용률이 내부 테스트 기준 40~80% 개선
- 도구 루프: 요청 한 번에 웹 검색, 파일 검색, 코드 인터프리터, 원격 MCP 같은 내장 도구를 이어서 호출
- 상태 유지:
store: true로 턴 사이의 추론과 도구 컨텍스트 보존
네 번째가 코드 구조를 가장 크게 바꿉니다. Chat Completions에서는 대화 기록을 클라이언트가 들고 있다가 매 턴 전부 다시 보내야 하지만, Responses는 직전 응답의 ID만 넘기면 됩니다.
API 구조 비교
# Chat Completions API
completion = client.chat.completions.create(
model="gpt-5.1",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"}
]
)
print(completion.choices[0].message.content)
# Responses API
response = client.responses.create(
model="gpt-5.1",
instructions="You are a helpful assistant.",
input="Hello!"
)
print(response.output_text)Multi-turn 대화 처리
# Chat Completions API: 컨텍스트를 수동으로 관리
messages = [{"role": "user", "content": "What is the capital of France?"}]
res1 = client.chat.completions.create(model="gpt-5.1", messages=messages)
messages += [res1.choices[0].message]
messages.append({"role": "user", "content": "And its population?"})
res2 = client.chat.completions.create(model="gpt-5.1", messages=messages)
# Responses API: previous_response_id로 체이닝
res1 = client.responses.create(
model="gpt-5.1",
input="What is the capital of France?",
store=True
)
res2 = client.responses.create(
model="gpt-5.1",
input="And its population?",
previous_response_id=res1.id,
store=True
)previous_response_id는 직전 응답의 top-level instructions까지 이어받지는 않습니다. 시스템 지시가 매 턴 유지되어야 한다면 요청마다 다시 넣어야 합니다.
Function 정의
Chat Completions는 function 아래에 한 겹 더 감쌉니다.
{
"type": "function",
"function": {
"name": "get_weather",
"strict": true,
"parameters": {}
}
}Responses는 그 래퍼 없이 평평하게 씁니다.
{
"type": "function",
"name": "get_weather",
"parameters": {}
}strict를 생략했을 때의 동작도 다릅니다. Chat Completions는 non-strict가 기본이지만, Responses는 strict를 먼저 시도하고 스키마를 strict로 만들 수 없으면 non-strict로 물러선 뒤 strict: false로 표시해 돌려줍니다. Responses에서 non-strict를 확정하고 싶다면 strict: false를 직접 넣어야 합니다.
Structured Outputs 정의
# Chat Completions API: response_format 사용
completion = client.chat.completions.create(
model="gpt-5.1",
messages=[],
response_format={
"type": "json_schema",
"json_schema": {}
}
)
# Responses API: text.format 사용
response = client.responses.create(
model="gpt-5.1",
input="...",
text={
"format": {
"type": "json_schema",
"name": "person",
"schema": {}
}
}
)마치며
GPT-5.1의 API 변경 중 실제로 문제를 일으키는 것은 reasoning effort 기본값 하나입니다. minimal 제거나 파라미터 이름 변경은 요청이 곧바로 실패하니 배포 전에 잡힙니다. 반면 기본값 변경은 에러 없이 통과하고 응답도 정상으로 오기 때문에, 품질이 떨어진 다음에야 원인을 찾게 됩니다. 모델 ID를 올릴 때는 reasoning_effort를 항상 명시해 두는 편이 안전합니다.
Responses 전환은 성격이 다른 판단입니다. Chat Completions로 잘 돌아가는 단발성 호출을 서둘러 옮길 이유는 없습니다. 다만 도구를 여러 개 붙이거나 턴 사이에 추론을 이어가야 하는 구조라면, 직접 만든 컨텍스트 관리 코드를 계속 손보는 것보다 Responses 쪽이 품이 덜 듭니다.
함께 보면 좋은 글
- Test Time Scaling : 추론 시간에 사고량을 늘리면 성능이 왜 오르는지
- Prefill과 Decode로 이해하는 LLM 추론 과정 : 사고 토큰이 늘어날 때 지연이 어디서 생기는지
- Claude Sonnet 5 출시, Opus급 성능? : 이후 나온 경쟁 모델의 가격과 벤치마크