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.

Upstage Solar Pro 4 ile güvenli araç çağrısı döngüsü konusu için üç ayrı bilgi kutusunu karşılaştıran veya sıralayan açıklayıcı LLMTR rehber şeması.

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.

Araç döngüsünde uygulamanın uyguladığı hata politikası
DurumUygulama kontrolüSonuç
Bilinmeyen işlev adıSabit izin listesiÇalıştırmadan durdur
Bozuk veya fazla argümanJSON, alan, tür, enum ve aralık denetimiÇağrıyı reddet
Yinelenen çağrı kimliğiTurlar boyunca kimlik kümesiİkinci kez çalıştırma
Çok fazla çağrı veya turSabit işlem bütçesiBütçe hatasıyla bitir
Kesilmiş ya da boş nihai yanıtBitiş nedeni ve içerik denetimiGö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.

İlgili yazılar