Skip to content
Announcements7 min read

Potato 2.3: 에이전트 어노테이션, Solo Mode, Best-Worst Scaling

Potato 2.3.0은 인간-LLM 레이블링을 위한 Solo Mode, 에이전트 트레이스 어노테이션, Best-Worst Scaling, SSO 및 OAuth 로그인, Parquet 내보내기, 15개의 데모 프로젝트를 추가합니다.

Potato Team

참고: 이 게시물은 2026년 3월 출시 당시의 Potato 2.3을 설명합니다. 아래 설정 키 중 일부는 이후 버전에서 이름이 바뀌거나 다른 키로 대체되었으며, 현재 구문은 문서에 있습니다. 이 블록들을 현재 버전의 Potato를 사용하는 프로젝트에 복사하지 마세요.

Potato 2.3.0은 문서화된 10개 단계를 거치는 인간-LLM 레이블링 워크플로인 Solo Mode를 추가합니다. 이와 함께 등록된 트레이스 변환기 11개를 갖춘 에이전트 트레이스 어노테이션, 세 가지 점수 산출 방법을 갖춘 Best-Worst Scaling, Google, GitHub 및 일반 OIDC 공급자를 위한 SSO 및 OAuth 로그인, Parquet 내보내기, 15개의 데모 프로젝트가 추가되었습니다. 릴리스 노트에는 2.2.0 이후 50개 이상의 커밋과 8개 모듈에 걸친 12개 보안 취약점의 수정이 기록되어 있습니다.

이번 릴리스는 사람들이 어노테이션하는 대상의 변화에 따른 것입니다. 2년 전 감정과 개체명을 레이블링하던 연구자들은 이제 다단계 에이전트 트레이스를 세밀하게 분석하고, 모델 출력을 대량으로 비교하며, Potato의 스키마 세트가 설계될 때는 존재하지 않던 작업을 위한 데이터셋을 구축합니다. Solo Mode와 에이전트 트레이스 작업은 모두 이 변화를 겨냥합니다.

업그레이드

bash
pip install --upgrade potato-annotation==2.3.0

Parquet 내보내기에는 PyArrow 12.0.0 이상이 필요하며, 이는 별도로 설치합니다:

bash
pip install "pyarrow>=12.0.0"

에이전트 트레이스 어노테이션

에이전트 실행은 도구 호출, 추론 단계, 중간 출력의 연속이며, 이를 일반 텍스트로 평탄화하면 평가자가 봐야 할 구조가 사라집니다. 그래서 Potato 2.3은 트레이스를 디스플레이 시스템으로 렌더링하여, 트레이스를 대화 형태로 배치하고 개별 턴에 평가를 붙입니다.

디스플레이는 instance_display에서 선언하며, 턴별 평가 스킴은 대화를 담은 필드 아래에 중첩됩니다:

yaml
instance_display:
  layout:
    direction: vertical
    gap: 16px
  fields:
    - key: task_description
      type: text
      label: "Task"
    - key: conversation
      type: dialogue
      label: "Agent Trace"
      span_target: true
      display_options:
        show_turn_numbers: true
        alternating_shading: true

2.3에서 에이전트 작업을 담당하는 디스플레이 타입은 두 가지입니다. dialogue 디스플레이는 트레이스를 턴 단위로 렌더링하고 턴 위에서의 스팬 어노테이션을 지원하며, interactive_chat은 어노테이터가 나중에 읽는 것이 아니라 직접 참여하는 대화를 다룹니다. span_target: true를 설정해야 어노테이터가 턴 안의 구절을 하이라이트할 수 있으며, 환각과 근거 없는 주장은 이런 방식으로 발생한 위치에 표시됩니다.

다른 프레임워크의 트레이스는 변환기를 통해 들어오며, 이번 릴리스에서 변환기에 등록된 형식은 11개입니다: openai, anthropic, swebench, otel, mcp, multi_agent, langchain, langfuse, react, webarena, atif.

bash
python -m potato.trace_converter -i traces.json -f react -o data/traces.jsonl

Solo Mode

여러 어노테이터를 두는 레이블링에는 사람을 고용하고, 교육하고, 조율하는 일이 필요하며, 많은 연구 프로젝트에서는 어노테이션 인터페이스보다 이 운영상의 문제가 병목입니다. Solo Mode는 대신 한 명의 도메인 전문가와 LLM을 짝지웁니다. 인간이 레이블을 달고, LLM이 제안하고, 각 수정 사항이 프롬프트에 다시 반영되며, 둘의 판단이 수렴할수록 인간은 대기열의 더 많은 부분을 넘겨줍니다.

