개발·프레임워크

BUILD / 8번째 글

AI 고객 지원 자동화: 티켓 분류부터 답변 생성까지

자동화 범위를 데이터로 정하고, 티켓 분류기를 만들고, 근거 있는 답변과 에스컬레이션 임계값·회로 차단기까지 — 고객 지원 자동화를 운영 기준으로 설계합니다.

PALDYN Team32 MIN READ

지난 글에서 문서를 청킹해 인덱싱하고 키워드 검색과 벡터 검색을 합쳐 근거 있는 답을 만드는 파이프라인을 세운 뒤, 권한 필터를 붙여 사내 지식 검색까지 넓혔다. 이번에는 외부 고객을 대상으로 하는 AI 고객 지원 자동화를 만든다.

이 주제는 모델 성능보다 경계 설계가 결과를 가른다. 사내 검색은 답이 틀려도 사람이 문서를 다시 열어 보면 그만이지만, 고객 지원은 틀린 답이 그대로 회사의 공식 답변이 된다. 환불 가능 여부를 잘못 안내하면 그 문장이 분쟁의 근거가 되고, 품절 상품을 있다고 답하면 주문이 들어온다. 그래서 「AI가 얼마나 잘 답하는가」보다 「AI가 어디까지만 답하게 할 것인가」가 먼저다. 아래 순서는 그 경계를 데이터로 정하고, 넘었을 때 사람에게 넘기고, 넘긴 비율을 지표로 관리하는 흐름을 따른다.

자동화 범위

AI 고객 지원 처리 워크플로우

티켓을 유형별로 세기

범위를 감으로 정하면 거의 항상 틀린다. 상담팀에 물으면 기억에 남는 어려운 케이스를 먼저 말하는데, 그런 케이스는 대개 건수가 적다. 반대로 하루에 수십 건씩 들어오는 단순 문의는 너무 당연해서 언급되지 않는다. 그래서 시작점은 지난 석 달 치 티켓을 꺼내 유형별로 세는 일이다.

세는 방법은 처음부터 정교할 필요가 없다. 기존 CRM의 분류 필드가 있으면 그것으로 세고, 없으면 제목을 모델에 넣어 열 개 안팎의 유형으로 묶은 뒤 건수를 센다. 이 단계에서 나오는 표가 이후 모든 판단의 근거가 된다 — 어떤 유형을 먼저 자동화할지, 분류기의 라벨을 무엇으로 둘지, 성과를 무엇으로 잴지가 전부 여기서 나온다.

상위 유형이 덮는 비율

세고 나면 거의 예외 없이 같은 모양이 나온다. 유형 서넛이 전체 문의의 절반을 넘게 차지하고, 나머지가 긴 꼬리로 흩어진다. 배송 조회, 반품 규정, 로그인 문제, 결제 수단 변경 같은 것들이다.

유형별 문의 건수

이 분포가 중요한 이유는 자동화의 상한을 알려 주기 때문이다. 상위 다섯 유형이 문의의 60%라면 그 다섯을 완벽히 처리해도 자동 처리율의 천장은 60%다. 여기서 두 가지 결정이 갈린다. 목표를 60%로 잡고 그 다섯에 집중할 것인가, 아니면 꼬리 쪽까지 범위를 넓힐 것인가. 대개는 앞쪽이 옳다. 꼬리 유형은 건수가 적어 학습·검증에 쓸 사례가 모자라고, 사례가 적을수록 틀릴 확률이 높으며, 틀렸을 때 잡아낼 기회도 적다. 건수가 적다는 성질 하나가 세 가지 불리함을 동시에 만든다.

숫자를 한 번 따라가 보면 우선순위가 분명해진다. 월 4,000건이 들어오고 배송 조회가 1,100건, 반품 규정이 620건, 로그인 문제가 380건이라고 하자. 앞의 셋이 2,100건으로 전체의 52%다. 여기서 절반만 자동으로 끝내도 1,050건, 건당 상담 시간을 6분으로 잡으면 월 105시간이 빠진다. 반면 꼬리에 있는 30건짜리 유형을 하나 자동화하면 최대 3시간이다. 같은 노력을 들여도 돌아오는 것이 서른 배 차이인데, 틀릴 위험은 오히려 꼬리 쪽이 크다.

그래서 첫 범위는 상위 유형 두셋으로 좁게 잡고, 그 유형의 지표가 안정된 뒤에 하나씩 늘리는 순서가 좋다. 한 번에 다섯 유형을 열면 지표가 나빠졌을 때 어느 유형 탓인지 갈라내는 데 몇 주가 든다.

