Want to find the answer quick?
Ask AI endpoint
The ask
endpoint helps you create interactive and engaging conversational interfaces, Q&A assistants, and chatbots. It gives users the information they need quickly and directly, letting them engage with your product without having to wade through documentation on articles. It uses up-to-date information from your database inside of Xata. This could be your documentation, team knowledge base, or any source of data you've set up. The ask endpoint uses search or similarity search algorithms to find relevant information from your database, and then applies the OpenAI ChatGPT API to generate natural language responses to user queries.
At a high level, the ask
endpoint works like this:
- Run a text search against the database to find the records that are most relevant to the question asked by the user.
- Produce a prompt with this general form:
With these rules: {rules} And this text: {context} Given the above text, answer the question: {question} Answer:
- Send the prompt to the ChatGPT API and let the model complete the answer.
The ask endpoint can use either keyword search or vector/similarity search to find records that are most relevant to the user's query. To learn more about keyword or vector searches, see our blog the compares the two approaches.
Usage
The ask
endpoint has the following general form:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
const result = await xata.db.Tutorial.ask("<question>", { rules: [ // ...array of strings with the rules for the model..., ], searchType: "keyword|vector", search: { fuzziness: 0|1|2, prefix: "phrase|disabled", target: { // ...search target options... }, filter: { // ...search filter options... }, boosters: [ // ...search boosters options... ] }, vectorSearch: { column: "<embedding column>", contentColumn: "<content column>", filter: { // ...search filter options... }, }, });
The ask
endpoint works at the table level. In the above snippet, the name of the table is called Tutorial
, as a placeholder. Replace Tutorial
with the name of your table name.
The only mandatory parameter is the question
, which is the question that the ask endpoint will attempt to answer.
The other options are:
rules
: an array of strings with the rules for the model. The rules are passed as part of the prompt and control the behavior of the model. For example, you can use the rules to tell the model to answer the question in a specific way, for example, more or less concise. See the examples on this page for some ideas.searchType
: the type of search to use to find the relevant records. Can be either"keyword"
, for using the keyword free-text-search, or"vector"
, for using semantic/similarity search. The default is"keyword"
.search
: options for the keyword search. See the Keyword search options section for the available options.vectorSearch
: options for the vector search. See the Vector search options section for the available options.
Note that after performing the search step, the ask
endpoint will use the top 3 results. In case of keyword search, all string or text columns that have more than 150 characters in the top 3 results will be added to the prompt. In case of vector search, the specified contentColumn
from the top 3 results will be added to the prompt.
Because the context size is limited, if the generated context is too large, the ask endpoint will attempt to dynamically select the portions of the text that are more relevant.
The response contains the generated answer and the record IDs that were used as context:
1 2 3 4 5 6 7 8
{ "answer": "<< answer >>", "records":[ "b70d541d114ff54ad15915636450663f" "8ae4837002e21f013aa85c30a126ea1c" "4b137344a3c53d5152c45ed514188cd2" ] }
You can lookup the records by IDs in the database to get their contents.
Keyword search options
The options that you can pass under the search
key mirror a subset of the options from the search endpoint. See that section of the guide for more details.
target
to select the columns to search in and to configure column weights.prefix
to configure the prefix matching behavior.fuzziness
to configure the fuzzy matching behavior.filter
to filter the records that are returned by the search.boosters
to tune the relevancy controls.
Vector search options
The options that you can pass under the search
key mirror a subset of the options from the vector search endpoint. See that section of the guide for more details.
column
to select the column that contains the vector embeddings.contentColumn
to select the column that contains the text content that will be used as context.filter
to filter the records that are returned by the search.
Streaming the response
Because the ask
endpoint can take several seconds to complete, it supports streaming the response using server-sent events.
To enable this mode, pass the Accept: text/event-stream
header in the request. The response will be a stream of JSON objects, prefixed by the keywords data
. The last object in the stream contains the "done": true
:
data: {"text":""} data: {"text":"To"} data: {"text":" perform"} data: {"text":" an"} ... data: {"done":true,"records":["0415d654cc8dd113e9b9423f425697ae","91301cdc08524e6f6eef5d0b9d66e345","ae0c68966fc0f00cb913b3c209a7c5a1"]}
You can find a full Next.js application using the ask endpoint with server-sent events in our examples repository.
Examples
To run these examples you need to have a table that contains enough text to make the context useful for a question. String/text columns that are less than 150 characters are ignored by the model.
To index your custom data in Xata, you can use, for example, this web crawler.
The following is the simplest example of using the ask
endpoint:
1
const result = await xata.db.Tutorial.ask("What is this tutorial about?");
Because the search step is not specified, keyword search is being used with the default configuration.
The following example tunes the rules and the search step, while still using keyword search:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
const result = await xata.db.Tutorial.ask("How do a retrieve a single record?", { rules: [ "Do not answer questions about pricing or the free tier. Respond that Xata has several options available, please check https://xata.io/pricing for more information.", "When you give an example, this example must exist exactly in the context given.", "Only answer questions that are relating to the defined context or are general technical questions. If asked about a question outside of the context, you can respond with \"It doesn't look like I have enough information to answer that. Check the documentation or contact support.\"", "Your name is DanGPT" ], searchType: "keyword", search: { fuzziness: 2, prefix: "phrase", target: [ "slug", { column: "title", weight: 4 }, "content", "section", { column: "keywords", weight: 4 } ], boosters: [ { valueBooster: { column: "section", value: "guide", factor: 18 } } ] } })
The following example uses vector search:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
const result = await xata.db.Tutorial.ask("How do a retrieve a single record?", { rules: [ "Do not answer questions about pricing or the free tier. Respond that Xata has several options available, please check https://xata.io/pricing for more information.", "If the user asks a how-to question, provide a code snippet in the language they asked for with TypeScript as the default.", "Only answer questions that are relating to the defined context or are general technical questions. If asked about a question outside of the context, you can respond with \"It doesn't look like I have enough information to answer that. Check the documentation or contact support.\"", "Results should be relevant to the context provided and match what is expected for a cloud database.", "If the question doesn't appear to be answerable from the context provided, but seems to be a question about TypeScript, Javascript, or REST APIs, you may answer from outside of the provided context.", "Your name is DanGPT" ], searchType: "vector", vectorSearch: { column: "embeddings", contentColumn: "content", filter: { section: "guide" } } })
Troubleshooting
No records found
If you see the following error:
1
no records found, it seems that I don't have enough data to answer this question.
It means that the search step did not return any results or that the returned results don't have enough text to generate a prompt. Note that string and text columns that have less than 150 characters are ignored.
To solve the issue, you typically need to add more text to the content column, making it sure it has more than 150 characters for most records.