워크플로는 문서화된 10개 단계를 거칩니다: 설정, 프롬프트 검토, 엣지 케이스 합성, 엣지 케이스 레이블링, 프롬프트 검증, 병렬 어노테이션, 불일치 해소, 주기적 검토, 자율 레이블링, 최종 검증. 모든 프로젝트가 모든 단계를 거치지는 않습니다.

yaml
solo_mode:
  enabled: true
 
  labeling_models:
    - endpoint_type: "ollama"
      model: "qwen3:4b"
      endpoint_url: "http://localhost:11434"
      max_tokens: 256
      temperature: 0.1
 
  revision_models:
    - endpoint_type: "ollama"
      model: "qwen3:4b"
      endpoint_url: "http://localhost:11434"
 
  uncertainty:
    strategy: "direct_confidence"
 
  thresholds:
    end_human_annotation_agreement: 0.90
    minimum_validation_sample: 20
    confidence_low: 0.5
    periodic_review_interval: 50
 
  instance_selection:
    low_confidence_weight: 0.4
    diversity_weight: 0.3
    random_weight: 0.2
    disagreement_weight: 0.1
 
  state_dir: "solo_state"

instance_selection의 네 가중치는 어떤 항목이 인간의 주의를 받을 가치가 있는지 결정합니다. 낮은 신뢰도에 0.4, 다양성에 0.3의 가중치를 두면 인간의 시간 대부분이 모델이 확신하지 못하는 인스턴스로 가면서도, 체계적 오류를 알아챌 만큼 분포의 나머지 부분도 다루게 됩니다. 무작위 샘플링의 0.2는 end_human_annotation_agreement의 일치도 추정치를 의미 있게 만드는 값입니다. 어려운 인스턴스만으로 계산한 일치율은 코퍼스 전체에서 얻는 일치율과 다르기 때문입니다.

Solo Mode에는 85개의 통합 테스트 및 엔드투엔드 테스트, 개발자 가이드, 그리고 examples/advanced/solo-mode/와 examples/advanced/simple-solo-mode/에 있는 두 개의 예제 프로젝트가 포함되어 있습니다. 간단한 쪽부터 시작하세요. 로컬 Ollama 모델로 실행되고 API 키가 필요 없으므로, 처음 평가하는 대상이 모델이 비용만큼의 가치가 있는지가 아니라 워크플로가 작업에 맞는지가 됩니다.

Best-Worst Scaling

Best-Worst Scaling은 어노테이터에게 항목들의 튜플(보통 네 개)을 보여 주고, 하나의 기준에 따라 가장 좋은 것과 가장 나쁜 것만 고르게 합니다. 이 두 선택에는 일련의 쌍대 비교가 함축되어 있으며, 서로 겹치는 많은 튜플에 걸친 점수는 평점을 매기는 것보다 빠르게 내릴 수 있는 판단으로부터 실수 척도 위에 산출됩니다.

yaml
annotation_schemes:
  - annotation_type: bws
    name: sentiment_bws
    description: "Sentiment Intensity"
    best_description: "Which sentence expresses the MOST positive sentiment?"
    worst_description: "Which sentence expresses the LEAST positive sentiment?"
    tuple_size: 4
    sequential_key_binding: true

수집된 튜플에는 세 가지 점수 산출 방법을 적용합니다. counting은 (best_count - worst_count) / appearances로 계산하는 투명한 기준선으로, 추가 의존성이 필요 없고 결정론적입니다. bradley_terry는 쌍대 비교 모델을 적합하여 로그 척도의 강도 파라미터를 산출합니다. plackett_luce는 전체 순위 모델을 적합합니다. 모델 기반의 두 방법에는 pip install choix가 필요합니다.

bash
python -m potato.bws_scoring --config config.yaml --method bradley_terry

점수는 출력 디렉터리의 bws_scores.tsv에 기록되며, 각 항목의 점수, 순위, best와 worst 횟수, 출현 횟수가 담깁니다. 관리자 대시보드에는 BWS Scoring 탭이 있어 버튼 하나로 같은 계산을 실행하고 결과를 표로 보여 줍니다.

SSO와 OAuth

어노테이터가 인터넷으로 접속하는 배포에는 실제 계정이 필요하며, 2.3은 OAuth 2.0과 OpenID Connect를 추가하여 어노테이터가 이미 가진 ID를 사용할 수 있게 합니다. Google, GitHub 및 모든 일반 OIDC 공급자를 지원하며, 이메일 도메인이나 GitHub 조직으로 접근을 제한할 수 있습니다.

