게이트웨이를 지우고 배선을 고쳤다

이틀 전에 세운 게이트웨이가 요리 질문에까지 증시 개장일을 붙이고 있었다. 4월에 제지당한 패턴을 그대로 반복했고, 지우고 나니 채팅 품질 문제의 대부분은 모델이 아니라 조용히 무시되는 설정이었다

집에 둔 GPU 장비는 vLLM으로 로컬 모델을 서빙하고, 자동매매 봇과 지인용 채팅 UI가 그 위에 붙어 있다. 이틀 전에 서버 앞에 게이트웨이를 하나 세웠는데, 채팅을 붙이고 받은 첫 평가가 품질이 못 쓸 수준이라는 것이었다. 모델이 나쁜 건지 사이에 낀 것들이 나쁜 건지부터 갈라야 했다.

하려던 것

8월 17일에 서버 앞에 게이트웨이를 하나 세웠다. 8002 포트에서 검색 왕복을 서버가 대신 처리하고, 날짜와 휴장일과 근거 강제 규칙을 프롬프트에 끼워 넣는다. 자동매매 봇이 편하게 부르라고 만든 것이다.

다음 날 지인용 채팅 UI를 그 위에 붙였다. 첫 평가는 “품질은 확실히 못 쓸 수준이다. 어려운 것도 아닌데. 속도는 빠르다”였다.

어떻게 시켰나

모델 탓을 하기 전에 배선을 의심했다.

main.py에 의존성이 엄청나게 많은 거 아냐? 이것 때문에 이상하게 동작하는 거 아냐? 원래 이런 식으로 게이트웨이가 조정하는 게 맞아?

파 보니 도메인 규칙이 모든 요청에 붙고 있었다. 요리 질문에도, 여행 질문에도 “오늘 한국 증시는 정규 개장일이다”가 들어갔다. 다음 날 아침에 한 마디로 정리했다. “게이트웨이도 없애. 원래 안 쓴다며.” 생성 8월 17일 오후 2시, 제거 8월 19일 오후 1시. 수명 이틀이었다.

4월에 똑같은 자리에서 제지당했다. 10화에서 서버 앞에 범용 엔드포인트를 만들려던 걸 끊고 “표준 인터페이스 위에 내 스키마를 얹지 마라”고 적어 뒀다. 넉 달 만에 같은 걸 다시 만들었고, 이번에는 내가 아니라 에이전트가 제안했고, 나는 승인했다.

게이트웨이가 남긴 건 기술 교훈 셋이다. 스트리밍에서 청크를 모았다 내보내면 첫 토큰이 6.2초, 즉시 흘리고 도구 호출 델타만 삼키면 0.22초. 검색 왕복 중에는 나가는 바이트가 없어 Cloudflare 터널의 100초 유휴 타임아웃에 걸리므로 SSE keepalive가 필요하다. 검색 옵션은 tools에 넣는 게 아니라 OpenAI 규격의 web_search_options다.

어디서 막혔나

게이트웨이를 빼도 채팅 품질이 돌아오지 않았다. 이번에는 Open WebUI 쪽이었다. 실측으로 확인한 함정들의 공통점은 틀렸다고 알려 주지 않고 조용히 무시된다는 것이었다.

함정증상
컨테이너 기본 TZ가 UTC시각이 9시간 어긋남
chat_template_kwargs가 허용 목록 밖띵킹 설정이 조용히 버려짐
webSearch를 settings.ui에 넣음무시됨. settings 루트여야 작동
설정이 DB에 영구 저장env를 바꿔도 첫 부팅 값이 이김
모델 파라미터가 두 번 적용요청 단위 오버라이드를 덮어씀
:main 이미지 태그재시작마다 프론트가 바뀜

진단 실패도 하나 있었다. “이 모델엔 띵킹이 없다”고 결론 냈는데, vLLM이 델타를 reasoning_content가 아니라 reasoning 키로 보내고 있었다. 엉뚱한 키를 보고 없다고 한 것이다.

어떻게 풀었나

실패한 대화를 하나씩 원인별로 분류시켰다. 결론은 “대부분 모델이 아니라 배선”이었다. 사실 질문에 거절한 사례는 검색 토글이 꺼져 있었고, 날짜 오답은 TZ였고, 띵킹 없음은 키 이름이었다.

Open WebUI를 v0.11.0으로 고정하고, 날짜를 시스템 프롬프트에 주입하고, 시스템 프롬프트 정본을 한 곳에 두고, 검색을 상시로 켰다. 서버는 다시 순수 모델 서빙만 남았다. 8000 포트 하나, OpenAI 호환 API 하나.

배운 점