20 % Rabatt auf alle kostenpflichtigen Tarife mit dem Code

Python · KI-Agenten · Amazon

Live-Produktdaten für Ihren KI-Agenten

Ein Sprachmodell weiß nur, was in seinen Trainingsdaten stand. Fragen Sie es, was ein Produkt heute kostet, wird es raten oder sagen, dass es das nicht weiß. Die Lösung: Das Modell fragt beim Schreiben Ihren Code nach der Antwort. Sie beschreiben ein paar „Tools“ – einen Shop durchsuchen, ein Produkt abfragen –, und wenn das Modell Live-Daten braucht, bittet es Ihr Programm, eines davon auszuführen.

Ihr Programm ruft dann everydata.io auf, holt die aktuellen Daten von der Live-Seite und gibt sie an das Modell zurück, das mit echten Preisen und echter Verfügbarkeit antwortet. Das funktioniert mit OpenAI, Anthropic und den meisten anderen Anbietern gleich; nur die Verpackung unterscheidet sich leicht. Diese Anleitung hält die Tools anbieterneutral und zeigt beide Verpackungen.

Aktualisiert am · von everydata.io

Was Sie am Ende haben

  • Zwei Python-Funktionen, die Live-Suchergebnisse und Produktdetails von Amazon abrufen.
  • Eine neutrale Tool-Beschreibung, umgewandelt in Tool-Definitionen im OpenAI- und im Anthropic-Stil.
  • Eine funktionierende Frage-Antwort-Schleife für jeden Anbieter.

Was Sie brauchen

  • Python 3.10 oder neuer, pip install requests sowie das SDK Ihres Modellanbieters (pip install openai oder pip install anthropic).
  • Ein kostenloser everydata.io-API-Schlüssel – hier anlegen – in EVERYDATA_API_KEY.
  • Ein API-Schlüssel Ihres Modellanbieters in OPENAI_API_KEY oder ANTHROPIC_API_KEY.

01So funktioniert Tool Calling – in vier Schritten

  • Sie senden die Frage zusammen mit einer Liste von Tools: einem Namen, einem Satz dazu, was jedes Tool tut, und welche Eingaben es erwartet.
  • Statt sofort zu antworten, erwidert das Modell: „Bitte führe search_amazon mit dem Keyword ‚usb c charger 20w‘ aus.“
  • Ihr Code führt diese Funktion aus – hier: eine Anfrage an everydata.io – und schickt das Ergebnis zurück.
  • Das Modell liest das Ergebnis und schreibt die endgültige Antwort. Braucht es mehr, fordert es zuerst ein weiteres Tool an.

Das Modell sieht Ihren everydata.io-Schlüssel nie und ruft die API nie selbst auf. Ihr Code entscheidet, was tatsächlich ausgeführt wird.

02Die Funktionen schreiben, die die Daten abrufen

Das sind ganz normale Python-Funktionen. Jede stellt eine Anfrage und behält nur die Felder, die das Modell braucht – eine vollständige Produktseite hat Dutzende Felder, und jedes zusätzliche Feld kostet Tokens, ohne die Antwort zu verbessern.

tools.py
"""Two tools an AI model can call: search Amazon and look up one product – live, through everydata.io."""
import json
import os
import re
import time

import requests

API = "https://api.everydata.io"
KEY = os.environ["EVERYDATA_API_KEY"]


def _get(path: str, params: dict) -> dict:
    """One everydata.io request. Errors come back as data, so the model can explain them instead of crashing."""
    retried = False
    for _ in range(4):
        try:
            resp = requests.get(f"{API}{path}", params=params, headers={"x-api-key": KEY}, timeout=60)
        except requests.RequestException as exc:
            return {"error": "network", "detail": str(exc)[:300]}
        if resp.status_code == 429:
            # Too many requests at once. The answer says how long to wait: "... Try again in 12 seconds."
            wait = re.search(r"in (\d+) seconds", resp.text)
            time.sleep(int(wait.group(1)) + 1 if wait else 60)
            continue
        if resp.status_code >= 500 and not retried:
            retried = True  # the page could not be loaded – try once more (5xx answers are not counted)
            time.sleep(5)
            continue
        if resp.status_code >= 400:
            return {"error": resp.status_code, "detail": resp.text[:300]}
        return resp.json()
    return {"error": 429, "detail": "Still rate limited after waiting. Try again in a minute."}


def search_amazon(keyword: str, domainCode: str = "com") -> dict:
    data = _get("/amz/amazon-search-by-keyword-asin",
                {"keyword": keyword, "domainCode": domainCode, "excludeSponsored": "true"})
    if "error" in data:
        return data
    keep = ("asin", "productDescription", "price", "currency", "productRating", "countReview")
    # Only the first five results and only the fields the model needs: fewer tokens, better answers.
    return {"results": [{k: p.get(k) for k in keep} for p in data.get("searchProductDetails", [])[:5]]}


