Anbinden · Weg A

Proxy: alle Anbieter

Der Proxy ist der Kern. Er reicht Ihre Anfrage unverändert an den Anbieter durch, liest die Nutzungsangaben aus der Antwort und kann vor dem Aufruf eingreifen. Ihr Anbieterschlüssel geht durch und wird nie gespeichert; Inhalte werden nie gespeichert.

Basis-URLs

AnbieterBasis-URL bei TokenwachtIhr AnbieterschlüsselHinweis
Anthropichttps://tokenwacht.de/anthropicx-api-key wie bisherMessages API, Streaming, Werkzeuge, Prompt-Caching, Batches werden durchgereicht.
OpenAIhttps://tokenwacht.de/openai/v1Authorization: Bearer wie bisherChat Completions und Responses API. Bei Streams setzt der Proxy stream_options.include_usage, damit die Zählung exakt bleibt.
Google Geminihttps://tokenwacht.de/geminix-goog-api-key oder ?key=generateContent und streamGenerateContent?alt=sse. Modell aus dem Pfad.
Amazon Bedrockhttps://tokenwacht.de/bedrockBedrock-API-Schlüssel als Authorization: Bearer/model/<id>/invoke, /converse, jeweils mit -with-response-stream. SigV4-signierte Aufrufe funktionieren über einen Proxy nicht; verwenden Sie einen Bedrock-API-Schlüssel. Region der Installation: eu-central-1.
Azure OpenAIhttps://tokenwacht.de/azureapi-key wie bisher, dazu X-TW-Ziel: https://<ressource>.openai.azure.comBereitstellungspfade /openai/deployments/… und /openai/v1/… werden unverändert an Ihre Ressource weitergereicht; nur Microsoft-Domänen sind als Ziel erlaubt. Preise: OpenAI-Listenpreise des Grundmodells, das Azure in der Antwort nennt.
Mistralhttps://tokenwacht.de/mistral/v1Authorization: Bearer wie bisherOpenAI-Format (/chat/completions). Der Proxy verändert den Anfragekörper nicht; die Nutzung steht bei Mistral im letzten Chunk. Preiskatalog mistral.yaml.
DeepSeekhttps://tokenwacht.de/deepseek/v1Authorization: Bearer wie bisherOpenAI-Format. DeepSeek rechnet nach Tageszeit; der Katalog führt den Spitzensatz als Obergrenze.
Groqhttps://tokenwacht.de/groq/v1Authorization: Bearer wie bisherOpenAI-Format; die Nutzung im Strom liest der Proxy aus x_groq.usage. Katalog kennt die belegten Modelle, weitere über eigene Preise.
OpenRouterhttps://tokenwacht.de/openrouter/v1Authorization: Bearer wie bisherOpenAI-Format. Der Proxy fordert usage.include an und übernimmt den Betrag aus usage.cost als verbindliche Kosten — kein Katalog nötig, jedes Modell hinter OpenRouter wird richtig gerechnet.
Eigenes Zielhttps://tokenwacht.de/ziel/<name>/v1wie beim Ziel (Ollama: keiner)Ollama, vLLM, LM Studio, LiteLLM oder eine feste Azure-Ressource — im Cockpit unter Anbindung angelegt. Siehe Eigene Ziele und Preise.

Mistral, DeepSeek, Groq und OpenRouter brauchen keinen eigenen Client: der OpenAI-Client mit der jeweiligen Basis-URL und dem Schlüssel des Anbieters genügt. Im Ereignis steht der echte Anbietername (mistral, azure, groq …), im Cockpit erscheinen sie getrennt.

Kopfzeilen

KopfzeilePflichtBedeutung
X-TW-KeyjaIhr Tokenwacht-Schlüssel tw_live_…. Ohne ihn antwortet der Proxy mit 401 und reicht nichts weiter.
X-TW-AgentempfohlenDer Agent als dauerhafte Einheit, z. B. nils-icp-research. Fehlt er, heißt der Agent „unbenannt“.
X-TW-RunempfohlenLauf-Kennung: UUID oder beliebiger Text (z. B. RL-0815). Fehlt sie, bildet Tokenwacht Läufe automatisch: gleicher Agent, weniger als 15 Minuten Pause = derselbe Lauf.
X-TW-StepoptionalSchrittnummer im Lauf. Fehlt sie, zählt der Proxy hoch.
X-TW-KundeoptionalEndkunden-Kennung für die Weiterbelastung (Reiter Endkunden, CSV, DATEV, PDF).
X-TW-FunktionoptionalFachliche Funktion, z. B. leadliste_erzeugen. Erscheint im Lauf-Detail.
X-TW-BenutzeroptionalMenschlicher Benutzer hinter dem Aufruf, wenn Sie Kosten je Person sehen wollen.