넘기기로 정해 두는 것

범위를 정할 때 함께 적어 두어야 하는 것이 반대쪽 목록이다. 성공률과 무관하게 무조건 사람에게 넘길 유형이다.

  • 금액이 오가는 예외 처리 — 정책 밖 환불, 보상, 부분 취소
  • 계정 침해나 결제 도용이 의심되는 건
  • 법적 분쟁을 언급한 건
  • 이미 같은 건으로 두 번 이상 연락한 고객

이 목록을 분류기의 정확도와 분리해 두는 것이 요점이다. 「분류기가 환불 요청을 잘 잡아내면 자동 처리해도 된다」가 아니라, 잡아내든 못 잡아내든 환불은 사람이 본다. 모델 성능이 좋아졌다고 이 목록을 줄이는 손질은 사고가 났을 때 가장 먼저 후회하는 자리다.

티켓 분류기

라벨 체계

분류기가 내놓을 값은 하나가 아니라 네 축이다. 문의 유형, 우선순위, 감정 상태, 그리고 자동 답변 가능 여부다. 이 넷을 한 번의 호출로 받는 이유는 뒤의 판단이 전부 이 조합으로 갈리기 때문이다 — 유형이 배송이어도 감정이 격앙돼 있으면 사람에게 가고, 유형이 환불이면 감정과 무관하게 사람에게 간다.

라벨을 설계할 때 가장 흔한 실수는 유형을 너무 잘게 나누는 것이다. 스무 개로 나누면 경계가 모호한 쌍이 생기고, 그 쌍에서 분류가 흔들리며, 어느 쪽으로 가든 결과가 같은 자리에서까지 오분류로 집계된다. 처리 방식이 달라지는 지점에서만 라벨을 가른다는 기준이면 대개 대여섯 개로 줄어든다.

import anthropic, json

client = anthropic.Anthropic()

CLASSIFY_SYSTEM = """고객 문의를 분석하고 다음 JSON 형식으로만 응답하세요.
{
  "category": "billing|technical|shipping|account|general",
  "priority": "critical|high|medium|low",
  "sentiment": "positive|neutral|negative|angry",
  "can_auto_reply": true,
  "summary": "문의 내용 한 줄 요약"
}"""

def classify_ticket(text: str) -> dict:
    res = client.messages.create(
        model="claude-haiku-4-5-20251001",
        max_tokens=256,
        system=CLASSIFY_SYSTEM,
        messages=[{"role": "user", "content": text}],
    )
    return json.loads(res.content[0].text)

분류에 작고 빠른 모델을 쓰는 것은 비용 때문만이 아니다. 분류는 모든 티켓이 반드시 거치는 길목이라 지연이 그대로 첫 응답 시간에 더해진다. 답변 생성은 일부 티켓만 거치지만 분류는 100%가 거친다는 점이 모델을 가르는 기준이다.

200건 라벨링

프롬프트를 고치면서 「이제 잘 되는 것 같다」로 판단하면 끝이 없다. 고정된 평가 세트가 있어야 바꾼 것이 나아진 것인지 알 수 있다. 실제 티켓 200건을 사람이 직접 라벨링해 두는 것이 최소 단위다.

200건을 고를 때는 무작위로만 뽑으면 안 된다. 무작위 표본은 실제 분포를 따르므로 흔한 유형이 대부분을 차지하고, 정작 궁금한 경계 사례가 두어 건밖에 안 들어온다. 유형마다 최소 20건씩 채우고 남는 자리를 무작위로 메우는 쪽이 낫다. 라벨링은 두 사람이 따로 하고 어긋난 건만 모아 맞추는 방식이 좋다 — 두 사람이 다르게 판단한 티켓은 대개 라벨 정의 자체가 모호한 자리라, 그 목록이 곧 정의를 다듬을 목록이 된다.

혼동 행렬과 경계 유형

평가 결과를 전체 정확도 한 숫자로만 보면 어디를 고쳐야 할지 알 수 없다. 실제 라벨과 예측 라벨을 교차로 세는 표, 곧 혼동 행렬을 그려야 한다. 대각선은 맞힌 것이고 그 밖의 칸이 틀린 것인데, 틀린 칸이 골고루 흩어져 있는 경우는 드물다. 거의 항상 특정 두 유형 사이에 몰린다.

