HelpStackDocs

Integrationen

Benutzerdefinierte Agent-Tools

Geben Sie der KI Live-Zugriff auf Ihre Systeme: Definieren Sie Tools, die das LLM während der Antworterstellung aufrufen kann, um Bestellstatus abzurufen, Konten nachzuschlagen, den Lagerbestand zu prüfen und vieles mehr.

Kurzüberblick#

Tool-TypenSERVER_SIDE (HTTP-Aufruf von HelpStack) oder CLIENT_SIDE (im Browser des Besuchers ausgeführt)
Verwaltung überDashboard + /api/agent-tools (Organisationsebene), /api/channels/[id]/agent-tools (Kanalebene)
AuthentifizierungDashboard-Sitzung (werden von Ihrem Team konfiguriert)
Server-Tool-Timeout~10s, Antwort auf 128 KB begrenzt
Client-Tool-Timeout~5s (Socket-Roundtrip)
ProtokollierungJeder Aufruf wird in ToolCallLog aufgezeichnet

Die konzeptuelle Übersicht finden Sie im Agent-Tools-Leitfaden. Diese Seite ist die technische Referenz.

Tool-Anatomie#

Eine Tool-Definition enthält folgende Felder:

FeldErforderlichHinweise
NamejaDer Funktionsname, den das LLM aufruft, z. B. get_order_status. Muss ein gültiger Funktionsbezeichner sein
BeschreibungjaDas LLM liest diese, um zu entscheiden, wann das Tool aufgerufen werden soll. Max. ~2000 Zeichen (validiert). Seien Sie präzise
URLja (serverseitig)Muss HTTPS sein. SSRF-geschützt: eine Blockliste lehnt interne/private Netzwerkziele ab
MethodeneinGET | POST | PUT | PATCH. Standard POST
HeaderneinOptionales JSON-Objekt. Kann verschlüsselt/maskiert werden (für API-Schlüssel/Token verwenden)
Parameter-SchemajaEin JSON-Schema-Objekt, das die Argumente beschreibt, die das LLM ausfüllt (parametersSchema)
TypjaSERVER_SIDE oder CLIENT_SIDE
AktivUmschalten, um das Tool zu aktivieren/deaktivieren, ohne es zu löschen

Arbeitsbeispiel — get_order_status (SERVER_SIDE)#

Tool-Definition

FeldWert
Nameget_order_status
TypSERVER_SIDE
MethodePOST
URLhttps://api.YOURCOMPANY.com/orders/status
Header{ "Authorization": "Bearer YOUR_API_TOKEN" } (als verschlüsselten Header speichern)
BeschreibungLook up the current status and tracking info for a customer order by its order number. Call this whenever the customer asks where their order is, when it will arrive, or to confirm an order was placed.

Parameter-Schema (JSON Schema)

{
  "type": "object",
  "properties": {
    "order_number": {
      "type": "string",
      "description": "The customer's order number, e.g. ORD-10432"
    }
  },
  "required": ["order_number"]
}

Anfrage, die Ihr Endpunkt erhält

Bei einem Tool-Aufruf sendet HelpStack die vom LLM bereitgestellten Argumente als Request-Body (bei POST/PUT/PATCH), zusammen mit Ihren konfigurierten Headern und Content-Type: application/json:

POST /orders/status HTTP/1.1
Host: api.YOURCOMPANY.com
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json

{ "order_number": "ORD-10432" }

Antwort-Vertrag, den Ihr Endpunkt einhalten muss

Geben Sie JSON zurück, das das Modell lesen kann. Der Aufruf läuft nach ~10s ab und die Antwort ist auf 128 KB begrenzt.

Eine Antwort über dem Limit wird abgelehnt, nicht gekürzt — ein halbes JSON-Dokument lässt sich entweder nicht parsen oder ergibt schlimmstenfalls eine andere Bedeutung —, der Aufruf schlägt also fehl und der KI wird mitgeteilt, dass das Tool nicht verfügbar ist. Dasselbe passiert, wenn der Körper gar kein JSON ist, meist eine HTML-Fehlerseite eines Proxys.