Die Kopfzeilen X-TW-* werden vor der Weiterleitung entfernt. Der Anbieter sieht sie nicht.

Beispiele

Anthropic · Python

from anthropic import Anthropic
client = Anthropic(base_url="https://tokenwacht.de/anthropic",
                   default_headers={"X-TW-Key": TW_KEY, "X-TW-Agent": "nils-icp-research", "X-TW-Run": lauf_id, "X-TW-Kunde": "kunde-4711"})
with client.messages.stream(model="claude-sonnet-5", max_tokens=800, messages=[…]) as strom:
    for text in strom.text_stream:
        print(text, end="")

OpenAI · Python, Responses API

from openai import OpenAI
client = OpenAI(base_url="https://tokenwacht.de/openai/v1", default_headers={"X-TW-Key": TW_KEY, "X-TW-Agent": "erik-closer"})
antwort = client.responses.create(model="gpt-5", input="Fasse den Anruf zusammen.")

Gemini · Python (google-genai)

from google import genai
from google.genai import types
client = genai.Client(api_key=GOOGLE_KEY, http_options=types.HttpOptions(
    base_url="https://tokenwacht.de/gemini", headers={"X-TW-Key": TW_KEY, "X-TW-Agent": "magnus-texter"}))
antwort = client.models.generate_content(model="gemini-2.5-flash", contents="Sag Hallo.")

Gemini · REST

curl "https://tokenwacht.de/gemini/v1beta/models/gemini-2.5-flash:generateContent" \
  -H "x-goog-api-key: $GOOGLE_API_KEY" -H "X-TW-Key: $TOKENWACHT_KEY" -H "X-TW-Agent: probe" \
  -H "content-type: application/json" -d '{"contents":[{"role":"user","parts":[{"text":"Sag Hallo."}]}]}'

Bedrock · Converse mit API-Schlüssel

curl "https://tokenwacht.de/bedrock/model/eu.anthropic.claude-sonnet-5-v1:0/converse" \
  -H "Authorization: Bearer $AWS_BEARER_TOKEN_BEDROCK" -H "X-TW-Key: $TOKENWACHT_KEY" -H "X-TW-Agent: probe" \
  -H "content-type: application/json" -d '{"messages":[{"role":"user","content":[{"text":"Sag Hallo."}]}]}'

# boto3 mit Bedrock-API-Schlüssel (ohne SigV4): Umgebung AWS_BEARER_TOKEN_BEDROCK setzen, dann
# client = boto3.client("bedrock-runtime", region_name="eu-central-1", endpoint_url="https://tokenwacht.de/bedrock")
# Kopfzeilen X-TW-* über ein botocore-Ereignis (before-send) ergänzen — Beispiel in der Fehlersuche.

Azure OpenAI · Python

from openai import AzureOpenAI
client = AzureOpenAI(azure_endpoint="https://tokenwacht.de/azure", api_key=os.environ["AZURE_OPENAI_API_KEY"], api_version="2024-10-21",
                     default_headers={"X-TW-Key": TW_KEY, "X-TW-Agent": "ingrid-termine",
                                      "X-TW-Ziel": "https://meine-firma.openai.azure.com"})   # Ihre Ressource, je Aufruf
antwort = client.chat.completions.create(model="gpt-4.1-prod", messages=[…])   # model = Ihr Bereitstellungsname

Tokenwacht bei sich selbst betrieben? Dann genügt TW_AZURE_OPENAI_URL in der Umgebung, die Kopfzeile entfällt. Alternativ legen Sie die Ressource als eigenes Ziel an.

Mistral, DeepSeek, Groq, OpenRouter · Python mit dem OpenAI-Client

from openai import OpenAI
mistral = OpenAI(base_url="https://tokenwacht.de/mistral/v1", api_key=os.environ["MISTRAL_API_KEY"],
                 default_headers={"X-TW-Key": TW_KEY, "X-TW-Agent": "liv-connector"})
