Úvod >AI >AI v PHP >Dávkové zpracování přes Batch API

Dávkové zpracování přes Batch API

Popisky k tisícům produktů, štítky ke starým článkům, překlad celého webu – úlohy, na jejichž výsledek nikdo nečeká u obrazovky. Batch API je zpracuje najednou za polovinu běžné ceny. Jak dávku v PHP odeslat, hlídat a vyzvednout. Popis API odpovídá stavu k říjnu 2026.

Jak to funguje

  1. Pošlete dávku požadavků – každý má vlastní identifikátor custom_id a stejné parametry jako běžný dotaz.
  2. API dávku zpracuje na pozadí. Většina dávek je hotová do hodiny, nejpozději do 24 hodin (pak nezpracované požadavky vyprší).
  3. Stav kontrolujete dotazem na dávku. Když je processing_status "ended", stáhnete výsledky.

Dávka se platí za polovinu běžné ceny tokenů a může mít až 100 000 požadavků nebo 256 MB.

Pomocná funkce

Batch API má vlastní adresy, proto se hodí obecná funkce pro GET i POST:

// zavolá adresu Claude API, vrátí stavový kód a tělo odpovědi
function claude_api($klic, $adresa, ?array $data = null)
{
  $ch = curl_init("https://api.anthropic.com" . $adresa);
  $volby = array(
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 120,
    CURLOPT_HTTPHEADER => array(
      "content-type: application/json",
      "x-api-key: " . $klic,
      "anthropic-version: 2023-06-01",
    ),
  );
  if ($data !== null) {
    $volby[CURLOPT_POST] = true;
    $volby[CURLOPT_POSTFIELDS] = json_encode($data);
  }
  curl_setopt_array($ch, $volby);
  $telo = curl_exec($ch);
  if ($telo === false) {
    throw new RuntimeException("Spojení se nezdařilo: " . curl_error($ch));
  }
  return array(curl_getinfo($ch, CURLINFO_HTTP_CODE), $telo);
}

Odeslání dávky

Skript vybere produkty bez popisku a pro každý připraví požadavek. Identifikátor custom_id smí obsahovat jen písmena bez diakritiky, číslice, podtržítko a pomlčku (nejvýš 64 znaků) a v dávce musí být jedinečný. Číslo dávky se uloží do databáze, ať ji další skript najde.

$pozadavky = array();
$vysledek = mysqli_query($db, "SELECT id, nazev, parametry FROM produkty WHERE popis = '' LIMIT 1000");
while ($p = mysqli_fetch_assoc($vysledek)) {
  $pozadavky[] = array(
    "custom_id" => "produkt-" . $p["id"],
    "params" => array(
      "model" => "claude-sonnet-5-5",
      "max_tokens" => 400,
      "system" => "Píšeš krátké a věcné popisky produktů pro český e-shop. Žádné superlativy.",
      "messages" => array(array("role" => "user", "content" => "Produkt: " . $p["nazev"] . "\nParametry: " . $p["parametry"])),
    ),
  );
}
if ($pozadavky) {
  list($kod, $telo) = claude_api($klic, "/v1/messages/batches", array("requests" => $pozadavky));
  $davka = json_decode($telo, true);
  if ($kod !== 200) {
    throw new RuntimeException("Dávku se nepodařilo odeslat: HTTP " . $kod . " " . $telo);
  }
  $stmt = mysqli_prepare($db, "INSERT INTO ai_davky (id_davky, stav, vytvoreno) VALUES (?, 'odeslano', NOW())");
  mysqli_stmt_bind_param($stmt, "s", $davka["id"]);
  mysqli_stmt_execute($stmt);
}

Kontrola a výsledky

Druhý skript spouští cron třeba každých deset minut. Výsledky přicházejí jako soubor JSONL (na každém řádku jeden JSON) a nemusí být ve stejném pořadí jako požadavky – k produktu se přiřazují podle custom_id. Každý výsledek má typ succeeded, errored, canceled nebo expired.

$davky = mysqli_query($db, "SELECT id_davky FROM ai_davky WHERE stav = 'odeslano'");
while ($d = mysqli_fetch_assoc($davky)) {
  list($kod, $telo) = claude_api($klic, "/v1/messages/batches/" . rawurlencode($d["id_davky"]));
  $stav = json_decode($telo, true);
  if ($kod !== 200 || $stav["processing_status"] !== "ended") {
    continue;
  }
  // results_url je adresa na api.anthropic.com, stačí z ní cesta
  list($kod, $jsonl) = claude_api($klic, parse_url($stav["results_url"], PHP_URL_PATH));
  $ulozit = mysqli_prepare($db, "UPDATE produkty SET popis = ? WHERE id = ?");
  foreach (explode("\n", trim($jsonl)) as $radek) {
    $r = json_decode($radek, true);
    if (!is_array($r) || $r["result"]["type"] !== "succeeded" || strpos($r["custom_id"], "produkt-") !== 0) {
      continue;
    }
    $text = "";
    foreach ($r["result"]["message"]["content"] as $blok) {
      if ($blok["type"] === "text") {
        $text .= $blok["text"];
      }
    }
    $id = (int) substr($r["custom_id"], 8);
    mysqli_stmt_bind_param($ulozit, "si", $text, $id);
    mysqli_stmt_execute($ulozit);
  }
  $hotovo = mysqli_prepare($db, "UPDATE ai_davky SET stav = 'hotovo' WHERE id_davky = ?");
  mysqli_stmt_bind_param($hotovo, "s", $d["id_davky"]);
  mysqli_stmt_execute($hotovo);
}

Na co si dát pozor

  • Stav dávky má hodnoty in_progress, canceling a ended. Počty v request_counts (processing, succeeded, errored, canceled, expired) se doplní až po dokončení celé dávky.
  • Chybné požadavky (errored, expired) se v ukázce přeskočí a produkty zůstanou bez popisku – při dalším běhu se pošlou znovu. Jen pozor, ať se do nové dávky nedostanou produkty, které ještě čekají v rozpracované dávce.
  • Výsledky jsou dostupné omezenou dobu, pak se dávka archivuje. Stahujte je hned po dokončení.
  • Kontrola textu. Popisky od AI před zveřejněním aspoň namátkou přečtěte. Mohou obsahovat nepravdivé údaje o produktu.
  • S dávkou jde kombinovat i mezipaměť (prompt caching) – stejné instrukce v parametru system pak vyjdou ještě levněji.
  • Na dotazy, na které někdo čeká (chat, formulář), se dávka nehodí – použijte běžné volání, případně streamování.

Související články:
Prompt caching: levnější opakované dotazy
Chyby a opakování dotazů na Claude API
Bezpečné a úsporné použití AI API na webu
parse_url()