Das Limit ist eine Absicherung gegen einen außer Kontrolle geratenen Endpunkt (eine paginierte Liste ohne Seitengröße, ein Debug-Dump), kein Zielwert. Größe kostet Sie auch darunter: Was Sie zurückgeben, wird vollständig geparst, ins Aufrufprotokoll geschrieben und dem Modell vorgelegt und daher bei jeder Antwort, die es verwendet, in Tokens bezahlt. Geben Sie die wenigen Felder zurück, die die KI zum Antworten braucht, nicht Ihren gesamten Datensatz — Status, voraussichtliche Lieferzeit und Sendungsnummer einer Bestellung, nicht das ganze Bestellobjekt.

{
  "status": "shipped",
  "carrier": "DHL",
  "tracking_number": "JD0140...",
  "estimated_delivery": "2026-06-02"
}

Die KI erhält diesen Payload als Tool-Ergebnis und verarbeitet ihn in ihre Antwort. Es gibt keinen vorgeschriebenen Envelope — geben Sie beliebige nützliche Felder zurück, aber machen Sie sie selbstbeschreibend, damit das Modell sie korrekt verwendet.

Gute Beschreibungen verfassen#

Die Beschreibung ist das bei weitem wichtigste Feld — sie ist das Einzige, was das LLM verwendet, um zu entscheiden, ob und wann das Tool aufgerufen werden soll.

  • Geben Sie an, was das Tool zurückgibt und wann es aufgerufen werden soll („Rufen Sie dies auf, wenn der Kunde fragt …").
  • Erwähnen Sie die Formulierungen, die Kunden tatsächlich verwenden.
  • Beschreiben Sie jeden Parameter klar in der description seines Schemas.
  • Bleiben Sie unter dem ~2000-Zeichen-Limit (der Speicherdialog validiert dies und zeigt Fehler an).

Sicherheit & SSRF-Schutz#

  • Nur HTTPS. Einfache HTTP-URLs werden abgelehnt.
  • SSRF-Blockliste. Interne/private Netzwerkziele (Loopback, private RFC1918-Bereiche, Link-local, Metadaten-Endpunkte) sind blockiert, damit ein Tool nicht auf interne Infrastruktur gerichtet werden kann.
  • Geheime Header. Legen Sie API-Schlüssel/Token in Header, die verschlüsselt/maskiert statt im Klartext gespeichert werden können.
  • Behandeln Sie den Tool-Endpunkt als öffentlich zugänglich — authentifizieren Sie Anfragen (z. B. ein Bearer-Token in Headern) und validieren Sie Eingaben auf Ihrer Seite.

Timeouts & Limits#

ServerseitigClientseitig
Timeout~10s~5s
Antwort-Limit128 KB (abgelehnt, nicht gekürzt)
Bei Fehler/TimeoutProtokolliert; KI wird informiert, dass das Tool nicht verfügbar ist, und setzt mit der bestmöglichen Antwort fort

Fehler werden graceful degradiert — ein defektes oder langsames Tool blockiert nie eine Antwort; die KI fährt einfach ohne diese Daten fort.

Organisations- vs. Kanal-Tools + semantische Filterung#

  • Tools können auf Organisations-Ebene und auf Kanal-Ebene definiert werden.
  • Für ein bestimmtes Gespräch werden Organisations- und Kanal-Tools zusammengeführt, wobei ein Kanal-Tool ein Organisations-Tool mit demselben Namen überschreibt.
  • Der zusammengeführte Satz wird semantisch nach Relevanz für die Kundenanfrage gefiltert, sodass ein großer Tool-Katalog nicht jeden LLM-Aufruf aufbläht — nur relevante Tools werden angeboten.
  • Ausgewählte Tools werden in OpenAI/Anthropic-Funktionsdefinitionen umgewandelt und bei der Antworterstellung angeboten.

OpenAPI-Import#

Sie können Tools aus einer vorhandenen API bootstrappen: Fügen Sie eine OpenAPI 3.0-Spezifikation ein oder laden Sie sie hoch, und HelpStack extrahiert deren Operationen in Tool-Definitionen, die Sie prüfen und speichern. Dies ist der schnellste Weg, eine vorhandene REST-API der KI zugänglich zu machen.

Protokollierung#

Jeder Tool-Aufruf wird in ToolCallLog aufgezeichnet. Den Aufrufverlauf eines Tools (Argumente, Ergebnis, Timing) können Sie über folgenden Endpunkt einsehen:

GET /api/agent-tools/[id]/logs

Verwenden Sie die Protokolle, um zu debuggen, warum ein Tool aufgerufen wurde oder nicht, und um Timeouts/Fehler zu erkennen.

Clientseitige Tools (fortgeschritten)#

CLIENT_SIDE-Tools werden auf dieselbe Weise deklariert (Name, Beschreibung, Parameter-Schema), werden aber im Browser des Website-Besuchers ausgeführt, vermittelt durch den Widget-Socket:

  1. Die KI gibt einen Tool-Aufruf für ein CLIENT_SIDE-Tool aus.
  2. Der Server sendet tool:execute an das Widget.
  3. Das Widget führt es aus und antwortet mit tool:result (oder tool:error).
  4. Es gibt einen ~5s-Timeout; bei Timeout wird der Aufruf graceful degradiert (Tool nicht verfügbar).

Einen Handler registrieren

Das Widget-Skript stellt window.HelpStack bereit. Registrieren Sie einen Handler namentlich, und er wird aufgerufen, sobald die KI dieses Tool nutzt:

<script src="https://helpstack.eu/widget.js?id=CHANNEL_ID" async></script>
<script>
  window.HelpStack = window.HelpStack || function () {
    (window.HelpStack.q = window.HelpStack.q || []).push(arguments);
  };

  window.HelpStack('registerTool', 'highlight', async ({ section }) => {
    document.querySelector(`#${section}`)?.scrollIntoView({ behavior: 'smooth' });
    return { highlighted: section };
  });
</script>

Der Queue-Shim in der Mitte bedeutet, dass Sie registrieren können, bevor widget.js geladen ist; das Skript leert die Warteschlange beim Start. Was Ihr Handler zurückgibt, ist das, was die KI liest, und wenn er eine Ausnahme wirft, wird der KI mitgeteilt, dass das Tool fehlgeschlagen ist. Dieselbe Funktion liegt nach dem Laden des Skripts auch auf ChatWidget.registerTool(name, fn).

Beispiel-Handler

Vier Muster, in der Reihenfolge, in der Teams sie üblicherweise bauen. Jedes zeigt die Tool-Definition, die Sie im Dashboard eintragen, und den Handler, den Sie auf Ihrer Seite registrieren. Sie sind bewusst klein gehalten: Ein clientseitiges Tool sollte eine Sache tun und ein kurzes, schlichtes Objekt zurückgeben.

1. Auslesen, wo der Besucher ist (ohne Parameter)

Das nützlichste erste Tool. Es kostet nichts und verhindert, dass die KI rät, was der Besucher gerade ansieht.

Definition

FeldWert
Namewhere_is_the_user
TypCLIENT_SIDE
BeschreibungCheck which page and section the customer is currently looking at. Call this before giving directions, so you can describe what is actually on their screen.
{ "type": "object", "properties": {}, "required": [] }

Handler

window.HelpStack('registerTool', 'where_is_the_user', async () => ({
  page: location.pathname,
  title: document.title,
  // Whatever "where they are" means in your UI: an open tab, a wizard step, a route.
  section: document.querySelector('[data-active-section]')?.dataset.activeSection ?? null,
}));

2. Auf etwas auf der Seite zeigen

Definition

FeldWert
Namehighlight
TypCLIENT_SIDE
BeschreibungScroll to and visually highlight a control or section on the customer's screen so they can see exactly what you mean. Use this instead of describing where something is.
{
  "type": "object",
  "properties": {
    "target": {
      "type": "string",
      "description": "What to highlight, in the customer's own words: a button label, a section name, or a menu item."
    }
  },
  "required": ["target"]
}

Handler

window.HelpStack('registerTool', 'highlight', async ({ target }) => {
  const el = document.querySelector(`[data-tour="${CSS.escape(target)}"]`);
  if (!el) {
    // Not found is a normal outcome, not a failure. Say so and let the AI recover.
    return { found: false, target };
  }
  el.scrollIntoView({ behavior: 'smooth', block: 'center' });
  el.classList.add('hs-highlight');
  setTimeout(() => el.classList.remove('hs-highlight'), 3000);
  return { found: true, target };
});

3. Inhalte an die KI zurücklesen

Definition

FeldWert
Nameread_section
TypCLIENT_SIDE
BeschreibungRead what is currently written in one section of the page, field by field, so you can answer about the customer's real content instead of guessing.
{
  "type": "object",
  "properties": {
    "section": { "type": "string", "description": "Section name as the customer would say it." }
  },
  "required": ["section"]
}

Handler

window.HelpStack('registerTool', 'read_section', async ({ section }) => {
  const root = document.querySelector(`[data-section="${CSS.escape(section)}"]`);
  if (!root) return { found: false, section };

  const fields = {};
  root.querySelectorAll('[data-field]').forEach((el) => {
    // Keep it small — the result goes into the AI's context on every call.
    fields[el.dataset.field] = (el.value ?? el.textContent ?? '').trim().slice(0, 500);
  });
  return { found: true, section, fields };
});

Geben Sie Feldschlüssel zurück, die die KI Ihnen zitieren kann. Genau das macht ein Schreib-Tool wie das nächste möglich.

4. Etwas für den Besucher schreiben

Das wertvollste Muster und dasjenige, bei dem die größte Vorsicht geboten ist: Die KI verändert jetzt den Bildschirm des Besuchers.

Definition

FeldWert
Namefill_field
TypCLIENT_SIDE
BeschreibungPut suggested text into a specific field on the customer's page so they can review it and save it themselves. Only use a field key that read_section returned. Never save or submit on the customer's behalf.
{
  "type": "object",
  "properties": {
    "section": { "type": "string", "description": "Section name, as returned by read_section." },
    "field":   { "type": "string", "description": "Field key exactly as read_section returned it." },
    "text":    { "type": "string", "description": "The complete new contents of that field." }
  },
  "required": ["section", "field", "text"]
}

Handler

window.HelpStack('registerTool', 'fill_field', async ({ section, field, text }) => {
  const el = document.querySelector(
    `[data-section="${CSS.escape(section)}"] [data-field="${CSS.escape(field)}"]`
  );
  if (!el) return { written: false, reason: 'field not found', section, field };

  el.value = text;
  // Frameworks that track their own state need to be told.
  el.dispatchEvent(new Event('input', { bubbles: true }));
  el.scrollIntoView({ behavior: 'smooth', block: 'center' });
  return { written: true, section, field };
});

⚠️ Ausfüllen, nicht absenden. Lassen Sie den Besucher die Änderung lesen und selbst speichern. Ein Tool, das an seiner Stelle veröffentlicht, macht aus einem hilfreichen Vorschlag eine nicht rückgängig zu machende Aktion, und die KI kann das Ergebnis nicht sehen.

Handler schreiben, die sich anständig verhalten

  • Geben Sie kleine, schlichte Objekte zurück. Das Ergebnis fließt bei jedem Aufruf in den Kontext der KI. Geben Sie { found: true, section, fields } zurück, niemals einen DOM-Knoten, eine Komponente oder einen 50-KB-Blob.
  • „Nicht gefunden" ist ein Ergebnis, kein Fehler. Geben Sie { found: false } zurück und lassen Sie die KI etwas Sinnvolles sagen. Eine Ausnahme erzeugt einen Tool-Fehlschlag, und die KI erfährt nur, dass etwas kaputt ist.
  • Bleiben Sie deutlich unter dem ~5-Sekunden-Timeout. Keine Netzwerkaufrufe, auf die der Besucher warten muss. Wenn Sie Ihr Backend brauchen, machen Sie stattdessen ein SERVER_SIDE-Tool daraus.
  • Legen Sie niemals etwas offen, das der Besucher nicht ohnehin sehen kann. Ein clientseitiges Tool läuft auf einer öffentlichen Seite ohne eigene Authentifizierung. Lesen Sie keine Auth-Tokens, keine Daten anderer Kunden und nichts hinter Ihren eigenen Berechtigungsprüfungen.
  • Benennen Sie Parameter in der Sprache des Kunden, nicht in der Ihres Schemas. Die KI füllt sie aus dem, was der Kunde geschrieben hat. target: "der Speichern-Button" funktioniert; elementId: "btn-save-primary" nicht.

Das zugrunde liegende Protokoll

registerTool ist eine dünne Hülle um postMessage, und Sie können die Nachrichten auch selbst beantworten — nützlich, wenn Sie bereits einen Message-Router haben oder ein Tool bedienen möchten, das das Widget nicht kennt.

⚠️ Wenn Sie einen Handler über window.HelpStack registrieren, beantworten Sie dasselbe Tool nicht zusätzlich mit einem eigenen Listener. Das iframe nimmt die erste Antwort pro callId, zwei Antworten liefern sich also ein Rennen. Das Widget bleibt bei Tools ohne Handler stumm, genau damit ein bestehender eigener Listener weiter funktioniert.

Das Widget-iframe sendet jeden clientseitigen Aufruf an sein übergeordnetes Fenster:

{ type: 'TOOL_EXECUTE', callId: '…', toolName: 'highlight', parameters: { … } }

Anschließend wartet es auf eine dieser Antworten, abgeglichen über callId:

{ type: 'TOOL_RESULT', callId: '…', result: { … } }   // whatever the AI should read
{ type: 'TOOL_ERROR',  callId: '…', error: 'why it failed' }

Ein Handler auf Ihrer eigenen Seite genügt also:

window.addEventListener('message', (event) => {
  // Required. Without this check any page in an iframe could drive your tools.
  if (event.origin !== 'https://helpstack.eu') return;
  const { type, callId, toolName, parameters } = event.data ?? {};
  if (type !== 'TOOL_EXECUTE') return;

  const reply = (result) =>
    event.source.postMessage({ type: 'TOOL_RESULT', callId, result }, event.origin);
  const fail = (error) =>
    event.source.postMessage({ type: 'TOOL_ERROR', callId, error }, event.origin);

  if (toolName === 'highlight') {
    const el = document.querySelector(parameters.selector);
    if (!el) return fail('No element matches that selector.');
    el.scrollIntoView({ behavior: 'smooth', block: 'center' });
    el.classList.add('my-highlight');
    reply({ ok: true, message: 'Highlighted it. Tell the customer to look at the ring.' });
  }
});

Drei Dinge, die Sie wissen sollten, bevor Sie darauf aufbauen:

  • Antworten Sie innerhalb des 5-Sekunden-Timeouts, und antworten Sie ehrlich. Bei einem Timeout löst der Aufruf zu { success: false, error: 'timeout' } auf, und die KI macht ohne ihn weiter. Antworten Sie nicht, bevor Sie wissen, dass die Aktion funktioniert hat — eine KI, der „hervorgehoben" gesagt wird, obwohl nichts hervorgehoben wurde, schickt den Kunden auf die Suche nach etwas, das nicht auf seinem Bildschirm ist, und das ist schlimmer als gar kein Tool.
  • Was Sie in result schreiben, ist das, was die KI liest. Ein Satz, der erklärt, was passiert ist, bringt Ihnen eine bessere Antwort als { ok: true }.
  • Der Besucher ist womöglich nicht auf einer Seite, die das leisten kann. Geben Sie ein Ergebnis zurück, das das sagt, statt still zu scheitern, damit die KI es erklären kann.

Kombinieren Sie das mit window.ChatWidget.identify(identity, metadata), damit die KI weiß, welchem Konto sie hilft, bevor sie irgendetwas aufruft.

Verwandte Themen#