Integracije
Orodja agenta po meri
Dajte AI-ju neposreden dostop do vaših sistemov: definirajte orodja, ki jih LLM lahko pokliče med ustvarjanjem odgovora, da pridobi status naročila, poišče račune, preveri zalogo in več.
Hitre dejstvice#
| Vrste orodij | SERVER_SIDE (HTTP klic iz HelpStack) ali CLIENT_SIDE (deluje v brskalniku obiskovalca) |
| Upravljanje | Nadzorna plošča + /api/agent-tools (na ravni organizacije), /api/channels/[id]/agent-tools (na ravni kanala) |
| Avtentikacija | Seja nadzorne plošče (konfigurira vaša ekipa) |
| Časovna omejitev za strežniška orodja | ~10s, odgovor omejen na 128 KB |
| Časovna omejitev za odjemalska orodja | ~5s (krog prek vtičnice) |
| Beleženje | Vsak klic se zabeleži v ToolCallLog |
Za konceptualni pregled glejte Navodila za orodja agenta. Ta stran je tehnična referenca.
Anatomija orodja#
Definicija orodja ima ta polja:
| Polje | Obvezno | Opombe |
|---|---|---|
| Ime | da | Ime funkcije, ki jo LLM pokliče, npr. get_order_status. Mora biti veljaven identifikator funkcije |
| Opis | da | LLM ga prebere, da odloči, kdaj poklicati orodje. Največ ~2000 znakov (prevereno). Bodite natančni |
| URL | da (strežniška stran) | Mora biti HTTPS. Zaščiteno pred SSRF: seznam blokiranih zavrne notranje/zasebne omrežne cilje |
| Metoda | ne | GET | POST | PUT | PATCH. Privzeto POST |
| Glave | ne | Neobvezni objekt JSON. Lahko šifrirano/zamaskirano (uporabite za API ključe/žetone) |
| Shema parametrov | da | Objekt JSON Schema, ki opisuje argumente, ki jih LLM izpolni (parametersSchema) |
| Tip | da | SERVER_SIDE ali CLIENT_SIDE |
| Aktivno | — | Vklopi/izklopi orodje brez brisanja |
Delovni primer — get_order_status (SERVER_SIDE)#
Definicija orodja
| Polje | Vrednost |
|---|---|
| Ime | get_order_status |
| Tip | SERVER_SIDE |
| Metoda | POST |
| URL | https://api.YOURCOMPANY.com/orders/status |
| Glave | { "Authorization": "Bearer YOUR_API_TOKEN" } (shranite kot šifrirano glavo) |
| Opis | Look 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. |
Shema parametrov (JSON Schema)
{
"type": "object",
"properties": {
"order_number": {
"type": "string",
"description": "The customer's order number, e.g. ORD-10432"
}
},
"required": ["order_number"]
}
Zahteva, ki jo prejme vaša končna točka
Ob klicu orodja HelpStack pošlje argumente, ki jih je posredoval LLM, kot telo zahteve (za POST/PUT/PATCH), z vašimi konfiguriranimi glavami ter 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" }
Pogodba o odzivu, ki jo mora spoštovati vaša končna točka
Vrnite JSON, ki ga model lahko prebere. Klic preteče po ~10s, odgovor pa je omejen na 128 KB.
Odgovor nad omejitvijo je zavrnjen in ne skrajšan — polovica dokumenta JSON se bodisi ne razčleni bodisi, še slabše, razčleni v drugačen pomen — zato klic ne uspe, AI pa dobi informacijo, da orodje ni na voljo. Enako se zgodi, če telo sploh ni JSON, kar je običajno stran z napako HTML izpred posredniškega strežnika.
Omejitev je varovalo pred končno točko, ki se ji iztrga nadzor (stran z razdeljenim seznamom brez velikosti strani, izpis za razhroščevanje), in ne cilj, h kateremu bi merili. Velikost vas stane tudi pod njo: kar vrnete, se v celoti razčleni, zapiše v dnevnik klicev in postavi pred model, zato se plača v žetonih pri vsakem odgovoru, ki to uporabi. Vrnite tistih nekaj polj, ki jih AI potrebuje za odgovor, ne celotnega zapisa — status naročila, predviden čas dostave in številko za sledenje, ne celotnega objekta naročila.
{
"status": "shipped",
"carrier": "DHL",
"tracking_number": "JD0140...",
"estimated_delivery": "2026-06-02"
}
AI prejme to koristno obremenitev kot rezultat orodja in jo vpleta v odgovor. Ni zahtevane ovojnice — vrnite katerakoli polja so koristna, vendar jih naredite samorazlagajoča, da jih model pravilno uporabi.
Pisanje dobrih opisov#
Opis je najpomembnejše polje — to je edina stvar, ki jo LLM uporabi za odločitev, ali in kdaj poklicati orodje.
- Navedite kaj orodje vrne in kdaj ga poklicati ("Pokliči, ko stranka vpraša ...").
- Omenite sprožilne fraze, ki jih stranke dejansko uporabljajo.
- Jasno opišite vsak parameter v
descriptionsheme. - Ostanite pod omejitvijo ~2000 znakov (pogovorno okno za shranjevanje to preverja in prikaže napake).
Varnost in zaščita pred SSRF#
- Samo HTTPS. Navadni HTTP URL-ji so zavrnjeni.
- Seznam blokiranih za SSRF. Notranje/zasebne omrežne cilje (povratna zanka, zasebni obsegi RFC1918, lokalna povezava, končne točke metapodatkov) so blokirani, da orodje ne more biti usmerjeno na notranjo infrastrukturo.
- Skrivne glave. Dajte API ključe/žetone v Glave, ki so lahko šifrirane/zamaskirane namesto shranjene v navadnem besedilu.
- Obravnavajte končno točko orodja kot javno dosegljivo — avtenticirajte zahteve (npr. žeton za prenos v Glavah) in preverjajte vhodne vrednosti pri sebi.
Časovne omejitve in omejitveni parametri#
| Strežniška stran | Odjemalska stran | |
|---|---|---|
| Časovna omejitev | ~10s | ~5s |
| Omejitev odgovora | 128 KB (zavrnjen, ne skrajšan) | — |
| Ob napaki/prekoračitvi časa | Zabeleženo; AI obveščen, da orodje ni na voljo, in nadaljuje z najboljšim možnim odgovorom |
Napake se postopno razrešijo — pokvarjeno ali počasno orodje nikoli ne blokira odgovora; AI preprosto nadaljuje brez teh podatkov.
Orodja organizacije vs. kanala in semantično filtriranje#
- Orodja se lahko definirajo na ravni organizacije in na ravni kanala.
- Za dani pogovor se orodja na ravni organizacije in kanala združijo, orodje kanala pa prepiše orodje organizacije z enakim imenom.
- Združeni nabor se semantično filtrira glede na ustreznost poizvedbi stranke, tako da velik katalog orodij ne napiha vsakega klica LLM — ponujena so samo relevantna orodja.
- Izbrana orodja se pretvorijo v definicije funkcij OpenAI/Anthropic in ponudijo med ustvarjanjem odgovora.
Uvoz OpenAPI#
Orodja lahko bootstrapirate iz obstoječega API-ja: prilepite ali naložite specifikacijo OpenAPI 3.0, in HelpStack iz nje izvleče operacije v definicije orodij, ki jih pregledate in shranite. To je najhitrejši način za izpostavitev obstoječega REST API-ja AI-ju.
Beleženje#
Vsak klic orodja se zabeleži v ToolCallLog. Oglejte si zgodovino klicev orodja (argumente, izid, čas) prek:
GET /api/agent-tools/[id]/logs
Uporabite dnevnike za odpravljanje napak, zakaj orodje je ali ni bilo poklicano, in za prepoznavanje prekoračitev časa/napak.
Orodja na strani odjemalca (napredno)#
Orodja CLIENT_SIDE so deklarirana enako (ime, opis, shema parametrov), vendar se izvajajo v brskalniku obiskovalca spletnega mesta, posredovano prek vtičnice widgeta:
- AI odda klic orodja za orodje
CLIENT_SIDE. - Strežnik pošlje
tool:executewidgetu. - Widget ga izvede in odgovori z
tool:result(alitool:error). - Časovna omejitev je ~5s; ob prekoračitvi se klic postopno razreši (orodje ni na voljo).
Registracija rokovalnika
Skripta pripomočka izpostavi window.HelpStack. Rokovalnik registrirajte po imenu in
poklican bo vsakič, ko UI uporabi to orodje:
<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>
Vmesnik čakalne vrste na sredini pomeni, da lahko registrirate preden se widget.js
naloži; skripta ob zagonu vrsto izprazni. Kar rokovalnik vrne, je tisto, kar prebere UI, če pa
vrže napako, se UI sporoči, da orodje ni uspelo. Ista funkcija je po nalaganju skripte na voljo
tudi kot ChatWidget.registerTool(name, fn).
Primeri rokovalnikov
Štirje vzorci, v vrstnem redu, po katerem jih ekipe običajno gradijo. Vsak prikazuje definicijo orodja, ki jo vnesete v nadzorno ploščo, in rokovalnik, ki ga registrirate na svoji strani. Namenoma so majhni: orodje na strani odjemalca naj naredi eno stvar in vrne kratek, preprost objekt.
1. Preberite, kje je obiskovalec (brez parametrov)
Najbolj uporabno prvo orodje. Nič ne stane in prepreči, da bi UI ugibala, kaj obiskovalec gleda.
Definicija
| Polje | Vrednost |
|---|---|
| Ime | where_is_the_user |
| Tip | CLIENT_SIDE |
| Opis | Check 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": [] }
Rokovalnik
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. Pokažite na nekaj na strani
Definicija
| Polje | Vrednost |
|---|---|
| Ime | highlight |
| Tip | CLIENT_SIDE |
| Opis | Scroll 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"]
}
Rokovalnik
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. Preberite vsebino nazaj UI
Definicija
| Polje | Vrednost |
|---|---|
| Ime | read_section |
| Tip | CLIENT_SIDE |
| Opis | Read 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"]
}
Rokovalnik
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 };
});
Vrnite ključe polj, ki jih UI lahko citira nazaj. Prav to omogoča orodje za pisanje, kakršno je naslednje.
4. Napišite nekaj za obiskovalca
Najbolj dragocen vzorec in tisti, pri katerem je potrebna največja previdnost: UI zdaj spreminja zaslon obiskovalca.
Definicija
| Polje | Vrednost |
|---|---|
| Ime | fill_field |
| Tip | CLIENT_SIDE |
| Opis | Put 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"]
}
Rokovalnik
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 };
});
⚠️ Izpolnite, ne pošljite. Pustite obiskovalcu, da spremembo prebere in sam pritisne shrani. Orodje, ki objavi namesto njega, iz koristnega predloga naredi nepovrnljivo dejanje, UI pa rezultata ne vidi.
Pisanje rokovalnikov, ki se lepo obnašajo
- Vračajte majhne, preproste objekte. Rezultat se ob vsakem klicu vključi v kontekst UI.
Vrnite
{ found: true, section, fields }, nikoli vozlišča DOM, komponente ali 50 KB velikega bloba. - »Ni najdeno« je rezultat, ne napaka. Vrnite
{ found: false }in pustite UI, da pove kaj smiselnega. Vržena napaka pomeni odpoved orodja in UI izve le, da se je nekaj pokvarilo. - Ostanite krepko pod ~5-sekundno časovno omejitvijo. Nobenih omrežnih klicev, na katere bi
moral obiskovalec čakati. Če potrebujete svoj zaledni sistem, naredite raje orodje
SERVER_SIDE. - Nikoli ne razkrijte ničesar, česar obiskovalec ne vidi že sam. Orodje na strani odjemalca teče na javni strani brez lastnega overjanja. Ne berite žetonov za overjanje, podatkov drugih strank ali česar koli za vašimi preverjanji dovoljenj.
- Parametre poimenujte v jeziku stranke, ne v jeziku svoje sheme. UI jih zapolni iz tega, kar
je stranka napisala.
target: "gumb za shranjevanje"deluje;elementId: "btn-save-primary"ne.
Osnovni protokol
registerTool je tanka ovojnica okoli postMessage in sporočila lahko odgovorite tudi sami —
uporabno, če že imate usmerjevalnik sporočil ali če želite streči orodju, ki ga pripomoček ne
pozna.
⚠️ Če rokovalnik registrirate prek window.HelpStack, istega orodja ne odgovarjajte še z
lastnim poslušalcem. Iframe upošteva prvi odgovor na posamezno callId, zato se dva odgovora
poženeta v tekmo. Pripomoček ostane tiho pri orodjih, za katera nima rokovalnika, prav zato, da
obstoječi lastni poslušalec deluje naprej.
Iframe pripomočka vsak klic na strani odjemalca pošlje nadrejenemu oknu:
{ type: 'TOOL_EXECUTE', callId: '…', toolName: 'highlight', parameters: { … } }
Nato čaka na enega od teh odgovorov, ujetega po callId:
{ type: 'TOOL_RESULT', callId: '…', result: { … } } // whatever the AI should read
{ type: 'TOOL_ERROR', callId: '…', error: 'why it failed' }
Torej zadostuje rokovalnik na vaši strani:
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.' });
}
});
Tri stvari, ki jih velja vedeti, preden na tem gradite:
- Odgovorite znotraj 5-sekundne omejitve in odgovorite iskreno. Ob poteku časa se klic razreši
v
{ success: false, error: 'timeout' }in UI nadaljuje brez njega. Ne odgovarjajte, preden veste, da je dejanje uspelo — UI, ki ji rečete »označeno«, čeprav ni bilo označeno nič, bo stranko poslala iskat nekaj, česar na njenem zaslonu ni, in to je slabše od nobenega orodja. - Kar zapišete v
result, je tisto, kar prebere UI. Stavek, ki pojasni, kaj se je zgodilo, vam prinese boljši odgovor kot{ ok: true }. - Obiskovalec morda ni na strani, ki to zmore. Vrnite rezultat, ki to pove, namesto da tiho odpoveste, da lahko UI to pojasni.
To združite z window.ChatWidget.identify(identity, metadata), da UI ve, kateremu računu
pomaga, preden karkoli pokliče.