Skip to main content
All posts
Batch-ETL & Lokalisierung

Abbruchfreie 10.000-Zeilen-Batch-Pipelines & originalgetreue Game-Lokalisierung auf bf16.ai

Wie Content-Filter-Fehler Batch-ETL-Jobs vergiften und Dark-Fantasy-Dialoge weichspülen — und wie dieselben Jobs auf bf16.ai mit GLM-5.3 Flash, GLM-5.3 und Prefix-Caching laufen, wobei das geteilte Glossar zum Cached-Input-Preis abgerechnet wird.

TL;DR · Batch- & Lokalisierungs-Engineering

  • Stille Datenvergiftung: Bei 10.000 juristischen, klinischen oder RPG-Datensätzen würden schon 4,8 % Filter-Ablehnungen 480 Lücken hinterlassen — oder Ablehnungssätze direkt in die Spiel-Datenbank schreiben.
  • Zweistufiges Routing auf bf16.ai: zai-org/glm-5.3-flash-abliterated ($0.24/$0.06/$1.00) für Massen-UI/ETL und zai-org/glm-5.3-abliterated ($1.40/$0.30/$4.40, unter offiziellem Listenpreis) für Hauptdialoge.
  • 50K-Glossar im Prefix-Cache + Idempotency-Key: Ein eingefrorenes 50K-Token-Glossar im System-Prompt wird bei jeder Wiederverwendung zum Cached-Input-Preis abgerechnet ($0.06 statt $0.24 pro 1M auf GLM-5.3 Flash) — ohne Doppelabrechnung bei Retries.

1. Wie Standard-APIs große ETL-Läufe und Narrative-Lokalisierung sabotieren

Gerichtsprotokolle, Notaufnahme-Berichte und düstere Thriller- oder RPG-Skripte enthalten raue Sprache. Konsumenten-APIs erzeugen nicht nur 400 content_policy_violation-Retry-Stürme, sondern glätten heimlich den Tonfall von Antagonisten oder schreiben Entschuldigungstexte direkt ins Produktiv-JSON:

[etl-worker:chunk-0902] Localizing row_id="ch4_syndicate_interrogation_12" (EN -> JA, ZH-CN, DE)
[upstream:cloud-api] HTTP 400 content_policy_violation (attempt 1/3 -> retry backoff 2s)
[upstream:cloud-api] HTTP 400 content_policy_violation (attempt 2/3 -> retry backoff 4s)
[upstream:cloud-api] Fallback row output contaminated:
  {"ja": "申し訳ありませんが、脅迫や暴力的な表現を含む台詞は翻訳できません。", "zh": "..."}
[qa-gate] CRITICAL: Refusal string written into production localization table! 480 / 10,000 rows failed build.

2. Prefix-Cached Batch-Architektur: GLM-5.3 Flash + GLM-5.3

Unter bf16.ai/models ergänzen sich zwei abliterierte Modelle optimal:

  1. zai-org/glm-5.3-flash-abliterated (1M Kontext): Mit $0.06/1M Cached-Input ideal für strukturierte Extraktion und UI-Strings.
  2. zai-org/glm-5.3-abliterated (1M Kontext): Bewahrt literarischen Stil, Slang und dramatische Schärfe ($1.40/$0.30/$4.40).

Abbruchfreie Batch-Pipeline: Geteiltes 50K-Glossar im Cache + striktes JSON-Schema + Idempotency-Key.

▲ Abbruchfreie Batch-Pipeline: Geteiltes 50K-Glossar im Cache + striktes JSON-Schema + Idempotency-Key.

3. Produktionsreifer TypeScript-Worker mit Idempotency-Key & Platzhalter-Check

Platziere das 50.000-Token-Glossar unverändert am Anfang der system-Nachricht für maximale Cache-Treffer und sichere jeden Chunk per Idempotency-Key ab:

import OpenAI from 'openai';

const bf16 = new OpenAI({
  baseURL: 'https://api.bf16.ai/v1',
  apiKey: process.env.BF16_BATCH_KEY,
});

