English translation is not available yet. Showing Russian content.
Как вы fine-tune модель для функции "вызов внешнего API"?
Краткий тезис
Fine-tuning для вызова внешнего API — это обучение языковой модели генерировать структурированные вызовы функций (function calls]]) вместо обычного текстового ответа. Для этого создаётся специальный датасет, где на инструкцию пользователя модель должна выдать команду вида <function_call>имя_функции(параметры)</function_call>. После дообучения модель способна понимать, когда нужно обратиться к внешнему сервису, а когда ответить самой. Это основа для построения AI-агентов, которые могут взаимодействовать с реальными системами.
1. Зачем fine-tune для вызова API?
Стандартная языковая модель обучена генерировать связный текст, но не умеет «понимать», что ответ должен быть вызовом функции. Если просто попросить модель «скажи погоду в Москве», она может написать «Погода в Москве сегодня +15°C», хотя у неё нет доступа к реальным данным. Function calling (вызов функций) решает эту проблему: модель учится распознавать намерение пользователя и формировать команду для внешнего API.
Почему fine-tuning, а не промпт-инжиниринг?
- Промпт может работать для простых случаев, но плохо масштабируется на множество функций и сложные параметры.
- Fine-tuning даёт более надёжное и детерминированное поведение, модель реже «выдумывает» вызовы.
- Модель запоминает точный формат функции и правила заполнения параметров.
2. Формат датасета для function calling
Датасет должен состоять из пар «инструкция пользователя → вызов функции». Самый распространённый формат — обернуть вызов в специальные теги или JSON.
Пример:
Инструкция: "Какая погода в Москве?"
Ассистент: <function_call>get_weather(city="Москва")</function_call>
Или в формате JSON:
Инструкция: "Отправь письмо Ивану на почту с темой 'Встреча' и текстом 'Привет, Иван!'"
Ассистент: {"function": "send_email", "parameters": {"to": "ivan@example.com", "subject": "Встреча", "body": "Привет, Иван!"}}
Термин «слоты» (slots) — параметры функции, которые модель должна заполнить. В датасете нужно показать разные комбинации слотов: обязательные, опциональные, с дефолтными значениями.
Для каждого примера можно добавить контекст разговора (историю сообщений), если вызов зависит от предыдущего общения.
| Инструкция | Ожидаемый вызов |
|---|---|
| "Закажи пиццу с пепперони" | place_order(item="пицца с пепперони", quantity=1) |
| "Мне нужно две пиццы, одну с грибами, другую с курицей" | place_order(item="пицца с грибами", quantity=1) + place_order(item="пицца с курицей", quantity=1) |
| "Отмени заказ #123" | cancel_order(order_id=123) |
Совет для повышения устойчивости модели добавляйте примеры, где функция не должна вызываться (например, вопрос о личных предпочтениях). Модель должна отвечать текстом, а не вызовом.
3. Обучаем модель генерировать function call
Шаги обучения
- Выбор базовой модели Лучше всего подходят модели, уже умеющие следовать инструкциям (instruct-версии), например Llama‑3‑Instruct, Mistral‑Instruct, Qwen‑Instruct.
- Подготовка датасета в формате чата Каждый пример — это список сообщений:
- Роль
user: инструкция. - Роль
assistant: вызов функции в заданном формате.
- Роль
- Обучение с учителем (SFT). Используется стандартный loss (cross-entropy) только на токенах ответа ассистента. Функциональный вызов маскируется как обычный текст.
- Добавление системного сообщения В системном сообщении можно описать доступные функции, их параметры и правила. Это помогает модели, но не заменяет fine-tuning.
Пример кода обучения (PyTorch + transformers):
from transformers import AutoTokenizer, AutoModelForCausalLM, Trainer, TrainingArguments
model_name = "meta-llama/Llama-3.2-1B-Instruct" # или другая модель
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)
# Подготовка датасета (пример одного элемента)
def format_example(user_input, api_call):
return f"<|user|>\n{user_input}\n<|assistant|>\n{api_call}"
# Токенизация, даталоадер, аргументы обучения
training_args = TrainingArguments(
output_dir="./function-calling-model",
per_device_train_batch_size=4,
num_train_epochs=3,
learning_rate=2e-5,
save_steps=500,
)
trainer = Trainer(model=model, args=training_args, train_dataset=dataset)
trainer.train()
Термин «контролируемое обучение» (supervised fine-tuning, SFT) — модель учится на примерах с правильными ответами. После обучения она будет выдавать вызовы в том же формате, что в датасете.
4. Обработка результата вызова API и многошаговый диалог
После того как модель сгенерировала вызов, нужно:
- Парсить теги или JSON (например, с помощью регулярных выражений или json.loads).
- Выполнить внешний API (например, запрос к погодному сервису).
- Вернуть результат обратно в разговор как системное сообщение или сообщение пользователя.
Пример пайплайна для одного шага
response = model.generate(prompt)
if "<function_call>" in response:
# Извлекаем имя функции и параметры
match = re.search(r'<function_call>(.*?)</function_call>', response)
call_str = match.group(1)
function_name, params = parse_call(call_str)
api_result = call_external_api(function_name, params)
# Возвращаем результат в контекст
new_prompt = prompt + f"\n<|system|>\nРезультат вызова {function_name}: {api_result}\n<|user|>\nПродолжай."
else:
# модель ответила текстом — готово
print(response)
Термин «multi-turn» (многошаговость) — модель может последовательно вызывать несколько API, опираясь на предыдущие результаты. Fine-tuning поддерживает это, если в датасете есть примеры продолжения после получения результата.
5. Пайплайн: от запроса к ответу через API
Полный цикл работы дообученной модели:
- Пользователь вводит запрос.
- Система формирует промпт (системное сообщение + история).
- Модель генерирует ответ (текст или вызов).
- Если ответ содержит вызов:
- Извлечь имя функции и параметры.
- Проверить безопасность (валидация параметров, контроль доступа к API).
- Выполнить реальный вызов (например, к REST API или библиотеке).
- Результат (успех/ошибка) передаётся обратно в контекст.
- Модель генерирует следующий ответ (завершающий, или следующий вызов).
- Если ответ — обычный текст, отдать его пользователю.
Графическое представление (текстовая схема):
[Пользователь] -> Промпт -> [Модель] -> <function_call> -> [Парсер] -> [API] -> Результат -> [Контекст] -> [Модель] -> Текст (ответ)
6. Инструменты и фреймворки
| Инструмент | Описание | Особенности |
|---|---|---|
| LangChain Tool Calling | Абстракция над вызовами функций. Позволяет определить Tool с именем, описанием, схемой параметров. Модель генерирует JSON с tool_calls. | Встроен в ChatOpenAI, ChatAnthropic. Не требует отдельного fine-tuning, если модель уже поддерживает tool calling. |
| LlamaIndex Function Calling | Аналогично LangChain, интеграция с LLM и индексами. | Поддерживает автогенерацию схем из Python-функций через декоратор @tool. |
| OpenAI Function Calling (fine-tuning) | OpenAI позволяет дообучать модели (GPT-3.5, GPT-4) с функциональными вызовами. Датасет должен включать вызовы в формате messages с role: function. | Закрытый API, нет контроля над обучением. |
| AutoGen (Microsoft) | Фреймворк для многолетних агентов. Модели могут вызывать функции друг у друга. | Хорош для сложных multi-agent сценариев. |
| CrewAI / smolagents | Лёгкие библиотеки для AI-агентов с tool calling. | Открытый код, простота интеграции. |
Термин «tool calling» — синоним function calling, часто используется в современных LLM API.
Если модель не поддерживает нативно tool calling (например, Mistral 7B), fine-tuning — единственный способ научить её этому.
7. Особенности и подводные камни
- Безопасность Модель может генерировать опасные вызовы (удаление данных, отправка писем). Нужно ограничивать набор функций и валидировать параметры на стороне сервера.
- Переобучение на конкретные API Если датасет содержит только один API для погоды, модель не сможет вызывать другие сервисы. Лучше использовать абстрактные функции с разными именами и параметрами.
- Обработка ошибок API Если внешний сервис вернул ошибку, модель должна уметь переспросить пользователя или предложить альтернативу. В датасет нужно включать примеры с ошибочными вызовами и корректной реакцией.
- Формат тегов Выбор разделителей (теги, JSON, маркдаун) влияет на стабильность генерации. Рекомендуется тестировать несколько вариантов на небольшом наборе.
- Смешанные сценарии Иногда модель должна сначала ответить текстом, потом вызвать API, потом снова текстом. В датасете должны быть примеры таких последовательностей.
- Размер датасета Для простых 1-2 функций достаточно 200–500 примеров. Для 10+ функций нужно 1000+.
8. Пет-проект для закрепления
Задача создать чат-бота, который умеет искать информацию в интернете через API (например, SerpAPI или DuckDuckGo Instant Answer API) и отвечать на вопросы на основе результатов.
Инструменты
- Модель: Llama‑3.2‑1B‑Instruct (или любая другая instruct-модель из Hugging Face)
- Фреймворк: Hugging Face Transformers + TRL (SFTTrainer)
- API: SerpAPI (ключ бесплатно, 100 запросов/месяц)
- Датасет: 300–500 пар вопрос-поисковый запрос (например, "Какая столица Франции?" ->
<function_call>search(query="столица Франции")</function_call>)
Шаги:
- Собрать датасет вопросов, которые требуют интернета (текущие события, погода, новости). Для каждого вопроса вручную написать корректный вызов
search. - Загрузить базовую модель, токенизировать датасет, выполнить SFT на 3 эпохи.
- Написать пайплайн: модель отвечает -> парсинг
<function_call>-> вызов SerpAPI -> получение результатов -> отправка их обратно в контекст -> модель генерирует финальный ответ. - Протестировать на новых вопросах.
Ожидаемый результат бот, который вместо "Я не знаю" делает поиск и даёт ответ с актуальными данными. При этом модель не должна вызывать поиск для вопросов вроде "Что такое 2+2?", а отвечать сама.
Дополнительно добавить функцию get_current_time для проверки даты, чтобы модель научилась выбирать между разными вызовами.
9. Связь с другими вопросами
| Вопрос | Тема | Связь |
|---|---|---|
| 2 | RAG и внешние данные | Fine-tuning для вызова API — альтернативный способ интеграции внешних данных (когда RAG не подходит из-за динамики). |
| 20 | Prompt engineering vs fine-tuning | Сравнение подходов: промпт для function calling (меньше контроля) против fine-tuning (больше надёжности). |
| 24 | Как обучить модель на собственном датасете | Техника SFT, применимая и для function calling. |
| 37 | Fine-tuning для чат-бота | Частный случай: чат-бот с вызовом API (погода, поиск). |
| 39 | Проблемы безопасности при fine-tuning | Безопасность function calling (защита от инъекций). |
| 45 | AI-агенты и tool use | Function calling — основа для агентов, см. также вопросы про ReAct, планирование. |
Навигация
- Предыдущий: 37
- Следующий: 39
- Индекс: 00. Индекс разборов