Küsimuste ja vastuste boti loomine
See juhend loob boti põhiosa, mis vastab küsimustele teie teadmusbaasi põhjal: vestlusrakenduses, teie abikeskuses või teie tootes. Assistent leiab vajalikud teadmised ja vastab, viidates kasutatud kaartidele; teie kood saadab küsimuse ja näitab tulemust.
Vajate võtit ulatustega search ja ask. Vastus kasutab ainult kaarte, mida võtmel on
lubatud lugeda, seega määravad võtme roll, andmeprofiil ja kogud, millest bot saab rääkida. Andke klientidele
mõeldud botile võti, mis näeb ainult avalikke kogusid.
Kolm viisi vastuse saamiseks
| Lõpp-punkt | Tagastab | Kasutage |
|---|---|---|
POST /v1/search | Sobivad tekstilõigud, parim esimesena. Kirjutatud vastust ei ole. | Otsingukasti, „seotud artiklite“ ja oma järjestuse jaoks. |
POST /v1/ask | Täieliku vastuse koos allikatega ühes vastuses. | Bottide jaoks, mis postitavad iga vastuse kohta ühe sõnumi; taustatöödeks. |
POST /v1/chat | Vastuse sündmuste voona selle koostamise ajal. | Vestlusliideste jaoks, kus kasutaja peaks nägema vastuse tekkimist. |
Otsing
curl -X POST https://api.sursa.com/v1/search \
-H "Authorization: Bearer $SURSA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "how do I return a damaged item", "collection": "support"}'Iga tabamus on kaardi tekstilõik: kaardi doc_id ja doc_name, jaotise heading, tekstilõigu text, leheküljed
või tabeliread, kust see leiti, ning kaardi usaldus ja kontroll.
collection valib kogu, millest otsida; ilma selleta kasutatakse kogu, mille nimi on default. tags ja card_ids
kitsendavad otsingu nende siltidega kaartidele või konkreetsetele kaartidele.
Küsimine ja täieliku vastuse saamine
curl -X POST https://api.sursa.com/v1/ask \
-H "Authorization: Bearer $SURSA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "How do I return a damaged item?", "collection": "support"}'Väljal answer olev vastuse tekst on Markdown. Selle viited, näiteks [1] või [1, 3], vastavad loendi sources
kirjete väärtusele ref; linkige iga viide kaardiga (doc_id), et lugeja saaks vastust kontrollida.
Tekstis olev arv, mida ei õnnestunud dokumentide põhjal kinnitada, võib ilmuda tähisena, näiteks ⟦n:a1⟧.
verification.items kirjeldab iga tähist: selle marker, põhjus reason ja algne tekst original. Kui teie kood
tähiseid ei käsitle, asendage iga tähis selle väärtusega original.
Kui vastust ei ole
Vastus on alati 200. Kui assistent ei saa vastata, ütleb empty, miks, ja answer sisaldab lühikest teadet, mida
saate näidata:
empty | Tähendus |
|---|---|
no_hits | Teadmusbaasis ei ole midagi, mis küsimusele vastaks. |
restricted | Teema on kaartides, mida võtmel ei ole lubatud lugeda. |
guardrail | Küsimus jääb väljapoole seda, millele organisatsioon lubab assistendil vastata. |
no_data_for_period | Küsimus puudutab perioodi, mille kohta dokumente ei ole. |
no_hits on kasulik signaal: see näitab, mida teie kasutajad küsivad, kuid mida teadmusbaas veel ei kata.
Režiimid „Fast“ ja „Precise“
Edastage "quality": "precise" (režiim „Precise“, täpne), et saada keerulisele küsimusele põhjalikum vastus, mis
võtab rohkem aega. Vaikimisi kasutatav "fast" (režiim „Fast“, kiire) sobib enamikule küsimustele.
Vastuse voogedastus
Näidake vestlusliideses vastust selle koostamise ajal. POST /v1/chat väärtusega
"stream": true vastab vormingus text/event-stream: üks sündmus sõnumi kohta, igaühel rida id: (selle number
voos, alates 1-st) ja rida data: JSON-iga. JSON-i väli type ütleb, millise sündmusega on tegu.
id: 1
data: {"type":"meta","sources":3,"timings":{…},"answer_id":"…"}
id: 2
data: {"type":"sources","sources":[{"ref":1,"doc_id":"8c1d…","doc_name":"Returns","text":"…"}]}
id: 3
data: {"type":"token","text":"Send a photo of the item "}
id: 4
data: {"type":"token","text":"within 7 days [1]."}
id: 5
data: {"type":"done","answer":"Send a photo of the item within 7 days [1].","question_id":9812,"sources":[…]}
type | Mida teha |
|---|---|
meta | Vastus on alanud. Kui logite vastuseid, jätke answer_id alles. |
sources | Kaardid, millel vastus põhineb. Võib tulla mitu korda; kehtib viimane. |
token | Tükk vastuse tekstist. Lisage see näidatava teksti lõppu. |
done | Vastus on valmis. Sellel on samad väljad mis päringu /v1/ask vastusel. |
error | Vastus peatus. Voog lõpeb ilma sündmuseta done. Vt allpool. |
followups | Pärast sündmust done: soovitatud järgmised küsimused, mida saate pakkuda nuppudena. |
| kõik muu | Jätke vahele. Uued sündmusetüübid võivad ilmuda igal ajal. |
Rida, mis algab märgiga : (näiteks : ping, mida saadetakse vastuse ettevalmistamise ajal iga 15 sekundi järel), on
kommentaar. Jätke see vahele.
messages sisaldab senist vestlust, vanim esimesena, ja lõpeb kasutaja küsimusega. Saatke paar viimast vooru, et
jätkuküsimused, näiteks „aga välismaalt tehtud tellimuste puhul?“, oleksid arusaadavad.
// Streams an answer and calls onText with each piece of text. Node.js 20+ or a browser.
export async function streamAnswer({ messages, collection, requestId, lastEventId, onText }) {
const response = await fetch("https://api.sursa.com/v1/chat", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SURSA_API_KEY}`,
"Content-Type": "application/json",
Accept: "text/event-stream",
...(lastEventId ? { "Last-Event-ID": String(lastEventId) } : {}),
},
body: JSON.stringify({ messages, collection, stream: true, request_id: requestId }),
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
const decoder = new TextDecoder();
let buffer = "";
let event = { id: 0, data: "" };
let done = null;
for await (const piece of response.body) {
buffer += decoder.decode(piece, { stream: true });
let newline;
while ((newline = buffer.indexOf("\n")) >= 0) {
const line = buffer.slice(0, newline).replace(/\r$/, "");
buffer = buffer.slice(newline + 1);
if (line.startsWith("id:")) event.id = Number(line.slice(3).trim());
else if (line.startsWith("data:")) event.data += line.slice(5).trim();
else if (line === "" && event.data) {
const message = JSON.parse(event.data);
if (message.type === "token") onText(message.text, event.id);
else if (message.type === "done") done = message;
else if (message.type === "error") throw Object.assign(new Error(message.message), { event: message, id: event.id });
event = { id: 0, data: "" };
}
}
}
if (!done) throw new Error("the stream ended before the answer was complete"); // resume it
return done;
}Ilma väärtuseta "stream": true tagastab POST /v1/chat täieliku vastuse JSON-ina nagu /v1/ask.
Katkenud voo jätkamine
Ühendused katkevad: mobiilsidevõrk vahetub, puhverserveril saab aeg täis, teie server taaskäivitub. Andke igale
küsimusele request_id ja vastus elab katkestuse üle:
- Väärtusega
request_idvalmistatakse vastus ette ühendusest sõltumatult. Ühenduse katkemine seda ei peata: vastus lõpetatakse ja salvestatakse. - Jätkamiseks saatke sama päring uuesti sama väärtusega
request_idja päisesLast-Event-IDviimase saadud sündmuse numbriga. - Kasutage ühe küsimuse kohta üht väärtust
request_id(näiteks UUID) ja sama väärtust selle küsimuse igas korduskatses. Uus küsimus saab uue väärtuserequest_id.
See, mida korduv päring saab, sõltub vastuse seisust:
| Olukord | Korduv päring saab |
|---|---|
| Vastust alles kirjutatakse või see just lõppes | Sündmused pärast väärtust Last-Event-ID, samade numbritega: voog lihtsalt jätkub. |
| Vastus lõppes mõni minut tagasi | Salvestatud vastuse: token kogu tekstiga ja done, nummerdatud alates 1-st. Küsimust uuesti ei esitata. |
| Voog ei saa sellest numbrist jätkuda | Vastuse algusest, nummerdatud alates 1-st. |
Teie kood käsitleb kõiki kolme juhtumit ühe reegliga: kui esimese saadud sündmuse number ei ole suurem kui
Last-Event-ID, algab vastus otsast; tühjendage näidatu ja koostage see uuesti. Vastasel juhul lisage lõppu.
import { randomUUID } from "node:crypto";
async function answerWithResume(messages, collection, show) {
const requestId = randomUUID();
let text = "";
let lastId = 0;
for (let attempt = 1; ; attempt++) {
let first = true;
try {
return await streamAnswer({
messages, collection, requestId, lastEventId: lastId,
onText(piece, id) {
if (first && lastId && id <= lastId) text = ""; // the answer starts over
first = false;
text += piece;
lastId = id;
show(text);
},
});
} catch (error) {
const retry = error.event ? error.event.retry === true : true; // a network error, or a server restart
if (!retry || attempt === 5) throw error;
await new Promise((resolve) => setTimeout(resolve, 1000 * attempt));
}
}
}Sursa API võib töötada mitmes serveris. Voog jätkub päise Last-Event-ID põhjal ainult serveris, mis vastust
kirjutab; kui teie korduv päring jõuab teise serverisse, saab see salvestatud vastuse, kui see on valmis, või
kirjutatakse vastus algusest uuesti. Ülaltoodud reegel katab mõlemad juhtumid ja küsimust ei loeta kunagi kaks korda.
Ilma väärtuseta request_id tühistab ühenduse sulgemine vastuse.
Vead voos
Enne voo algust tekkinud vead on tavalised HTTP-vead: 401, 403, 422 või 429 päisega Retry-After, kui
organisatsioon on ära kasutanud oma küsimuste limiidi või kui tal on korraga liiga palju
koostamisel olevaid vastuseid.
Kui voog on alanud, on selle HTTP-olek alati 200 ja probleem saabub sündmusena error:
{"type": "error", "code": "server_restart", "retry": true, "message": "…", "answer_id": "…"}
retry: truetähendab, et vastus peatus serveri tõttu, näiteks uuenduse ajal, ja võite saata sama päringu muutmata kujul uuesti.- Muud koodid, näiteks
timeout, on loetletud API teatmikus. Käsitlege tundmatut koodi nagu iga muud voo viga: teavitage kasutajat ja laske tal uuesti küsida.
Vastuste hinnangud kasutajatelt
Igal vastusel on question_id. Saatke kasutaja hinnang lõpp-punktile
POST /v1/questions/{question_id}/feedback: 1 tähendab abiks, -1 mitte
abiks, valikuliselt koos väljadega reason ja note. Hinnangud aitavad organisatsioonil näha, millised kaardid
vajavad tööd.
curl -X POST https://api.sursa.com/v1/questions/9812/feedback \
-H "Authorization: Bearer $SURSA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"value": -1, "reason": "outdated", "note": "The return window is now 14 days."}'Tootmisboti kontroll-loend
- Võti, millel on ainult
searchjaaskning mis on piiratud kogudega, mida boti sihtrühm näha tohib. - Iga küsimuse jaoks
request_idja ülaltoodud jätkamise reegel. - Voo lugemise ajalõpp, mis on pikem kui 15 sekundit, et kommentaarid
: pinghoiaksid voo elus. - Vastused kuvatakse Markdownina ja viited on lingitud oma allikatega.
- Selge teade, kui
emptyon määratud, ja võimalus jõuda inimeseni. - Vastust
429käsitletakse nii, et päisesRetry-Afterantud aeg oodatakse ära. - Hinnangud saadetakse tagasi, et teadmusbaas aja jooksul paremaks muutuks.