-
[OpenAI][Responses API] web search에서 action.sources는 같은데 raw results만 달라질 때 query trace와 저장 범위를 어떤 기준으로 다시 나누나기타개발지식/풀스택개발 2026. 7. 24. 20:16
IT 리서치 노트
[OpenAI][Responses API] web search에서 action.sources는 같은데 raw results만 달라질 때 query trace와 저장 범위를 어떤 기준으로 다시 나누나
OpenAI Responses API web search를 운영하다 보면 `action.sources`는 그대로인데 `raw results`만 달라지는 경우가 생긴다. 2026년 7월 24일 기준 OpenAI 공식 문서를 다시 보면 `web_search_call.action.sources`, `web_search_call.results`, answer annotations는 서로 다른 층이다. 이 글은 action.sources는 같은데 raw results만 달라질 때 query trace와 저장 범위를 어떤 기준으로 다시 나누는 편이 빠른지 정리한 것이다.
1. 개요
결론부터 말하면 이 상황은 먼저 request config를 고정한 뒤, 그다음 annotations, action.sources, raw results 순서로 비교해야 한다. action.sources가 같은데 raw results만 다르다면 tool trace의 상위 source 선택은 유지됐고 retrieval 후보 풀만 흔들렸을 가능성이 크다.
따라서 이 문제는 answer diff보다 retrieval drift에 가깝다. 다만 query hash, user_location, search_context_size, include가 조금이라도 다르면 raw results 차이를 persistence 문제로 오해하게 되므로 비교 기준부터 먼저 고정해야 한다.
2. 어디서 실제로 막히는가
실무에서 먼저 꼬이는 지점은 세 가지다. 첫째, sources라는 단일 키에 annotations와 action.sources와 raw results를 함께 저장한다. 둘째, request config를 안 남겨서 raw results가 달라진 이유가 검색 조건 변화인지 후보 풀 변화인지 분간이 안 된다. 셋째, action.sources가 같으면 아무것도 안 바뀌었다고 단정한다.
하지만 OpenAI 문서 구조를 보면 annotations는 사용자에게 노출된 인용 층이고, action.sources는 tool call의 source trace이며, raw results는 후보 결과 층이다. 같은 URL이 겹쳐 보여도 역할은 다르다. 특히 raw results에는 최종 답변에 쓰이지 않은 후보가 섞이므로 이 층만 달라졌다고 해서 바로 answer 품질 저하로 이어진다고 볼 수는 없다.
반대로 이 차이를 무시하면 grounding drift의 초기 신호를 놓친다. action.sources와 annotations는 아직 안정적인데 raw results만 흔들린다면, search_context_size 조정이나 user_location 변경, 검색 시점 차이, 최신성 변화가 후속 증상으로 이어질 수 있다. 그래서 비교를 생략하지 말고 계층별로 분리해서 봐야 한다.
- 증상: answer는 비슷한데 저장한 raw results URL 목록만 매 호출마다 조금씩 달라진다.
- 실패: action.sources가 같다는 이유로 retrieval 후보 차이를 무시한다.
- 막힘: request config를 저장하지 않아 호출 조건이 같았는지부터 다시 찾는다.
- 누락: annotations, action.sources, raw results를 서로 다른 컬럼으로 저장하지 않는다.
보이는 상태 먼저 볼 값 의미 annotations 동일 user-visible citation 사용자가 본 근거는 유지됐을 수 있다 action.sources 동일 tool trace 도구의 상위 source trace는 안정적일 수 있다 raw results만 변함 retrieval 후보 풀 후보 재배열 또는 부분 교체 신호일 수 있다 3. 실무에서 적용하는 순서
가장 짧은 점검 순서는 다섯 단계다. 먼저 query hash, user_location, search_context_size, include를 남긴 request config를 비교한다. 두 번째로 annotations URL 목록을 비교해 user-visible citation이 같은지 확인한다. 세 번째로 action.sources URL 목록을 비교해 tool trace가 같은지 본다. 네 번째로 raw results URL과 rank 변화를 본다. 마지막으로 raw results만 달랐다면 retrieval drift로 분류하고, answer diff는 별도 사건으로 남긴다.
- request config를 먼저 비교한다.
- annotations가 같은지 확인한다.
- action.sources가 같은지 확인한다.
- raw results 후보와 rank 변화를 본다.
- raw results-only drift를 별도 사건으로 기록한다.
이 순서를 쓰면 search_context_size를 바꿨는데 action.sources가 같은 이유, user_location은 그대로인데 raw results만 달라진 이유를 훨씬 짧게 좁힐 수 있다. 핵심은 URL 목록을 한 배열로 합치지 않는 것이다. annotations는 user-visible, action.sources는 tool trace, raw results는 retrieval 후보라는 역할을 유지해야 한다.
운영자는 같은 incident마다 request config를 저장하고, diff 결과를 기록하고, 재현 호출을 실행하고, 세 층의 URL을 다시 조회해 비교한다. 이 네 동작을 매번 반복해야 drift와 answer diff를 같은 로그에 섞지 않는다.
if request_config_changed: classify = "config_change" elif annotations_changed: classify = "answer_diff" elif action_sources_changed: classify = "tool_trace_diff" elif raw_results_changed: classify = "retrieval_drift" else: classify = "no_material_diff"이미 results와 action.sources를 같이 보는 글, annotations만 저장하면 부족한 경우를 정리한 글을 읽었다면, 이번 글은 그 둘을 한 단계 묶는 drift triage 규칙이라고 보면 된다.
4. 공식 문서와 예시 화면으로 확인하기
첫 화면은 user-visible citation 층이 어디인지 다시 고정해 준다. OpenAI web search guide는 answer text와 inline citation이 assistant message 쪽에 남는다고 설명한다.
따라서 annotations가 안 바뀌었다면 사용자 화면은 유지됐을 가능성이 크다. 이번 글의 질문은 그 아래쪽 trace가 왜 흔들렸는지를 어디서부터 분리해 보느냐에 가깝다.
두 번째 자료는 tool trace 층의 대표 값이다. items reference는 include 값으로 `web_search_call.action.sources`를 따로 요청할 수 있다고 적고 있다.
즉 action.sources는 answer citation과 같은 배열이 아니라 tool call이 어떤 source trace를 남겼는지 보는 층이다. 이 값이 그대로라면 검색 도구의 상위 source trace는 안정적이었다고 해석할 여지가 생긴다.
세 번째 자료는 raw results 층을 실제 저장 키로 나눠 적은 예시다. 문서에서 `web_search_call.results`를 별도 include로 요청할 수 있다는 점을 운영 로그 필드로 바로 옮겨 놓았다.
raw results는 retrieval 후보 풀이므로 여기만 달라졌다면 '후보 재배열 또는 후보 교체는 있었지만 최종 source trace는 유지됐다'는 해석이 가능하다. 그래서 이 층을 answer나 tool trace와 분리 저장하고, 다음 호출에서도 같은 키 이름으로 조회하고 비교해야 한다.
실무에서는 drift를 세 칸으로 나눠 적어야 한다. action.sources가 같고 raw results만 달라졌는지, request config도 바뀌었는지, citations까지 바뀌었는지를 한 표에 두면 사고 범위가 줄어든다.
이미 raw results와 action.sources와 annotations를 언제 저장할지 정리한 글이 저장 층을 열어 줬다면, 이번 표는 그다음 단계인 drift 해석 순서다.
마지막 자료는 query trace 스키마 예시다. request config와 세 층의 URL 목록을 따로 남기면 다음 incident에서 무엇이 바뀌었는지 바로 비교할 수 있다.
이 구조를 쓰면 user_location diff 글과 search_context_size diff 글을 같은 persistence 계약 안에서 재사용하기 쉽다.
실제 비교 순서도 정해 두어야 한다. raw results만 달라졌다는 사실을 확인하기 전에 query trace를 빼먹으면 요청 조건 자체가 달랐는지부터 다시 찾아야 한다.
이 순서를 고정해 두면 raw results drift를 과잉 해석하지 않게 된다. 같은 action.sources를 보고도 왜 후보 풀이 달랐는지 더 짧게 좁힐 수 있다.
5. 주의사항과 리스크
첫 번째 리스크는 raw results만 달라도 answer 품질이 무너졌다고 과잉 해석하는 것이다. 두 번째는 반대로 action.sources가 같으니 raw results는 볼 가치가 없다고 판단하는 것이다. 세 번째는 request config 없이 URL 배열만 남겨 재현 가능한 비교 기준을 잃는 것이다.
운영 로그에는 최소한 query hash, user_location, search_context_size, include, annotations URLs, action.sources URLs, raw results URLs를 따로 남기는 편이 좋다. 그래야 다음 호출에서 무엇이 달라졌는지 기계적으로 비교할 수 있고, 검색 조건 변화와 실제 retrieval drift를 섞지 않는다. 팀 문서에도 조회 경로, 저장 컬럼, diff 결과, 후속 실행 명령을 같이 적어 두는 편이 안전하다.
6. 결론
web search에서 action.sources는 같은데 raw results만 달라질 때는, 먼저 request config를 고정하고 그다음 annotations, action.sources, raw results 순서로 비교해야 한다. 이 순서를 지켜야 retrieval 후보 변화와 user-visible answer 변화를 섞지 않고 기록할 수 있다.
같은 가지의 선행 글로는 세 층을 언제 저장할지 정리한 글, search_context_size를 키웠는데 source URLs만 달라질 때의 글, user_location diff 글을 같이 보면 좋다.
이번 분기를 조금 더 넓게 incident 규칙으로 정리한 후속 글로는 request config diff와 retrieval drift를 어떤 비교 순서로 먼저 고정할지 정리한 글을 이어서 보면 좋다. raw results만 흔들린 사례를 기록하는 데서 멈추지 않고, 다음 incident에서 answer diff와 retrieval drift를 다른 사건으로 남기는 기준까지 바로 이어진다.
7. 참고 링크
'기타개발지식 > 풀스택개발' 카테고리의 다른 글