Skip to main content
Summary

Promptfoo가 뭔가

Promptfoo는 LLM 프롬프트(또는 에이전트 출력)를 "테스트 가능한 산출물"로 보고, 입력(테스트 케이스)과 기대 조건(어서션)을 정의해 반복 실행·비교·회귀(regression) 검증을 돕는 도구다.1 코드 테스트처럼 프롬프트/모델 변경이 실제 품질에 어떤 영향을 주는지 숫자와 리포트로 남기는 데 초점이 있다.12

언제 쓰나(개념과 용도)

프롬프트를 조금만 바꿔도 답변 톤, 사실성, 포맷이 흔들릴 때가 많다. 이때 Promptfoo는 "몇 개 예시로 잘 되는지" 감으로 판단하는 대신, 테스트 케이스 묶음을 돌려 점수와 실패 케이스를 누적한다.1 모델을 바꾸거나(system prompt, RAG 컨텍스트, 템플릿, 파라미터 등) 배포 전후에 결과가 나빠졌는지 확인하는 용도로도 자주 쓴다.2

핵심 기능 요약

프롬프트/모델 비교는 같은 테스트 케이스를 여러 프롬프트(또는 여러 모델/provider)에 동시에 실행해 결과를 나란히 비교하는 방식이다.1

평가/어서션은 출력이 "정답 문자열과 완전 일치"가 아니어도, 포함/정규식/JSON 스키마/커스텀 JS 등 다양한 조건으로 합격·불합격을 정한다.1 정량 점수가 필요하면 LLM-as-a-judge 같은 채점 방식도 붙일 수 있다.1

테스트 케이스는 입력 변수(예: question, context)와 기대 조건을 케이스 단위로 관리한다. 케이스를 늘려가며 "우리가 중요하게 생각하는 실패 유형"을 회귀 테스트로 고정할 수 있다.1

리그레션/CI는 CLI 실행이 가능해서, PR마다 자동으로 돌려 실패를 막는 흐름을 만들 수 있다.2 특히 "프롬프트는 코드와 다르게 리뷰만으로 품질을 예측하기 어렵다"는 점에서 CI가 가치가 있다.

리포트는 실행 결과를 표 형태로 보여주고, 어떤 케이스에서 어떤 변형이 실패했는지 추적하게 해준다.1

기본 워크플로(실무에서 이렇게 굴린다)

먼저 "지금 우리가 원하는 출력 조건"을 어서션으로 적는다. 그다음 대표적인 질문/컨텍스트를 테스트 케이스로 모으고, 현재 프롬프트(또는 모델)를 기준선(baseline)으로 실행해 결과를 저장한다.1

이후 프롬프트/모델을 바꿀 때마다 동일 케이스를 다시 실행해, 점수 하락이나 특정 케이스 실패가 생겼는지 확인한다. 실패 케이스는 대부분 제품에서 자주 나오는 불만(헷갈리는 답, 포맷 깨짐, 금칙어 포함, 환각 등)과 연결되므로, 케이스를 계속 보강하면서 "품질 기준"을 팀 자산으로 만든다.

설치와 최소 예시(YAML 기반)

로컬 설치는 보통 npm으로 한다.2

npm install -D promptfoo
# 또는
npx promptfoo --help

아래는 아주 작은 promptfooconfig.yaml 예시다. "모델 2개를 같은 케이스로 비교"하고, 답변에 특정 단어가 포함되는지로 단순 합격/불합격을 만든다.1

# promptfooconfig.yaml
description: "간단 비교 예시"

providers:
  - openai:gpt-4o-mini
  - openai:gpt-4.1-mini

prompts:
  - "질문: {{question}}n한국어로 한 문단으로 답해줘."

tests:
  - vars:
      question: "Promptfoo는 무엇에 쓰는 도구야?"
    assert:
      - type: icontains
        value: "테스트"

실행은 아래처럼 한다.2

npx promptfoo eval -c promptfooconfig.yaml

팀에서 자주 쓰는 패턴은 "프롬프트를 2~3개 후보로 두고(prompts 배열), 테스트 케이스는 늘려가면서 가장 안정적인 조합을 고르는 방식"이다. 이때 어서션은 너무 엄격하게 "정답 문장 일치"를 강제하기보다, 제품 요구(형식, 금칙어, 핵심 정보 포함, 길이 제한 등)부터 고정해두는 편이 유지보수가 쉽다.

실무 활용 체크리스트와 팁

  • 테스트 케이스는 "좋은 예시"보다 "자주 깨지는 예시(엣지/클레임/규정/긴 입력)"를 우선으로 모은다.

  • 어서션은 처음부터 완벽하게 만들려고 하지 말고, 실패 로그를 보며 조건을 조금씩 현실화한다(너무 엄격하면 전부 빨간불이 된다).

  • 포맷이 중요한 출력은 JSON 스키마/정규식 같은 "형식 어서션"을 먼저 걸고, 내용 평가는 그다음에 붙인다.

  • 모델 비교는 비용이 커지기 쉬우니, CI에서는 케이스 수를 줄인 "스모크 세트"와 배치로 돌리는 "풀 세트"를 분리한다.

  • LLM 채점(judge)을 쓸 때는 채점 프롬프트/모델도 버전 관리하고, 동일 조건으로 재현 가능하게 고정한다.

  • 실패 케이스는 그냥 고치고 끝내지 말고 "케이스로 박제"해서 같은 문제가 다시 나오지 않게 만든다.

한계와 주의사항

LLM 출력은 본질적으로 변동성이 있어, 같은 입력이라도 미세하게 다른 문장이 나올 수 있다. 그래서 "문장 일치" 중심 테스트는 쉽게 깨지고, 제품 요구에 가까운 조건(포맷/핵심 포함/금칙어/길이 등)으로 설계하는 편이 현실적이다.1

또한 LLM-as-a-judge 평가는 편리하지만, 채점 모델 자체의 편향과 일관성 문제가 들어온다. "사람이 보기엔 별로인데 점수는 높게 나오는" 상황이 생길 수 있으니, 중요한 품질 축은 사람이 정의한 규칙(형식/정책) + 샘플링된 수동 리뷰를 같이 두는 게 안전하다.

마지막으로 비용과 데이터 취급도 고려해야 한다. CI에서 외부 LLM API를 호출하면 비용이 누적되고, 입력에 민감 정보가 섞이면 그대로 전송될 수 있다. 운영 환경의 실제 데이터로 테스트할 땐 익명화/마스킹, 그리고 provider 설정을 포함한 보안 정책 점검이 필요하다.12

참고

1promptfoo 공식 문서

2promptfoo GitHub 저장소

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기