Zum Inhalt springen
LIVOI
Dashboard

Custom Tools Technical Deep Dive

Custom Tools in LIVOI

Custom Tools verbinden einen LIVOI-Agenten mit beliebigen HTTP-APIs. Ein Tool beschreibt, welche Eingaben das Modell liefern darf, und getrennt davon, wie daraus ein konkreter HTTP-Request entsteht. Das Modell sieht nur das Eingabeschema. URL, Methode, Header, API-Key und feste Body-Bestandteile bleiben Konfiguration, die der Agent nicht verändern kann.

Tool Call im Überblick

Beim Laden des Agenten wird jede Tool-Definition erneut validiert. Danach durchläuft jeder Tool Call Validierung, Request-Aufbau, HTTP-Aufruf und Auswertung. Ergebnis und geschwärzter Request-Snapshot landen getrennt in der Chat-Historie.

Custom Tools · Ablauf
100%

Die Grafik zeigt den Standardpfad eines Custom Tool Calls. Die Tool-Suche ist nur aktiv, wenn mindestens ein Tool des Agenten defer_loading nutzt. Preview und Test laufen ohne Agent und ohne Modell, aber über denselben Request-Builder.

Kurzfassung

  • Ein Custom Tool besteht aus request_config, input_schema und optionalen Laufzeitwerten.
  • Eingaben werden als path-, query- oder body-Parameter deklariert.
  • Ein body_template legt die Body-Struktur fest; {“$livoi_input”: “name”} markiert die Stellen, an denen validierte Eingaben eingesetzt werden.
  • Unbekannte Argumente werden abgelehnt. Das Modell kann feste Template-Werte nicht überschreiben.
  • Konfigurationsfehler werden beim Speichern mit 422 und exaktem Feldpfad abgelehnt, nicht erst zur Laufzeit.
  • Die Preview baut den Request ohne Upstream-Kontakt; der Testrequest sendet genau einen echten Request nach expliziter Bestätigung.
  • Jeder Tool Call speichert eine geschwärzte Inspection am tool_call-Teil der Historie. Das Modell erhält sie nie.
  • Mit defer_loading: true bleiben Tools aus dem initialen Kontext heraus und werden über search_tools gefunden.
  • Upstream-Fehler werden klassifiziert und als terminales Ergebnis zurückgegeben, nicht automatisch wiederholt.
  • Der HTTP-Client für Custom Tools speichert und sendet keine Cookies.

Aufbau einer Tool-Definition

Custom Tools gehören immer zu genau einem Agenten und werden als Agent-Tool gespeichert. Der Tool-Name ist pro Agent eindeutig.

tool_name und tool_description

Name in lower_snake_case, maximal 128 Zeichen, nicht identisch mit eingebauten oder internen Tools. Die Beschreibung ist der wichtigste Hinweis für das Modell, wann das Tool passt.

request_config

Ziel-URL, HTTP-Methode, Authentifizierung, zusätzliche Header, optionales body_template und Timeout.

input_schema

Liste der Parameter, die das Modell befüllt, jeweils mit Typ, Ort und optional Default oder Auswahlwerten.

Laufzeitwerte

response_config für eine Erfolgsbedingung, max_retries für fehlerhafte Argumente und defer_loading für die Tool-Suche.

api_key

Optionaler Schlüssel für das Zielsystem. Er wird nie zurückgegeben; Antworten enthalten nur has_api_key.

{
"tool_name": "search_companies",
"tool_description": "Searches companies by name and returns their ID, name, and email address.",
"request_config": {
"api_url": "https://api.example.com/v1/contacts/search",
"http_method": "POST",
"api_key_location": "header",
"auth_param": "Authorization",
"api_key_prefix": "Bearer",
"additional_headers": { "X-Workspace-Id": "example" },
"timeout_seconds": 15,
"body_template": {
"filter": { "name": { "contains": { "$livoi_input": "name" } }, "type": "company" },
"fields": ["id", "name", "email"],
"limit": 10
}
},
"input_schema": {
"parameters": [
{ "name": "name", "type": "string", "location": "body", "description": "Company name to search for." }
]
},
"response_config": {
"success_condition": { "path": ["errors"], "operator": "absent_or_empty_list" }
},
"max_retries": 1,
"defer_loading": true,
"api_key": "sk_tool_live_123456"
}