몰리는 자리를 찾았으면 고치는 방법은 셋 중 하나다. 프롬프트에 그 둘을 가르는 기준을 한 줄 명시하거나, 헷갈리는 예시 두어 개를 프롬프트에 넣거나, 아예 두 유형을 합친다. 세 번째가 답인 경우가 생각보다 많다 — 사람도 흔들리는 경계라면 그 구분이 실제로 처리를 다르게 만드는지 되물어야 한다.

방향을 가르는 판단도 있다. 자동 답변 가능 여부에서 두 종류의 오류는 무게가 다르다. 답할 수 있는 것을 사람에게 넘기면 상담원 한 명의 몇 분이 들고, 답하면 안 되는 것을 자동 답변하면 잘못된 안내가 고객에게 나간다. 그래서 이 축은 정확도를 맞추는 것이 아니라 한쪽으로 기울여 두는 것이 맞다. 애매하면 사람에게 보내는 쪽으로 프롬프트를 적는다.

근거 있는 답변

FAQ에서 근거 찾기

자동 답변은 모델이 아는 것을 말하게 하는 구조여서는 안 된다. 회사의 배송 정책은 모델이 알 수 없는 정보이고, 물어보면 그럴듯한 일반론을 답한다. 그래서 답변 생성은 반드시 검색을 앞에 둔다 — FAQ와 정책 문서에서 관련 조각을 찾아 함께 넣고, 그 안에서만 답하게 한다.

여기서 결정적인 것은 검색이 실패했을 때의 동작이다. 관련 조각을 못 찾았으면 모델을 부르지 않고 바로 사람에게 넘겨야 한다. 근거 없이 부르면 모델은 답을 만들어 내고, 그 답은 형식도 어조도 멀쩡해서 걸러지지 않는다.

def generate_auto_reply(ticket: str, cls: dict, conn) -> str | None:
    if not cls.get("can_auto_reply") or cls.get("sentiment") == "angry":
        return None

    chunks = retrieve_faq_chunks(ticket, top_k=3, conn=conn)
    if not chunks:                      # 근거 없으면 생성하지 않는다
        return None

    res = client.messages.create(
        model="claude-sonnet-5",
        max_tokens=512,
        system=(
            "아래 FAQ 내용에 있는 사실만으로 답변하세요. "
            "FAQ에 없는 내용은 추측하지 말고 담당자 연결을 안내하세요. "
            "금액·기간·예외 조건은 FAQ 문장을 그대로 인용하세요."
        ),
        messages=[{"role": "user",
                   "content": f"FAQ:\n{chr(10).join(chunks)}\n\n문의:\n{ticket}"}],
    )
    return res.content[0].text

인용과 「답할 수 없습니다」

프롬프트에 「FAQ에 있는 사실만」이라고 적는 것만으로는 부족하다. 지시는 대부분 지켜지지만 대부분으로는 모자란 영역이다. 실제로 듣는 장치는 두 가지다.

첫째, 숫자와 조건은 인용하게 한다. 「환불은 7일 이내 가능합니다」라고 요약하는 대신 정책 문장을 그대로 옮기게 하면, 옮길 문장이 없을 때 모델이 멈추기 쉬워진다. 요약은 없는 것도 만들어 낼 수 있지만 인용은 원본이 있어야 성립한다.

둘째, 답할 수 없을 때의 문장을 미리 고정해 둔다. 「확인이 필요한 내용이라 담당자에게 연결하겠습니다」 같은 한 문장을 정해 두고 그대로 쓰게 하면, 모델이 답을 짜내는 대신 그 문장으로 빠져나갈 길이 생긴다. 출구를 안 만들어 두면 지시를 어기고서라도 답을 만드는 쪽으로 기운다.

검색이 못 찾는 문의

근거를 못 찾아 사람에게 넘어간 건은 실패가 아니라 가장 값진 데이터다. 그 목록이 곧 FAQ에 빠진 항목의 목록이기 때문이다. 이 건들을 따로 모아 주마다 훑으면 두 종류가 나온다. 하나는 정말로 FAQ에 없는 내용이라 문서를 추가해야 하는 것이고, 다른 하나는 문서에는 있는데 검색이 못 찾은 것이다.

둘은 고치는 자리가 완전히 다르다. 앞쪽은 문서를 쓰는 일이고, 뒤쪽은 검색 쪽 문제다. 고객이 쓰는 말과 문서에 적힌 말이 달라서 생기는 경우가 대부분이다 — 고객은 「돈 언제 들어와요」라고 쓰는데 문서 제목은 「환불 처리 소요 기간」인 식이다. 문서에 고객이 실제로 쓰는 표현을 함께 적어 두거나, 검색 단계에서 문의를 한 번 다듬어 넣는 것으로 풀린다.

