Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

도구 호출을 활용한 미세 조정

trl 0.19.0이 출시되면서 이제 사용자 정의 도구를 사용하는 모델의 미세 조정을 기본적으로 지원하며, 이 기능은 Dataset 및 SFTTrainer 클래스에 자연스럽게 통합되어 있습니다. 이를 통해 모델이 외부 함수를 어떻게, 그리고 언제 호출해야 하는지 가르치는 학습 과정이 간소화됩니다. 이제 도구 사용의 전체 대화 흐름을 포함하도록 학습 데이터를 구성할 수 있습니다. 즉, 최초의 사용자 프롬프트부터 도구를 호출하기로 한 모델의 결정, 해당 도구에서 나온 결과 출력, 그리고 모델이 종합하여 내놓은 최종 응답까지 모두 포함합니다.

이 워크플로에서 기존부터 있던 구성 요소는 get_json_schema 유틸리티 함수로, 이 함수는 여러분의 Python 코드와 모델이 요구하는 구조화된 형식 사이의 간극을 깔끔하게 메워 줍니다. 이 함수는 Python 함수로부터 규격에 맞는 JSON 스키마를 직접 자동 생성하지만, 두 가지 핵심 코딩 관행을 전제로 합니다. 첫째, 함수는 모든 인수와 반환값에 대해 최신 Python 타입 어노테이션을 포함해야 합니다. 둘째, 함수의 docstring은 Google docstring 스타일로 작성되어야 합니다. get_json_schema를 사용하면 함수를 파싱하여 매개변수의 이름과 데이터 타입뿐만 아니라 함수와 각 인수가 무엇을 하는지 설명하는 서술 텍스트까지 추출할 수 있습니다. 그럼 예제를 살펴봅시다.

from transformers.utils import get_json_schema

def multiply(a: float, b: float):
    """
    A function that multiplies two numbers

    Args:
        a: The first number to multiply
        b: The second number to multiply
    """
    return a * b

schema = get_json_schema(multiply)
print(schema)

이렇게 하면 해당 함수에 대한 데이터셋 JSON 스키마를 얻을 수 있습니다.

{
  "type": "function",
  "function": {
    "name": "multiply",
    "description": "A function that multiplies two numbers",
    "parameters": {
      "type": "object",
      "properties": {
        "a": {
          "type": "number",
          "description": "The first number to multiply"
        },
        "b": {
          "type": "number",
          "description": "The second number to multiply"
        }
      },
      "required": ["a", "b"]
    }
  }
}

이제 이 스키마를 사용하여 도구 호출이 포함된 데이터셋을 만들 수 있습니다. 예를 들어 mpmath 라이브러리를 래핑하여 다항식의 근과 베셀 함수에 관련된 도구 호출 데이터셋을 만들 수 있습니다. 데이터셋에 도구 스키마를 담은 tools 열만 추가하면 됩니다.

import mpmath
from datasets import Dataset
from transformers.utils import get_json_schema
from trl import SFTTrainer


def find_polynomial_roots(coefficients: list[float]) -> str:
    """
    Finds the roots of a polynomial given its coefficients.

    Args:
        coefficients: A list of coefficients [c_n, ..., c_1, c_0] for c_n*x^n + ... + c_0.

    Returns:
        A string representation of the list of roots.
    """
    roots = mpmath.polyroots(coefficients)
    return str(roots)


def calculate_bessel_j(order: float, value: float) -> float:
    """
    Calculates the Bessel function of the first kind, J_v(z).

    Args:
        order: The order 'v' of the Bessel function.
        value: The value 'z' at which to evaluate the function.

    Returns:
        The result of the Bessel function J_v(z).
    """
    return mpmath.besselj(order, value)


polyroots = get_json_schema(find_polynomial_roots)
bessel = get_json_schema(calculate_bessel_j)

dataset = Dataset.from_dict(
    {
        "messages": [
            [
                {
                    "role": "user",
                    "content": "Find the roots of the polynomial x^2 - 4.",
                },
                {
                    "role": "assistant",
                    "tool_calls": [
                        {
                            "type": "function",
                            "function": {
                                "name": "find_polynomial_roots",
                                "arguments": {"coefficients": [1, 0, -4]},
                            },
                        }
                    ],
                },
                {
                    "role": "tool",
                    "name": "find_polynomial_roots",
                    "content": "[-2.0, 2.0]",
                },
                {
                    "role": "assistant",
                    "content": "The roots of x^2 - 4 are -2.0 and 2.0.",
                },
            ],
            [
                {
                    "role": "user",
                    "content": "What is the value of the Bessel function J0(2.5)?",
                },
                {
                    "role": "assistant",
                    "tool_calls": [
                        {
                            "type": "function",
                            "function": {
                                "name": "calculate_bessel_j",
                                "arguments": {"order": 0, "value": 2.5},
                            },
                        }
                    ],
                },
                {
                    "role": "tool",
                    "name": "calculate_bessel_j",
                    "content": "0.0483837764022209",
                },
                {
                    "role": "assistant",
                    "content": "The value of J0(2.5) is approximately 0.04838.",
                },
            ],
        ],
        "tools": [
            [polyroots, bessel],
            [polyroots, bessel],
        ],
    }
)

trainer = SFTTrainer(
    model="Qwen3-0.6B",
    train_dataset=dataset,
)

trainer.train()

제가 제한적으로 테스트해 본 바로는, 현재 사용자 정의 도구 사용을 위한 미세 조정에는 Qwen3-0.6B와 Llama-3.1-70B-Instruct가 가장 뛰어난 오픈 웨이트 모델입니다. 물론 결과는 환경에 따라 다를 수 있습니다.


원문 © Stephen Diehl, stephendiehl.com · 글 CC BY-SA 4.0, 코드 MIT · Stephen Diehl은 런던의 소프트웨어 엔지니어이자 작가입니다(저자가 정한 소개 문구). 이 글은 저자가 개인 자격으로 쓴 것이며 어떤 조직과의 연관도 밝히거나 암시해서는 안 됩니다 (라이선스와 고지).
이 페이지는 원문을 한국어로 옮기며 변경한 비공식 번역이며 같은 CC BY-SA 4.0으로 제공합니다 · yeokja 한국어 번역 · Anthropic 사의 claude-opus-5-5 모델을 활용하여 번역되었으며 학습을 모두 비허용한 상태로 작업하였습니다.