Skip to content

Search knowledge collections

Your organization can hold knowledge collections: PDF, Word, slide, and Markdown files that Urai indexes for search. You upload them in the app under Knowledge, you push them with the Knowledge API, and you group them into collections.

Two other pages cover the same documents from another side. Use the Knowledge API to search them from your own code and to get the passages back. Use the extraction API to read the text of one file without keeping it.

Two built-in tools read that index:

  • search_documents returns the passages that match a query.
  • read_document returns one document in full.

You name them in tools[] like any other tool. Urai runs the search before the model writes the answer, so one request gives you a grounded reply.

Terminal window
curl https://chat.app.urai.dev/api/openai/v1/chat/completions \
-H "Authorization: Bearer $URAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-haiku-4-5",
"messages": [
{ "role": "user", "content": "What is our refund window for annual plans?" }
],
"tools": [
{ "type": "function", "function": { "name": "search_documents" } },
{ "type": "function", "function": { "name": "read_document" } }
]
}'

Name both tools together. The two work as a pair: search finds the document, and read returns all of it. You can name only one if you want only that behaviour.

If your organization has no collections, a request that names either tool fails with 400 and the code tool_not_configured. Upload a document first.

Without a limit, the tools search every collection in the API key’s organization. That is the correct default for most applications.

To narrow the scope, send the top-level knowledge field:

{
"model": "anthropic/claude-haiku-4-5",
"messages": [{ "role": "user", "content": "What is our refund window?" }],
"tools": [{ "type": "function", "function": { "name": "search_documents" } }],
"knowledge": {
"collections": ["billing-policies", "support-playbooks"]
}
}

Four rules apply:

  • The limit is absolute. The model can narrow the scope further with its own collections argument. It cannot reach a collection you left out.
  • A name matches the collection slug or the display name. Case does not matter.
  • Find the slug in the app URL. The page /knowledge/billing-policies has the slug billing-policies.
  • An unknown name fails the request with 400 and the code unknown_collection. The message lists the valid slugs. Urai does not fall back to a search of everything.

Use this field when one API key serves several products, and each product must see only its own documents.

knowledge is a top-level field in the request body. It is not a key inside tools[].function, because a typed OpenAI SDK builds the function object from a fixed shape and drops any extra key.

Every OpenAI client can add a root-level field.

response = client.chat.completions.create(
model="anthropic/claude-haiku-4-5",
messages=[{"role": "user", "content": "What is our refund window?"}],
tools=[{"type": "function", "function": {"name": "search_documents"}}],
extra_body={"knowledge": {"collections": ["billing-policies"]}},
)
const response = await client.chat.completions.create({
model: "anthropic/claude-haiku-4-5",
messages: [{ role: "user", content: "What is our refund window?" }],
tools: [{ type: "function", function: { name: "search_documents" } }],
// @ts-expect-error The Urai extension is not in the OpenAI types.
knowledge: { collections: ["billing-policies"] },
});

The model chooses the arguments. You do not send them.

Argument Effect
query Required. The question or the keywords to look for.
collections Narrows the search to these collections, inside the limit you set.
documents Restricts the search to named documents from an earlier result.
limit Number of passages to return. The default is 8 and the maximum is 25.

Each result carries the passage and enough information to cite it.

{
"query": "refund window annual plans",
"results": [
{
"document_id": "3f2a…",
"document_name": "Billing Policy 2026.pdf",
"page": 4,
"reference": "p. 4",
"collection_id": "9b1c…",
"collection_name": "Billing policies",
"seq": 12,
"score": 0.81,
"content": "Annual plans may be refunded in full within 30 days of renewal…"
}
]
}
  • reference is one string the model can quote, such as p. 4, Billing > Refunds, or excerpt 13.
  • page and section appear only when the file format has them. A Word file has no pages.
  • The tool instructs the model to name the source document in its answer, so citations appear in the answer text. The response body has no separate citation field.

When nothing matches, the tool returns an empty results array and a note. The model then says that the knowledge base does not cover the question.

Search returns passages. Some questions need the whole file, such as the total of an invoice or every row of a table. The model calls read_document for that.

Argument Effect
document Required. The document_name from a search result. The file extension is optional.
from_seq Resume position. Omit it to start at the beginning.

A long document returns in windows of about 40,000 characters. When a reply carries next_seq, the model calls again with from_seq set to that value.

{
"document_id": "3f2a…",
"document_name": "Billing Policy 2026.pdf",
"collection_name": "Billing policies",
"page_count": 18,
"chunk_count": 96,
"from_seq": 0,
"next_seq": 41,
"content": "[p. 1] Billing Policy…"
}

read_document reads the same collections as search_documents. Your knowledge.collections limit applies to both.

Name the built-in tools and your UraiJS tools in the same request. The model picks between them.

{
"model": "anthropic/claude-haiku-4-5",
"messages": [
{ "role": "user", "content": "Is account acct_8812 inside the refund window?" }
],
"tools": [
{ "type": "function", "function": { "name": "search_documents" } },
{ "type": "function", "function": { "name": "orders" } }
],
"knowledge": { "collections": ["billing-policies"] },
"metadata": { "account_id": "acct_8812" }
}

The model reads the policy from the collection, reads the account from your tool, and answers with both. See Call your UraiJS tools for how metadata reaches the tool.