AACSearch
SDKs

Python SDK

Der generierte Client aacsearch — Installation, Konstruktor, Keyword-only-Methoden, AACSearchError und der Retry-Vorbehalt.

Der Python-Client liegt in packages/sdk-python, Distributionsname aacsearch, Paket aacsearch. Er benötigt Python 3.9+ und requests>=2.31 und wird aus demselben OpenAPI-Dokument erzeugt wie der TypeScript-Client.

pip install -e packages/sdk-python     # innerhalb des Monorepos
from aacsearch import AACSearchClient, AACSearchError

client = AACSearchClient("aac_live_9f3c2a1b…", base_url="https://search.example.com/api/v1")
result = client.search(index="documentation", query={"q": "preise", "per_page": 5})
print(result["found"], result["hits"][0]["document"]["title"])

Konstruktor

AACSearchClient(
    api_key: str,
    base_url: str = "http://localhost:3000/api/v1",
    max_retries: int = 2,
)

Der Client hält eine requests.Session und sendet bei jedem Aufruf Authorization: Bearer <key> plus Content-Type: application/json. Ein leerer api_key wirft vor dem Request:

AACSearchClient("")
# AACSearchError: api_key is required (status=401, code=MISSING_API_KEY)

Fehler

class AACSearchError(Exception):
    status: int          # HTTP-Status
    code: str            # UNAUTHORIZED, QUOTA_EXCEEDED, VALIDATION_ERROR …
    details: Any         # details aus dem Fehler-Umschlag
    request_id: str | None
try:
    client.upsert_documents(
        index="documentation",
        body={"documents": [{"external_id": "pricing", "content": "Pro kostet 29 USD im Monat."}]},
    )
except AACSearchError as error:
    if error.code == "RATE_LIMITED":
        time.sleep(2)
    elif error.code == "QUOTA_EXCEEDED":
        raise SystemExit(f"Kontingent erschöpft bis {(error.details or {}).get('resetsAt')}")
    else:
        raise RuntimeError(f"{error.code} {error} (request {error.request_id})")

__str__ liefert die message aus dem Umschlag, deshalb liest sich str(error) wie ein Satz und nicht wie ein Statuscode.

Retries

Der Client enthält einen Helfer _request, der 429 und 5xx bis max_retries mit 250 ms × 2ⁿ Backoff wiederholt. Die generierten Methoden rufen requests jedoch direkt auf und laufen nicht durch diesen Helfer — im aktuellen Build ist daher kein automatischer Retry anzunehmen: umwickeln Sie wichtige Aufrufe mit eigenem Retry samt Jitter und beachten Sie, dass 429 ohne Retry-After kommt; lesen Sie bei Bedarf error.details["reset_at"].

Methoden

Alle Methoden sind nach self keyword-only, nutzen snake_case und geben das geparste JSON als dict zurück. query-Argumente werden Query-Parameter, body-Argumente der JSON-Body.

Suche und Discovery

MethodeHTTP
search(index=..., query={...})GET /indexes/{index}/search
search_post(index=..., body={...})POST /indexes/{index}/search
suggest(index=..., query={...})GET /indexes/{index}/suggest
multi_search(body={...})POST /indexes/multi_search
nl_search(index=..., body={...})POST /indexes/{index}/nl-search
index_stats(index=..., query={...})GET /indexes/{index}/stats
health(), capabilities(), openapi()öffentliche Discovery-Endpunkte
metrics()GET /metrics (Betriebs-Token nötig)
hits = client.search(
    index="documentation",
    query={"q": "preise", "query_by": "title,content", "filter_by": "tags:=[billing]", "per_page": 5},
)
for hit in hits["hits"]:
    print(hit["document"]["title"], hit["score"])

Dokumente

MethodeHTTP
upsert_documents(index=..., body={...})POST /indexes/{index}/documents
get_document(index=..., externalId=...)GET /indexes/{index}/documents/{externalId}
delete_document(index=..., externalId=...)DELETE /indexes/{index}/documents/{externalId}
delete_documents(index=..., query={...})DELETE /indexes/{index}/documents?filter_by=…
bulk_update_documents(index=..., body={...})POST /indexes/{index}/documents/bulk
export_documents(index=...)GET /indexes/{index}/documents/export

Beachten Sie externalId in camelCase — die einzige Stelle, an der die generierte Signatur den Protokollnamen behalten hat.

client.upsert_documents(
    index="documentation",
    body={
        "documents": [
            {
                "external_id": "pricing",
                "title": "Preise",
                "content": "Pro kostet 29 USD im Monat und enthält 500.000 Suchen.",
                "tags": ["billing"],
            }
        ],
        "action": "upsert",
    },
)

document = client.get_document(index="documentation", externalId="pricing")
client.delete_documents(index="documentation", query={"filter_by": "source_type:=connector"})

KI

MethodeHTTP
answer(index=..., body={...})POST /indexes/{index}/answer
assistant_ask(index=..., body={...})POST /indexes/{index}/assistant
assistant_stream(index=..., body={...})POST /indexes/{index}/assistant/stream — Generator
assistant_native(index=..., body={...})POST /indexes/{index}/assistant/native
assistant_threads(index=...)GET /indexes/{index}/assistant
assistant_thread(index=..., conversationId=...)GET /indexes/{index}/assistant/{conversationId}
conversation_models(index=...)GET /indexes/{index}/conversation-models
voice_search(index=..., body={...})POST /indexes/{index}/voice
image_search(index=..., body={...})POST /indexes/{index}/image
answer = client.answer(index="documentation", body={"question": "Was kostet Pro?"})
print(answer["answer"])
for citation in answer["citations"]:
    print(f"[{citation['index']}] {citation['title']} {citation['url'] or ''}")

for event in client.assistant_stream(index="documentation", body={"question": "Und die Limits?"}):
    if event["type"] == "delta":
        print(event["payload"].get("text", ""), end="")

assistant_stream ist ein Generator über geparste SSE-Frames: {"type": "citations" | "delta" | "done" | "error", "payload": …}.

Relevanz, Betrieb, Analytics

MethodeHTTP
list_synonyms / put_synonym / delete_synonym/indexes/{index}/synonyms
list_curations / put_curation / delete_curation/indexes/{index}/curations
track_event(index=..., body={...})POST /indexes/{index}/events
reindex(index=...)POST /indexes/{index}/reindex
scoped_key(index=..., body={...})POST /indexes/{index}/scoped-key
usage(), wallet()/billing/usage, /billing/wallet
analytics_overview(query={...})GET /analytics/overview
analytics_overview_csv(query={...})GET /analytics/overview.csv
slow_queries(query={...}), trending_queries(query={...})/analytics/slow-queries, /analytics/trending
export_organization(), purge_organization(query={...})/organization/export, /organization/data
trigger_snapshot(), run_jobs(query={...})/admin/snapshot, /admin/jobs/run

Vorbehalte

Der generierte Python-Client übernimmt auch die Abweichungen des TypeScript-Clients vom Server:

  • multi_search(body={...}) sendet an die föderierte Route /indexes/multi_search und liefert ein Ergebnis pro Suche.
  • export_documents ruft response.json() auf einem NDJSON-Stream auf und wirft. Lesen Sie response.text.
  • webhook_ingest sendet weder Body noch Signatur-Header; signieren Sie selbst und nutzen Sie requests.
  • multi_suggest sendet keinen Body, obwohl der Endpunkt indexes und q verlangt.

Für alles außerhalb der generierten Oberfläche sind die rohen Endpunkte der API-Referenz der Vertrag — der Client fügt nichts hinzu außer Basis-URL-Handling und JSON-Kodierung.

On this page