Yanıtlar API'sı web_araması

Barındırılan web aramasını PHP cURL ile kullanın ve JSON veya SSE yanıtlarının kodunu güvenle çözün.

Yanıtlar API'sı web_search

Barındırılanı kullanın web_search Bir yanıtın mevcut kamuya açık bilgilere (en son sürümler, belge güncellemeleri, fiyatlar, programlar, düzenlemeler, ürün değişiklikleri veya model eğitim döneminden sonra değişmiş olabilecek diğer gerçekler) bağlı olduğu durumlarda kullanılan araç.

Bu sayfada açıklanmaktadır web_search Açık POST /v1/responses. Bağımsız olandan farklıdır 'POST /v1/web araması' uç nokta.

Önerilen istek

Kurallı bir Responses API giriş dizisi gönderin. Yanıtın canlı kaynaklara dayandırılması gerektiğinde araca ihtiyaç duyulur.

{
  "model": "gpt-5.5",
  "input": [
    {
      "role": "user",
      "content": [
        {
          "type": "input_text",
          "text": "Find the current stable PHP version. Use web search and cite the official sources."
        }
      ]
    }
  ],
  "tools": [
    {
      "type": "web_search"
    }
  ],
  "tool_choice": "required",
  "include": [
    "web_search_call.action.sources"
  ],
  "stream": false
}

Bu alanlar neden önemlidir?

  • tools Barındırılan aramanın model için kullanılabilir olmasını sağlar.
  • tool_choice: required Canlı doğrulama zorunlu olduğunda yalnızca bellekten yanıt verilmesini engeller.
  • include: ["web_search_call.action.sources"] API'den arama çağrısı tarafından dikkate alınan URL'leri eklemesini ister.
  • stream: false akışsız bir yanıt ister ancak uyumlu ağ geçitleri yine de bir Yanıtlar olay akışı döndürebilir. Müşterinizin her iki formatı da desteklemesi gerekir.

Seçilen model belgeleri bunları desteklemediği sürece sağlayıcıya özel oluşturma parametreleri eklemeyin. Yönlendirilmiş sağlayıcılar aşağıdaki gibi parametreleri reddedebilir: temperature, backgroundveya çıkış belirteci kontrolleri.

PHP cURL örneğini tamamlayın

Aşağıdaki örnek, isteği gönderir, yukarı akış hata gövdesini korur ve normal bir JSON yanıtının veya Sunucu Tarafından Gönderilen Olaylar yanıtının kodunu çözer.

<?php

declare(strict_types=1);

$baseUrl = 'https://api.model-gate.com';
$apiKey = getenv('MODEL_GATE_API_KEY') ?: '';

if ($apiKey === '') {
    throw new RuntimeException('MODEL_GATE_API_KEY is not configured.');
}

$url = rtrim($baseUrl, '/') . '/v1/responses';

$request = [
    'model' => 'gpt-5.5',
    'input' => [[
        'role' => 'user',
        'content' => [[
            'type' => 'input_text',
            'text' => 'Find the current stable PHP version. '
                . 'Use web search and cite official sources.',
        ]],
    ]],
    'tools' => [[
        'type' => 'web_search',
    ]],
    'tool_choice' => 'required',
    'include' => [
        'web_search_call.action.sources',
    ],
    'stream' => false,
];

$json = json_encode(
    $request,
    JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR
);

$responseHeaders = [];
$ch = curl_init($url);
if ($ch === false) {
    throw new RuntimeException('Unable to initialize cURL.');
}

curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CONNECTTIMEOUT => 15,
    CURLOPT_TIMEOUT => 900,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
        'Accept: application/json, text/event-stream',
    ],
    CURLOPT_POSTFIELDS => $json,
    CURLOPT_HEADERFUNCTION => static function ($ch, string $line) use (&$responseHeaders): int {
        $length = strlen($line);
        $line = trim($line);
        if ($line === '' || !str_contains($line, ':')) {
            return $length;
        }
        [$name, $value] = array_map('trim', explode(':', $line, 2));
        $responseHeaders[strtolower($name)] = $value;
        return $length;
    },
]);

$responseBody = curl_exec($ch);
$httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlErrorNumber = curl_errno($ch);
$curlError = curl_error($ch);
curl_close($ch);

if ($responseBody === false) {
    throw new RuntimeException(
        sprintf('cURL error %d: %s', $curlErrorNumber, $curlError)
    );
}

if ($httpCode < 200 || $httpCode >= 300) {
    // Keep the exact upstream body. It usually contains the parameter or model error.
    throw new RuntimeException(
        "API returned HTTP {$httpCode}: {$responseBody}"
    );
}

$response = decodeResponsesBody(
    $responseBody,
    $responseHeaders['content-type'] ?? ''
);

$text = '';
$sources = [];
$searchCalls = 0;

foreach (($response['output'] ?? []) as $item) {
    if (($item['type'] ?? null) === 'web_search_call') {
        $searchCalls++;
        foreach (($item['action']['sources'] ?? []) as $source) {
            $url = trim((string) ($source['url'] ?? ''));
            if ($url !== '') {
                $sources[$url] = $url;
            }
        }
    }

    if (($item['type'] ?? null) !== 'message') {
        continue;
    }

    foreach (($item['content'] ?? []) as $part) {
        if (($part['type'] ?? null) !== 'output_text') {
            continue;
        }
        $text .= (string) ($part['text'] ?? '');
        foreach (($part['annotations'] ?? []) as $annotation) {
            if (($annotation['type'] ?? null) !== 'url_citation') {
                continue;
            }
            $url = trim((string) ($annotation['url'] ?? ''));
            if ($url !== '') {
                $sources[$url] = $url;
            }
        }
    }
}

