Function Calling ile OpenAI API’yi Dış Araçlara Bağlama
Yapay zeka modelleriyle çalışırken bir noktada şunu fark ediyorsunuz: ChatGPT veya GPT-4 harika sorular cevaplayabiliyor, ama kendi veritabanınızdaki müşteri bilgisine erişemiyor, sisteminizdeki servisleri kontrol edemiyor ya da anlık hava durumu verisi çekemiyor. İşte tam burada Function Calling devreye giriyor. OpenAI’nin bu özelliği, dil modelini gerçek dünya araçlarına bağlamanın resmi ve güvenilir yolu. Bu yazıda, Function Calling’in nasıl çalıştığını, nasıl implemente edileceğini ve production ortamında nasıl kullanılabileceğini elimden geldiğince pratik bir şekilde anlatacağım.
Function Calling Nedir ve Neden Önemli?
Normalde bir LLM’e soru sorduğunuzda, model eğitim verisine dayanarak bir metin cevabı üretir. Bu cevap bazen yanlış olabilir, bazen güncel olmayabilir, bazen de sisteminizle hiçbir ilgisi olmayabilir. Function Calling ise modele şunu söylemenizi sağlar: “Sen bu fonksiyonları çağırabilirsin, ihtiyaç duyduğunda kullan.”
Model aslında fonksiyonu direkt çalıştırmıyor, bunu anlamak çok önemli. Model size yapılandırılmış bir JSON çıktısı döndürüyor: “Şu fonksiyonu, şu parametrelerle çağırmak istiyorum.” Sonra siz bu çağrıyı yapıyor, sonucu modele geri veriyorsunuz ve model nihai cevabını oluşturuyor. Bu döngüsel yapı, modeli kendi araçlarınıza entegre etmenin temel mekanizması.
Neden önemli? Şunlar için:
- Gerçek zamanlı veri: Veritabanı sorguları, API çağrıları, servis kontrolleri
- Güvenilir yapılandırılmış çıktı: JSON parse etmek için regex yazmak zorunda kalmıyorsunuz
- Aksiyon alma: Sunucuda komut çalıştırmak, ticket açmak, bildirim göndermek
- Hibrit sistemler: LLM zekasını mevcut altyapınızla birleştirmek
Temel Yapı ve İlk Örnek
Önce gerekli kurulumları yapalım. OpenAI Python kütüphanesinin güncel versiyonunu kullanıyoruz:
pip install openai python-dotenv
Basit bir ortam değişkeni dosyası oluşturalım:
cat > .env << 'EOF'
OPENAI_API_KEY=sk-your-api-key-here
EOF
Şimdi en temel Function Calling örneğine bakalım. Bir sunucunun CPU kullanımını sorgulayan basit bir senaryo:
cat > basic_function_calling.py << 'EOF'
import os
import json
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
# Fonksiyon tanımları - modele hangi araçlara sahip olduğumuzu söylüyoruz
tools = [
{
"type": "function",
"function": {
"name": "get_server_cpu_usage",
"description": "Belirtilen sunucunun anlık CPU kullanım yüzdesini döndürür",
"parameters": {
"type": "object",
"properties": {
"server_name": {
"type": "string",
"description": "Sunucu adı veya IP adresi"
},
"interval": {
"type": "integer",
"description": "Ölçüm aralığı saniye cinsinden, varsayılan 1",
"default": 1
}
},
"required": ["server_name"]
}
}
}
]
# Gerçek fonksiyon implementasyonu (normalde burada psutil veya SSH bağlantısı olurdu)
def get_server_cpu_usage(server_name: str, interval: int = 1) -> dict:
# Demo amaçlı sahte veri döndürüyoruz
import random
return {
"server": server_name,
"cpu_usage": round(random.uniform(10, 95), 2),
"interval": interval,
"unit": "percent"
}
# Konuşmayı başlatıyoruz
messages = [
{"role": "user", "content": "web-server-01 sunucusunun CPU kullanımı ne kadar?"}
]
# İlk API çağrısı
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools,
tool_choice="auto"
)
response_message = response.choices[0].message
# Model bir fonksiyon çağırmak istiyor mu kontrol ediyoruz
if response_message.tool_calls:
tool_call = response_message.tool_calls[0]
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
print(f"Model şu fonksiyonu çağırmak istiyor: {function_name}")
print(f"Parametreler: {function_args}")
# Fonksiyonu çalıştırıyoruz
result = get_server_cpu_usage(**function_args)
# Sonucu konuşmaya ekliyoruz
messages.append(response_message)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result)
})
# Model nihai cevabını oluştursun
final_response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools
)
print(f"nAsistan: {final_response.choices[0].message.content}")
EOF
python basic_function_calling.py
Bu temel akışı anladıktan sonra daha karmaşık senaryolara geçebiliriz.
Çoklu Fonksiyon Tanımlama
Gerçek dünya uygulamalarında tek bir fonksiyonla iş bitmez. Bir sysadmin asistanı düşünelim: sunucu durumu, disk kullanımı, aktif servisler, log analizi gibi pek çok aracın olması gerekir.
cat > sysadmin_assistant.py << 'EOF'
import os
import json
import subprocess
import psutil
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
tools = [
{
"type": "function",
"function": {
"name": "get_disk_usage",
"description": "Sistemdeki disk kullanım bilgilerini döndürür",
"parameters": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "Kontrol edilecek dizin yolu, varsayılan /",
"default": "/"
}
},
"required": []
}
}
},
{
"type": "function",
"function": {
"name": "check_service_status",
"description": "Belirtilen Linux servisinin çalışıp çalışmadığını kontrol eder",
"parameters": {
"type": "object",
"properties": {
"service_name": {
"type": "string",
"description": "Kontrol edilecek servis adı (örn: nginx, mysql, docker)"
}
},
"required": ["service_name"]
}
}
},
{
"type": "function",
"function": {
"name": "get_memory_info",
"description": "Sistem bellek kullanım bilgilerini döndürür",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
}
}
]
def get_disk_usage(path: str = "/") -> dict:
usage = psutil.disk_usage(path)
return {
"path": path,
"total_gb": round(usage.total / (1024**3), 2),
"used_gb": round(usage.used / (1024**3), 2),
"free_gb": round(usage.free / (1024**3), 2),
"percent": usage.percent
}
def check_service_status(service_name: str) -> dict:
try:
result = subprocess.run(
["systemctl", "is-active", service_name],
capture_output=True, text=True, timeout=5
)
status = result.stdout.strip()
return {
"service": service_name,
"status": status,
"is_running": status == "active"
}
except subprocess.TimeoutExpired:
return {"service": service_name, "status": "timeout", "is_running": False}
except Exception as e:
return {"service": service_name, "status": "error", "error": str(e)}
def get_memory_info() -> dict:
mem = psutil.virtual_memory()
return {
"total_gb": round(mem.total / (1024**3), 2),
"available_gb": round(mem.available / (1024**3), 2),
"used_gb": round(mem.used / (1024**3), 2),
"percent": mem.percent
}
# Fonksiyon dispatcher
function_map = {
"get_disk_usage": get_disk_usage,
"check_service_status": check_service_status,
"get_memory_info": get_memory_info
}
def run_conversation(user_message: str):
messages = [
{
"role": "system",
"content": "Sen bir sysadmin asistanısın. Sistem bilgilerini sorgulayabilirsin. Türkçe cevap ver."
},
{"role": "user", "content": user_message}
]
# Model birden fazla fonksiyon çağırabilir, döngüyle takip ediyoruz
while True:
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools,
tool_choice="auto"
)
msg = response.choices[0].message
messages.append(msg)
# Fonksiyon çağrısı yoksa bitiyoruz
if not msg.tool_calls:
return msg.content
# Tüm fonksiyon çağrılarını işliyoruz
for tool_call in msg.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
if func_name in function_map:
result = function_map[func_name](**func_args)
else:
result = {"error": f"Bilinmeyen fonksiyon: {func_name}"}
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result, ensure_ascii=False)
})
# Test
print(run_conversation("Nginx servisi çalışıyor mu ve disk doluluk durumu ne?"))
EOF
Paralel Fonksiyon Çağrısı
GPT-4o ve GPT-4 Turbo, birden fazla fonksiyonu aynı anda çağırabiliyor. Bu özelliği kullanmak performansı ciddi ölçüde artırır:
cat > parallel_calls.py << 'EOF'
import os
import json
import concurrent.futures
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def process_parallel_tool_calls(msg, function_map):
"""Birden fazla tool call'u paralel olarak işler"""
results = {}
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
future_to_call = {}
for tool_call in msg.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
if func_name in function_map:
future = executor.submit(function_map[func_name], **func_args)
future_to_call[future] = tool_call
for future in concurrent.futures.as_completed(future_to_call):
tool_call = future_to_call[future]
try:
results[tool_call.id] = future.result()
except Exception as e:
results[tool_call.id] = {"error": str(e)}
return results
# Bu yapı sayesinde model "hem nginx'i hem mysql'i hem de disk durumunu kontrol et"
# dediğinde, üç sorgu sırayla değil paralel yapılır
EOF
Gerçek Dünya Senaryosu: Monitoring Chatbot
Şimdi production’a yakın bir senaryo yazalım. Prometheus veya benzeri bir monitoring sistemine bağlanan, alert sorgulayabilen ve ticket açabilen bir chatbot:
cat > monitoring_chatbot.py << 'EOF'
import os
import json
import requests
from datetime import datetime, timedelta
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
PROMETHEUS_URL = os.getenv("PROMETHEUS_URL", "http://localhost:9090")
JIRA_URL = os.getenv("JIRA_URL", "http://localhost:8080")
JIRA_TOKEN = os.getenv("JIRA_TOKEN", "")
tools = [
{
"type": "function",
"function": {
"name": "query_prometheus",
"description": "Prometheus'a PromQL sorgusu gönderir ve metrik verisi döndürür",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "PromQL sorgusu, örn: up{job='node'} veya rate(http_requests_total[5m])"
},
"time_range_minutes": {
"type": "integer",
"description": "Kaç dakika geriye bakılacak, varsayılan 30"
}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "get_active_alerts",
"description": "Şu anda aktif olan tüm alertleri listeler",
"parameters": {
"type": "object",
"properties": {
"severity": {
"type": "string",
"enum": ["critical", "warning", "info", "all"],
"description": "Alert ciddiyet seviyesi filtresi"
}
},
"required": []
}
}
},
{
"type": "function",
"function": {
"name": "create_incident_ticket",
"description": "Jira'da yeni bir incident ticket oluşturur",
"parameters": {
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "Ticket başlığı"
},
"description": {
"type": "string",
"description": "Sorunun detaylı açıklaması"
},
"priority": {
"type": "string",
"enum": ["Highest", "High", "Medium", "Low"],
"description": "Ticket önceliği"
},
"affected_service": {
"type": "string",
"description": "Etkilenen servis adı"
}
},
"required": ["title", "description", "priority"]
}
}
}
]
def query_prometheus(query: str, time_range_minutes: int = 30) -> dict:
try:
end_time = datetime.now()
start_time = end_time - timedelta(minutes=time_range_minutes)
params = {
"query": query,
"start": start_time.timestamp(),
"end": end_time.timestamp(),
"step": "60s"
}
response = requests.get(
f"{PROMETHEUS_URL}/api/v1/query_range",
params=params,
timeout=10
)
if response.status_code == 200:
data = response.json()
return {"status": "success", "data": data.get("data", {})}
else:
return {"status": "error", "message": f"HTTP {response.status_code}"}
except requests.exceptions.ConnectionError:
# Demo modda sahte veri
return {
"status": "success",
"demo_mode": True,
"data": {
"resultType": "matrix",
"result": [
{
"metric": {"__name__": "up", "job": "node", "instance": "web-01:9100"},
"values": [[datetime.now().timestamp(), "1"]]
}
]
}
}
def get_active_alerts(severity: str = "all") -> dict:
# Demo veri
alerts = [
{
"name": "HighCPUUsage",
"severity": "warning",
"instance": "db-server-01",
"value": "87.3%",
"started": "2024-01-15T10:23:00Z"
},
{
"name": "DiskSpaceLow",
"severity": "critical",
"instance": "storage-01",
"value": "94.1% dolu",
"started": "2024-01-15T09:45:00Z"
}
]
if severity != "all":
alerts = [a for a in alerts if a["severity"] == severity]
return {
"alert_count": len(alerts),
"alerts": alerts
}
def create_incident_ticket(title: str, description: str, priority: str,
affected_service: str = "unknown") -> dict:
# Gerçek implementasyonda Jira API çağrısı yapılır
ticket_id = f"INC-{datetime.now().strftime('%Y%m%d%H%M%S')}"
print(f"n[TICKET OLUŞTURULUYOR]nID: {ticket_id}nBaşlık: {title}nÖncelik: {priority}")
return {
"ticket_id": ticket_id,
"status": "created",
"url": f"{JIRA_URL}/browse/{ticket_id}",
"title": title,
"priority": priority,
"affected_service": affected_service
}
function_map = {
"query_prometheus": query_prometheus,
"get_active_alerts": get_active_alerts,
"create_incident_ticket": create_incident_ticket
}
def chat(user_input: str, conversation_history: list = None) -> tuple:
if conversation_history is None:
conversation_history = [
{
"role": "system",
"content": """Sen bir DevOps/SRE asistanısın. Prometheus metrikleri sorgulayabilir,
aktif alertleri görebilir ve Jira'da incident ticket oluşturabilirsin.
Türkçe cevap ver. Kritik durumları tespit ettiğinde proaktif olarak ticket açmayı öner."""
}
]
conversation_history.append({"role": "user", "content": user_input})
while True:
response = client.chat.completions.create(
model="gpt-4o",
messages=conversation_history,
tools=tools,
tool_choice="auto"
)
msg = response.choices[0].message
conversation_history.append(msg)
if not msg.tool_calls:
return msg.content, conversation_history
for tool_call in msg.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
result = function_map.get(func_name, lambda **k: {"error": "Fonksiyon bulunamadı"})(**func_args)
conversation_history.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result, ensure_ascii=False)
})
# Test konuşması
history = None
sorular = [
"Şu anda kritik alert var mı?",
"Storage-01 için hemen ticket aç, çünkü disk dolmak üzere"
]
for soru in sorular:
print(f"nKullanici: {soru}")
cevap, history = chat(soru, history)
print(f"Asistan: {cevap}")
EOF
Hata Yönetimi ve Güvenlik
Production’da dikkat edilmesi gereken en önemli konulardan biri güvenlik. Model size kötü parametreler gönderebilir, fonksiyon çağrısı başarısız olabilir:
cat > secure_function_calling.py << 'EOF'
import os
import json
import logging
from functools import wraps
from openai import OpenAI
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# İzin verilen komutlar whitelist
ALLOWED_COMMANDS = {
"systemctl": ["status", "is-active", "is-enabled"],
"df": ["-h", "-k"],
"free": ["-h", "-m"]
}
def validate_function_call(func_name: str, func_args: dict, allowed_functions: list) -> bool:
"""Fonksiyon çağrısının güvenlik kontrolü"""
if func_name not in allowed_functions:
logger.warning(f"İzinsiz fonksiyon çağrısı girişimi: {func_name}")
return False
# Tehlikeli parametre kontrolü
args_str = json.dumps(func_args)
dangerous_patterns = [";", "&&", "||", "`", "$(", "../", "rm ", "dd "]
for pattern in dangerous_patterns:
if pattern in args_str:
logger.error(f"Tehlikeli parametre tespit edildi: {pattern}")
return False
return True
def safe_tool_executor(func):
"""Fonksiyon çağrılarını güvenli şekilde çalıştıran decorator"""
@wraps(func)
def wrapper(*args, **kwargs):
try:
result = func(*args, **kwargs)
logger.info(f"Fonksiyon başarıyla çalıştı: {func.__name__}")
return result
except PermissionError as e:
logger.error(f"İzin hatası: {e}")
return {"error": "Bu işlem için yetkiniz yok", "type": "permission_error"}
except TimeoutError as e:
logger.error(f"Timeout hatası: {e}")
return {"error": "İşlem zaman aşımına uğradı", "type": "timeout_error"}
except Exception as e:
logger.error(f"Beklenmeyen hata {func.__name__}: {e}")
return {"error": f"İşlem başarısız: {str(e)}", "type": "general_error"}
return wrapper
# Rate limiting için basit bir implementasyon
from collections import defaultdict
from time import time
call_counts = defaultdict(list)
def rate_limit_check(func_name: str, max_calls: int = 10, window_seconds: int = 60) -> bool:
"""Dakika başına maksimum çağrı sayısını kontrol eder"""
now = time()
window_start = now - window_seconds
# Eski kayıtları temizle
call_counts[func_name] = [t for t in call_counts[func_name] if t > window_start]
if len(call_counts[func_name]) >= max_calls:
logger.warning(f"Rate limit aşıldı: {func_name}")
return False
call_counts[func_name].append(now)
return True
EOF
Streaming ile Real-Time Yanıtlar
Uzun işlemler için streaming kullanmak kullanıcı deneyimini iyileştirir:
cat > streaming_with_functions.py << 'EOF'
import os
import json
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def stream_with_function_calling(user_message: str, tools: list, function_map: dict):
messages = [{"role": "user", "content": user_message}]
# İlk streaming yanıt (fonksiyon çağrısını yakala)
stream = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools,
tool_choice="auto",
stream=True
)
tool_calls = []
current_tool_call = None
final_content = ""
for chunk in stream:
delta = chunk.choices[0].delta if chunk.choices else None
if not delta:
continue
# Normal metin akışı
if delta.content:
print(delta.content, end="", flush=True)
final_content += delta.content
# Fonksiyon çağrısı akışı
if delta.tool_calls:
for tc_chunk in delta.tool_calls:
if tc_chunk.index is not None:
# Yeni tool call başlıyor
while len(tool_calls) <= tc_chunk.index:
tool_calls.append({
"id": "",
"type": "function",
"function": {"name": "", "arguments": ""}
})
if tc_chunk.id:
tool_calls[tc_chunk.index]["id"] = tc_chunk.id
if tc_chunk.function:
if tc_chunk.function.name:
tool_calls[tc_chunk.index]["function"]["name"] += tc_chunk.function.name
if tc_chunk.function.arguments:
tool_calls[tc_chunk.index]["function"]["arguments"] += tc_chunk.function.arguments
print() # Yeni satır
# Fonksiyon çağrıları varsa işle
if tool_calls:
messages.append({
"role": "assistant",
"content": final_content or None,
"tool_calls": tool_calls
})
for tc in tool_calls:
func_name = tc["function"]["name"]
func_args = json.loads(tc["function"]["arguments"])
print(f"n[{func_name} çalıştırılıyor...]")
result = function_map.get(func_name, lambda **k: {})(** func_args)
messages.append({
"role": "tool",
"tool_call_id": tc["id"],
"content": json.dumps(result, ensure_ascii=False)
})
# Final streaming yanıt
print("nSonuç: ", end="")
final_stream = client.chat.completions.create(
model="gpt-4o",
messages=messages,
stream=True
)
for chunk in final_stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
print()
EOF
Production’da Function Calling: İpuçları ve Dikkat Edilecekler
Birkaç ayda bu yapıyı gerçek projelerde kullandıktan sonra öğrendiğim dersleri paylaşayım.
Fonksiyon açıklamalarını ciddiye alın. Model, hangi fonksiyonu ne zaman kullanacağına description’a bakarak karar veriyor. “Disk bilgisi döndürür” yerine “Belirtilen dizin veya tüm mount noktaları için disk kullanım yüzdesi, toplam alan ve boş alan bilgisini döndürür” gibi detaylı yazın.
Tool choice parametresini akıllıca kullanın. Şu seçenekler var:
- “auto”: Model istediği zaman fonksiyon çağırabilir
- “required”: Model mutlaka bir fonksiyon çağırmak zorunda
- {“type”: “function”, “function”: {“name”: “fonksiyon_adi”}}: Belirli bir fonksiyon mutlaka çağrılmalı
- “none”: Fonksiyon çağrısı yapılamaz, sadece metin yanıtı
Token maliyetine dikkat edin. Her fonksiyon tanımı token tüketiyor. 20 fonksiyon tanımlarsanız ve bunların yarısı nadiren kullanılıyorsa, kullanıcının sorusuna göre dinamik olarak tool listesi oluşturmayı düşünün.
Async yapı kullanın. Production uygulamalarda asyncio ile aiohttp kombinasyonu, özellikle paralel tool call’larda büyük performans farkı yaratır:
cat > async_function_calling.py << 'EOF'
import asyncio
import json
from openai import AsyncOpenAI
from dotenv import load_dotenv
import os
load_dotenv()
async_client = AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY"))
async def async_execute_tools(tool_calls: list, async_function_map: dict) -> list:
"""Tüm tool call'ları asenkron ve paralel çalıştırır"""
tasks = []
for tool_call in tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
if func_name in async_function_map:
task = asyncio.create_task(
async_function_map[func_name](**func_args)
)
tasks.append((tool_call.id, task))
results = []
for call_id, task in tasks:
try:
result = await task
results.append({
"role": "tool",
"tool_call_id": call_id,
"content": json.dumps(result, ensure_ascii=False)
})
except Exception as e:
results.append({
"role": "tool",
"tool_call_id": call_id,
"content": json.dumps({"error": str(e)})
})
return results
# Örnek async fonksiyon
async def async_check_url_health(url: str) -> dict:
import aiohttp
async with aiohttp.ClientSession() as session:
try:
async with session.get(url, timeout=aiohttp.ClientTimeout(total=5)) as response:
return {
"url": url,
"status_code": response.status,
"is_healthy": response.status == 200,
"response_time_ms": 0 # gerçekte time ölçülür
}
except Exception as e:
return {"url": url, "is_healthy": False, "error": str(e)}
EOF
Conversation state’i veritabanında saklayın. Uzun süreli chatbot uygulamalarında, konuşma geçmişini Redis veya PostgreSQL’de tutun. Hem kullanıcıya “geçen haftaki incident neydi?” sorusunu sorma imkanı tanır, hem de token limitine takılmazsınız.
Logging ve audit trail şart. Hangi fonksiyon, hangi parametrelerle, kim tarafından, ne zaman çağrıldığını mutlaka kaydedin. Hem debugging için hem de güvenlik auditi için kritik.
Sonuç
Function Calling, OpenAI API’yi gerçek anlamda işe yarar bir araca dönüştürüyor. Saf bir chatbot ile bir sysadmin asistanı arasındaki fark tam olarak burada: biri size genel bilgi verirken, diğeri sisteminize bakıyor, gerçek verileri okuyor ve aksiyonlar alabiliyor.
Bu yazıda anlattıklarımı özetlersek: temel request-response döngüsü, çoklu fonksiyon yönetimi, paralel çalıştırma, güvenlik kontrolleri, streaming ve async yapı. Bunların hepsini anlamadan production’a çıkmayın derim.
Bir sonraki adım olarak bu yapıyı MCP (Model Context Protocol) ile genişletmeyi, ya da LangChain/LlamaIndex gibi frameworklerin Function Calling’i nasıl soyutladığını inceleyebilirsiniz. Ama temeli sağlam atmadan framework soyutlamalarına geçmek, temeli olmayan binaya kat eklemek gibi. Önce buradaki kavramları özümseyin, sonra üstüne inşa edin.
Sorunuz varsa yorumlarda yazın, elimden geldiğince döneceğim.