groq = OpenAI(base_url="https://tokenwacht.de/groq/v1", api_key=os.environ["GROQ_API_KEY"], default_headers={…})
router = OpenAI(base_url="https://tokenwacht.de/openrouter/v1", api_key=os.environ["OPENROUTER_API_KEY"], default_headers={…})
antwort = mistral.chat.completions.create(model="mistral-small-latest", messages=[{"role": "user", "content": "Sag Hallo."}])

Ollama im eigenen Netz · eigenes Ziel

# einmalig im Cockpit: Anbindung › Eigene Ziele → Name "ollama", Adresse http://127.0.0.1:11434, Format OpenAI (Selbstbetrieb)
from openai import OpenAI
client = OpenAI(base_url="https://tokenwacht.ihre-firma.de/ziel/ollama/v1", api_key="ollama",
                default_headers={"X-TW-Key": TW_KEY, "X-TW-Agent": "lokal-zusammenfasser"})

Node · Anthropic und OpenAI

const client = new Anthropic({ baseURL: "https://tokenwacht.de/anthropic",
  defaultHeaders: { "X-TW-Key": process.env.TOKENWACHT_KEY, "X-TW-Agent": "liv-connector" } });
const openai = new OpenAI({ baseURL: "https://tokenwacht.de/openai/v1",
  defaultHeaders: { "X-TW-Key": process.env.TOKENWACHT_KEY, "X-TW-Agent": "liv-connector" } });

Was der Proxy misst

  • Eingabe-, Ausgabe-, Cache-Lese-, Cache-Schreib- und Denk-Token exakt aus den Nutzungsangaben des Anbieters, auch bei Streams.
  • Latenz bis zum ersten Zeichen und gesamt, HTTP-Status, Stop-Grund, Werkzeugaufrufe mit Fingerabdruck (für die Leerschleifen-Erkennung), Fingerabdruck des Prompt-Präfixes (für die Cache-Blindheit).
  • Nicht: Prompt, Antwort, Werkzeugargumente, Systemtext. Nur Längen und Hash-Werte.

Ablehnung mit HTTP 402

Greift eine scharfe Regel mit Stufe „stoppen“ oder eine Schutzregel eines Detektors, antwortet der Proxy statt des Anbieters. Ihr Client bekommt ein JSON, mit dem der Agent geordnet enden kann:

HTTP/1.1 402 Payment Required
{"fehler": "tokenwacht_budget_ueberschritten", "regel": "lauf_budget", "regel_id": "…", "regel_name": "Lauf max. 3 €",
 "grenze": "3.0000", "wert": "3.0412", "einheit": "eur", "verbraucht_eur": "2.9800", "schritte": 41,
 "lauf_id": "…", "hinweis": "Lauf-Budget 3 € erschöpft (2.9800 € verbraucht)", "cockpit_url": "https://tokenwacht.de/cockpit"}

So fangen Sie es ab:

# Python (Anthropic-SDK wirft bei 402 einen APIStatusError)
from anthropic import APIStatusError
try:
    client.messages.create(…)
except APIStatusError as e:
    if e.status_code == 402 and e.body and str(e.body.get("fehler", "")).startswith("tokenwacht_"):
        lauf_geordnet_beenden(e.body["hinweis"]); raise SystemExit(0)
    raise

Stufe „drosseln“ verzögert den Aufruf vor der Weiterleitung um bis zu zehn Sekunden; der Client merkt nur eine längere Antwortzeit. Die SDKs von Tokenwacht (Python, Node) werfen bei 402 eine benannte Ausnahme BudgetUeberschritten.

Ausfallverhalten

  • Ist die Regelprüfung gestört, ist der Proxy durchlässig: der Aufruf geht ohne Prüfung zum Anbieter.
  • Ist die Datenbank gestört, werden Ereignisse in eine Nachtragsdatei geschrieben und später nachgetragen; der Aufruf selbst wird nicht verzögert.
  • Ist Tokenwacht komplett nicht erreichbar, setzen Sie die Basis-URL zurück. Den Zustand zeigt die Statusseite. Empfehlung für kritische Agenten: ein Rückfall auf die Anbieteradresse nach einem Verbindungsfehler, wie es das Python-SDK vorsieht.

Grenzen

  • Anfragekörper bis 20 MB, Antwortzeit bis 600 Sekunden (Streams eingeschlossen).
  • Der Proxy ändert keine Parameter, bis auf stream_options.include_usage bei OpenAI-Streams.
  • Anbieter außerhalb der vier genannten: Ingest (Weg D) oder Anfrage an uns.