Ajan ve MCP rehberleri · 2026-08-28
Upstage Solar Pro 4 ile güvenli araç çağrısı döngüsü
Solar Pro 4 araç çağrılarını LLMTR üzerinden alın, argümanları uygulamada kesin kurallarla doğrulayın ve çok adımlı ajan döngüsünü sınırlandırın.
Model çağrıyı önerir, uygulama çalıştırır
Upstage Solar Pro 4 ile araç çağrısı kurmak için LLMTR üzerindeki upstage/solar-pro4 modeline araç şemalarını gönderin, yanıttaki tool_calls listesini inceleyin ve yalnızca izin verdiğiniz yerel işlevleri çalıştırın. Model bir işlev adı ve argüman üretir; veritabanına, ağa veya işletim sistemine kendiliğinden erişmez.
LLMTR katalog kaydı bu modeli metin girdili Chat Completions ve function calling yeteneğiyle bağlar. Upstage’ın resmî belgesi de Solar Pro 4 için tools dizisi, tool sonucu mesajı ve birden çok tur örneği gösterir. Bu rehber yalnız tool_choice değeri olarak auto kullanır; başka modellerin ya da sağlayıcıların aynı seçim biçimlerini desteklediği varsayılmaz.
Araç şemasını küçük ve kapalı tutun
Şema, modelin doğru argümanı üretmesine yardım eder. Örnekte yalnız convert_length adlı işlev vardır; üç alan zorunludur, birimler enum ile sınırlıdır ve additionalProperties false değerindedir. İşlev açıklaması ne kadar dar olursa modelin belirsiz bir işlem önermesi o kadar azalır.
Şema bir güvenlik sınırı değildir. Modelden gelen arguments alanı JSON metnidir ve bozuk JSON, fazla alan, boolean biçimindeki sayı, sonsuz değer ya da izin verilen aralığın dışındaki sayı taşıyabilir. Uygulama JSON ayrıştırmasından sonra alan kümesini, gerçek türleri, sonlu olma durumunu, enum değerlerini ve sayısal aralığı yeniden doğrulamalıdır.
Her turda konuşma zincirini eksiksiz koruyun
İlk istek kullanıcı mesajını, araç şemasını ve auto seçimini taşır. Model araç isterse dönen assistant mesajını tool_calls alanıyla geçmişe ekleyin. Ardından her çağrı için aynı tool_call_id değerini kullanan ayrı bir tool mesajı ekleyin; content alanı serileştirilmiş metin olmalıdır. Güncellenmiş geçmiş sonraki model isteğine gider.
Model yeni bir araç isteyebileceği için akış bir döngüdür. Yine de sınırsız ajan değildir: tur, tur başına çağrı ve yanıt boyutu bütçeleri bulunur. Aynı çağrı kimliği ikinci kez görünürse işlem yeniden çalıştırılmaz. Model tools gönderildiği hâlde doğrudan metin döndürürse auto seçiminin izin verdiği normal bitiş yolu uygulanır.
| Durum | Uygulama kontrolü | Sonuç |
|---|---|---|
| Bilinmeyen işlev adı | Sabit izin listesi | Çalıştırmadan durdur |
| Bozuk veya fazla argüman | JSON, alan, tür, enum ve aralık denetimi | Çağrıyı reddet |
| Yinelenen çağrı kimliği | Turlar boyunca kimlik kümesi | İkinci kez çalıştırma |
| Çok fazla çağrı veya tur | Sabit işlem bütçesi | Bütçe hatasıyla bitir |
| Kesilmiş ya da boş nihai yanıt | Bitiş nedeni ve içerik denetimi | Görevi tamamlandı sayma |
Yan etkisiz, sınırlı Python örneği
LLMTR_BASE_URL değişkenini hesabınız için doğrulanmış ve v1 bölümünü içeren tam API taban adresine, LLMTR_API_KEY değişkenini LLMTR anahtarınıza ayarlayın. Bunlar doğrudan Upstage kimlik bilgileri değildir. Kod taban adrese yalnız chat/completions yolunu ekler.
Bu eğitim örneği burada canlı çalıştırılmadı. Çalıştırırsanız ücretli model istekleri oluşturabilir. Örnek müşteri içeriği kullanmaz, dosya yazmaz, ağ aracına veya kabuğa erişmez; yerel araç yalnız verilen uzunluğu deterministik biçimde dönüştürür. En fazla dört model turu ve tur başına iki araç çağrısı kabul edilir.
Auto araç seçimi, katı argüman doğrulama ve sonuç geri dönüşü
import json
import math
import os
from urllib.request import Request, urlopen
MAX_TURNS = 4
MAX_CALLS_PER_TURN = 2
MAX_RESPONSE_BYTES = 1_000_000
TOOL = {
"type": "function",
"function": {
"name": "convert_length",
"description": "Convert a nonnegative length between centimeters and meters.",
"parameters": {
"type": "object",
"properties": {
"value": {"type": "number", "minimum": 0, "maximum": 1000000},
"from_unit": {"type": "string", "enum": ["cm", "m"]},
"to_unit": {"type": "string", "enum": ["cm", "m"]},
},
"required": ["value", "from_unit", "to_unit"],
"additionalProperties": False,
},
},
}
def convert_length(value, from_unit, to_unit):
meters = value * {"cm": 0.01, "m": 1.0}[from_unit]
return {"value": meters / {"cm": 0.01, "m": 1.0}[to_unit], "unit": to_unit}
HANDLERS = {"convert_length": convert_length}
def execute_tool(call):
if type(call) is not dict or call.get("type") != "function":
raise ValueError("Unsupported tool call")
function = call.get("function")
if type(function) is not dict:
raise ValueError("Missing function object")
name = function.get("name")
if name not in HANDLERS:
raise ValueError("Tool not allowed")
raw = function.get("arguments")
if type(raw) is not str or not 1 <= len(raw) <= 512:
raise ValueError("Invalid argument size")
try:
args = json.loads(raw)
except json.JSONDecodeError as exc:
raise ValueError("Arguments must be valid JSON") from exc
if type(args) is not dict or set(args) != {"value", "from_unit", "to_unit"}:
raise ValueError("Invalid argument fields")
value = args["value"]
if type(value) not in (int, float) or not math.isfinite(value):
raise ValueError("value must be a finite number")
if not 0 <= value <= 1_000_000:
raise ValueError("value outside permitted range")
if args["from_unit"] not in {"cm", "m"} or args["to_unit"] not in {"cm", "m"}:
raise ValueError("Unsupported unit")
return HANDLERS[name](value, args["from_unit"], args["to_unit"])
def post_json(endpoint, payload):
request = Request(
endpoint,
data=json.dumps(payload).encode("utf-8"),
headers={
"Authorization": "Bearer " + os.environ["LLMTR_API_KEY"],
"Content-Type": "application/json",
},
method="POST",
)
with urlopen(request, timeout=45) as response:
raw = response.read(MAX_RESPONSE_BYTES + 1)
if len(raw) > MAX_RESPONSE_BYTES:
raise RuntimeError("Response too large")
data = json.loads(raw)
if type(data) is not dict or type(data.get("choices")) is not list or not data["choices"]:
raise RuntimeError("Malformed model response")
choice = data["choices"][0]
if type(choice) is not dict or type(choice.get("message")) is not dict:
raise RuntimeError("Malformed response choice")
return choice
def run():
endpoint = os.environ["LLMTR_BASE_URL"].rstrip("/") + "/chat/completions"
messages = [{
"role": "user",
"content": "Use convert_length to convert 125 centimeters to meters, then answer briefly.",
}]
seen_ids = set()
for turn in range(MAX_TURNS):
choice = post_json(endpoint, {
"model": "upstage/solar-pro4",
"messages": messages,
"tools": [TOOL],
"tool_choice": "auto",
"parallel_tool_calls": False,
"stream": False,
"max_tokens": 1024,
})
if choice.get("finish_reason") == "length":
raise RuntimeError("Incomplete model response")
message = choice["message"]
calls = message.get("tool_calls") or []
if type(calls) is not list:
raise RuntimeError("Malformed tool call list")
if not calls:
content = message.get("content")
if type(content) is not str or not content.strip():
raise RuntimeError("Missing final answer")
return content
if turn == MAX_TURNS - 1 or len(calls) > MAX_CALLS_PER_TURN:
raise RuntimeError("Tool budget exhausted")
results = []
turn_ids = set()
for call in calls:
call_id = call.get("id") if type(call) is dict else None
if type(call_id) is not str or not 1 <= len(call_id) <= 256:
raise ValueError("Invalid tool call id")
if call_id in seen_ids or call_id in turn_ids:
raise ValueError("Repeated tool call id")
turn_ids.add(call_id)
results.append((call_id, execute_tool(call)))
messages.append({
"role": "assistant",
"content": message.get("content"),
"tool_calls": calls,
})
for call_id, result in results:
messages.append({
"role": "tool",
"tool_call_id": call_id,
"content": json.dumps(result, allow_nan=False),
})
seen_ids.update(turn_ids)
raise RuntimeError("Turn budget exhausted")
if __name__ == "__main__":
run()
Kodun doğrulama sırasını bozmayın
Önce çağrı zarfı ve izinli ad, sonra arguments metninin boyutu ve JSON biçimi, en son alan ve değer kuralları kontrol edilir. Dinamik modül yükleme, globals üzerinden işlev arama veya modelin verdiği adı kabuk komutuna dönüştürme yoktur. Boolean değerleri Python’da sayı alt türü olduğundan type kontrolü özellikle isinstance yerine kesin tür karşılaştırması kullanır.
Araç sonuçları modelin talimatı değil uygulamanın hesapladığı veridir. Yine de sonraki model isteğine girdikleri için gereksiz alanları çıkarmak gerekir. HTTP, JSON veya şema hatası oluştuğunda örnek işlemi keser; aynı geçersiz çağrıyı otomatik olarak tekrar göndermez ve hatalı sonucu başarı metnine dönüştürmez.
Üretimde yetki ve gözlemlenebilirlik ekleyin
Yan etkili bir araç eklerseniz model çağrı kimliği tek başına yeterli olmaz. Kullanıcı yetkisini sunucuda doğrulayın, işlem öncesi açık onay alın ve yeniden denemelerde aynı yazmayı önleyen kalıcı bir işlem anahtarı kullanın. Okuma araçlarında da tenant kapsamını model argümanından değil oturum kimliğinden türetin.
Tur sayısını, hata sınıfını, araç adını ve sağlayıcının raporladığı kullanımı ölçebilirsiniz; istemleri, model yanıtlarını ve araç sonuçlarını loglamayın. Her ajan turu ayrı model isteğidir. Toplam maliyet ve gecikme hesabı yalnız ilk isteği değil, sonuç geri dönüşleri dâhil bütün turları kapsamalıdır.
Sık sorulan sorular
Solar Pro 4 aracı kendi başına çalıştırır mı?
Hayır. Model yalnız yapılandırılmış bir araç çağrısı önerir. Uygulama adı ve argümanları doğrular, izinli işlevi çalıştırır ve sonucu eşleşen tool_call_id ile sonraki isteğe ekler.
JSON Schema doğrulaması tek başına yeterli mi?
Hayır. Şema üretimi yönlendirir, fakat uygulama modelden gelen JSON metnini bağımsız olarak ayrıştırıp tam alan kümesini, türleri, enum değerlerini ve iş kurallarını doğrulamalıdır.
Auto seçildiğinde model araç çağırmadan yanıt verebilir mi?
Evet. Araç kanıtı iş kuralı için zorunluysa doğrudan metni doğrulanmış sonuç saymayın. Uygulama kontrollü biçimde durmalı veya yalnız izin verilen başka bir akışa geçmelidir.
Paralel araç çağrılarını açmalı mıyım?
Yalnız bağımsız çağrıları ve tüm sonuçların eşleşmesini güvenle yönetebiliyorsanız. Bu örnek davranışı basitleştirmek için paralel çağrıları kapatır ve yine de yanıt başına çağrı sayısını sınırlar.