Outlines 퀵스타트

Outlines 퀵스타트

Outlines는 LLM의 출력을 구조에 맞게 강제하는(구조화 생성) 파이썬 라이브러리예요. 파싱에 실패한 JSON을 고치려 애쓰는 대신, 생성 단계에서부터 토큰을 제약해 항상 유효한 구조가 나오게 해요. 모델에 prompt와 output_type만 넘기면 되고, 사용하는 모델도 바꾸기 쉬워서 OpenAI·Ollama·vLLM 등에서 같은 코드가 동작해요.

모델 초기화

첫 단계는 모델을 초기화하는 거예요. 이때 웨이트가 디바이스에 로드돼요.

import outlines

model = outlines.models.transformers(
    "microsoft/Phi-3-mini-4k-instruct",
    device="cuda"  # 선택, 기본은 cpu
)

Outlines는 다양한 추론 엔진과 웨이트 타입을 지원해요. 자세한 건 "Models" 문서에서 확인할 수 있어요.

출처: https://dottxt-ai.github.io/outlines/latest/quickstart/

생성(generation)

모델을 초기화했으면 outlines.generate로 generator를 만들 수 있어요. generator는 prompt를 직접 받아 호출할 수 있어요.

generator = outlines.generate.text(model)
result = generator("Question: What's 2+2? Answer:", max_tokens=100)
print(result)  # The answer is 4

스트리밍도 지원해요. generator.stream(...)으로 토큰을 하나씩 순회할 수 있어요.

stream = generator.stream("What's 2+2?", max_tokens=4)
for i in range(5):
    token = next(stream)
    print(repr(token))

구조화 생성

outlines.generate.text와 달리, 구조화 생성은 모델이 미리 정한 구조를 따르도록 보장해요. 구조는 regex, JSON 스키마, 파이썬 객체 타입, 또는 SQL·Python 같은 파서블 언어를 정의하는 Lark 문법으로 만들 수 있어요. 예를 들어 Pydantic으로 JSON 스키마를 강제해 볼게요.

from enum import Enum
from pydantic import BaseModel, constr, conint

class Character(BaseModel):
    name: str
    age: int
    armor: str
    strength: int

generator = outlines.generate.json(model, Character)
character = generator(
    "Generate a new character for my awesome game: "
    "name, age, armor and strength. "
)
print(character)

vLLM·FastAPI로 서빙

Outlines는 vLLM과 FastAPI로 LLM 서비스로 배포할 수도 있어요. 먼저 서버를 시작해요.

python -m outlines.serve.serve --model="microsoft/Phi-3-mini-4k-instruct"

공식 Docker 이미지로도 실행할 수 있어요. 이러면 기본적으로 http://127.0.0.1:8000에 서버가 뜨고, --model을 안 주면 OPT-125M 모델이 쓰여요. 쉘에서 prompt와 JSON 스키마를 같이 보내면 됩니다.

curl http://127.0.0.1:8000/generate \
  -d '{ "prompt": "Question: What is a language model? Answer:", "schema": {"type": "string"} }'

프롬프트 템플릿

@outlines.prompt 데코레이터를 쓰면 함수 docstring을 템플릿으로 쓸 수 있어요. 반복, 조건, 딕셔너리 등 템플릿 언어 기능을 지원해요.

import outlines

@outlines.prompt
def few_shots(instructions, examples, question):
    """{{ instructions }}
    {% for example in examples %}
    Q: {{ example.question }}
    A: {{ example.answer }}
    {% endfor %}
    Question:
    Q: {{ question }}
    A:
    """

더 알아보기