request_config

FeldStandardBedeutung
api_url–Muss mit http:// oder https:// beginnen. {name} markiert Pfad-Platzhalter.
http_method–GET, POST, PUT, PATCH oder DELETE.
api_key_locationheaderOb der API-Key als Header oder als Query-Parameter übertragen wird.
auth_paramAuthorizationName des Headers oder Query-Parameters für den API-Key.
api_key_prefixBearerPräfix vor dem Key. Leer oder null sendet den Key ohne Präfix.
additional_headers{}Feste Header. Namen und Werte werden getrimmt; Zeilenumbrüche werden abgelehnt.
body_template–Optionale feste JSON-Struktur des Request-Bodys mit Verweisen auf Body-Parameter.
unwrap_single_body_parameterfalseOhne Template: sendet einen einzelnen Body-Parameter als gesamten Body statt als Objekt.
timeout_secondsPlattformTimeout pro Request in Sekunden, größer als 0. Ohne Wert gilt der Plattform-Standard (30 Sekunden).

input_schema

Jeder Parameter wird zu einem Feld im Eingabemodell des Tools. Aus diesem Modell entsteht das JSON-Schema, das das Modell sieht, und dieselbe Definition validiert später die Argumente.

Felder pro Parameter

name, type, location

description

required (Standard true)

default (nur bei optionalen Parametern)

choices (nur string, integer, number)

properties bei object, items bei array

Typen

string

integer

number

boolean

object

array

OrtRegeln
pathPflichtfeld mit skalarem Typ. Jeder Platzhalter in api_url braucht genau einen passenden Path-Parameter und umgekehrt. Werte werden URL-kodiert eingesetzt.
queryKein object. Arrays sind erlaubt, wenn ihre Items skalar sind.
bodyAlle Typen. Mit Template muss jeder Body-Parameter im Template referenziert sein; ohne Template bilden alle Body-Parameter zusammen ein JSON-Objekt.

Body-Templates

Viele APIs erwarten verschachtelte Request-Bodys mit Filtern, Feldlisten oder Limits. Ohne Template müsste das Modell diese Struktur selbst erzeugen. Mit body_template gehört die Struktur dem Tool, und das Modell liefert nur die deklarierten Variablen, etwa {“name”: “Acme”}.

{
"filter": { "name": { "contains": { "$livoi_input": "name" } }, "type": "company" },
"fields": ["id", "name", "email"],
"limit": 10
}

Mit dem Argument {“name”: “Acme”} sendet LIVOI exakt diesen Body:

{"filter":{"name":{"contains":"Acme"},"type":"company"},"fields":["id","name","email"],"limit":10}

Typerhaltende Ersetzung

Ein Verweis wird durch den validierten Wert ersetzt, nicht durch Text. Zahlen bleiben Zahlen, Objekte bleiben Objekte. Strings werden immer als ein JSON-String eingesetzt, auch wenn sie Anführungszeichen oder JSON-ähnlichen Inhalt enthalten.

Feste Werte

Alles außer den Verweisen ist feste Konfiguration. Es taucht nicht im Eingabeschema auf, und da unbekannte Argumente abgelehnt werden, kann das Modell diese Werte nicht überschreiben.

null bedeutet „nicht angegeben“

Bei Tools mit Template wird ein null vom Modell wie ein fehlendes Argument behandelt, auch in verschachtelten Objekten: Der Default greift, sonst wird das referenzierende Objekt-Member entfernt.

Validierungsregeln