이 되먹임이 돌기 시작하면 자동 처리율이 저절로 올라간다. 처음 몇 달 동안 자동 처리율을 끌어올리는 것은 모델을 바꾸는 일이 아니라 거의 전부 이 작업이다. 자동화의 상한을 정하는 것은 모델 성능이 아니라 지식 문서의 범위이고, 그 사실을 늦게 깨달을수록 프롬프트만 고치며 몇 주를 쓴다.

발신 전 마지막 검사

생성된 답변을 그대로 내보내기 전에 규칙 기반 검사를 한 겹 둔다. 모델이 아니라 코드가 보는 검사라 값이 싸고 결과가 일정하다. 볼 것은 대체로 넷이다 — 답변에 있는 금액·기간 같은 수치가 근거 조각에도 있는가, 약속을 뜻하는 표현이 들어갔는가, 링크가 허용된 도메인인가, 길이가 지나치게 짧거나 길지 않은가. 하나라도 걸리면 발신하지 않고 상담원 대기열로 보낸다. 이 검사에 걸린 건수를 따로 세어 두면 그것이 곧 프롬프트를 다시 봐야 한다는 신호가 된다.

에스컬레이션

에스컬레이션 우선순위 기준

임계값을 정하는 곡선

자동 처리율과 만족도는 맞바꾸는 관계다. 기준을 느슨하게 하면 더 많은 티켓을 AI가 처리하지만 그중 아슬아슬한 건이 늘어 만족도가 내려간다. 그래서 「어디서 끊을 것인가」는 계산으로 나오지 않고 그려 봐야 나온다.

방법은 기준을 여러 단계로 나눠 각각의 결과를 재는 것이다. 자동 답변한 건에 한해 만족도와 재문의율을 기준별로 집계하면, 대개 어느 지점부터 만족도가 꺾이는 구간이 보인다. 그 직전이 끊을 자리다. 처음 몇 주는 기준을 일부러 빡빡하게 잡고 자동 처리율을 낮게 시작하는 편이 안전하다 — 넓혔다 줄이는 것보다 좁혔다 넓히는 쪽이 고객이 겪는 피해가 작다.

def should_escalate(cls: dict, attempts: int) -> tuple[bool, str]:
    if cls["priority"] == "critical":      return True, "긴급 케이스"
    if cls["sentiment"] == "angry":        return True, "고객 감정 격앙"
    if not cls["can_auto_reply"]:          return True, "자동 답변 불가 카테고리"
    if attempts >= 2:                      return True, "자동 답변 반복 실패"
    return False, ""

회로 차단기

개별 티켓의 판단과 별개로, 시스템 전체를 멈추는 장치가 필요하다. 프롬프트를 바꿨는데 특정 유형에서 답이 어긋나기 시작하거나, FAQ 문서가 갱신되며 인덱스가 깨지는 일이 실제로 일어난다. 이때 한 건씩 판단하는 로직은 아무것도 못 잡는다 — 각각은 정상으로 보이기 때문이다.

그래서 최근 구간의 집계로 판단하는 차단기를 따로 둔다. 최근 100건의 자동 답변에서 부정 피드백 비율이 평소의 두 배를 넘거나, 24시간 재문의율이 기준선을 넘거나, 발신 전 검사에 걸린 비율이 급히 오르면 자동 답변을 끄고 전량을 상담원 대기열로 보낸다. 세 조건 모두 절대값이 아니라 평소 대비로 잡는 것이 핵심이다. 절대 기준은 유형 구성이 바뀔 때마다 오작동한다.

차단기는 자동으로 다시 켜지지 않게 둔다. 사람이 원인을 확인하고 켜는 절차를 거치게 해야 같은 문제가 반복되지 않는다. 그리고 차단기를 전체가 아니라 유형별로 두면 피해가 작아진다. 배송 유형의 답변만 어긋났는데 전량을 사람에게 보내면 멀쩡히 돌던 나머지까지 상담 대기열에 쌓인다.

차단기가 작동한 순간을 기록으로 남기는 것도 잊으면 안 된다. 언제, 어떤 조건에서, 그 직전에 무엇을 배포했는지를 함께 남겨 두면 원인을 찾는 시간이 크게 줄어든다. 대부분의 작동은 프롬프트나 문서 변경 직후에 몰린다.

