Gemini generateContent
MarkdownDas native Google-Gemini-Format: für Gemini CLI, Google GenAI SDK und REST-Clients.
Vollständiger Leitfaden
https://api.ailoot.ai/v1beta/models/{model}:generateContentcurl "https://api.ailoot.ai/v1beta/models/gemini-3.8-flash:generateContent" \
-H "x-goog-api-key: $AILOOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{"role": "user", "parts": [{"text": "Denk dir drei Namen für ein Kaffeehaus aus."}]}
]
}' from google import genai
from google.genai import types
import os
client = genai.Client(
api_key=os.environ["AILOOT_API_KEY"],
http_options=types.HttpOptions(base_url="https://api.ailoot.ai"), # ohne /v1beta
)
resp = client.models.generate_content(
model="gemini-3.8-flash",
contents="Denk dir drei Namen für ein Kaffeehaus aus.",
)
print(resp.text)import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({
apiKey: process.env.AILOOT_API_KEY,
httpOptions: { baseUrl: "https://api.ailoot.ai" }, // ohne /v1beta
});
const resp = await ai.models.generateContent({
model: "gemini-3.8-flash",
contents: "Denk dir drei Namen für ein Kaffeehaus aus.",
});
console.log(resp.text);{
"candidates": [
{
"content": {
"role": "model",
"parts": [{ "text": "1. «Bohne und Dampf» 2. «Morgendlicher Mahlgrad» 3. «Kaffeehaus ums Eck»" }]
},
"finishReason": "STOP"
}
],
"usageMetadata": {
"promptTokenCount": 9,
"candidatesTokenCount": 27,
"totalTokenCount": 36
},
"modelVersion": "gemini-3.8-flash"
}Authentifizierung
- x-goog-api-keyheadererforderlich
Schlüssel
sk-…. Akzeptiert werden auchAuthorization: Beareroderx-api-key. Für die Kompatibilität mit Google wird auch?key=in der Adresse akzeptiert — mit der niedrigsten Priorität;?api_key=wird mit 400 abgelehnt. Wir empfehlen einen Header: So gelangt der Schlüssel nicht in die Logs.
Pfad
- modelstringerforderlich
ID eines Modells mit Gemini-Format, zum Beispiel
gemini-3.8-flashodergemini-3.1-pro. Insgesamt 27.
https://api.ailoot.ai/v1beta/models/{model}:streamGenerateContent?alt=ssehttps://api.ailoot.ai/v1beta/modelsRequest-Body
- contentsarrayerforderlich
Nachrichten mit
role(user/model) undparts: text, inlineData/fileData, functionCall/functionResponse. Als Anhänge sind die vom Modell unterstützten Eingabearten zulässig. - systemInstructionobjectoptional
Systemanweisung als Text:
{"parts": [{"text": "…"}]}. - generationConfigobjectoptional
generationConfigakzeptierttemperature,topP,topK,maxOutputTokens,thinkingConfig,responseMimeType(text/plainoderapplication/json),responseSchemaoderresponseJsonSchema(JSON-Objekt),stopSequences(Array aus Strings),candidateCount: 1, ganzzahligesseed, numerische Werte fürpresencePenaltyundfrequencyPenalty. Zulässige Wertebereiche und Funktionen hängen vom konkreten Modell ab; wählen Sie für JSON-Antworten eine unterstützte Schemaform undapplication/json. Bei Textmodellen istresponseModalities— ausschließlich["TEXT"]. - safetySettingsarrayoptional
Objekte mit den erforderlichen Feldern
categoryundthreshold, dem optionalen Feldmethod. Die Werte müssen vom konkreten Modell unterstützt werden. - toolsarrayoptional
Clientseitige
functionDeclarationsführt Ihre Anwendung aus. Textmodelle akzeptieren außerdem{"googleSearch": {}}und{"urlContext": {}}: einzeln oder gemeinsam im Arraytools. Weder Google Search noch URL context darf gemeinsam mitfunctionDeclarationsin einem Request verwendet werden. Für die Bildausgabe sind nur clientseitige Funktionen verfügbar. Andere integrierte Werkzeuge und explicit cache werden nicht unterstützt. Search/URL context kann eine Reservierung für das volle Eingabelimit erfordern; die tatsächlichentoolUsePromptTokenCountwerden als Eingabetokens berücksichtigt. - toolConfigobjectoptional
functionCallingConfig: mode (AUTO/ANY/NONE/VALIDATED/MODE_UNSPECIFIED), allowedFunctionNames.
Unterstützt das Modell ein Feld, einen Anhang oder eine Werkzeugkombination nicht, wird der Request vor der Reservierung abgelehnt — es wird nichts abgebucht. Sie erhalten HTTP 400 mit status INVALID_ARGUMENT und der Klasse invalid_request (in ErrorInfo.reason — INVALID_REQUEST). Ungültiges JSON, Fehler bei Pfadparametern und anderen Prüfungen liefern ebenfalls 400; lesen Sie den Fehlertext und die Request ID. Die Funktionen hängen vom Modell ab: Prüfen Sie dessen Formate und Eingabearten im Katalog.
PDF, Audio, Video und Links
Bei Gemini-Modellen mit Unterstützung der jeweiligen Eingabeart gilt: parts[].inlineData enthält mimeType und nicht leere base64-Daten; ein PDF muss eine echte PDF-Datei sein. fileData enthält eine öffentliche https-Adresse in fileUri und den MIME-Typ der Datei. Bei YouTube kann der MIME-Typ entfallen. http, private Adressen, gs:// und Objekte der Google Files API werden nicht unterstützt, ebenso wenig Uploads über die Google Files API. Bei Videos können Sie außerdem Folgendes ergänzen: videoMetadata: startOffset/endOffset als String in Sekunden (zum Beispiel 1.5s) und fps größer als 0 und höchstens 24. Größe des Request-Bodys, Kontext, zulässige Eingabe und Antwortlimit werden anhand von Modell und Format geprüft.
| Eingabe | Unterstützte MIME-Typen |
|---|---|
| Inline-Bilder | image/png, image/jpeg, image/webp |
| Dokumente | application/pdf; text/plain, text/html, text/css, text/csv, text/xml, text/rtf, text/markdown, text/javascript, application/x-javascript, text/x-python, application/x-python |
| Audio | audio/wav, audio/mp3, audio/mpeg, audio/aiff, audio/aac, audio/ogg, audio/flac |
| Video | video/mp4, video/mpeg, video/mov, video/quicktime, video/avi, video/x-flv, video/mpg, video/webm, video/wmv, video/3gpp |
import json, os, urllib.request
def generate(model, payload):
req = urllib.request.Request(
"https://api.ailoot.ai/v1beta/models/" + model + ":generateContent",
data=json.dumps(payload).encode(),
headers={"x-goog-api-key": os.environ["AILOOT_API_KEY"],
"Content-Type": "application/json"},
)
# Nur einmal senden. Prüfen Sie nach einer Zeitüberschreitung zuerst die Request ID in Ihrem Nutzungsverlauf, bevor Sie es erneut versuchen.
with urllib.request.urlopen(req, timeout=300) as response:
print("Request ID:", response.headers.get("X-Request-ID"))
return json.load(response)
import base64, pathlib, sys
# Geben Sie eine tatsächlich vorhandene lokale PDF-, Audio- oder Videodatei und ihren unterstützten MIME-Typ an.
path, mime = pathlib.Path(sys.argv[1]), sys.argv[2]
payload = {"contents": [{"role": "user", "parts": [
{"text": "Beschreibe kurz den Inhalt der Datei."},
{"inlineData": {"mimeType": mime,
"data": base64.b64encode(path.read_bytes()).decode()}},
]}]}
print(generate("gemini-3.8-flash", payload))
# Alternativer Anhang: {"fileData": {"mimeType": mime, "fileUri": public_https_url}}
# Für eine echte YouTube-URL: {"fileData": {"fileUri": youtube_url}}Search und URL context
Clientseitige functionDeclarations führt Ihre Anwendung aus. Textmodelle akzeptieren außerdem {"googleSearch": {}} und {"urlContext": {}}: einzeln oder gemeinsam im Array tools. Weder Google Search noch URL context darf gemeinsam mit functionDeclarations in einem Request verwendet werden. Für die Bildausgabe sind nur clientseitige Funktionen verfügbar. Andere integrierte Werkzeuge und explicit cache werden nicht unterstützt. Search/URL context kann eine Reservierung für das volle Eingabelimit erfordern; die tatsächlichen toolUsePromptTokenCount werden als Eingabetokens berücksichtigt.
{"tools": [{"googleSearch": {}}, {"urlContext": {}}]}Bildausgabe
Bilder in einer Antwort im Gemini-Format unterstützt ausschließlich gemini-3.1-flash-image. Diese Funktion ist unabhängig von /v1/images/generations: Andere Bildmodelle funktionieren hier nicht. Dieses Modell erlaubt Eingaben mit bis zu 131072 Tokens und Antworten mit bis zu 32768 Tokens; die vollen Kosten der längstmöglichen Antwort werden vorab reserviert.
responseModalities — eine nicht leere Menge aus TEXT/IMAGE ohne Wiederholungen. imageConfig.imageSize: 1K/2K/4K; aspectRatio: 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9, 1:4, 4:1, 1:8, 8:1. Als Eingabe akzeptiert dieses Modell Text und inline PNG/JPEG/WebP; PDF/audio/video/fileData sowie integrierte Search/URL context werden hier nicht akzeptiert. Verfügbarkeit und Preise für Ihren Schlüssel finden Sie im Katalog und in GET /v1/models.
import json, os, urllib.request
def generate(model, payload):
req = urllib.request.Request(
"https://api.ailoot.ai/v1beta/models/" + model + ":generateContent",
data=json.dumps(payload).encode(),
headers={"x-goog-api-key": os.environ["AILOOT_API_KEY"],
"Content-Type": "application/json"},
)
# Nur einmal senden. Prüfen Sie nach einer Zeitüberschreitung zuerst die Request ID in Ihrem Nutzungsverlauf, bevor Sie es erneut versuchen.
with urllib.request.urlopen(req, timeout=300) as response:
print("Request ID:", response.headers.get("X-Request-ID"))
return json.load(response)
import base64, pathlib
reply = generate("gemini-3.1-flash-image", {
"contents": [{"role": "user", "parts": [{"text": "Aquarell: Leuchtturm im Morgengrauen"}]}],
"generationConfig": {
"responseModalities": ["TEXT", "IMAGE"],
"imageConfig": {"aspectRatio": "1:1", "imageSize": "1K"},
},
})
index = 0
for candidate in reply.get("candidates", []):
for part in candidate.get("content", {}).get("parts", []):
if "text" in part:
print(part["text"])
blob = part.get("inlineData", {})
if blob.get("mimeType", "").startswith("image/") and blob.get("data"):
index += 1
extension = {"image/png": "png", "image/jpeg": "jpg",
"image/webp": "webp"}.get(blob["mimeType"], "bin")
pathlib.Path(f"gemini-image-v{index}.{extension}").write_bytes(
base64.b64decode(blob["data"]))
print("All returned images:", index)Vollständiger Function-Calling-Zyklus
Funktionen führt der Client aus. Geben Sie den gesamten ursprünglichen content des Modells samt thoughtSignature unverändert zurück, anschließend functionResponse mit demselben name und id, sofern id im functionCall enthalten war.
import json, os, urllib.request
def generate(model, payload):
req = urllib.request.Request(
"https://api.ailoot.ai/v1beta/models/" + model + ":generateContent",
data=json.dumps(payload).encode(),
headers={"x-goog-api-key": os.environ["AILOOT_API_KEY"],
"Content-Type": "application/json"},
)
# Nur einmal senden. Prüfen Sie nach einer Zeitüberschreitung zuerst die Request ID in Ihrem Nutzungsverlauf, bevor Sie es erneut versuchen.
with urllib.request.urlopen(req, timeout=300) as response:
print("Request ID:", response.headers.get("X-Request-ID"))
return json.load(response)
tools = [{"functionDeclarations": [{
"name": "multiply", "description": "Zwei Zahlen multiplizieren",
"parameters": {"type": "object", "properties": {
"a": {"type": "number"}, "b": {"type": "number"}},
"required": ["a", "b"]},
}]}]
contents = [{"role": "user", "parts": [{"text": "Multipliziere 7 mit 8 mithilfe der Funktion"}]}]
for turn in range(4): # Begrenzen Sie die Tool-Schleife; senden Sie eine Anfrage mit unklarem Ergebnis nicht erneut.
reply = generate("gemini-3.8-flash", {"contents": contents, "tools": tools})
content = reply["candidates"][0]["content"]
contents.append(content) # Lassen Sie ALLE (ALL) ursprünglichen parts und thoughtSignature unverändert.
results = []
for part in content.get("parts", []):
call = part.get("functionCall")
if not call:
continue
if call["name"] != "multiply":
raise ValueError("Unexpected function")
args = call["args"]
result = {"name": call["name"], "response": {"value": args["a"] * args["b"]}}
if "id" in call:
result["id"] = call["id"]
results.append({"functionResponse": result})
if not results:
print(content)
break
contents.append({"role": "user", "parts": results})
else:
raise RuntimeError("Tool loop limit reached")Antwort
- candidates[].content.partsarray
Antwort des Modells.
- usageMetadataobject
promptTokenCount,candidatesTokenCount,totalTokenCount.