RegelGrenze
WurzelJSON-Objekt oder Array. Für einen einzelnen Wert als ganzen Body dient unwrap_single_body_parameter.
GrößeMaximal 65.536 Bytes als kompaktes JSON.
TiefeMaximal 32 Ebenen.
VerweiseMaximal 64. Ein Verweis-Objekt enthält ausschließlich $livoi_input.
Ziel eines VerweisesNur existierende Parameter mit location: body.
VollständigkeitJeder Body-Parameter muss im Template referenziert sein.
ArraysEin optionaler Parameter ohne Default darf nicht als Array-Element referenziert werden, weil dort kein Member entfernt werden kann.
KombinationNicht zusammen mit unwrap_single_body_parameter: true.

Request-Aufbau

  1. Die validierten Argumente werden nach path, query und body aufgeteilt.
  2. Pfad-Platzhalter in api_url werden URL-kodiert ersetzt.
  3. Query-Parameter und, bei api_key_location: query, der API-Key werden an die URL gehängt.
  4. additional_headers und, bei api_key_location: header, der API-Key mit Präfix werden gesetzt.
  5. Der Body entsteht aus dem Template, aus dem Parameter-Objekt oder aus dem entpackten Einzelwert.
  6. Ein konfiguriertes timeout_seconds wird an den Request gebunden.

Antwortauswertung

Der Response-Body wird als JSON geparst, wenn möglich, sonst als Text übergeben. HTTP-Fehler werden in stabile Fehlertypen übersetzt, damit das Modell sinnvoll reagieren kann, ohne rohe Upstream-Fehler zu interpretieren.

Auslösererror.type
HTTP 408, 425, 429, 5xxupstream_unavailable
HTTP 401, 403authorization_error
HTTP 404not_found
HTTP 400, 409, 422request_rejected
Andere 4xxrequest_failed
Timeouttimeout_error
Verbindungsfehlerconnection_error
Erfolgsbedingung nicht erfülltapplication_error
Erfolgsbedingung nicht auswertbarunexpected_response
{ "status": "completed", "status_code": 200, "response": [{ "id": 7, "name": "Acme GmbH" }] }
{ "status": "failed", "retryable": false, "status_code": 404, "error": { "type": "not_found", "message": "The connected service could not find the requested resource." } }

Erfolgsbedingung

Manche APIs antworten mit HTTP 200, obwohl die Operation fehlgeschlagen ist. response_config.success_condition prüft dafür nach der HTTP-Fehlerbehandlung einen Pfad im geparsten Body. Pfade bestehen aus Objekt-Keys und nicht-negativen Array-Indizes, maximal 16 Segmente.

equals

Vergleicht einen skalaren Wert ohne Typumwandlung. Integer und Float werden numerisch verglichen, Booleans sind nie gleich Zahlen.

absent_or_empty_list

Erfolg, wenn der Pfad fehlt oder auf eine leere Liste zeigt, etwa [“errors”]. Andere Typen gelten als unerwartete Antwort.

Preview und Testrequest

Beide Endpunkte nehmen eine vollständige Tool-Definition plus Beispielargumente entgegen. Damit lassen sich auch ungespeicherte Entwürfe prüfen. Mit agent_tool_id werden fehlende Werte aus dem gespeicherten Tool ergänzt.

Preview

Validiert Konfiguration und Argumente, baut Methode, URL, Header und Body und kontaktiert das Zielsystem nicht. Der gespeicherte API-Key wird dafür nicht einmal aus der Datenbank geladen; an seiner Stelle steht <redacted>.

Testrequest

Sendet genau einen echten Request und liefert Status, Dauer, geschwärzte Header, einen begrenzten Body und das Ergebnis, das der Agent erhalten würde. Es wird nichts gespeichert.