컨텍스트 카드

사람에게 넘길 때 티켓 원문만 던지면 상담원이 처음부터 읽어야 하므로 자동화로 아낀 시간이 그 자리에서 돌아간다. 넘기는 순간 AI가 정리한 카드를 함께 붙인다.

읽는 순서를 고려해 배치해야 한다. 상담원이 가장 먼저 보는 것은 무엇을 해 주면 되는가이므로 요청 요약이 맨 위에 오고, 그다음이 넘어온 이유, 그다음이 이미 시도한 답변과 고객 반응, 마지막이 계정·주문 정보다. 순서가 뒤집혀 계정 정보가 맨 위에 있으면 상담원이 스크롤을 내려 요약을 찾는다 — 한 건에 몇 초지만 하루 수백 건이면 무시할 수 없다.

def escalate_to_agent(ticket: str, cls: dict, reason: str) -> dict:
    res = client.messages.create(
        model="claude-haiku-4-5-20251001",
        max_tokens=256,
        system="상담원이 바로 대응할 수 있도록 고객의 요청을 3줄 이내로 요약하세요.",
        messages=[{"role": "user", "content": ticket}],
    )
    return {
        "request_summary": res.content[0].text,   # 상담원이 먼저 읽는 자리
        "escalation_reason": reason,
        "attempted_reply": cls.get("last_reply"),
        "classification": cls,
        "priority_queue": cls["priority"],
    }

답변 톤

감정 신호 읽기

분류기가 내놓은 감정 값은 톤을 바꾸는 데 쓰기 전에 넘길지 말지를 정하는 데 먼저 쓴다. 격앙된 고객에게 AI가 답하는 것은 톤이 좋고 나쁘고의 문제가 아니라, 그 상황에서 필요한 것이 대개 권한이기 때문이다. 예외 처리나 보상은 AI가 할 수 없는 일이고, 할 수 없는 일을 정중하게 거절하는 답변은 상황을 더 나쁘게 만든다.

감정 값이 유용해지는 자리는 그 바로 아래 단계, 곧 불편을 겪었지만 요구가 명확한 고객이다. 배송이 늦어 화가 났지만 묻는 것은 언제 오느냐인 경우, 답변에 필요한 것은 사과 문장이 아니라 정확한 날짜다.

과한 공감의 역효과

공감 표현을 프롬프트에 강하게 넣으면 답변이 길어지면서 정작 답이 뒤로 밀린다. 「불편을 끼쳐 드려 진심으로 죄송합니다」로 시작해 세 문장이 지난 뒤에야 배송 예정일이 나오는 식이다. 고객이 원하는 정보가 스크롤 아래에 있으면 공감이 아니라 지연으로 읽힌다.

기준을 세워 두는 편이 낫다. 사과는 한 문장, 그다음은 바로 사실이다. 그리고 상황을 확인하지 않은 채 사과부터 하는 것은 피해야 한다 — 고객의 주장이 사실과 다를 때 먼저 한 사과가 뒤에 오는 안내와 부딪힌다. 「죄송합니다」로 시작해 「확인 결과 정상 발송되었습니다」로 이어지는 답변은 무엇에 대한 사과인지가 없어서 읽는 쪽을 더 불쾌하게 만든다.

답변 길이 자체를 제한해 두는 것도 듣는다. 문장 수의 상한을 프롬프트에 적고 발신 전 검사에서도 재면, 공감 표현이 늘어나는 만큼 사실이 밀려나는 구조 자체가 막힌다.

약속하면 안 되는 것

톤을 다루는 프롬프트에 반드시 함께 넣어야 하는 것이 금지 목록이다. 공감적으로 답하라는 지시는 모델을 고객 편에 서게 만들고, 그 상태에서는 확인되지 않은 것을 긍정하는 쪽으로 기운다. 보상이나 할인을 임의로 제안하는 것, 처리 기한을 단정하는 것, 정책 예외를 시사하는 것이 실제로 새어 나오는 자리다.

이 금지 목록은 프롬프트에만 두지 말고 앞서 말한 발신 전 검사에도 같은 항목을 넣는다. 지시로 한 번, 코드로 한 번 거르는 이중 구조여야 한다.

운영 지표

자동 처리율

자동 처리율은 전체 문의 중 상담원을 거치지 않고 끝난 비율이다. 가장 많이 보는 숫자이지만 혼자 보면 위험하다. 이 값은 답변 품질을 낮추면 언제든 올라가기 때문에, 반드시 만족도와 재문의율 옆에 놓고 봐야 한다.

