LLM 엔지니어링17장 · Project 02. LLM 추론 API 서빙9 / 14← 이전목차다음 →MetaContents

17장. Project 02. LLM 추론 API 서빙

평가표와 발표

가게를 열기 전에는 리허설을 합니다. 맛을 보고, 주문 받는 말을 연습하고, 점심 손님이 몰리는 상황을 흉내 내고, 안내문을 붙입니다. 추론 API 도 약속, 품질, 속도, 쓰는 법을 함께 평가합니다.

약속 시험, 품질, 속도, 쓰는 법의 네 가지 평가 항목을 카드로 놓은 그림

네 카드가 이 장의 평가 항목입니다. 약속 시험은 정상 요청과 422, 503, 504 가 약속대로 나오는지, 품질은 요약의 핵심 사실과 분류의 정확도, 속도는 p50·p95 와 초당 처리 수, 쓰는 법은 /docs 화면과 다른 팀이 따라 쓸 부르는 예입니다. 여기서 리허설이 부하 시험과 약속 시험입니다.

평가 항목

항목재는 법프로젝트
약속정상, 짧은 글(422), 붐빔(503), 시간 초과(504)를 일부러 만들어 상태 코드를 본다1
요약 품질문서마다 핵심 사실 셋 가운데 요약에 든 수, 문장 수를 지킨 수1
분류 품질손으로 쓴 시험 문의 40개의 정확도, LLM 에 넘긴 수2
속도동시 요청 수를 바꿔 가며 초당 처리 수, p50, p953
쓰는 법/docs 가 열리고, 503 을 받으면 기다렸다 다시 보내는 부르는 예가 있다3

부르는 쪽의 예

다른 팀에 API 를 건넬 때는 503 을 받으면 어떻게 하는지까지 예로 줍니다.

Python
import time

answers = iter([(503, {"Retry-After": "1"}), (503, {"Retry-After": "1"}), (200, {})])


def send():
    """실제로는 HTTP 요청을 보낸다. 여기서는 503 두 번 뒤에 200 을 돌려주는 흉내"""
    return next(answers)


def call_with_retry(send, tries=4):
    """503 이면 Retry-After 만큼 기다렸다 다시 보낸다. 다른 코드는 바로 돌려준다"""
    for i in range(tries):
        status, headers = send()
        if status != 503:
            return status, i + 1
        time.sleep(float(headers.get("Retry-After", 1)) * 0.1)   # 예시라 기다리는 시간을 10분의 1로 줄였다
    return status, tries


print(call_with_retry(send))

(200, 3) 이 나옵니다. 두 번 붐빔을 받고 세 번째에 답을 받았다는 뜻입니다. 422 처럼 다시 보내도 같은 결과가 나올 오류는 다시 보내지 않습니다.

코드에 나오는 함수

코드쉬운 뜻
iter([...])iterator(반복자)를 만든다. 목록의 값을 하나씩 꺼낼 수 있다
next(answers)다음 값을 하나 꺼낸다. 여기서는 서버의 답을 흉내 낸다
call_with_retry(send, tries=4)retry(다시 시도)를 붙인 부르기 함수다. 최대 네 번까지 보낸다
headers.get("Retry-After", 1)머리글에 Retry-After 가 없으면 1초로 둔다
float(...)머리글의 값은 글자라 초를 소수로 바꾼다
time.sleep(... * 0.1)예시라서 기다릴 시간을 10분의 1로 줄였다
return status, i + 1마지막 상태 코드와 몇 번째에 받았는지를 함께 돌려준다

이 코드가 뜻하는 것

인기 식당에 전화했더니 "1분 뒤에 다시 걸어 주세요"라는 안내가 두 번 나오고, 세 번째에 주문을 받았습니다. 안내대로 기다렸다 거는 손님이 식당도 덜 붐비게 합니다. 여기서 안내 멘트가 503 과 Retry-After, 전화 거는 손님이 call_with_retry 입니다.

줄하는 일쉽게 말하면
answers = iter([...])503, 503, 200 을 차례로 돌려줄 흉내 서버두 번은 안내 멘트, 세 번째에 연결
status, headers = send()요청을 보내고 답을 받는다전화를 건다
if status != 503:503 이 아니면 바로 돌려준다연결되면(또는 다른 이유면) 끊고 결과를 쓴다
time.sleep(...)Retry-After 만큼 기다린다안내대로 1분 기다린다
print(...)(200, 3)세 번째 전화에서 주문했다

결과 (200, 3) 은 성공 코드와 시도 횟수입니다. 422 같은 다른 오류는 다시 걸어도 같으므로 첫 시도에서 바로 돌려줍니다.

작게 줄여서 눈으로 보기

iter 와 next, 머리글의 기본값을 따로 떼어 봅니다. 값은 설명용입니다.

Python
answers = iter(["503", "200"])   # 차례로 꺼낼 답(설명용)
print(next(answers))
print(next(answers))
try:
    next(answers)
except StopIteration:
    print("더 꺼낼 것이 없다")

headers = {"Retry-After": "2"}
print(float(headers.get("Retry-After", 1)), float({}.get("Retry-After", 1)))
출력
503
200
더 꺼낼 것이 없다
2.0 1.0
결과읽는 법
503, 200next 를 부를 때마다 목록의 다음 값이 하나씩 나온다
더 꺼낼 것이 없다값이 다 떨어지면 StopIteration 이 난다. 위 예시가 tries=4 로 횟수를 묶은 것도 끝없이 다시 보내지 않으려는 것이다
2.0 1.0머리글에 값이 있으면 그 값(2초), 없으면 기본값 1초를 소수로 바꿨다

주의할 점

  • 부하 시험은 실제로 받을 법한 글로 합니다. 같은 글만 되풀이하면 캐시가 모두 받아 내어 실제보다 빠르게 나옵니다.
  • 발표에는 잘 되는 요청만이 아니라 503, 504 가 나오는 장면도 보여 줍니다. 붐빌 때 어떻게 되는지 아는 서비스가 믿을 만한 서비스입니다.
← 이전 절17장 · 묶어서 배포하기다음 절 →17장 · 프로젝트 1 — 요약 API 서비스