if ($searchCalls === 0) {
    throw new RuntimeException('The response did not contain web_search_call.');
}
if ($sources === []) {
    throw new RuntimeException('The response did not contain auditable source URLs.');
}

echo $text . PHP_EOL;
echo "Sources:" . PHP_EOL;
foreach ($sources as $sourceUrl) {
    echo '- ' . $sourceUrl . PHP_EOL;
}

function decodeResponsesBody(string $body, string $contentType): array
{
    $trimmed = ltrim($body);
    $looksLikeSse = str_contains(strtolower($contentType), 'text/event-stream')
        || str_starts_with($trimmed, 'event:')
        || str_starts_with($trimmed, 'data:');

    if (!$looksLikeSse) {
        $decoded = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
        if (!is_array($decoded)) {
            throw new RuntimeException('Responses API returned a non-object JSON value.');
        }
        return $decoded;
    }

    return decodeResponsesSse($body);
}

function decodeResponsesSse(string $body): array
{
    $output = [];
    $completedResponse = [];
    $eventName = '';
    $dataLines = [];

    $flush = static function () use (&$eventName, &$dataLines, &$output, &$completedResponse): void {
        if ($dataLines === []) {
            $eventName = '';
            return;
        }

        $rawData = implode("\n", $dataLines);
        $dataLines = [];
        if ($rawData === '[DONE]') {
            $eventName = '';
            return;
        }

        $event = json_decode($rawData, true, 512, JSON_THROW_ON_ERROR);
        $type = (string) ($event['type'] ?? $eventName);

        if ($type === 'response.output_item.done' && is_array($event['item'] ?? null)) {
            $output[] = $event['item'];
        }
        if ($type === 'response.completed' && is_array($event['response'] ?? null)) {
            $completedResponse = $event['response'];
        }

        $eventName = '';
    };

    foreach (preg_split('/\r\n|\r|\n/', $body) ?: [] as $line) {
        if ($line === '') {
            $flush();
            continue;
        }
        if (str_starts_with($line, 'event:')) {
            $eventName = trim(substr($line, 6));
            continue;
        }
        if (str_starts_with($line, 'data:')) {
            $dataLines[] = ltrim(substr($line, 5));
        }
    }
    $flush();

    if ($completedResponse === [] && $output === []) {
        throw new RuntimeException('No completed Responses API event was found.');
    }

    // Some compatible gateways send an empty output array in response.completed.
    // Preserve the completed metadata but reconstruct output from output_item.done events.
    $completedResponse['output'] = $output !== []
        ? $output
        : ($completedResponse['output'] ?? []);

    return $completedResponse;
}

Önemli: stream: false yine de SSE'yi döndürebilir

stream: false İstenilen yanıt modunu ifade eder. Uyumlu bir proxy veya yönlendirilmiş bir yukarı akış, tamamlanan Yanıtlar yaşam döngüsünü şu şekilde serileştirmeye devam edebilir: text/event-stream gibi olaylarla:

event: response.output_item.done
data: {"type":"response.output_item.done","item":{"type":"web_search_call",...}}

event: response.completed
data: {"type":"response.completed","response":{"status":"completed",...}}

Koşma json_decode() JSON mu yoksa SSE mi olduğunu belirleyene kadar doğrudan tüm vücudunuza uygulayın. SSE için toplama işlemi tamamlandı response.output_item.done öğeler ve final response.completed meta veriler.

Kaynak doğrulama

Güncel bilgi iş akışları için yanıtı kabul etmeden önce aşağıdakilerin tümünü doğrulayın:

  1. En az biri tamamlandı web_search_call var.
  2. En az bir URL mevcut web_search_call.action.sources veya bir output_text URL alıntısı.
  3. Nihai yanıt durumu: completed.
  4. Kaynaklar kullanmayı düşündüğünüz iddiaları desteklemektedir.
  5. Önemli gerçekler tercihen resmi veya birincil bir kaynak tarafından onaylanır.

Akıcı bir cevabı, aramanın yapıldığının kanıtı olarak görmeyin. Araç çıktısını programlı olarak kontrol edin.

Hata işleme ve yeniden denemeler

  • 2xx olmayan yanıt gövdelerini koruyun. Yararlı sağlayıcı doğrulama mesajları içerirler.
  • HTTP'yi yeniden denemeyin 400 reddedilen isteği değiştirmeden.
  • Geçici yeniden dene 429, 502, 503, 504ve üstel gerileme ve titreşimle birlikte aktarım hataları.
  • Yeniden denemenin bir iş eylemini tetikleyebileceği durumlarda, kendi uygulamanızda bir idempotency anahtarı kullanın.
  • Uzun arama istekleri için uygulamayı, PHP'yi, ters proxy'yi ve ağ geçidi zaman aşımlarını uyumlu tutun.
  • API anahtarlarını veya yakalanan ham yükleri hiçbir zaman son kullanıcılara göstermeyin.

İlgili sayfalar