Jautājumu un atbilžu robota izveide
Šajā ceļvedī tiek izveidots pamats tērzēšanas robotam, kas atbild uz jautājumiem no jūsu zināšanu bāzes: tērzēšanas rīkā, jūsu palīdzības centrā vai jūsu produktā. Asistents atrod vajadzīgās zināšanas un atbild, atsaucoties uz izmantotajām kartītēm; jūsu kods nosūta jautājumu un parāda rezultātu.
Jums vajadzīga atslēga ar tvērumiem search un ask. Atbildē tiek izmantotas tikai tās
kartītes, kuras atslēgai ir atļauts lasīt, tāpēc to, par ko robots var runāt, nosaka atslēgas loma, datu profils un
kolekcijas. Klientiem paredzētam robotam piešķiriet atslēgu, kas redz tikai publiskās kolekcijas.
Trīs veidi, kā saņemt atbildi
| Operācija | Atgriež | Kam izmantot |
|---|---|---|
POST /v1/search | Atbilstošos izvilkumus, sākot ar labākajiem. Bez uzrakstītas atbildes. | Meklēšanas laukam, sadaļai „saistītie raksti“, savai rezultātu kārtošanai. |
POST /v1/ask | Pilnu asistenta atbildi ar avotiem vienā HTTP atbildē. | Robotiem, kas publicē vienu ziņojumu katrai atbildei; servera puses darbiem. |
POST /v1/chat | Atbildi kā notikumu straumi, kamēr tā tiek rakstīta. | Tērzēšanas saskarnēm, kur lietotājam jāredz, kā atbilde parādās. |
Meklēšana
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"}'Katrs trāpījums ir kartītes izvilkums: kartītes doc_id un doc_name, sadaļas heading, izvilkuma text, lappuses
vai tabulas rindas, kurās tas atrasts, kā arī kartītes uzticamība un pārbaudes statuss.
collection izvēlas kolekciju, kurā meklēt; bez tā tiek izmantota kolekcija ar nosaukumu default. tags un
card_ids sašaurina meklēšanu līdz kartītēm ar šīm birkām vai līdz konkrētām kartītēm.
Jautājums un pilna atbilde
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"}'Atbildes teksts laukā answer ir Markdown formātā. Tā atsauces, piemēram, [1] vai [1, 3], atbilst sources
ierakstu laukam ref; sasaistiet katru no tām ar kartīti (doc_id), lai lasītājs varētu pārliecināties, uz ko
atbilde balstīta.
Skaitlis tekstā, ko nevarēja apstiprināt pēc dokumentiem, var parādīties kā atzīme, piemēram, ⟦n:a1⟧.
verification.items apraksta katru atzīmi: tās marker, reason un original tekstu. Ja jūsu kods atzīmes
neapstrādā, aizstājiet katru no tām ar tās original tekstu.
Kad atbildes nav
HTTP atbilde vienmēr ir 200. Ja asistents nevar atbildēt, empty norāda iemeslu, bet answer satur īsu ziņojumu,
ko varat parādīt:
empty | Nozīme |
|---|---|
no_hits | Zināšanu bāzē nekas neatbilst jautājumam. |
restricted | Tēma ir kartītēs, kuras atslēgai nav atļauts lasīt. |
guardrail | Jautājums ir ārpus tā, uz ko organizācija atļauj asistentam atbildēt. |
no_data_for_period | Jautājums attiecas uz periodu, par kuru nav dokumentu. |
no_hits ir noderīgs signāls: tas parāda, par ko jūsu lietotāji jautā, bet zināšanu bāze vēl neaptver.
Režīmi „Fast“ un „Precise“
Nododiet "quality": "precise", lai uz sarežģītu jautājumu saņemtu rūpīgāku atbildi, kas prasa vairāk laika.
Noklusējums "fast" der vairumam jautājumu.
Atbildes straumēšana
Tērzēšanas saskarnē rādiet atbildi, kamēr tā tiek rakstīta. POST /v1/chat ar
"stream": true atbild ar text/event-stream: viens notikums katram ziņojumam, katrs ar rindu id: (tā numurs
straumē, sākot no 1) un rindu data: ar JSON. JSON lauks type norāda, kas tas par notikumu.
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 | Kas jādara |
|---|---|
meta | Atbilde ir sākusies. Saglabājiet answer_id, ja ierakstāt atbildes žurnālā. |
sources | Kartītes, uz kurām atbilde balstīta. Var pienākt vairāk nekā vienu reizi; noteicošā ir pēdējā. |
token | Atbildes teksta daļa. Pievienojiet to jau parādītajam. |
done | Atbilde ir pabeigta. Tajā ir tie paši lauki, kas /v1/ask atbildē. |
error | Atbilde apstājās. Straume beidzas bez done. Sk. tālāk. |
followups | Pēc done: ieteiktie nākamie jautājumi, ko varat piedāvāt kā pogas. |
| jebkas cits | Izlaidiet to. Jauni notikumu tipi var parādīties jebkurā laikā. |
Rinda, kas sākas ar : (piemēram, : ping, kas tiek sūtīts ik pēc 15 sekundēm, kamēr atbilde tiek sagatavota), ir
komentārs. Izlaidiet to.
messages satur līdzšinējo sarunu, sākot ar vecāko repliku un beidzot ar lietotāja jautājumu. Nosūtiet dažas
pēdējās replikas, lai papildjautājumi, piemēram, „un pasūtījumiem no ārzemēm?“, tiktu saprasti.
// 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;
}Bez "stream": true operācija POST /v1/chat atgriež pilnu atbildi JSON formātā, tāpat kā /v1/ask.
Pārtrauktas straumes turpināšana
Savienojumi pārtrūkst: mainās mobilais tīkls, starpniekserverim iestājas noildze, jūsu serveris tiek restartēts.
Piešķiriet katram jautājumam request_id, un atbilde pārdzīvos pārtraukumu:
- Ar
request_idatbilde tiek sagatavota neatkarīgi no savienojuma. Atvienošanās to neaptur: atbilde tiek pabeigta un saglabāta. - Lai turpinātu, vēlreiz nosūtiet to pašu pieprasījumu ar to pašu
request_idun pēdējā saņemtā notikuma numuru galvenēLast-Event-ID. - Izmantojiet vienu
request_id(piemēram, UUID) katram jautājumam un to pašu – katrā šī jautājuma atkārtojumā. Jauns jautājums saņem jaunurequest_id.
Ko saņem atkārtotais pieprasījums, ir atkarīgs no tā, kādā stāvoklī ir atbilde:
| Situācija | Atkārtotais pieprasījums saņem |
|---|---|
| Atbilde vēl tiek rakstīta vai tikko pabeigta | Notikumus pēc Last-Event-ID ar tiem pašiem numuriem: straume vienkārši turpinās. |
| Atbilde pabeigta pirms dažām minūtēm | Saglabāto atbildi kā token ar visu tekstu un done, numurētus no 1. Jautājums netiek uzdots vēlreiz. |
| Straumi nevar turpināt no šī numura | Atbildi no sākuma, numurētu no 1. |
Jūsu kods visus trīs gadījumus apstrādā ar vienu noteikumu: ja pirmā saņemtā notikuma numurs nav lielāks par
Last-Event-ID, atbilde sākas no jauna; notīriet parādīto un veidojiet to vēlreiz. Pretējā gadījumā pievienojiet
jauno tekstu.
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 var darboties vairākos serveros. Straume turpinās no Last-Event-ID tikai tajā serverī, kas raksta
atbildi; ja jūsu atkārtotais pieprasījums nonāk citā serverī, tas saņem saglabāto atbildi, tiklīdz tā ir pabeigta,
vai arī atbilde tiek uzrakstīta vēlreiz no sākuma. Iepriekš minētais noteikums aptver abus gadījumus, un jautājums
nekad netiek ieskaitīts divreiz.
Bez request_id savienojuma aizvēršana atceļ atbildi.
Kļūdas straumē
Kļūdas pirms straumes sākuma ir parastas HTTP kļūdas: 401, 403, 422 vai 429 ar Retry-After, ja
organizācija ir izlietojusi savu jautājumu limitu vai tai vienlaikus ir pārāk daudz
sagatavojamu atbilžu.
Kad straume ir sākusies, tās HTTP statuss vienmēr ir 200, un problēma tiek paziņota kā notikums error:
{"type": "error", "code": "server_restart", "retry": true, "message": "…", "answer_id": "…"}
retry: truenozīmē, ka atbilde apstājās servera dēļ, piemēram, atjaunināšanas laikā, un varat nosūtīt to pašu pieprasījumu vēlreiz nemainītu.- Citi kodi, piemēram,
timeout, ir uzskaitīti API rokasgrāmatā. Nezināmu kodu apstrādājiet tāpat kā jebkuru citu straumes kļūdu: informējiet lietotāju un ļaujiet jautāt vēlreiz.
Atbilžu vērtēšana
Katrai atbildei ir question_id. Nosūtiet lietotāja vērtējumu uz
POST /v1/questions/{question_id}/feedback: 1 – noderīga, -1 – nav
noderīga, ar neobligātu reason un note. Vērtējumi palīdz organizācijai saprast, kuras kartītes jāuzlabo.
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."}'Kontrolsaraksts robotam darba vidē
- Atslēga tikai ar
searchunask, ierobežota ar kolekcijām, kuras drīkst redzēt robota auditorija. request_idkatram jautājumam un iepriekš aprakstītais turpināšanas noteikums.- Straumes lasīšanas noildze, kas ir garāka par 15 sekundēm, lai komentāri
: pinguzturētu savienojumu. - Atbildes attēlotas kā Markdown, atsauces sasaistītas ar to avotiem.
- Skaidrs ziņojums, ja iestatīts
empty, un iespēja sazināties ar cilvēku. 429apstrāde, nogaidotRetry-After.- Vērtējumi tiek nosūtīti atpakaļ, lai zināšanu bāze laika gaitā uzlabotos.