def get_amazon_product(asin: str, domainCode: str = "com") -> dict:
    data = _get("/amz/amazon-lookup-product-by-asin", {"asin": asin, "domainCode": domainCode})
    if "error" in data:
        return data
    keep = ("productTitle", "asin", "price", "retailPrice", "currency",
            "productRating", "countReview", "warehouseAvailability", "features")
    return {k: data.get(k) for k in keep}


FUNCTIONS = {"search_amazon": search_amazon, "get_amazon_product": get_amazon_product}


def run_tool(name: str, args: dict) -> str:
    """Run the tool the model asked for and return the result as a JSON string."""
    fn = FUNCTIONS.get(name)
    if fn is None:
        return json.dumps({"error": f"unknown tool {name}"})
    try:
        return json.dumps(fn(**args), ensure_ascii=False)
    except Exception as exc:  # wrong arguments, unexpected data … – tell the model instead of crashing
        return json.dumps({"error": "tool failed", "detail": f"{type(exc).__name__}: {exc}"[:300]})

So sieht die Antwort des Such-Endpoints aus, bevor die Funktion sie kürzt (gekürztes dokumentiertes Beispiel):

Beispielantwort · GET /amz/amazon-search-by-keyword-asin
{
  "responseStatus": "PRODUCT_FOUND_RESPONSE",
  "responseMessage": "Product successfully found!",
  "domainCode": "com",
  "keyword": "laptop",
  "numberOfProducts": 26,
  "searchProductDetails": [
    {
      "productDescription": "Acer Aspire 14 AI Copilot+ PC - Intel Core Ultra 5 226V & 14” WUXGA Touch - NPU: Up to 40 Tops - GPU: Up to 53 Tops | Intel Arc 130V | 16GB LPDDR5X | 1TB Gen 4 SSD | Wi-Fi 6E | A14-52MT-59DP",
      "asin": "B0FGJ14KRX",
      "countReview": 20,
      "price": 548.44,
      "productRating": "4.0 out of 5 stars",
      "currency": "USD"
    }
  ],
  "currentPage": 1,
  "lastPage": 20
}

03Die Tools einmal beschreiben und dann pro Anbieter verpacken

Anhand der Beschreibung entscheidet das Modell, wann es ein Tool nutzt – schreiben Sie sie also für das Modell: was das Tool liefert und wann es nützlich ist. Die Eingaben werden in JSON Schema beschrieben, das jeder große Anbieter versteht. Nur die Hülle darum unterscheidet sich.

tools.py (Fortsetzung)
# Add to tools.py – one description per tool, written for the model, in plain JSON Schema.
TOOL_SPECS = [
    {
        "name": "search_amazon",
        "description": "Search Amazon right now. Returns up to 5 products with ASIN, title, current price, "
                       "currency and rating. Use it when the user asks what is available or what something costs.",
        "parameters": {
            "type": "object",
            "properties": {
                "keyword": {"type": "string", "description": "What to search for, e.g. 'usb c charger 20w'"},
                "domainCode": {"type": "string", "description": "Amazon marketplace: com, de, co.uk, fr, it, es …"},
            },
            "required": ["keyword"],
        },
    },
    {
        "name": "get_amazon_product",
        "description": "Live details of one Amazon product by ASIN: title, price, list price, availability, "
                       "rating and key features. A price of 0 means the page shows no price right now.",
        "parameters": {
            "type": "object",
            "properties": {
                "asin": {"type": "string", "description": "10-character Amazon product ID, e.g. B07ZPKN6YR"},
                "domainCode": {"type": "string", "description": "Amazon marketplace: com, de, co.uk, fr, it, es …"},
            },
            "required": ["asin"],
        },
    },
]

# OpenAI-style (Chat Completions): the schema goes under "function" -> "parameters".
OPENAI_TOOLS = [{"type": "function", "function": spec} for spec in TOOL_SPECS]

# Anthropic-style (Messages API): the same schema is called "input_schema".
ANTHROPIC_TOOLS = [
    {"name": s["name"], "description": s["description"], "input_schema": s["parameters"]}
    for s in TOOL_SPECS
]

Die Parameternamen entsprechen der API (keyword, asin, domainCode), sodass die Argumente des Modells direkt an die Funktionen aus Schritt 2 weitergereicht werden können.

04Mit einer API im Anthropic-Stil ausführen

Die Schleife sendet die Frage, führt jedes Tool aus, das das Modell anfordert, gibt die Ergebnisse als tool_result-Blöcke zurück und endet, sobald das Modell mit Text antwortet.