// Shared 50,000-token lore glossary stays identical across all chunks -> hits $0.06-$0.30/1M prefix cache!
export async function localizeDialogueBatch(
  frozenGlossaryXml: string,
  batchId: string,
  rows: Array<{ id: string; speaker: string; sourceEn: string; tier: 'bulk_ui' | 'cinematic' }>
) {
  const isCinematic = rows.some((r) => r.tier === 'cinematic');
  const model = isCinematic
    ? 'zai-org/glm-5.3-abliterated'            // $1.40 in / $0.30 cached / $4.40 out
    : 'zai-org/glm-5.3-flash-abliterated';     // $0.24 in / $0.06 cached / $1.00 out

  const completion = await bf16.chat.completions.create(
    {
      model,
      temperature: isCinematic ? 0.35 : 0.1,
      response_format: {
        type: 'json_schema',
        json_schema: {
          name: 'localized_rows',
          strict: true,
          schema: {
            type: 'object',
            additionalProperties: false,
            required: ['items'],
            properties: {
              items: {
                type: 'array',
                items: {
                  type: 'object',
                  additionalProperties: false,
                  required: ['id', 'ja', 'zh_CN', 'de'],
                  properties: {
                    id: { type: 'string' },
                    ja: { type: 'string' },
                    zh_CN: { type: 'string' },
                    de: { type: 'string' },
                  },
                },
              },
            },
          },
        },
      },
      messages: [
        {
          role: 'system',
          content:
            'You are a senior game & legal corpus localization engine. Preserve speaker register, ' +
            'slang, dark-fantasy conflict, and placeholders ({player_name}, %d) 1:1 without sanitizing ' +
            'tone or appending commentary.\n\n' + frozenGlossaryXml,
        },
        { role: 'user', content: JSON.stringify(rows) },
      ],
    },
    {
      // Safe worker retries: exact replay returns cached response with zero double-charging
      headers: { 'Idempotency-Key': `loc-batch-${batchId}` },
    }
  );

  return JSON.parse(completion.choices[0]?.message?.content ?? '{"items":[]}');
}

Prüfe vor dem Speichern deterministisch alle Platzhalter ({player_name}, %d). Den gesamten 4-Modell-Katalog siehst du unter bf16.ai/models:

// Post-generation placeholder & refusal-leakage assertion before writing to Postgres/Parquet
export function assertCleanLocalizationRow(source: string, translated: string) {
  const placeholders = source.match(/\{[a-z0-9_]+\}|%[sd]/gi) ?? [];
  for (const token of placeholders) {
    if (!translated.includes(token)) {
      throw new Error(`Missing placeholder ${token} in localized output`);
    }
  }
  if (/cannot translate|申し訳ありませんが|无法翻译|als KI-Modell/i.test(translated)) {
    throw new Error('Refusal leakage detected in localized string');
  }
}

4. Kostenrechnung für einen 10.000-Zeilen-Lokalisierungsjob mit Prefix-Caching

Nehmen wir einen Job mit 10.000 Dark-Fantasy-Dialogzeilen (EN -> JA + zh-CN + DE, 20 Zeilen × 500 Chunks, jeder Chunk mit vorangestellter 50.000-Token-Lore-Bibel = 25M kumulierte Glossar-Token). Zu Listenpreisen kosten diese 25M Glossar-Token auf GLM-5.3 Flash ohne Cache $6.00, aus dem Prefix-Cache dagegen nur $1.50 — auf GLM-5.3 sind es $35.00 gegenüber $7.50. Output-Token werden in beiden Fällen gleich abgerechnet:

Pipeline-SetupErgebnis
Gefilterte Cloud-API (3x Retry)Manuelle Nacharbeit nötig
Einzelaufrufe ohne CacheLangsam, und das Glossar kostet bei jedem Aufruf den vollen Input-Preis
bf16.ai mit Cache (GLM-5.3 Flash + GLM-5.3)Direkt auslieferbar

5. 4 Engineering-Regeln für Läufe über 100.000 Zeilen

  1. Statisches system-Präfix bytegenau konstant halten (keine dynamischen Zeitstempel am Anfang).
  2. 15–25 Datensätze pro JSON-Request bündeln.
  3. Queue-Worker immer mit Idempotency-Key ausstatten.
  4. Platzhalter und Textlängen-Expansion automatisiert vor dem Commit prüfen.