분모도 정해 두어야 한다. 챗봇 창을 열었다가 닫은 것, 자동 답변 뒤에 고객이 다시 쓴 것을 어떻게 셀지에 따라 같은 시스템의 값이 크게 달라진다. 정의를 문서에 적어 두고 바꾸지 않는 것이 숫자 자체보다 중요하다 — 절대값보다 추세를 보는 지표다.

비용도 이 값에 붙여 함께 본다. 티켓 한 건을 처리하는 데 드는 모델 호출은 분류 한 번과 답변 생성 한 번, 넘어가는 건은 요약 한 번이 더 붙는다. 건당 토큰을 실제로 세어 월 문의량을 곱하면 자동화의 운영비가 나오고, 그것을 줄어든 상담 시간과 나란히 놓아야 판단이 선다. 대개 모델 비용보다 상담 시간의 값이 훨씬 커서 계산은 금방 끝나지만, 분류를 큰 모델로 돌리거나 실패한 답변을 여러 번 다시 생성하는 구조를 두면 이 비율이 빠르게 나빠진다.

만족도와 재문의율

만족도 점수는 응답률이 낮고 편향이 있다. 매우 만족했거나 매우 불만인 고객만 답하는 경향이 있어, 평균이 실제 경험을 대표하지 못한다. 그래서 자동 답변과 상담원 답변의 만족도를 같은 조건에서 비교해야 의미가 생긴다. 뒤에서 말할 품질 샘플링이 그 조건을 만든다.

재문의율은 같은 문제로 다시 연락한 비율이고, 만족도보다 조작하기 어려워 신뢰도가 높다. 답변이 형식만 그럴듯하고 문제를 해결하지 못했다면 고객은 반드시 다시 연락한다. 만족도가 유지되는데 재문의율이 오르고 있다면 답변이 정중하지만 쓸모없어지고 있다는 뜻이다.

품질 샘플링

자동 답변 가능으로 판정된 티켓 중 일부를 일부러 상담원에게 보낸다. 자동화의 목적에는 어긋나 보이지만, 이것이 비교 기준선을 만드는 유일한 방법이다. 같은 조건의 티켓이 양쪽으로 나뉘어야 만족도 차이를 답변 방식의 차이로 읽을 수 있다.

import random

def process_ticket(text: str, conn) -> dict:
    cls = classify_ticket(text)
    esc, reason = should_escalate(cls, attempts=0)
    if esc:
        return {"type": "escalation", "data": escalate_to_agent(text, cls, reason)}

    if random.random() < 0.1:            # 비교 기준선 확보
        return {"type": "quality_sample",
                "data": escalate_to_agent(text, cls, "품질 샘플링")}

    reply = generate_auto_reply(text, cls, conn)
    if reply is None:
        return {"type": "escalation", "data": escalate_to_agent(text, cls, "근거 없음")}
    return {"type": "auto_reply", "reply": reply, "classification": cls}

샘플링 비율은 상담팀이 감당할 수 있는 선에서 정한다. 초기에는 10% 정도로 두고, 지표가 안정되면 5%까지 줄여도 비교는 유지된다. 이 비율을 0으로 만드는 순간 자동 답변의 품질을 잴 수 있는 기준이 사라진다는 점만 기억하면 된다.

그리고 이 모든 지표는 유형별로 나눠 봐야 한다. 전체 평균은 상위 유형에 눌려 움직이지 않고, 문제는 거의 언제나 특정 유형 하나에서 시작한다.


읽어주셔서 감사합니다. 😊

LATEST

개발·프레임워크의 최신 글

개발·프레임워크2026.05.28

Google Gemini SDK 활용 가이드

google-genai 패키지의 Client 하나로 Gemini API를 부르는 법 — 응답 객체와 finish_reason, 생성 설정과 구조화 출력, 인라인 데이터와 Files API, 도구 호출 왕복, 안전 설정과 재시도, 대화 비용과 컨텍스트 캐싱까지 정리한다.

26 MIN
개발·프레임워크2026.05.28

OpenAI SDK 완전 정복

Python openai 패키지로 OpenAI API를 다루는 법 — 클라이언트 설정과 재시도, 메시지와 응답 구조, Responses API 대응, 모델 고르는 축, 도구 호출 루프, 구조화 출력, 임베딩·이미지 입력, 토큰 비용과 한도까지 정리

30 MIN