{
"agent_tool_id": "7300000000000000002",
"tool_name": "search_companies",
"tool_description": "Searches companies by name and returns their ID, name, and email address.",
"request_config": { "api_url": "https://api.example.com/v1/contacts/search", "http_method": "POST" },
"input_schema": { "parameters": [{ "name": "name", "type": "string", "location": "body" }] },
"arguments": { "name": "Acme" },
"confirm_upstream_request": true
}
Feld im RequestVerhalten
api_key weggelassenNutzt den gespeicherten Key des Tools (setzt agent_tool_id voraus).
api_key: nullBaut den Request ohne Key.
api_key: ”…”Nutzt den übergebenen Key.
body_template, response_config weggelassenÜbernimmt mit agent_tool_id den gespeicherten Wert; null entfernt ihn für diesen Aufruf.
confirm_upstream_requestNur beim Test, muss exakt true sein.

Ergebnis eines Testrequests

outcomeBedeutung
completedErfolgreiche Antwort, Erfolgsbedingung erfüllt.
http_errorDas Zielsystem antwortete mit einem HTTP-Fehlerstatus.
response_errorHTTP-Erfolg, aber die Erfolgsbedingung schlug fehl.
timeoutZeitüberschreitung.
connection_errorKeine Verbindung zum Zielsystem.
response_too_largeAntwort größer als 1 MiB; kein agent_result.

Upstream-Fehler, Timeouts und Verbindungsfehler kommen mit HTTP 200 und stehen im Response-Body. request_possibly_processed ist nur dann false, wenn der Request das Zielsystem sicher nicht erreicht hat, etwa bei Verbindungsaufbau-, Pool- oder Proxy-Fehlern. Validierungsfehler der Argumente liefern 422 mit Pfad unter body.arguments.

Inspection in der Chat-Historie

Jeder Custom Tool Call speichert unter metadata.custom_tool_inspection am tool_call-Teil der Historie, was tatsächlich gesendet wurde. Lesbar ist das für alle, die die Chat-Historie lesen dürfen. Das Modell erhält diese Daten nicht.

Gespeichert

Validierte Argumente (bis 8 KiB, sonst als ausgelassen markiert)

Methode, URL, Header, Body und Timeout des Requests

Statuscode, Dauer und Body-Größe der Antwort

Transportfehlertyp und request_possibly_processed

Ergebnisstatus und Fehler, wie sie der Agent sah

Geschwärzt

API-Key, auch URL-kodiert, JSON-escaped oder byte-escaped

Alle Werte aus additional_headers

Authorization, Proxy-Authorization, Cookie, Set-Cookie

Passwörter in der URL

GrenzeHistoriePreview und Test
URL2.048 Zeichen8.192 Zeichen
Header32 Header, je 512 Zeichen64 Header, je 1.024 Zeichen
Body16.384 Zeichen65.536 Zeichen

Gekürzte Werte sind über url_truncated, headers_truncated und body_truncated erkennbar.

Tool-Suche mit defer_loading

Jedes Tool kostet Kontext: Name, Beschreibung und Schema gehen mit jedem Model-Request mit. Bei großen Katalogen, etwa vollständigem CRUD auf ein ERP mit über hundert Tools, verdrängt das den eigentlichen Gesprächskontext. Mit defer_loading: true bleiben solche Tools aus dem ersten Request heraus.

  1. Nutzt mindestens ein Tool defer_loading, erhält der Agent das Tool search_tools.
  2. Das Modell sucht mit Schlüsselwörtern in Namen und Beschreibungen, bis zu 10 Treffer pro Suche.
  3. Gefundene Tools werden mit ihrem Originalschema verfügbar und über den normalen Ausführungspfad aufgerufen.
  4. Treffer mehrerer Suchen werden kombiniert. Ohne Treffer kann das Modell andere Begriffe probieren oder erklären, was fehlt.

Persistenz

Such-Austausche werden mit tool_kind: tool-search gespeichert und beim nächsten Lauf typisiert wiederhergestellt. Gefundene Tools bleiben im Chat verfügbar; neue Chats starten ohne sie. Gelöschte Tools bleiben unerreichbar.

Sichtbarkeit

Suchen sind für das Modell sichtbar, in den Tool-Logs für Nutzer aber ausgeblendet.

Katalog bleibt lokal

