-
[OpenAI][Responses API] function_call_output과 call_id를 로그 기준으로 검증하는 법기타개발지식/풀스택개발 2026. 6. 28. 20:14
IT 리서치 노트
[OpenAI][Responses API] function_call_output과 call_id를 로그 기준으로 검증하는 법
Responses API로 옮긴 뒤 함수 호출은 되는데 두 번째 응답에서 tool 결과가 제대로 이어지지 않는 경우가 있다. 2026년 6월 28일 기준 OpenAI 공식 문서를 다시 보면, Responses에서는 function call과 function result가 별도 item이며 `function_call_output`이 정확한 `call_id`를 가져야 모델이 어느 결과를 이어 써야 하는지 알 수 있다. 이 글은 output_text만 보는 로그에서 벗어나 item 단위로 무엇을 검증해야 하는지 정리한 것이다.
1. 개요
결론부터 말하면 Responses 함수 호출 검증은
function_call_output이 맞는call_id를 들고 돌아왔는지부터 본다. function result가 있어도 call_id가 틀리면 모델은 어느 호출의 결과인지 연결하지 못하고, response.output item을 일부만 저장하면 reasoning이나 function_call item이 조용히 빠질 수 있다. 그래서 output_text보다 response.output, call_id, function result payload를 같은 trace에서 같이 확인하는 편이 안전하다.이미 store: false와 encrypted reasoning 글이 stateless replay에서 item 보존을 다뤘다면, 이번 글은 그중에서도 function result 연결만 따로 검증하는 단계다. 또 reasoning summary와 usage 글을 같이 보면 비용과 디버깅 로그를 한 자리에서 묶는 기준도 잡힌다.
2. 어디서 실제로 막히는가
실무에서 많이 꼬이는 지점은 네 가지다. 첫째, function call이 응답에 들어왔는데 다음 요청에는 output_text만 이어 붙인다. 둘째, function result를 다시 넣지만
type: "function_call_output"대신 임의 메시지 문자열로 보낸다. 셋째, worker나 queue를 거치며call_id가 다른 요청의 값으로 섞인다. 넷째, response.output 안의 reasoning item이나 function_call item을 버리고 message만 남긴다.OpenAI 전환 가이드는 tool call item과 tool output item이 서로 다른 타입이며
call_id로 연결된다고 적고 있다. 또 같은 문서의 migration pitfalls는 Responses에서 output entry를 모두 message로 취급하면 안 되고, function result를 보낼 때 matchingcall_id가 빠지면 안 된다고 명시한다. 즉 이 문제는 모델 품질보다 응답 구조를 어떻게 저장하고 재전달했는지의 문제다.특히 기존 Chat Completions 코드가
choices[0].message.tool_calls와tool_call_id감각에 맞춰져 있으면 Responses 전환 뒤에도 비슷하게 다루기 쉽다. 하지만 Responses에서는 response.output item 전체를 보존하고, 그중 function_call item에서 나온call_id를 function_call_output에 그대로 되돌리는 흐름으로 생각을 바꿔야 한다.- 증상: 첫 번째 함수 호출은 되는데 두 번째 응답에서 결과 해석이 어긋난다.
- 실패: output_text만 저장하고 response.output item을 버린다.
- 막힘: function result는 넣었지만
call_id가 다른 요청과 섞인다. - 누락: reasoning, function_call, function_call_output을 같은 trace로 저장하지 않는다.
증상 먼저 볼 곳 판단 기준 도구 결과가 이어지지 않는다 function_call_output.call_id 원래 function_call.call_id와 일치하는지 본다 응답 품질이 턴마다 흔들린다 replayed item 목록 reasoning과 function_call item을 버리지 않았는지 본다 queue 뒤에서만 실패한다 trace id와 worker 로그 call_id가 다른 작업과 섞였는지 본다 3. 실무에서 적용하는 순서
검증 순서는 다섯 단계가 가장 빠르다. 먼저 첫 응답의
response.output에서 function_call item을 찾고call_id를 기록한다. 다음으로 실제 함수 실행 결과를type: "function_call_output"구조로 만들고 같은call_id를 붙인다. 세 번째로 response.output의 다른 item, 특히 reasoning item과 function_call item을 다음 입력 후보로 함께 보존한다. 네 번째로 second response 직전 input 배열에 어떤 item이 들어갔는지 로그로 남긴다. 마지막으로 mismatch, missing item, empty output 세 케이스를 별도 경고로 분리한다.- 첫 응답의 function_call item과
call_id를 로그에 남긴다. - function result는
function_call_output타입으로 다시 넣는다. - response.output item 목록을 message만 남기지 말고 같이 보존한다.
- second response 직전 input 배열을 trace 단위로 기록한다.
call_idmismatch와 item 누락을 같은 오류로 묶지 말고 별도 경고로 분리한다.
이 순서를 고정해 두면 구현 방식이 달라도 검증은 비슷하게 가져갈 수 있다. previous_response_id를 쓰든 stateless replay를 쓰든, function result를 넣는 순간에는 어느 function_call에 대한 output인지 명확해야 한다. 특히 비동기 worker가 여러 tool result를 병렬로 돌려주는 구조에서는 function name보다 call_id가 더 믿을 만한 기준이다.
또 one-shot 테스트에서는 잘 되는데 실제 운영에서만 흔들리면 queue나 webhook 경로에서 item이 줄어드는지부터 본다. 이때는 모델 설정을 바꾸기보다 어떤 item이 빠졌는지를 먼저 확인하는 편이 훨씬 빠르다.
4. 공식 문서와 예시 화면으로 확인하기
첫 화면은 Responses 전환 가이드다. 여기서는 function call과 function result가 같은 메시지 덩어리가 아니라, 서로 다른 item이며 call_id로 연결된다는 문장을 먼저 확인한다.
이 문장을 기준으로 보면 마이그레이션 점검 순서도 바뀐다. 결과 텍스트만 이어 붙이는 것이 아니라 어떤 function_call item에 어떤 function_call_output을 돌려줬는지부터 확인해야 한다.
두 번째 자료는 function calling 가이드의 용어 구간이다. OpenAI는 tool call output이 모델의 특정 tool call을 참조해야 한다고 적고 있다.
즉 function result를 큐나 worker에서 비동기로 생성하는 구조일수록 call_id 검증이 더 중요해진다. 이름이 같은 함수라도 어떤 호출의 결과인지 끊기면 다음 응답 품질이 조용히 흔들릴 수 있다.
세 번째 화면은 Responses 기준 complete tool calling example이다. 예시 코드를 보면 response.output을 보존한 뒤 function_call_output을 input 배열에 다시 넣는 흐름이 드러난다.
이 예시는 이전 Chat Completions 습관과 가장 크게 갈리는 지점이다. output_text만 저장하고 끝내면 function_call item과 결과 연결이 로그에서 사라진다.
코드 기준으로는 function_call을 받는 쪽과 function_call_output을 다시 보내는 쪽을 한 로그 묶음으로 남겨 두는 편이 좋다. 그래야 call_id 누락과 item 누락을 같은 자리에서 바로 볼 수 있다.
이미 encrypted reasoning replay 글을 읽었다면, 이번 글은 그 흐름에서 function result 연결만 따로 검증하는 단계다.
실무에서는 무엇을 어디서 확인할지 표로 고정해 두는 편이 낫다. 이 표는 output_text만 저장하는 로그와 item 단위 로그의 차이를 빠르게 보여 주는 용도다.
특히 마이그레이션 직후에는 response.output과 output_text를 같은 것으로 오해하기 쉽다. 이 표를 팀 로그 규칙으로 정해 두면 call_id 빠짐과 item 삭제를 더 빨리 잡을 수 있다.
마지막 자료는 운영 로그 예시다. call_id mismatch는 코드만 읽어서는 놓치기 쉬우므로 request 단위 로그에서 바로 보이게 하는 편이 좋다.
또 previous_response_id와 stateless replay 글을 같이 보면, 이 검증이 state management 선택과 별개로 항상 필요한 이유도 더 선명해진다.
5. 주의사항과 리스크
첫 번째 리스크는 function result를 일반 assistant message로 보내는 것이다. 두 번째 리스크는 response.output 전체를 저장하지 않고 output_text만 남겨 이후 replay가 약해지는 것이다. 세 번째 리스크는 동일한 함수 이름을 가진 여러 호출이 병렬로 있을 때 call_id 검증 없이 결과를 붙이는 것이다.
운영 전에는 최소한 정상 케이스, mismatched call_id 케이스, empty function output 케이스 세 가지를 짧은 테스트로 남기는 편이 좋다. 그래야 실제 장애가 났을 때 model issue와 integration issue를 빨리 나눌 수 있다.
call_id는 function name보다 더 강한 연결 기준이다.- response.output item을 버리면 stateless replay 품질이 조용히 흔들릴 수 있다.
- function result 로그는 second response 직전 input 배열과 함께 남긴다.
6. 결론
Responses 함수 호출이 흔들릴 때는 모델보다 먼저 item 구조를 본다. function_call과 function_call_output이 서로 다른 item이라는 점, 그리고 둘을 정확한 call_id로 연결해야 한다는 점을 기준으로 로그를 정리하면 tool 결과가 왜 끊겼는지 훨씬 빨리 좁힐 수 있다.
- function result는 반드시
function_call_output타입으로 넣는다. call_id는 trace 단위로 검증한다.- response.output item 목록을 output_text보다 먼저 본다.
7. 참고 링크
'기타개발지식 > 풀스택개발' 카테고리의 다른 글