ابزار جستجوی فایل
هشدار
File Search میزبانیشده و vector storeهای مدیریتشده توسط ارائهدهنده در AvalAI در حال توسعه هستند. برای RAG در production امروز، از /v1/embeddings، ذخیرهسازی chunk خودتان و /v1/responses استفاده کنید. RAG دستی با Embeddings، بهترین شیوههای RAG و Embeddings API را ببینید.
File Search الگوی retrieval میزبانیشده و سازگار با OpenAI برای دسترسی مدل به فایلهای آپلودشده است. مدل میتواند در یک vector store مدیریتشده جستجو کند، پاسخ grounded بسازد و citationهای فایل را در پاسخ برگرداند. این صفحه نشان میدهد چگونه برای این الگو طراحی کنید، در حالی که امروز از مسیر RAG دستی پشتیبانیشده در AvalAI استفاده میکنید.
امروز از چه چیزی استفاده کنیم
برای ساخت روی AvalAI در وضعیت فعلی، retrieval دستی را به کار ببرید:
- فایلها را به chunk تقسیم کنید و source ID پایدار مثل
policy.pdf#page=3نگه دارید. - با
/v1/embeddingsembedding بسازید. - متن chunk، embedding، permission و metadata را در database یا vector index خودتان ذخیره کنید.
- chunkهای مرتبط را با filterهایی مثل tenant، محصول، تاریخ یا نوع سند retrieve و rerank کنید.
- فقط context انتخابشده را به
/v1/responsesبفرستید و از مدل citation به source IDها بخواهید.
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["AVALAI_API_KEY"],
base_url="https://api.avalai.ir/v1",
)
# این لیست را با chunkهای برگشتی از 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",
});
// این آرایه را با نتایج 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);آمادهسازی فایل و metadata
چه امروز از RAG دستی استفاده کنید و چه بعدا به File Search میزبانیشده مهاجرت کنید، سندها را با همان انضباط retrieval آماده کنید:
- فایلهای متنی را به
utf-8،utf-16یاasciiنرمال کنید؛ فایل با encoding نامشخص را پیش از chunking رد یا تبدیل کنید. - هویت منبع را در هر chunk نگه دارید: نام فایل، صفحه یا بخش، tenant، مالک، نسخه و timestamp آخرین بهروزرسانی.
- فرمتهای پشتیبانیشده در مسیر میزبانیشده OpenAI مثل
.pdf،.docx،.md،.txt،.json، فایلهای رایج کدنویسی و slideهایی مثل.pptxرا تا زمان اعلام پشتیبانی میزبانیشده در AvalAI فقط مرجع برنامهریزی بدانید. - metadata را کوچک و قابل فیلتر نگه دارید. راهنمای Retrieval در OpenAI برای attributeهای فایل در vector store تا ۱۶ کلید فشرده را مستند کرده است؛ بنابراین در store دستی خودتان هم کلیدهای پایدار مثل
tenant،document_type،region،effective_dateوversionبسازید. - فیلتر permission و tenant را پیش از retrieval اعمال کنید. مدل هرگز نباید chunkهایی را دریافت کند که کاربر فعلی اجازه خواندنشان را ندارد.
شکل مهاجرت به حالت میزبانیشده
وقتی AvalAI پشتیبانی Hosted File Search را فعال کند، با جایگزین کردن retrieval خودتان با tool از نوع file_search در /v1/responses مهاجرت کنید.
| کنترل میزبانیشده | معادل دستی در AvalAI امروز |
|---|---|
vector_store_ids | collection، tenant یا namespace در vector database شما |
max_num_results | top_k یا محدودیت chunkهای rerankشده |
filters | فیلترهای metadata در SQL/vector DB |
ranking_options | reranker، score threshold و وزنهای hybrid search در سرویس retrieval شما |
include: ["file_search_call.results"] | لاگ debug شامل chunkهای انتخابشده، scoreها و source IDها |
annotationهای file_citation | source IDهایی که از مدل میخواهید cite کند |
expires_after | TTL یا job پاکسازی برای indexها و فایلهای آپلودی موقت |
flow میزبانیشده سازگار با OpenAI این است:
- فایلها را با
purpose="assistants"برای retrieval میزبانیشده آپلود کنید. - یک
vector_storeبسازید. - فایلها را با helperهای SDK از نوع
create_and_pollattach کنید، یاfile_countsرا poll کنید تا indexing بهcompletedبرسد. /v1/responsesرا باtools: [{ "type": "file_search", "vector_store_ids": ["..."] }]فراخوانی کنید.- آیتمهای خروجی
file_search_callو متنmessageدارای citation را بررسی کنید.
برای knowledge baseهای بزرگتر، به جای درخواستهای تکفایلی زیاد، از file_batches.create_and_poll استفاده کنید. مرجع OpenAI تا ۵۰۰ (500) فایل در هر batch را پشتیبانی میکند و هر فایل در آرایه files میتواند attributes و chunking_strategy مخصوص خودش را داشته باشد.
خواندن خروجی File Search میزبانیشده
File Search به سبک OpenAI فقط متن نهایی برنمیگرداند؛ خروجی ساختاریافته دارد. وقتی AvalAI پشتیبانی میزبانیشده را فعال کرد، هر دو لایه را بررسی کنید:
- آیتم
file_search_call: اجرای tool و status را نشان میدهد و اگرinclude: ["file_search_call.results"]درخواست کرده باشید میتواندqueriesساختهشده یاsearch_resultsخام را برگرداند. - آیتم
message: پاسخ assistant را دارد؛ citationهای فایل به شکل annotation از نوعfile_citationداخل blockهایoutput_textمیآیند. - معادل دستی امروز: شناسه chunkهای انتخابشده، scoreها، filterها و source IDها را در سرویس retrieval خودتان log کنید، سپس از مدل بخواهید همان source IDها را صریح cite کند.
Citationها را از annotationها یا source IDها در UI render کنید، نه از prose آزاد مدل. اگر citation به فایلی اشاره میکند که کاربر فعلی نباید به آن دسترسی داشته باشد، آن را پنهان کنید و قبل از نمایش پاسخ، فیلتر retrieval را بررسی کنید.
مثالهای میزبانیشده آینده
هشدار
این مثالها شکل مورد انتظار سازگار با OpenAI را برای پشتیبانی آینده File Search میزبانیشده در AvalAI نشان میدهند. تا زمانی که AvalAI در دسترس بودن vector_store و file_search را اعلام نکرده، دستورالعمل production نیستند.
آپلود، ایندکس و جستجو
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
}
}'
# پیش از ارسال traffic وابسته به فایل جدید، وضعیت vector store file یا
# vector_store.file_counts را poll کنید تا indexing کامل شود.
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
}]
}'بازگرداندن نتایج و فیلتر metadata
وقتی برای debug یا evaluation به chunkهای خام retrieveشده نیاز دارید از include استفاده کنید. برای اعمال محدودیتهای metadata پیش از رسیدن context به مدل، از filters استفاده کنید.
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);نکات طراحی از مستندات Retrieval شرکت OpenAI
- جستجوی معنایی میتواند chunkهای مرتبط را حتی با اشتراک کم در keywordها پیدا کند.
- vector storeهای میزبانیشده، فایلهای attachشده را parse، chunk، embed و index میکنند.
- جستجوی معنایی مستقیم بهصورت پیشفرض تا ۱۰ نتیجه برمیگرداند و با
max_num_resultsتا ۵۰ قابل تنظیم است. - سیستمهای retrieval میتوانند با query rewriting، فیلتر metadata، ranking options و score threshold کیفیت را بهتر کنند.
ranking_optionsشاملranker،score_thresholdو وزنهای hybrid مثلhybrid_search.embedding_weightوhybrid_search.text_weightاست؛ اگر hybrid search را تنظیم میکنید، حداقل یکی از وزنها باید بیشتر از صفر باشد.- query rewriting میتواند یک
search_queryکوتاهتر برای retrieval بسازد؛ direct hosted vector store search این کنترل را به شکلrewrite_query=trueنشان میدهد. هم input اصلی کاربر و هم query بازنویسیشده را log کنید تا regressionهای relevance قابل debug باشند. - مقدار پیشفرض مرجع OpenAI برای chunk برابر ۸۰۰ توکن با overlap برابر ۴۰۰ توکن است؛ chunk سفارشی باید بین ۱۰۰ تا ۴۰۹۶ توکن باشد و overlap بیشتر از نصف chunk size نباشد.
- batch ingestion یا
file_idsمشترک میپذیرد یا objectهای per-file درfiles؛ وقتی metadata یا chunking هر سند متفاوت است ازfilesاستفاده کنید. - policyهای انقضا با
expires_afterبرای indexهای موقت، demoها و فایلهای آپلودی مشتری که نباید دائمی بمانند مفیدند. - محدودیتهای مرجع OpenAI برای فایل vector store شامل ۵۱۲ MB و ۵٬۰۰۰٬۰۰۰ توکن برای هر فایل است. تا زمان اعلام پشتیبانی میزبانیشده در AvalAI، این موارد را فقط برای برنامهریزی در نظر بگیرید، نه تعهد AvalAI.
ایمنی و عملیات
- فقط فایلهایی را آپلود کنید که به آنها اعتماد دارید و مجاز به پردازش آنها هستید.
- فیلترهای tenant و permission را بیرون از مدل نگه دارید؛ برای کنترل دسترسی به prompt تکیه نکنید.
- شناسه chunkهای retrieveشده، scoreها، filterها و citation نهایی را برای audit لاگ کنید.
- برای کاهش خطر prompt injection و data exfiltration، argumentهای tool و لینکهای برگشتی را validate کنید.
- وقتی storage میزبانیشده فعال شد، فایلها یا vector storeهای بلااستفاده را حذف کنید.
- پس از حذف فایل از storage میزبانیشده، یک بازه کوتاه eventual consistency را در نظر بگیرید: permission checkها را در برنامه نگه دارید و فرض نکنید نتیجههای retrieveشده cacheشده فورا ناپدید میشوند.
- retrieval را با سوالهای واقعی، source IDهای مورد انتظار و بررسی کیفیت پاسخ پیش از launch ارزیابی کنید.