LLM 회귀 테스트: 모델 버전 고정으로 어제와 다른 답 잡기

결론부터 말씀드리면, 어제 잘 나오던 답이 오늘 갑자기 달라졌다면 첫 번째로 의심할 곳은 프롬프트가 아니라 모델 버전입니다. gpt-4o나 claude-3-5-sonnet-latest처럼 별칭(alias)으로 모델을 호출하고 있다면, 제공사가 내부적으로 스냅샷을 교체하는 순간 코드 한 줄 안 바꿨는데도 출력이 흔들립니다. 이 글에서는 모델 버전을 고정하는 구체적인 방법과, 그 위에 얹을 수 있는 최소 단위의 LLM 회귀 테스트 구성을 코드와 함께 … Read more

프롬프트 A/B 테스트, 운영 중 트래픽 분리와 품질 지표부터 정하세요

운영 중인 서비스에서 프롬프트 A/B 테스트는 요청 트래픽을 두 갈래로 나누고, 각 그룹의 응답 품질을 같은 기준으로 비교해 더 나은 프롬프트를 골라내는 작업입니다. 트래픽 분리를 대충 하면 두 그룹의 사용자 특성이 애초에 달라져 버리고, 품질 지표를 미리 정하지 않으면 결과를 보고 나서야 기준을 끼워 맞추게 됩니다. 이 글에서는 해시 기반 트래픽 분리 코드와, 실무에서 바로 … Read more

대화 히스토리 관리, 슬라이딩 윈도우와 요약 압축의 손익 계산법

챗봇을 붙여둔 서비스를 운영하다 보면 어느 순간 API 요금 청구서가 이상하게 부풀어 오르는 걸 발견하게 됩니다. 원인을 뜯어보면 대부분 대화 히스토리 관리를 손대지 않고 매 턴 전체 대화를 통째로 다시 보내고 있었던 경우입니다. 이 문제를 푸는 방법은 크게 두 갈래인데, 최근 몇 턴만 잘라 보내는 슬라이딩 윈도우와 오래된 대화를 요약해서 압축하는 방식 중 어느 하나가 … Read more

LLM rate limit 429 몰릴 때, 큐잉과 토큰 버킷 중 뭘 써야 할까요

LLM API에서 429 에러가 몰리면 재시도(retry) 로직만 촘촘하게 짜면 해결된다고 생각하기 쉬운데, 이건 절반만 맞는 이야기예요. 재시도는 이미 터진 429를 수습하는 방법이고, LLM rate limit을 근본적으로 관리하려면 요청을 내보내는 속도 자체를 조절하는 계층이 따로 필요합니다. 혼자 쓰는 배치 스크립트라면 토큰 버킷 하나로 충분하지만, 여러 사용자의 요청이 동시에 들어오는 서비스라면 큐잉까지 함께 둬야 429가 줄어들어요. 429가 … Read more

LLM 스트리밍 취소, 창을 닫으면 과금은 정말 멈출까

“스트리밍으로 답변받던 중에 브라우저 탭을 닫으면 LLM 과금은 바로 끊길까요?” 결론부터 말씀드리면, 정답은 “아니요, 서버가 취소 신호를 받아 실제로 생성을 멈춰야만 멈춥니다”입니다. 클라이언트 소켓이 끊긴 것과 추론 서버가 토큰 생성을 중단하는 것은 완전히 별개의 사건이라서, 요청 취소를 직접 전파하는 코드를 넣어두지 않으면 사용자가 사라진 뒤에도 서버는 혼자 계속 토큰을 뽑아내고 그만큼 과금됩니다. 브라우저 창을 닫으면 … Read more

AI 에이전트 무한 루프, 종료 조건과 최대 스텝은 이렇게 설계하세요

에이전트가 같은 도구만 계속 부르고 멈추지 않는데, 대체 어디서 끊어야 할까요? 답은 모델 호출 루프 안에 종료 조건과 최대 스텝을 코드로 직접 심어두는 것입니다. LLM 자체는 “이제 그만 부르자”는 판단을 스스로 하지 못하는 경우가 많아서, AI 에이전트 무한 루프는 안전장치를 따로 만들지 않으면 언제든 벌어질 수 있는 일입니다. 도구 호출이 멈추지 않는 구조적인 이유 에이전트 … Read more

tool calling이 엉뚱한 도구를 고를 때, 설명문부터 고치는 순서

tool calling 기능을 붙인 에이전트에서 모델이 분명 존재하는 도구를 두고 엉뚱한 함수를 호출하는 문제는, 프롬프트보다 도구 설명문(description)에서 시작되는 경우가 많습니다. 이름이 비슷하거나 설명이 짧은 도구 두세 개만 나란히 등록돼 있어도 모델이 그중 하나를 잘못 고르는 일이 흔하게 일어납니다. 그래서 함수 호출이 꼬였을 때는 시스템 프롬프트부터 뜯어고치기 전에, 도구 설명문을 먼저 점검하는 순서로 접근하는 편이 효율적입니다. … Read more

외부 API 응답을 곧이곧대로 믿으면 안 되는 이유

새벽 배포 직후 알림이 울리고, 로그를 열어보니 결제 API가 갑자기 amount 필드를 문자열 “1,000”으로 보내서 파서가 통째로 죽어 있는 상황, 한 번쯤 겪어보셨을 거예요. 외부 API 응답을 그대로 믿으면 안 되는 이유는 간단합니다. 상대 서버가 문서와 다르게 필드를 바꾸거나, 일부 데이터만 누락된 채 200 OK를 돌려주는 순간 내 서비스가 함께 무너지기 때문이에요. 이 글에서는 스키마 … Read more

크롤링이 403으로 막힐 때 확인할 순서: UA·robots·속도

크롤링이 403으로 막히면 다들 제일 먼저 프록시부터 바꾸는데, 사실 원인의 상당수는 IP가 아니라 요청 헤더와 속도에 있어요. User-Agent 하나만 제대로 채워도 뚫리는 경우가 많고, robots.txt를 무시한 경로만 골라 요청했다가 걸리는 경우도 흔합니다. 이 글에서는 403의 흔한 원인 네 가지를 실제 점검 순서대로 정리하고, 어디까지가 “고치면 되는 문제”이고 어디부터는 우회가 아니라 포기해야 하는 영역인지 구분해 드릴게요. … Read more

Windows에서 파이썬 cp949 오류 없애기: 로그·파일·서브프로세스 3곳 총정리

Windows에서 파이썬 스크립트를 돌리다가 UnicodeDecodeError나 UnicodeEncodeError 메시지에 ‘cp949’라는 단어가 찍혀 있어서 검색하셨다면, 답은 명확합니다. 표준 출력(로그·print)은 스트림 인코딩을 UTF-8로 재설정하고, 파일은 open()에 encoding=’utf-8’을 항상 명시하며, 서브프로세스는 자식 프로세스가 실제로 쓰는 인코딩에 맞춰 encoding 인자를 지정해야 세 곳 모두에서 오류가 사라집니다. 원인은 하나입니다. 한국어 Windows의 로컬 코드페이지가 cp949로 잡혀 있고, 파이썬이 인코딩을 따로 지정하지 않으면 이 … Read more