File Search Tool
Warning
Hosted File Search and provider-managed vector stores are under development in AvalAI. For production RAG today, use /v1/embeddings, your own chunk store, and /v1/responses. See Manual RAG with Embeddings, RAG Best Practices, and the Embeddings API.
File Search is the OpenAI-compatible hosted retrieval pattern for giving a model access to uploaded files. The model can search a managed vector store, produce a grounded answer, and return file citations in the response. This page documents how to design for that shape while using the AvalAI-supported manual RAG path today.
What To Use Today
Use manual retrieval when building on AvalAI now:
- Split files into chunks and keep stable source IDs such as
policy.pdf#page=3. - Create embeddings with
/v1/embeddings. - Store chunk text, embeddings, permissions, and metadata in your database or vector index.
- Retrieve and rerank relevant chunks with filters such as tenant, product, date, or document type.
- Send only the selected context to
/v1/responsesand require citations to the source IDs.
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["AVALAI_API_KEY"],
base_url="https://api.avalai.ir/v1",
)
# Replace this list with chunks returned by your vector database.
chunks = [
{
"source_id": "handbook.pdf#page=4",
"text": "Employees can request remote work approval from their manager.",
},
{
"source_id": "handbook.pdf#page=8",
"text": "Security training must be renewed every 12 months.",
},
]
context = "\n\n".join(f"[{chunk['source_id']}]\n{chunk['text']}" for chunk in chunks)
response = client.responses.create(
model="gpt-5.5",
input=[
{
"role": "system",
"content": (
"Answer only from the provided context. Cite source IDs in brackets. "
"If the context is insufficient, say what is missing."
),
},
{
"role": "user",
"content": f"Context:\n{context}\n\nQuestion: What approvals are needed?",
},
],
)
print(response.output_text)import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.AVALAI_API_KEY,
baseURL: "https://api.avalai.ir/v1",
});
// Replace this array with results from your vector database.
const chunks = [
{
source_id: "handbook.pdf#page=4",
text: "Employees can request remote work approval from their manager.",
},
{
source_id: "handbook.pdf#page=8",
text: "Security training must be renewed every 12 months.",
},
];
const context = chunks
.map((chunk) => `[${chunk.source_id}]\n${chunk.text}`)
.join("\n\n");
const response = await client.responses.create({
model: "gpt-5.5",
input: [
{
role: "system",
content:
"Answer only from the provided context. Cite source IDs in brackets. If the context is insufficient, say what is missing.",
},
{
role: "user",
content: `Context:\n${context}\n\nQuestion: What approvals are needed?`,
},
],
});
console.log(response.output_text);File Preparation And Metadata
Whether you use manual RAG today or hosted File Search later, prepare documents with the same retrieval discipline:
- Normalize text files to
utf-8,utf-16, orascii; reject or transcode files with unknown encodings before chunking. - Preserve source identity in every chunk: filename, page or section, tenant, owner, version, and last-updated timestamp.
- Treat OpenAI's supported hosted formats (
.pdf,.docx,.md,.txt,.json, common code files, and slides such as.pptx) as planning references until AvalAI announces hosted support. - Keep metadata small and filterable. OpenAI's retrieval guide documents compact vector-store file
attributeswith up to 16 keys, so model your manual store with stable keys such astenant,document_type,region,effective_date, andversion. - Apply permission and tenant filters before retrieval. The model should never receive chunks that the current user is not allowed to read.
Hosted Migration Shape
When AvalAI enables hosted File Search, migrate by replacing your retrieval call with a file_search tool attached to /v1/responses.
| Hosted control | Manual AvalAI equivalent today |
|---|---|
vector_store_ids | Collection, tenant, or namespace in your vector database |
max_num_results | top_k or reranked chunk limit |
filters | SQL/vector metadata filters |
ranking_options | Reranker, score-threshold, and hybrid-search weights in your retrieval service |
include: ["file_search_call.results"] | Debug logs containing selected chunks, scores, and source IDs |
file_citation annotations | Source IDs you require the model to cite |
expires_after | TTL or cleanup job for temporary indexes and uploaded files |
The OpenAI-compatible hosted flow is:
- Upload files with
purpose="assistants"for hosted retrieval. - Create a
vector_store. - Attach files with SDK
create_and_pollhelpers, or pollfile_countsuntil indexing iscompleted. - Call
/v1/responseswithtools: [{ "type": "file_search", "vector_store_ids": ["..."] }]. - Inspect
file_search_calloutput items and citedmessagecontent.
For larger knowledge bases, prefer file_batches.create_and_poll instead of many single-file create requests. OpenAI's reference supports batches of up to 500 files, and each file in the files array can carry its own attributes and chunking_strategy.
Reading Hosted File Search Output
OpenAI-style File Search returns structured output, not just final text. When AvalAI enables hosted support, inspect both layers:
file_search_callitem: confirms the tool ran, shows status, and may include generatedqueriesor rawsearch_resultswhen you requestinclude: ["file_search_call.results"].messageitem: contains the assistant answer; file citations appear asfile_citationannotations insideoutput_textcontent blocks.- Manual equivalent today: log selected chunk IDs, scores, filters, and source IDs in your retrieval service, then ask the model to cite those source IDs explicitly.
Render citations from annotations or source IDs in the UI instead of trusting free-form prose. If a citation points to a file the current user cannot access, hide it and investigate the retrieval filter before showing the answer.
Future Hosted Examples
Warning
These examples show the expected OpenAI-compatible shape for future AvalAI hosted File Search support. They are not production instructions until AvalAI announces vector_store and file_search availability.
Upload, Index, And Search
import os
from pathlib import Path
from openai import OpenAI
client = OpenAI(
api_key=os.environ["AVALAI_API_KEY"],
base_url="https://api.avalai.ir/v1",
)
file_obj = client.files.create(
file=Path("handbook.pdf").open("rb"),
purpose="assistants",
)
vector_store = client.vector_stores.create(
name="internal-handbook",
expires_after={"anchor": "last_active_at", "days": 30},
)
client.vector_stores.files.create_and_poll(
vector_store_id=vector_store.id,
file_id=file_obj.id,
attributes={"category": "handbook", "tenant": "internal"},
chunking_strategy={
"type": "static",
"max_chunk_size_tokens": 1000,
"chunk_overlap_tokens": 200,
},
)
response = client.responses.create(
model="gpt-5.5",
input="What does the handbook say about security training?",
tools=[
{
"type": "file_search",
"vector_store_ids": [vector_store.id],
"max_num_results": 5,
}
],
)
print(response.output_text)import fs from "node:fs";
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.AVALAI_API_KEY,
baseURL: "https://api.avalai.ir/v1",
});
const file = await client.files.create({
file: fs.createReadStream("handbook.pdf"),
purpose: "assistants",
});
const vectorStore = await client.vectorStores.create({
name: "internal-handbook",
expires_after: { anchor: "last_active_at", days: 30 },
});
await client.vectorStores.files.createAndPoll(vectorStore.id, {
file_id: file.id,
attributes: { category: "handbook", tenant: "internal" },
chunking_strategy: {
type: "static",
max_chunk_size_tokens: 1000,
chunk_overlap_tokens: 200,
},
});
const response = await client.responses.create({
model: "gpt-5.5",
input: "What does the handbook say about security training?",
tools: [
{
type: "file_search",
vector_store_ids: [vectorStore.id],
max_num_results: 5,
},
],
});
console.log(response.output_text);FILE_ID=$(curl -s "https://api.avalai.ir/v1/files" \
-H "Authorization: Bearer $AVALAI_API_KEY" \
-F purpose="assistants" \
-F file="@handbook.pdf" | jq -r .id)
VECTOR_STORE_ID=$(curl -s "https://api.avalai.ir/v1/vector_stores" \
-H "Authorization: Bearer $AVALAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"internal-handbook","expires_after":{"anchor":"last_active_at","days":30}}' | jq -r .id)
curl "https://api.avalai.ir/v1/vector_stores/$VECTOR_STORE_ID/files" \
-H "Authorization: Bearer $AVALAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_id": "'"$FILE_ID"'",
"attributes": {"category": "handbook", "tenant": "internal"},
"chunking_strategy": {
"type": "static",
"max_chunk_size_tokens": 1000,
"chunk_overlap_tokens": 200
}
}'
# Poll the vector store file or vector_store.file_counts until indexing completes
# before sending traffic that depends on the new file.
curl "https://api.avalai.ir/v1/responses" \
-H "Authorization: Bearer $AVALAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.5",
"input": "What does the handbook say about security training?",
"tools": [{
"type": "file_search",
"vector_store_ids": ["'"$VECTOR_STORE_ID"'"],
"max_num_results": 5
}]
}'Include Results And Filter Metadata
Use include when you need the raw retrieved chunks for debugging or evaluation. Use filters to enforce metadata constraints before the model receives context.
response = client.responses.create(
model="gpt-5.5",
input="Summarize policy updates for enterprise customers.",
tools=[
{
"type": "file_search",
"vector_store_ids": ["vs_123"],
"max_num_results": 3,
"filters": {
"type": "and",
"filters": [
{"type": "eq", "key": "tenant", "value": "acme"},
{"type": "in", "key": "category", "value": ["policy", "faq"]},
],
},
"ranking_options": {
"ranker": "auto",
"score_threshold": 0.25,
"hybrid_search": {"embedding_weight": 0.7, "text_weight": 0.3},
},
}
],
include=["file_search_call.results"],
)
print(response.output_text)const response = await client.responses.create({
model: "gpt-5.5",
input: "Summarize policy updates for enterprise customers.",
tools: [
{
type: "file_search",
vector_store_ids: ["vs_123"],
max_num_results: 3,
filters: {
type: "and",
filters: [
{ type: "eq", key: "tenant", value: "acme" },
{ type: "in", key: "category", value: ["policy", "faq"] },
],
},
ranking_options: {
ranker: "auto",
score_threshold: 0.25,
hybrid_search: { embedding_weight: 0.7, text_weight: 0.3 },
},
},
],
include: ["file_search_call.results"],
});
console.log(response.output_text);Design Notes From OpenAI Retrieval Docs
- Semantic search can find relevant chunks even when they share few keywords with the query.
- Hosted vector stores automatically parse, chunk, embed, and index attached files.
- Direct semantic search returns up to 10 results by default and can be configured up to 50 with
max_num_results. - Retrieval systems can improve quality with query rewriting, metadata filters, ranking options, and score thresholds.
ranking_optionsexposesranker,score_threshold, and hybrid weights such ashybrid_search.embedding_weightandhybrid_search.text_weight; keep at least one hybrid weight above zero when you configure hybrid search.- Query rewriting can create a concise
search_queryfor retrieval; direct hosted vector store search exposes this asrewrite_query=true. Log both the original user input and the rewritten query so you can debug relevance regressions. - OpenAI's reference defaults chunk files at 800 tokens with 400-token overlap; custom chunk sizes must stay between 100 and 4096 tokens, with overlap no more than half the chunk size.
- Batch ingestion accepts either shared
file_idsor per-filefilesobjects; usefileswhen metadata or chunking differs per document. - Expiration policies with
expires_afterare useful for temporary indexes, demos, and customer-uploaded files that should not live indefinitely. - OpenAI's reference vector store file limits include 512 MB and 5,000,000 tokens per file. Treat those as planning references, not AvalAI commitments, until hosted support is announced.
Safety And Operations
- Upload only files you trust and are allowed to process.
- Keep tenant and permission filters outside the model; do not rely on prompting for access control.
- Log retrieved chunk IDs, scores, filters, and final citations for audits.
- Validate tool arguments and returned links to reduce prompt-injection and data-exfiltration risk.
- Delete unused files or vector stores when hosted storage is available.
- After removing a file from hosted storage, expect a short consistency window: keep permission checks in your app and avoid assuming cached retrieval results disappear instantly.
- Evaluate retrieval with real questions, expected source IDs, and answer-quality checks before launch.