Show HN: MonkeyPatch – Python에서 저렴하고 빠르며 예측 가능한 LLM 함수 구현
요약
MonkeyPatch(Tanuki)는 Python 함수를 LLM 기반 함수로 쉽게 전환할 수 있게 해주는 라이브러리입니다. 데코레이터 방식을 통해 타입 안정성과 신뢰성을 보장하며, 사용량이 늘어날수록 모델 증류(distillation)를 통해 비용과 지연 시간을 획기적으로 줄여줍니다.
핵심 포인트
- @tanuki.patch 데코레이터를 사용하여 기존 Python 함수를 LLM 기반 함수로 즉시 변환 가능
- Pydantic 및 Python 타입 힌트를 지원하여 LLM 출력의 타입 안정성 보장
- 자동 모델 증류 기술을 통해 비용 최대 90%, 지연 시간 최대 80% 절감 가능
- OpenAI, Amazon Bedrock, Together AI 등 다양한 모델 및 RAG 워크플로우 지원
- assert 문을 활용한 Test-Driven Alignment로 LLM 출력의 신뢰성 확보
시간이 지남에 따라 비용 효율적이고 빠르게 작동하는 LLM 기반 앱을 쉽게 구축하세요.
Discord에서 저희와 함께 하세요.
- 소개
- 기능
- 설치 및 시작하기
- 작동 방식
- Typed Outputs
- Test-Driven Alignment
- 확장 및 파인튜닝
- 자주 묻는 질문
- 간단한 ToDo 리스트 앱
Tanuki는 Python에서 함수 본체 대신 LLM을 쉽게 호출하는 방법으로, 수동으로 구현된 함수가 제공할 것으로 예상되는 것과 동일한 매개변수와 출력을 가집니다.
이러한 LLM 기반 함수들은 타입 지정(well-typed)되어 있고, 신뢰성이 높으며(reliable), 상태 비저장(stateless)이며, 앱에 원활하게 적용할 수 있는 프로덕션 준비가 되어 있습니다. 끝없는 프롬프트 조작과 예상치 못한 문제들 대신, 이러한 LLM 기반 함수와 애플리케이션은 적절한 오류 처리를 갖춘 전통적인 함수처럼 작동합니다.
마지막으로, Tanuki 함수를 많이 사용할수록 자동 모델 증류(automatic model distillation)를 통해 더 저렴하고 빠르게 됩니다 (최대 9~10배!).
@tanuki.patch
def some_function(input: TypedInput) -> TypedOutput:
"""(선택 사항) 함수가 어떻게 사용될지에 대한 설명을 포함하세요."""
...
쉽고 원활한 통합: 몇 초 만에 모든 워크플로우에 LLM 증강 함수를 추가하세요. @tanuki.patch로 함수 스텁을 데코레이트하고, 선택적으로 타입 힌트와 독스트링을 추가하여 실행을 안내하면 됩니다. 끝입니다.
타입 인식(Type aware): LLM의 출력이 함수의 타입 제약 조건(Python 기본 타입, Pydantic 클래스, 리터럴, Generics 등)을 준수하도록 보장하여 LLM 사용 시 발생할 수 있는 버그나 예상치 못한 부작용으로부터 보호합니다.
정렬된 출력(Aligned outputs): LLM은 신뢰성이 낮아 전통적으로 프로그래밍된 함수를 대신하는 데 어려움이 있습니다. @tanuki.align으로 데코레이트된 함수에서 간단한 assert 문을 사용하면 됩니다.
, 패치된 함수의 동작을 기대하는 바와 일치시킬 수 있습니다.
더 낮은 비용과 지연 시간 (Lower cost and latency)
- 사용량이 증가함에 따라 비용은 최대 90%, 지연 시간 (latency)은 최대 80%까지 절감할 수 있습니다. 이 패키지는 지식 증류 (distillation)를 통해 LLM의 능력을 향상시키기 위한 모델 학습, MLOps 및 DataOps 노력을 대신 처리합니다.
대중적인 모델 지원 (Popular model support)
- Tanuki는 함수 실행을 위해 다양한 대중적인 모델 (OpenAI, Amazon Bedrock, Together AI)을 지원합니다.
RAG 지원 (RAG support)
- 다운스트림 RAG (Retrie-Augmented Generation, 검색 증강 생성) 구현을 위해 임베딩 (embedding) 출력을 원활하게 가져올 수 있습니다. 출력된 임베딩은 쉽게 저장되어 관련 문서 검색에 사용될 수 있으며, 이를 통해 비용과 지연 시간을 줄이고 긴 형식의 콘텐츠 (long-form content)에 대한 성능을 향상시킬 수 있습니다.
모든 기능 포함 (Batteries included)
- OpenAI 이외의 원격 의존성 (remote dependencies)이 없습니다.
pip install tanuki.py
또는 Poetry를 사용하여:
poetry add tanuki.py
다음 명령어로 OpenAI 키를 설정하세요:
export OPENAI_API_KEY=sk-...
시작하는 방법:
- 타입 힌트 (type hints)와 독스트링 (docstring)을 포함하여
@tanuki.patch로 데코레이트된 Python 함수 스텁 (stub)을 생성합니다. - (선택 사항) 다양한 입력값에 대해 패치된 함수의 기대 동작을 선언하는 일반적인
assert문을 포함하고,@tanuki.align으로 데코레이트된 또 다른 함수를 생성합니다. - (선택 사항) 함수에 사용할 모델을 구성합니다. 기본적으로 GPT-4가 사용되지만, 저희 스택에서 지원하는 다른 모델을 사용하려면
@tanuki.patch연산자에서 구성하면 됩니다. Amazon Bedrock 모델과 Together AI 모델을 정확히 어떻게 구성하는지는 문서를 통해 확인할 수 있습니다. 이제 패치된 함수를 코드의 나머지 부분에서 일반적인 방식과 동일하게 호출할 수 있습니다.
기능적 정렬 (functional alignment)을 추가하려면, 다음과 같은 경우에 align으로 주석 처리된 함수도 반드시 호출해야 합니다:
- 패치된 함수를 처음 호출하는 경우 (함수 시그니처의 모든 업데이트 포함, 즉 독스트링, 입력 인자, 입력 타입 힌트, 명명 규칙 또는 출력 타입 힌트 변경 시)
assert문을 수정한 경우
간단한 분류 (classification) 함수의 경우 다음과 같은 모습일 수 있습니다:
@tanuki.patch
def classify_sentiment(msg: str) -> Optional[Literal['Good', 'Bad']]:
"""사용자의 메시지를 Good, Bad 또는 None으로 분류합니다."""
...
패치된 Tanuki 함수의 설정 옵션은 여기를 참조하세요.
개발 중에 tanuki로 패치된 함수를 호출하면, n-shot 구성의 LLM이 호출되어 타입이 지정된 응답 (typed response)을 생성합니다.
사용되는 예시의 수는 align 데코레이터가 지정된 함수에 제공된 align 문(statements)의 수에 따라 달라집니다.
응답은 후처리 (post-processed)되며, 제공된 출력 타입이 프로그래밍 방식으로 인스턴스화되어 올바른 타입이 반환되도록 보장합니다.
이 응답은 애플리케이션의 나머지 부분으로 전달하거나, DB에 저장하거나, 사용자에게 표시할 수 있습니다.
예상되는 동작이 등록될 수 있도록, 패치된 함수를 실행하기 전에 모든 align 함수를 최소 한 번은 실행해야 합니다. 이들은 향후 참조를 위해 디스크에 캐싱 (cached)됩니다.
함수의 입력과 출력은 실행 중에 향후 학습 데이터 (training data)로 저장됩니다. 데이터 양이 증가함에 따라, 더 큰 모델의 출력을 사용하여 점점 더 작은 모델들이 증류 (distilled)됩니다.
작은 모델들은 MLOps의 노력 없이도 더 낮은 계산 비용 (computational cost)과 낮은 지연 시간 (latency)으로 원하는 동작과 성능을 포착할 것입니다.
LLM API의 출력은 일반적으로 자연어 (natural language)입니다. 많은 경우, 워크플로에 더 잘 통합하기 위해 출력 형식에 제약을 두는 것이 바람직합니다.
Tanuki의 핵심 개념은 타입이 지정된 매개변수 (typed parameters)와 출력 (outputs)을 지원하는 것입니다. 패치된 함수의 타입이 지정된 출력을 지원함으로써, 프로그램의 나머지 부분에서 사용할 수 있도록 패치된 함수가 반환할 수 있는 데이터의 종류에 대한 규칙을 선언할 수 있습니다. 이는 가능한 한
Literals를 사용하거나 Pydantic에서 커스텀 타입 (custom types)을 생성하여, 패치된 함수가 반환할 수 있는 데이터에 대한 매우 복잡한 규칙을 표현할 수 있습니다. 이는 모델을 위한 가드레일 (guard-rails) 역할을 하여, 패치된 함수가 코드나 다운스트림 워크플로우 (downstream workflows)를 망가뜨리는 것을 방지하며, 애플리케이션에서 별도의 커스텀 검증 로직 (custom validation logic)을 작성할 필요가 없음을 의미합니다.
@dataclass
class ActionItem:
goal: str = Field(description="완료해야 하는 작업")
...
패치된 함수를 통과할 수 있는 데이터의 타입을 제한함으로써, 모델이 반환할 수 있는 잠재적 출력값을 선언하고 프로그램이 존재하는 세계를 명시하게 됩니다.
Pydantic 필드 값에 대해 출력값의 정수 제약 조건 (integer constraints)을 추가할 수 있으며, 원하는 경우 제네릭 (generics)도 사용할 수 있습니다.
@tanuki.patch
def score_sentiment(input: str) -> Optional[Annotated[int, Field(gt=0, lt=10)]]:
"""입력값을 0-10 사이로 점수화합니다"""
...
다양한 사용 사례(FastAPI와의 통합 방법 포함)에서 Tanuki를 사용하는 더 많은 예시를 보려면, examples를 확인하세요.
RAG 지원을 위한 임베딩 (embedding) 출력에 대해서는 여기를 참조하세요.
전통적인 테스트 주도 개발 (TDD)에서는 코드를 통과시키기 위한 코드를 작성하기 전에 실패하는 테스트를 작성하는 것이 표준 관행입니다.
테스트 주도 정렬 (Test-Driven Alignment, TDA)은 이 개념을 응용하여, 패치된 함수의 동작을 테스트에 의해 정의된 기대치와 일치시킵니다.
패치된 함수의 동작을 사용자의 요구사항에 맞게 정렬하려면, 함수에 @align 데코레이터를 사용하세요.
그리고 표준 테스트에서와 마찬가지로 'assert' 문을 사용하여 함수의 출력을 단언 (assert)합니다.
@tanuki.align
def align_classify_sentiment():
assert classify_sentiment("I love this!") == 'Good'
...
tanuki로 패치된 함수의 기대 동작을 캡슐화하는 테스트를 작성함으로써, 함수가 반드시 이행해야 하는 계약 (contract)을 선언하게 됩니다. 이를 통해 다음과 같은 작업이 가능해집니다:
기대 사항 검증 (Verify Expectations): 함수가 원하는 출력에 부합하는지 확인합니다.
행동적 뉘앙스 포착 (Capture Behavioural Nuances): LLM이 테스트에서 규정된 엣지 케이스 (edge cases)와 뉘앙스를 준수하는지 확인합니다.
반복적 개발 (Develop Iteratively): 원하는 동작을 테스트로 선언함으로써 tanuki-patched 함수의 동작을 개선하고 업데이트합니다.
테스트를 통과하는 코드를 작성하는 것이 목적인 전통적인 TDD (Test-Driven Development)와 달리, TDA (Test-Driven Alignment)는 방식을 뒤집습니다: 테스트는 실패하지 않습니다. 테스트의 존재와 그 형태만으로도 LLM이 기대되는 동작에 스스로를 정렬 (align)하기에 충분합니다.
TDA는 기존 또는 새로운 Python 코드베이스에 머신러닝 (machine learning)을 접목하기 위한 가볍고도 강력한 방법론을 제공합니다. 이는 TDD의 예방적 미덕을 결합하는 동시에, LLM의 역동성으로 인해 발생하는 특수한 과제들을 해결합니다.
(함수 체인 정렬은 현재 개발 진행 중입니다)
def test_score_sentiment():
"""Pytest 또는 Unittest를 사용하여 일반적인 방식으로 함수를 테스트할 수 있습니다"""
assert multiply_by_two(score_sentiment("I like you")) == 14
...
워크플로우에 Tanuki를 사용할 때의 장점은 데이터 포인트 (datapoints)의 수가 증가함에 따라 비용과 지연 시간 (latency) 측면에서 이점을 얻을 수 있다는 것입니다.
미세 조정 (finetuning)에 적합한 패치된 함수의 성공적인 실행 결과는 학습 데이터셋 (training dataset)으로 저장되며, 이는 각 패치된 함수를 위한 더 작은 모델을 증류 (distil)하는 데 사용됩니다. 모델 증류 (Model distillation) 및 의사 라벨링 (pseudo-labelling)은 성능에 미치는 영향은 미미하고 적은 비용을 들여 모델 크기를 줄이고 지연 시간 및 메모리 사용량 (memory footprints)을 개선할 수 있는 검증된 방법입니다 (https://arxiv.org/pdf/2305.02301.pdf, https://arxiv.org/pdf/2306.13649.pdf, https://arxiv.org/pdf/2311.00430.pdf, 등).
더 작은 함수 전용 모델을 학습시키고 배포하는 과정은 Tanuki 라이브러리가 처리하므로, 사용자는 추가적인 MLOps 또는 DataOps 노력 없이도 이러한 이점을 누릴 수 있습니다. 참고: 현재 미세 조정 (Finetuning)은 GPT-4 (교사 모델)에서 GPT-3.5 (학생 모델)로만 가능하며, AWS Bedrock 및 Together AI 모델에 대해서는 아직 구현되지 않았습니다.
우리는 Squad2, Spider, 그리고 IMDB Movie Reviews 데이터셋을 사용하여 OpenAI 모델 기반의 Tanuki를 이용한 모델 증류 (Model Distillation)를 테스트했습니다. 우리는 GPT-4 (교사 모델)의 퓨샷 (Few-shot) 응답을 사용하여 GPT-3.5-turbo 모델 (학생 모델)을 미세 조정 (Finetuning)했습니다. 예비 테스트 결과, 학습 데이터에서 600개 미만의 데이터 포인트를 사용함으로써 GPT-3.5-turbo가 GPT-4와 실질적으로 동등한 성능(홀드아웃 개발 세트에서 성능 차이 1.5% 미만)을 내도록 할 수 있었습니다. 동시에 비용은 최대 12배 낮추고 지연 시간 (Latency)은 6배 이상 단축했습니다 (비용 및 지연 시간 감소는 입력-출력 토큰 크기 및 정렬 문구 (Align statement) 토큰 크기와 같은 작업별 특성에 매우 따라 달라집니다). 이러한 테스트는 성능을 희생하지 않으면서도 비용을 지능적으로 절감하고 지연 시간을 낮추는 데 있어 이러한 형태의 모델 증류 (Model Distillation)가 가진 잠재력을 보여줍니다.
Tanuki는 Python에서 LLM이 강화된 함수를 생성하는 간단하고 원활한 방법이며, LLM의 출력이 특정 구조를 따르도록 보장합니다. 또한, 패치된 함수를 더 많이 호출할수록 실행 비용은 더 저렴해지고 속도는 더 빨라집니다.
Langchain: Tanuki는 Langchain보다 범위가 더 좁습니다. 우리의 미션은 미세 조정 (Finetuning)을 통해 비용과 지연 시간을 자동으로 줄이면서, 예측 가능하고 일관된 LLM 실행을 보장하는 것입니다.
Magentic/Marvin: Tanuki는 Magentic/Marvin과 비교하여 두 가지 주요 이점을 제공합니다. 즉, 자동 증류 (Automatic Distillation)를 통한 낮은 비용과 지연 시간, 그리고 테스트 주도 정렬 (Test-driven Alignment)을 통한 더 예측 가능한 동작입니다. 현재 Magentic을 사용해야 하는 두 가지 경우가 있는데, 바로 도구 (함수) 지원이 필요한 경우(현재 로드맵에 포함된 기능임)와 비동기 함수 (Asynchronous functions) 지원이 필요한 경우입니다.
우리는 다양한 문제에 Tanuki를 사용하는 방법을 보여주기 위해 몇 가지 예시를 만들었습니다. 여기에서 확인하실 수 있습니다. 몇 가지 아이디어는 다음과 같습니다:
- 고객 요청에 중요도 분류기 (Importance classifier) 추가
- 공격적 언어 분류 (Offensive-language classification) 기능 생성
- 음식 리뷰 앱 생성
- 즉시 사용할 수 있도록 DB 스키마에 부합하는 데이터 생성
LLM (Large Language Models)을 호출할 때, 출력값은 자유 형식 (free-form)입니다. 이는 소프트웨어 제품에 사용될 때 예측 가능성이 낮다는 것을 의미합니다. 타입을 사용하면 출력값이 프로그램의 나머지 부분이 처리할 수 있는 특정 제약 조건이나 규칙을 준수하도록 보장할 수 있습니다.
지금 당장은 아니지만, 지원되기를 원하는 다른 언어가 있다면 저희 Discord 서버로 연락하시거나 Github issue를 생성해 주세요.
Installation (설치), Getting started (시작하기), 그리고 How it works (작동 원리) 섹션의 지침을 따르세요.
How it works (작동 원리) 및 Test-Driven Alignment (테스트 주도 정렬) 섹션 또는 여기에 표시된 예시를 참조하세요.
네
현재는 가능하지만, Anthropic 및 인기 있는 오픈 소스 모델들을 지원할 계획이 있습니다. 구체적인 요청 사항이 있다면 Discord 서버에 참여하거나 Github issue를 생성해 주세요.
요약하자면, 저희는 LLM 모델의 증류 (distillation) 기술을 사용합니다.
상세히 설명하자면, 더 큰 모델 (teacher model, 교사 모델)의 출력값을 사용하여, 더 작은 모델 (student model, 학생 모델)이 교사 모델의 동작을 모방하도록 학습시킵니다. 이 작은 모델은 크기가 작기 때문에 실행 속도가 더 빠르고 비용이 저렴합니다. 어떤 경우에는 패치된 함수를 적은 횟수만 실행해도 비용을 최대 90% 절감하고 지연 시간 (latency)을 80%까지 낮추는 것이 가능합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 HN OpenAI Codex의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기