Developer Dashboard

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:

  1. Split files into chunks and keep stable source IDs such as policy.pdf#page=3.
  2. Create embeddings with /v1/embeddings.
  3. Store chunk text, embeddings, permissions, and metadata in your database or vector index.
  4. Retrieve and rerank relevant chunks with filters such as tenant, product, date, or document type.
  5. Send only the selected context to /v1/responses and require citations to the source IDs.
python
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)
javascript
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, or ascii; 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 attributes with up to 16 keys, so model your manual store with stable keys such as tenant, document_type, region, effective_date, and version.
  • 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 controlManual AvalAI equivalent today
vector_store_idsCollection, tenant, or namespace in your vector database
max_num_resultstop_k or reranked chunk limit
filtersSQL/vector metadata filters
ranking_optionsReranker, 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 annotationsSource IDs you require the model to cite
expires_afterTTL or cleanup job for temporary indexes and uploaded files

The OpenAI-compatible hosted flow is:

  1. Upload files with purpose="assistants" for hosted retrieval.
  2. Create a vector_store.
  3. Attach files with SDK create_and_poll helpers, or poll file_counts until indexing is completed.
  4. Call /v1/responses with tools: [{ "type": "file_search", "vector_store_ids": ["..."] }].
  5. Inspect file_search_call output items and cited message content.

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_call item: confirms the tool ran, shows status, and may include generated queries or raw search_results when you request include: ["file_search_call.results"].
  • message item: contains the assistant answer; file citations appear as file_citation annotations inside output_text content 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.

python
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)
javascript
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);
bash
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.

python
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)
javascript
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_options exposes ranker, score_threshold, and hybrid weights such as hybrid_search.embedding_weight and hybrid_search.text_weight; keep at least one hybrid weight above zero when you configure hybrid search.
  • Query rewriting can create a concise search_query for retrieval; direct hosted vector store search exposes this as rewrite_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_ids or per-file files objects; use files when metadata or chunking differs per document.
  • Expiration policies with expires_after are 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.