도구 호출을 활용한 미세 조정
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가 가장 뛰어난 오픈 웨이트 모델입니다. 물론 결과는 환경에 따라 다를 수 있습니다.