Розвиток AI-агента з Function Calling (Tool Use)
Function Calling (Tool Use) — механізм, при якому LLM генерує структурований вклик функції замість текстової відповіді. Модель аналізує запит, визначає потрібний інструмент та його параметри, а хост-додаток виконує виклик і повертає результат. Це робить агента здатним взаємодіяти з будь-якими зовнішніми системами.
OpenAI Function Calling
from openai import OpenAI
import json
client = OpenAI()
# Схема інструментів
tools = [
{
"type": "function",
"function": {
"name": "get_customer_info",
"description": "Отримати інформацію про клієнта за ID або email",
"parameters": {
"type": "object",
"properties": {
"customer_id": {"type": "string"},
"email": {"type": "string"},
"fields": {
"type": "array",
"items": {"type": "string"},
"description": "Потрібні поля: name, orders, balance, status"
}
},
}
}
},
{
"type": "function",
"function": {
"name": "create_support_ticket",
"description": "Створити тикет у службу підтримки",
"parameters": {
"type": "object",
"properties": {
"customer_id": {"type": "string"},
"category": {"type": "string", "enum": ["billing", "technical", "account", "shipping"]},
"priority": {"type": "string", "enum": ["low", "medium", "high", "critical"]},
"description": {"type": "string"},
},
"required": ["customer_id", "category", "description"]
}
}
},
]
# Реєстр функцій
def get_customer_info(customer_id=None, email=None, fields=None) -> dict:
# Реальна реалізація: запит до CRM/БД
return {"id": customer_id, "name": "Іванов І.І.", "balance": 15000, "status": "active"}
def create_support_ticket(customer_id: str, category: str, description: str, priority: str = "medium") -> dict:
# Реальна реалізація: Jira/Zendesk API
return {"ticket_id": "TKT-12345", "status": "created"}
FUNCTION_MAP = {
"get_customer_info": get_customer_info,
"create_support_ticket": create_support_ticket,
}
# Цикл агента з Function Calling
def run_support_agent(user_message: str) -> str:
messages = [
{"role": "system", "content": "Ти — агент служби підтримки. Використовуй інструменти для допомоги клієнтам."},
{"role": "user", "content": user_message},
]
while True:
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools,
tool_choice="auto",
parallel_tool_calls=True, # Паралельні виклики
)
message = response.choices[0].message
messages.append(message)
if not message.tool_calls:
return message.content
# Виконуємо всі виклики (паралельно якщо кілька)
for tool_call in message.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
func = FUNCTION_MAP.get(func_name)
if func:
result = func(**func_args)
else:
result = {"error": f"Function {func_name} not found"}
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result, ensure_ascii=False),
})
Паралельні виклики інструментів
GPT-4o та Claude 3+ підтримують паралельний виклик кількох інструментів:
# Приклад: агент може запитати дані з кількох джерел одночасно
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Покажи замовлення та баланс клієнта #12345"}],
tools=tools,
tool_choice="auto",
parallel_tool_calls=True,
)
# Модель генерує два паралельних виклики:
# get_orders(customer_id="12345") AND get_balance(customer_id="12345")
Anthropic Tool Use
import anthropic
client = anthropic.Anthropic()
tools = [
{
"name": "search_knowledge_base",
"description": "Пошук у корпоративній базі знань",
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string"},
"category": {"type": "string"},
},
"required": ["query"],
}
}
]
def run_claude_agent(user_message: str) -> str:
messages = [{"role": "user", "content": user_message}]
while True:
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=4096,
tools=tools,
messages=messages,
)
if response.stop_reason == "end_turn":
# Фінальна текстова відповідь
return next(b.text for b in response.content if hasattr(b, "text"))
# Обробка tool_use блоків
messages.append({"role": "assistant", "content": response.content})
tool_results = []
for block in response.content:
if block.type == "tool_use":
result = execute_tool(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(result),
})
messages.append({"role": "user", "content": tool_results})
Практичний кейс: агент для HR-запитів
Інструменти:
-
get_employee_info(employee_id)— дані співробітника -
check_vacation_balance(employee_id)— залишок відпустки -
submit_vacation_request(employee_id, start_date, end_date)— заявка на відпустку -
get_company_policy(policy_name)— пошук у базі HR-політик
Запит: «Хочу взяти відпустку з 15 квітня по 25 квітня. У мене достатньо днів?»
Траєкторія агента:
-
get_employee_info(employee_id="emp_789")— отримуємо ID з контексту сесії -
check_vacation_balance(employee_id="emp_789")— залишок: 14 днів -
get_company_policy("vacation_approval")— читаємо правила узгодження - Фінальна відповідь: «У вас 14 днів відпустки. Період 15–25 квітня — 11 робочих днів (з урахуванням святих днів). Баланс достатній. Для оформлення — submit_vacation_request. Заявку має затвердити ваш керівник протягом 3 робочих днів за політикою.»
Метрики за перший місяць:
- Автономно обробленні запити (без оператора): 84%
- Точність інформації про баланс/політики: 97%
- Середній час відповіді: 4.2с
Валідація викликів інструментів
from pydantic import BaseModel, validator
from datetime import date
class VacationRequest(BaseModel):
employee_id: str
start_date: date
end_date: date
@validator("end_date")
def end_after_start(cls, v, values):
if "start_date" in values and v <= values["start_date"]:
raise ValueError("end_date must be after start_date")
return v
# Валідація перед виконанням
def safe_tool_execution(func_name: str, func_args: dict) -> dict:
try:
if func_name == "submit_vacation_request":
VacationRequest(**func_args) # Валідація
return FUNCTION_MAP[func_name](**func_args)
except Exception as e:
return {"error": str(e), "status": "validation_failed"}
Графік
- Розвиток агента з 3–7 інструментами: 2–4 тижні
- Інтеграція з корпоративними системами: 2–4 тижні
- Тестування та моніторинг: 1–2 тижні
- Всього: 5–10 тижнів