Die native Tool-Suche des Providers ist deaktiviert, weil sie Namen und Beschreibungen des Katalogs an den Provider senden würde. Für den Standard-OpenAI-Endpunkt werden neue Schemas angehängt; Custom Endpoints erhalten normale Function Definitions.

API-Endpunkte

Alle Endpunkte liegen unter /v1/agent/tools und verwenden die Ressource agent_tools aus dem RBAC-Permission-Katalog.

OperationEndpunktPermission
createCustomToolForAgentPOST /{agent_id}/custom/createagent_tools.create
getCustomToolForAgentGET /{agent_tool_id}/customagent_tools.read
updateCustomToolForAgentPATCH /{agent_tool_id}/custom/updateagent_tools.update
previewCustomToolRequestPOST /{agent_id}/custom/previewagent_tools.read
sendCustomToolTestRequestPOST /{agent_id}/custom/testagent_tools.update
deleteAgentToolsDELETE /{agent_id}/deleteagent_tools.delete

Anlegen

Mehrere Tools pro Aufruf möglich. Doppelte Namen innerhalb des Requests liefern 422, Namen, die am Agenten bereits existieren, liefern 409.

Lesen zum Bearbeiten

getCustomToolForAgent liefert die gespeicherte Konfiguration mit erhaltenen JSON-Typen, inklusive response_config, max_retries, defer_loading und has_api_key. Dynamic Query gibt Skalare aus den Tool-Metadaten als Strings zurück und eignet sich deshalb nicht, um ein body_template in einen Editor zu laden.

Aktualisieren

Die Definition wird vollständig gesendet. Weggelassene Felder body_template, response_config, defer_loading und api_key behalten ihren gespeicherten Wert; null entfernt body_template, response_config und api_key.

Sicherheitsgrenzen im Überblick

RisikoGegenmaßnahme
Modell manipuliert feste Request-WerteNur deklarierte Eingaben sind Teil des Schemas; unbekannte Argumente werden abgelehnt.
Injection über String-EingabenTyperhaltende Ersetzung im Template, URL-Kodierung im Pfad, keine Zeilenumbrüche in Headern.
Key-Leak in Logs oder HistorieSchwärzung in allen gängigen Kodierungen; API liefert nur has_api_key.
Key-Umleitung über TestrequestGespeicherte Keys nur an den gespeicherten Origin, inklusive Host-Header-Prüfung.
Cookie-Übertrag zwischen TenantsEigener HTTP-Client ohne Cookie-Speicher.
Doppelte SchreiboperationenUpstream-Fehler sind terminal und werden nicht automatisch wiederholt.
Katalog-Abfluss an ProviderTool-Suche läuft lokal; native Provider-Suche ist deaktiviert.

Kompatibilität

  • body_template und defer_loading liegen in den bestehenden Tool-Metadaten; ältere Tools brauchen keine Anpassung.
  • Tools ohne body_template bauen ihre Requests wie bisher; Tools ohne defer_loading bleiben eager.
  • In OpenAPI erscheinen einige Tool-Schemas als -Input- und -Output-Varianten. Das Wire-Format ist identisch, generierte Clients sehen aber getrennte Typen.

Design-Prinzipien

Ein Builder

Laufzeit, Preview und Test erzeugen Requests über denselben Code. Es gibt keine Abweichung zwischen Vorschau und Realität.

Struktur gehört dem Tool

Das Modell liefert Werte, nicht Request-Strukturen.

Früh validieren

Fehler in Konfiguration, Templates und Defaults werden beim Speichern abgelehnt, nicht im laufenden Chat.

Nachvollziehbar

Jeder Call hinterlässt einen geschwärzten Snapshot dessen, was wirklich gesendet wurde.

Sparsam im Kontext

Große Kataloge werden bei Bedarf gefunden statt vollständig mitgeschickt.

Sicher im Fehlerfall

Upstream-Fehler sind terminal, Keys bleiben an ihren Origin gebunden.

Weitere API-Themen