yaml
authentication:
  method: "oauth"
  providers:
    google:
      client_id: ${GOOGLE_CLIENT_ID}
      client_secret: ${GOOGLE_CLIENT_SECRET}
  user_identity_field: "email"
 
secret_key: ${POTATO_SECRET_KEY}

이 블록을 설정 파일에 추가하세요. 여기에는 두 가지 요구 사항이 따릅니다. OAuth에는 HTTPS 배포가 필요하고(개발용으로 localhost는 예외), 안정적인 secret_key도 필요합니다. 재시작할 때마다 바뀌는 서명 키는 로그인이 이미 발급한 세션을 무효화하기 때문입니다. 공급자에 리디렉션 URI를 https://your-domain.com/auth/callback/google 형태로 등록하되, 공급자 이름 부분을 바꿔 넣으세요.

Parquet 내보내기

어노테이션 데이터가 열 기반 형식을 요구하는 분석 도구로 넘어가는 일이 늘고 있어, 2.3은 내보내기 레지스트리에 Parquet을 추가합니다. 내보내기는 최대 세 개의 테이블을 생성합니다: 인스턴스와 어노테이터마다 한 행인 annotations.parquet, 스팬 어노테이션마다 한 행인 spans.parquet, 원본 데이터를 담은 items.parquet.

bash
python -m potato.export -c config.yaml -f parquet -o ./export/

옵션은 프로젝트에서 설정하지 않고 명령줄로 전달하며, 압축 코덱은 snappy(기본값), gzip, zstd, lz4, none 중 하나입니다:

bash
python -m potato.export -c config.yaml -f parquet -o ./export/ \
    --option compression=gzip --option include_items=false

테이블은 인스턴스 키로 조인되지만, 열 이름은 테이블마다 다릅니다. annotations.parquet와 spans.parquet에는 instance_id가 있고, items.parquet에는 item_id가 있습니다. 덕분에 먼저 pandas로 아무것도 불러오지 않고도 DuckDB에서 내보낸 데이터를 사용할 수 있습니다:

python
import duckdb
duckdb.sql("""
  SELECT i.item_id, a.user_id, a.*
  FROM './export/annotations.parquet' a
  JOIN './export/items.parquet' i ON a.instance_id = i.item_id
""")

annotations.parquet는 인스턴스와 어노테이터마다 한 행이며, 각 어노테이션 스킴은 자체 열로 평탄화되므로 선택할 수 있는 일반적인 value 열은 없습니다. 여러 답을 한꺼번에 저장하는 스킴은 <scheme>.<part> 형식의 점으로 구분된 하위 열로 펼쳐집니다.

보안 수정

이번 릴리스는 8개 모듈에 걸친 12개의 보안 취약점을 수정하며, 25개 파일에 걸친 XSS, 견고성, 데이터 무결성 문제와, 딕셔너리의 값 대신 키를 순회하여 링크 레코드를 남겨 두던 스팬 삭제 연쇄 처리도 함께 수정합니다. 의존성 감사를 통해 Python과 JavaScript 의존성을 현재 버전으로 올렸습니다.

다른 수정 중 두 가지는 이미 수집한 데이터를 바꿔 놓았을 수 있습니다. has_free_response 불리언 충돌(issue #111)과 전체 단계 탐색 루프는 모두 어노테이션이 의도대로 기록되는지에 영향을 주었고, 동적 multirate의 따옴표 처리는 그 값이 기록되는 방식에 영향을 주었습니다. 2.2에서 자유 응답 옵션이나 multirate 스킴을 사용해 연구를 진행했다면, 출력을 최종본으로 간주하기 전에 확인하세요.

데모 프로젝트

이번 릴리스에는 demo/ 아래에 15개의 데모 프로젝트가 포함되어 있으며, 서로를 기반으로 쌓이는 순서대로 01-sentiment-admin부터 15-agentic-chat까지 번호가 매겨져 있습니다. 스팬, 사용자 정의 모더레이션 레이아웃, 이미지 분류, 오디오 감정, 비디오, 멀티모달 항목, 판정, 슬라이더, 바운딩 박스, 의존 트리, 계층형 ELAN 어노테이션, 에이전트 채팅을 다룹니다. 각 데모 디렉터리에는 config.yaml과 해당 data/가 있으며, 전체 모음은 미디어 기반 데모에 필요한 미디어를 생성하는 스크립트 하나를 공유합니다.

bash
# From the repository root: generates the demo data, then starts all 15 servers
bash demo/launch.sh

위에 언급한 모든 수정을 포함한 전체 변경 로그는 저장소의 v2.3.0 릴리스 노트를 참조하세요. 이슈는 GitHub에 등록하거나 GitHub Discussions에서 스레드를 시작하세요.

링크