ask_claude.py
import anthropic

from tools import ANTHROPIC_TOOLS, run_tool

client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY
MAX_ROUNDS = 5  # hard limit on tool rounds – every tool call is one everydata.io request
messages = [{"role": "user", "content": "What does a 20W USB-C charger cost on amazon.com right now?"}]

for _ in range(MAX_ROUNDS):
    response = client.messages.create(
        model="claude-opus-5",
        max_tokens=16000,
        tools=ANTHROPIC_TOOLS,
        messages=messages,
    )
    if response.stop_reason != "tool_use":
        break
    messages.append({"role": "assistant", "content": response.content})
    messages.append({
        "role": "user",
        "content": [
            {"type": "tool_result", "tool_use_id": block.id, "content": run_tool(block.name, block.input)}
            for block in response.content
            if block.type == "tool_use"
        ],
    })
else:
    raise SystemExit(f"Stopped after {MAX_ROUNDS} tool rounds without a final answer. "
                     "Ask a more specific question or raise MAX_ROUNDS.")

print("".join(block.text for block in response.content if block.type == "text"))

05Mit einer API im OpenAI-Stil ausführen

Dieselbe Schleife, andere Nachrichtenformate: Tool-Anfragen kommen in tool_calls an, mit den Argumenten als JSON-String, und jedes Ergebnis geht als Nachricht mit der Rolle tool zurück. Viele andere Anbieter und lokale Modellserver akzeptieren dieses Format im OpenAI-Stil ebenfalls.

ask_openai.py
import json
import os

from openai import OpenAI

from tools import OPENAI_TOOLS, run_tool

client = OpenAI()  # reads OPENAI_API_KEY
MODEL = os.environ["OPENAI_MODEL"]  # any chat model that supports function calling
MAX_ROUNDS = 5  # hard limit on tool rounds – every tool call is one everydata.io request
messages = [{"role": "user", "content": "What does a 20W USB-C charger cost on amazon.com right now?"}]

for _ in range(MAX_ROUNDS):
    response = client.chat.completions.create(model=MODEL, messages=messages, tools=OPENAI_TOOLS)
    message = response.choices[0].message
    if not message.tool_calls:
        break
    messages.append(message)
    for call in message.tool_calls:
        try:
            args = json.loads(call.function.arguments)
        except json.JSONDecodeError:
            result = json.dumps({"error": "arguments were not valid JSON"})
        else:
            result = run_tool(call.function.name, args)
        messages.append({"role": "tool", "tool_call_id": call.id, "content": result})
else:
    raise SystemExit(f"Stopped after {MAX_ROUNDS} tool rounds without a final answer. "
                     "Ask a more specific question or raise MAX_ROUNDS.")

print(message.content)

06Bevor Sie es Nutzern zur Verfügung stellen

  • Behalten Sie die feste Obergrenze für Tool-Runden bei. Jeder Tool-Aufruf ist eine everydata.io-Anfrage, eine Schleife ohne Grenze kann also Ihr Kontingent aufbrauchen. Wird die Grenze erreicht, halten die Skripte oben mit einer klaren Meldung an, statt eine halbe Antwort auszugeben.
  • Geben Sie Fehler als Daten zurück (_get und run_tool tun das). Das Modell kann dem Nutzer dann sagen, dass eine Seite nicht geladen werden konnte, statt stillschweigend zu scheitern. _get wartet, wenn Sie zu viele Anfragen auf einmal senden (429), und versucht einen fehlgeschlagenen Seitenabruf (5xx) noch einmal; 5xx-Antworten werden nicht auf Ihr Kontingent angerechnet.
  • Kürzen Sie die Ergebnisse. Fünf Suchergebnisse mit je sechs Feldern reichen meist für eine gute Antwort.
  • Sagen Sie dem Modell in der Tool-Beschreibung, dass ein Preis von 0 „derzeit kein Preis angezeigt“ bedeutet, damit es das Produkt nicht als kostenlos meldet.

Sie möchten dieselben Tools in Claude Desktop, Claude Code oder ChatGPT statt in Ihrer eigenen App nutzen? Verpacken Sie sie in einen MCP-Server – siehe MCP-Tool für Live-Webdaten bauen.

In dieser Anleitung verwendete Endpoints

GET/amz/amazon-search-by-keyword-asin

Search Products · Amazon API

GET/amz/amazon-lookup-product-by-asin

Product Details by ASIN · Amazon API

Alle Parameter in der API-Referenz

Probieren Sie es mit Ihren eigenen Daten

Der kostenlose Tarif enthält 100 Anfragen pro Monat, nutzbar auf jeder Plattform – genug, um diese Anleitung vollständig durchzuspielen.