Web Search

دسترسی هر مدل به اطلاعات بلادرنگ وب؛ جست‌وجوی وب با ابزار web_search و پاسخ با استناد و حاشیه‌نویسی دقیق.

بتا: جست‌وجوی وب از طریق ابزار web_search در مرحلهٔ بتا است؛ API و رفتار ممکن است تغییر کند.

آشا ابزار استاندارد web_search (سازگار با OpenAI) را بدون تغییر به ارائه‌دهندهٔ بالادستی می‌فرستد؛ اجرای جست‌وجو و بازگرداندن نتایج بر عهدهٔ ارائه‌دهنده‌ای است که مدل را سرویس می‌کند. هنگامی که مدل تشخیص دهد به اطلاعات به‌روز نیاز دارد، ابزار را با یک پرس‌وجوی جست‌وجو فراخوانی می‌کند و از نتایج برای تدوین پاسخی مبتنی بر منبع و دارای استناد استفاده می‌کند.

نحوهٔ کار

  1. آیتم { "type": "web_search" } را در آرایهٔ tools قرار می‌دهید.
  2. بر اساس prompt کاربر، مدل تصمیم می‌گیرد آیا جست‌وجوی وب لازم است و یک پرس‌وجو می‌سازد.
  3. ارائه‌دهنده جست‌وجو را با موتور پیکربندی‌شده اجرا می‌کند (پیش‌فرض auto که در صورت وجود از جست‌وجوی بومیِ ارائه‌دهنده و در غیر این صورت از Exa استفاده می‌کند).
  4. نتایج جست‌وجو (URL، عنوان و قطعه‌های محتوا) به مدل برگردانده می‌شود.
  5. مدل نتایج را در پاسخ خود ترکیب می‌کند و در صورت نیاز، در یک درخواست ممکن است چند بار جست‌وجو انجام دهد.

شروع سریع

const response = await fetch('https://app.asha-ai.ir/v1/chat/completions', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer <ASHA_API_KEY>',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'openai/gpt-5.2',
    messages: [
      {
        role: 'user',
        content: 'What were the major AI announcements this week?'
      }
    ],
    tools: [
      { type: 'web_search' }
    ]
  }),
});

const data = await response.json();
console.log(data.choices[0].message.content);
import requests

response = requests.post(
  "https://app.asha-ai.ir/v1/chat/completions",
  headers={
    "Authorization": f"Bearer <ASHA_API_KEY>",
    "Content-Type": "application/json",
  },
  json={
    "model": "openai/gpt-5.2",
    "messages": [
      {
        "role": "user",
        "content": "What were the major AI announcements this week?"
      }
    ],
    "tools": [
      {"type": "web_search"}
    ]
  }
)

data = response.json()
print(data["choices"][0]["message"]["content"])
curl https://app.asha-ai.ir/v1/chat/completions 
  -H "Authorization: Bearer $ASHA_API_KEY" 
  -H "Content-Type: application/json" 
  -d '{
    "model": "openai/gpt-5.2",
    "messages": [
      {
        "role": "user",
        "content": "What were the major AI announcements this week?"
      }
    ],
    "tools": [
      {"type": "web_search"}
    ]
  }'

پیکربندی

ابزار جست‌وجوی وب برای شخصی‌سازی رفتار، پارامترهای اختیاری parameters را می‌پذیرد:

JSON web search tool
{
  "type": "web_search",
  "parameters": {
    "engine": "exa",
    "max_results": 5,
    "max_total_results": 20,
    "search_context_size": "medium",
    "allowed_domains": ["example.com"],
    "excluded_domains": ["reddit.com"]
  }
}
پارامترنوعپیش‌فرضتوضیح
enginestringautoموتور جست‌وجو: auto، native، exa، firecrawl، parallel یا perplexity
modestringپیش‌فرض موتورحالت مخصوص موتور. Exa: instant، fast، auto، deep-lite، deep یا deep-reasoning. Parallel: turbo، fast، basic یا advanced. سایر موتورها آن را نادیده می‌گیرند.
max_resultsinteger5حداکثر نتایج در هر فراخوانی جست‌وجو (1 تا 25؛ برای Perplexity 1 تا 20). برای موتورهای Exa، Firecrawl، Parallel و Perplexity اعمال می‌شود؛ با جست‌وجوی بومی نادیده گرفته می‌شود.
max_usesintegerحداکثر تعداد جست‌وجوهایی که مدل در یک درخواست می‌تواند انجام دهد. پس از رسیدن به حد، فراخوانی‌های بعدی به‌جای اجرا، پیام خطا برمی‌گردانند.
max_total_resultsintegerحداکثر کل نتایج در همهٔ فراخوانی‌های جست‌وجوی یک درخواست. برای کنترل هزینه و حجم بافتار در حلقه‌های عامل مفید است.
search_context_sizestringمیزان بافتار بازیابی‌شده: low، medium یا high. برای Exa سقف کاراکتر ثابت هر نتیجه را تعیین می‌کند (5K/15K/30K).
max_charactersintegerحداکثر دقیق کاراکتر محتوای هر نتیجه (1 تا 100,000). برای موتورهای Exa، Parallel و Perplexity. اگر هر دو تنظیم شوند، max_characters اولویت دارد.
user_locationobjectموقعیت تقریبی کاربر برای نتایج هدفمند جغرافیایی. فعلاً فقط در جست‌وجوی بومی پشتیبانی می‌شود.
allowed_domainsstring[]محدودکردن نتایج به این دامنه‌ها؛ توسط Exa، Firecrawl، Parallel، Perplexity و بیشتر ارائه‌دهنده‌های بومی پشتیبانی می‌شود.
excluded_domainsstring[]حذف نتایج از این دامنه‌ها؛ توسط Exa، Firecrawl، Parallel، Perplexity و برخی ارائه‌دهنده‌های بومی پشتیبانی می‌شود.

موقعیت کاربر

برای گرایش جغرافیایی نتایج جست‌وجو، موقعیت تقریبی کاربر را ارسال کنید:

JSON user_location
{
  "type": "web_search",
  "parameters": {
    "user_location": {
      "type": "approximate",
      "city": "San Francisco",
      "region": "California",
      "country": "US",
      "timezone": "America/Los_Angeles"
    }
  }
}

همهٔ فیلدهای داخل user_location اختیاری هستند.

ارائه‌دهنده‌های جست‌وجوی بومی

وقتی engine برابر "auto" (پیش‌فرض) یا "native" باشد، آشا برای مدل‌های پشتیبانی‌شده از جست‌وجوی داخلی ارائه‌دهنده استفاده می‌کند. ارائه‌دهنده‌های زیر جست‌وجوی وب بومی دارند:

  • OpenAI: GPT-5 و بعد، o3، o3 Pro، o4-mini
  • Anthropic: Claude 4 و بعد (همهٔ واریانت‌های Opus/Sonnet)
  • Google: Gemini 3 Flash، Gemini 3 Pro، Gemini 3.1 Flash/Lite، Gemini 3.5 Flash
  • SpaceXAI: Grok 4 و بعد (شامل جست‌وجوی وب و جست‌وجوی X)
  • Perplexity: همهٔ مدل‌های Perplexity (جست‌وجو بخش اصلی API آن‌هاست)
نکته: مدل‌های قدیمی‌تر OpenAI — از جمله GPT-4o، GPT-4o Mini و GPT-4 Turbo — از جست‌وجوی وبِ بومی پشتیبانی نمی‌کنند. اگر با این مدل‌ها engine: "native" تنظیم کنید، ارائه‌دهنده به‌صورت خودکار به جست‌وجوی Exa بازمی‌گردد. برای رفتار معادل از engine: "auto" (یا حذف فیلد) استفاده کنید.

انتخاب موتور جست‌وجو

ابزار جست‌وجوی وب از چند موتور جست‌وجو پشتیبانی می‌کند:

  • auto (پیش‌فرض): اگر ارائه‌دهنده از جست‌وجوی بومی پشتیبانی کند از آن استفاده می‌کند، در غیر این صورت به Exa بازمی‌گردد.
  • native: جست‌وجوی وب داخلی ارائه‌دهنده را ترجیح می‌دهد؛ اگر مدل از جست‌وجوی بومی پشتیبانی نکند به Exa بازمی‌گردد.
  • exa: از API جست‌وجوی Exa استفاده می‌کند که جست‌وجوی کلمه‌ای و مبتنی بر embedding را ترکیب می‌کند و به‌جای متنِ بریده‌شده، highlight (گزیده‌های مرتبط با پرس‌وجو) برمی‌گرداند.
  • firecrawl: از API جست‌وجوی Firecrawl استفاده می‌کند (BYOK: کلید خودتان).
  • parallel: از API جست‌وجوی Parallel استفاده می‌کند.
  • perplexity: از Search API پردازهای Perplexity برای نتایج رتبه‌بندی‌شده با فیلتر دامنه و کنترل اندازهٔ بافتار استفاده می‌کند.

قابلیت‌های موتورها

قابلیتExaFirecrawlParallelPerplexityNative
فیلتر دامنهبلهبلهبلهبله***بسته به ارائه‌دهنده
کنترل اندازهٔ بافتاربله*خیربله**بلهخیر
کلید APIسمت سرورBYOK (کلید شما)سمت سرورسمت سرورتوسط ارائه‌دهنده

* Exa: محدودیت به‌ازای هر نتیجه اعمال می‌شود — ** Parallel: محدودیت به‌صورت مجموع همهٔ نتایج — *** Perplexity: allowed_domains و excluded_domains متقابلاً انحصاری هستند.

Exa

آشا برای هر نتیجه، به‌جای گزینهٔ محتوای text، highlightهای Exa را درخواست می‌کند. Highlightها گزیده‌های استخراجی مستقیم از صفحه هستند که Exa آن‌ها را به‌عنوان مرتبط‌ترین بخش به پرس‌وجو انتخاب می‌کند و معمولاً به‌ازای هر توکن، بافتار باکیفیت‌تری نسبت به متن بریده‌شده برای ابزارهای عامل ارائه می‌دهند.

حالت mode در Exa تأخیر و عمق جست‌وجو را کنترل می‌کند. پیش‌فرض auto باقی می‌ماند:

حالتتأخیر تقریبی
instant~۲۵۰ میلی‌ثانیه
fast~۴۵۰ میلی‌ثانیه
auto (پیش‌فرض)~۱ ثانیه
deep-lite~۴ ثانیه
deep~۴ تا ۱۵ ثانیه
deep-reasoning~۱۲ تا ۴۰ ثانیه

به‌طور پیش‌فرض Exa اندازهٔ highlight را به‌صورت تطبیقی در هر پرس‌وجو و سند انتخاب می‌کند؛ معمولاً حدود ۲,۰۰۰ تا ۴,۰۰۰ کاراکتر به‌ازای هر نتیجه. بودجهٔ کاراکتری هر نتیجه را به دو روش کنترل کنید:

  • پیش‌تنظیمِ تقریبی با search_context_size: low: ۵,۰۰۰، medium: ۱۵,۰۰۰، high: ۳۰,۰۰۰ کاراکتر در هر نتیجه.
  • مقدار دقیق با max_characters: هر عدد صحیح (۱ تا ۱۰۰,۰۰۰) که بودجهٔ دقیق محتوای هر نتیجه را تعیین می‌کند. اگر هر دو تنظیم شوند، max_characters اولویت دارد.
JSON Exa max_characters
{
  "type": "web_search",
  "parameters": {
    "engine": "exa",
    "max_characters": 2000
  }
}

وقتی هیچ‌کدام از max_characters یا search_context_size تنظیم نشده باشد، آشا اجازه می‌دهد Exa اندازهٔ highlight را تطبیقی انتخاب کند و Parallel از پیش‌فرض ۱,۵۰۰ کاراکتری خود استفاده می‌کند. گزیده‌های انتخاب‌شده در هر نتیجه به مدل برگردانده می‌شوند و از طریق حاشیه‌نویسی url_citation در دسترس API قرار می‌گیرند. در یک نتیجه، گزیده‌های بخش‌های مختلف صفحه با نشانگر [...] جدا می‌شوند.

Firecrawl (BYOK)

Firecrawl از کلید API خودتان استفاده می‌کند. برای راه‌اندازی:

  1. به تنظیمات پلاگین آشا بروید و Firecrawl را به‌عنوان موتور جست‌وجوی وب انتخاب کنید.
  2. شرایط استفادهٔ Firecrawl را بپذیرید تا حساب Firecrawl متصل به ایمیل شما ساخته شود.
  3. حساب شما با ۱۰,۰۰۰ اعتبار رایگان شروع می‌کند (اعتبارها پس از ۳ ماه منقضی می‌شوند).

جست‌وجوهای Firecrawl مستقیماً از اعتبارهای Firecrawl شما استفاده می‌کنند و هزینهٔ جداگانه‌ای از آشا دریافت نمی‌شود. Firecrawl از فیلتر دامنه پشتیبانی می‌کند، اما allowed_domains و excluded_domains متقابلاً انحصاری هستند.

Parallel

Parallel از فیلتر دامنه و کنترل اندازهٔ بافتار (search_context_size) پشتیبانی می‌کند. برای انتخاب حالت از mode استفاده کنید؛ آشا به‌طور پیش‌فرض از basic استفاده می‌کند.

حالتتأخیرپشتیبانی زبان
turbo~۲۰۰ میلی‌ثانیهانگلیسی و ژاپنی
fast~۵۵۰ میلی‌ثانیهمستند نشده
basic (پیش‌فرض)~۱ ثانیهپشتیبانی گستردهٔ زبان
advanced~۳ ثانیهپشتیبانی گستردهٔ زبان

هر حالت شامل حداکثر ۱۰ نتیجه است.

Perplexity

Perplexity نتایج وب رتبه‌بندی‌شده (عنوان، URL و قطعه) را بدون سنتز LLM برمی‌گرداند. از فیلتر دامنه (allowed_domains / excluded_domains که متقابلاً انحصاری هستند)، search_context_size و max_characters پشتیبانی می‌کند.

فیلتر دامنه

با allowed_domains و excluded_domains دامنه‌های حاضر در نتایج را محدود کنید:

JSON domain filters
{
  "type": "web_search",
  "parameters": {
    "allowed_domains": ["arxiv.org", "nature.com"],
    "excluded_domains": ["reddit.com"]
  }
}
موتورallowedexcludedیادداشت
Exaبلهبلههر دو می‌توانند هم‌زمان استفاده شوند
Parallelبلهبلهمتقابلاً انحصاری
Firecrawlبلهبلهمتقابلاً انحصاری
Perplexityبلهبلهمتقابلاً انحصاری (اگر هر دو باشند، allowed_domains برنده است)
Native (Anthropic)بلهبلهمتقابلاً انحصاری
Native (OpenAI)بلهخیرexcluded_domains نادیده گرفته می‌شود (بدون خطا)
Native (Google)خیرخیرپشتیبانی نمی‌شود. با engine: "auto" در صورت تنظیم فیلتر به Exa برمی‌گردد؛ با engine: "native" خطای 400 برمی‌گردد
Native (SpaceXAI)بلهبلهمتقابلاً انحصاری

کنترل نتایج کل

وقتی مدل در یک درخواست چند بار جست‌وجو می‌کند، با max_total_results تعداد تجمعی نتایج را محدود کنید:

JSON total results
{
  "type": "web_search",
  "parameters": {
    "max_results": 5,
    "max_total_results": 15
  }
}

پس از رسیدن به حد، فراخوانی‌های جست‌وجوی بعدی به‌جای اجرای جست‌وجو، پیامی صادر می‌کنند که به مدل می‌گوید به سقف رسیده است. این روش برای کنترل هزینه و استفاده از پنجرهٔ بافتار در حلقه‌های عامل مفید است.

محدودکردن تعداد جست‌وجوها

برای سقف سخت تعداد جست‌وجوهایی که مدل می‌تواند در یک درخواست انجام دهد، max_uses را در parameters ابزار تنظیم کنید:

JSON max_uses
{
  "type": "web_search",
  "parameters": {
    "max_uses": 3
  }
}

هر جست‌وجو همچنین یک گام از بودجهٔ کلی ابزارهای سرورِ درخواست را مصرف می‌کند که بین همهٔ ابزارهای سرور مشترک است. با فیلد سطح-بالای max_tool_calls — خواهرِ messages و tools، نه یک پارامتر ابزار — آن بودجه را محدود کنید:

JSON max_tool_calls
{
  "model": "openai/gpt-5.2",
  "messages": [...],
  "tools": [{ "type": "web_search" }],
  "max_tool_calls": 5
}

وقتی این فیلد حذف شود، بودجه‌ای به‌طور پیش‌فرض روی ۳۰ گام قرار می‌گیرد که حداکثر هم هست. برای کنترل دقیق‌تر (سقف هزینه، شرایط توقف سفارشی) از stop_server_tools_when استفاده کنید که کاملاً جایگزین max_tool_calls می‌شود.

همکاری با Responses API

جست‌وجوی وب با Responses API نیز کار می‌کند:

const response = await fetch('https://app.asha-ai.ir/v1/responses', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer <ASHA_API_KEY>',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'openai/gpt-5.2',
    input: 'What is the current price of Bitcoin?',
    tools: [
      { type: 'web_search', parameters: { max_results: 3 } }
    ]
  }),
});

const data = await response.json();
console.log(data);
import requests

response = requests.post(
  "https://app.asha-ai.ir/v1/responses",
  headers={
    "Authorization": f"Bearer <ASHA_API_KEY>",
    "Content-Type": "application/json",
  },
  json={
    "model": "openai/gpt-5.2",
    "input": "What is the current price of Bitcoin?",
    "tools": [
      {"type": "web_search", "parameters": {"max_results": 3}}
    ]
  }
)

data = response.json()
print(data)

ردیابی مصرف

مصرف جست‌وجوی وب در شیٔ usage پاسخ گزارش می‌شود:

JSON usage
{
  "usage": {
    "input_tokens": 105,
    "output_tokens": 250,
    "server_tool_use": {
      "web_search_requests": 2
    }
  }
}

فیلد web_search_requests تعداد کل پرس‌وجوهای جست‌وجویی را که مدل در طول درخواست انجام داده است، شمارش می‌کند. این مقدار برای محاسبهٔ هزینهٔ جست‌وجو استفاده می‌شود.

قیمت‌گذاری

موتورقیمت‌گذاری
ExaInstant/Fast/Auto: $۰٫۰۰۷ در هر درخواست؛ Deep Lite/Deep: $۰٫۰۱۲؛ Deep Reasoning: $۰٫۰۱۵. شامل حداکثر ۱۰ نتیجه، سپس $۰٫۰۰۱ به‌ازای هر نتیجهٔ اضافه
ParallelTurbo یا Fast: $۰٫۰۰۱ در هر درخواست؛ Basic یا Advanced: $۰٫۰۰۵. شامل حداکثر ۱۰ نتیجه، سپس $۰٫۰۰۱ به‌ازای هر نتیجهٔ اضافه
Perplexity$۰٫۰۰۵ در هر درخواست با اعتبارهای آشا
Firecrawlمستقیماً از اعتبارهای Firecrawl شما کسر می‌شود بدون هیچ هزینه‌ای از سمت آشا
Nativeمستقیماً از ارائه‌دهنده گذرانده می‌شود (OpenAI، Anthropic، Google، Perplexity، SpaceXAI)

همهٔ قیمت‌ها علاوه بر هزینهٔ استاندارد توکن‌های LLM برای پردازش محتوای نتایج جست‌وجو هستند.

مهاجرت از پلاگین جست‌وجوی وب

هشدار: پلاگین جست‌وجوی وب (plugins: [{ id: "web" }]) و واریانت :online منسوخ (deprecated) شده‌اند. به‌جای آن از ابزار web_search استفاده کنید.

تفاوت‌های کلیدی:

پلاگین جست‌وجوی وب (منسوخ)ابزار جست‌وجوی وب
نحوهٔ فعال‌سازیplugins: [{ id: "web" }]tools: [{ type: "web_search" }]
چه کسی تصمیم به جست‌وجو می‌گیردهمیشه یک‌بار جست‌وجو می‌کندمدل تصمیم می‌گیرد چه زمانی جست‌وجو کند
تکرار فراخوانییک‌بار در هر درخواست۰ تا N بار در هر درخواست
گزینه‌های موتورNative، Exa، Firecrawl، Parallel، PerplexityAuto، Native، Exa، Firecrawl، Parallel، Perplexity
فیلتر دامنهبلهبله
کنترل اندازهٔ بافتاراز طریق web_search_optionsاز طریق پارامتر search_context_size
سقف نتایج کلخیربله (max_total_results)
قیمت‌گذاریبسته به موتوربسته به موتور (نرخ یکسان)

مثال مهاجرت

JSON migration
// قبل (منسوخ)
{
  "model": "openai/gpt-5.2",
  "messages": [...],
  "plugins": [{ "id": "web", "max_results": 3 }]
}

// بعد
{
  "model": "openai/gpt-5.2",
  "messages": [...],
  "tools": [
    { "type": "web_search", "parameters": { "max_results": 3 } }
  ]
}
JSON migration — engine and domains
// قبل (منسوخ): موتور و فیلتر دامنه
{
  "model": "openai/gpt-5.2",
  "messages": [...],
  "plugins": [{
    "id": "web",
    "engine": "exa",
    "max_results": 5,
    "include_domains": ["arxiv.org"]
  }]
}

// بعد
{
  "model": "openai/gpt-5.2",
  "messages": [...],
  "tools": [{
    "type": "web_search",
    "parameters": {
      "engine": "exa",
      "max_results": 5,
      "allowed_domains": ["arxiv.org"]
    }
  }]
}
JSON migration — :online variant
// قبل (منسوخ): واریانت :online
{
  "model": "openai/gpt-5.2:online"
}

// بعد
{
  "model": "openai/gpt-5.2",
  "tools": [{ "type": "web_search" }]
}

فیلترهای جست‌وجوی X (فقط SpaceXAI)

هنگام استفاده از مدل‌های SpaceXAI (مثلاً x-ai/grok-4.5) می‌توانید x_search_filter را به‌عنوان پارامتر سطح-بالای درخواست برای فیلترکردن نتایج جست‌وجوی X/Twitter ارسال کنید:

JSON x_search_filter
{
  "model": "x-ai/grok-4.5",
  "input": "What are people saying about AI?",
  "plugins": [{ "id": "web" }],
  "x_search_filter": {
    "allowed_x_handles": ["AshaAI"],
    "from_date": "2025-01-01",
    "enable_image_understanding": true
  }
}
پارامترنوعتوضیح
allowed_x_handlesstring[]فقط پست‌های این حساب‌ها (حداکثر ۲۰)
excluded_x_handlesstring[]حذف پست‌های این حساب‌ها (حداکثر ۲۰)
from_datestringتاریخ شروع (ISO 8601، مثلاً "2025-01-01")
to_datestringتاریخ پایان (ISO 8601، مثلاً "2025-12-31")
enable_image_understandingbooleanتحلیل تصاویر پست‌ها
enable_video_understandingbooleanتحلیل ویدیوهای پست‌ها
هشدار: allowed_x_handles و excluded_x_handles متقابلاً انحصاری هستند.

پاسخ همراه با حاشیه‌نویسی

پاسخ‌های جست‌وجوی وب شامل حاشیه‌نویسی استناد هستند:

JSON response with annotations
{
  "id": "resp_1234567890",
  "object": "response",
  "created_at": 1234567890,
  "model": "openai/o4-mini",
  "output": [
    {
      "type": "message",
      "id": "msg_abc123",
      "status": "completed",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "Asha is a unified API for accessing multiple Large Language Model providers through a single interface.",
          "annotations": [
            {
              "type": "url_citation",
              "url": "https://asha-ai.ir/docs",
              "start_index": 0,
              "end_index": 85
            },
            {
              "type": "url_citation",
              "url": "https://asha-ai.ir/models",
              "start_index": 120,
              "end_index": 180
            }
          ]
        }
      ]
    }
  ],
  "usage": {
    "input_tokens": 15,
    "output_tokens": 95,
    "total_tokens": 110
  },
  "status": "completed"
}

انواع حاشیه‌نویسی

پاسخ‌های جست‌وجوی وب می‌توانند انواع حاشیه‌نویسی متفاوت داشته باشند:

استناد URL

JSON url_citation
{
  "type": "url_citation",
  "url": "https://example.com/article",
  "start_index": 0,
  "end_index": 50,
  "content": "Excerpt from the web page..."
}

پردازش حاشیه‌نویسی

اطلاعات استناد را استخراج و پردازش کنید:

function extractCitations(response: any) {
  const messageOutput = response.output?.find((o: any) => o.type === 'message');
  const textContent = messageOutput?.content?.find((c: any) => c.type === 'output_text');
  const annotations = textContent?.annotations || [];

  return annotations
    .filter((annotation: any) => annotation.type === 'url_citation')
    .map((annotation: any) => ({
      url: annotation.url,
      text: textContent.text.slice(annotation.start_index, annotation.end_index),
      startIndex: annotation.start_index,
      endIndex: annotation.end_index,
    }));
}

const result = await response.json();
const citations = extractCitations(result);
console.log('Found citations:', citations);
def extract_citations(response_data):
    output = response_data.get('output', [])
    message_output = next((o for o in output if o.get('type') == 'message'), {})
    content = message_output.get('content', [])
    text_content = next((c for c in content if c.get('type') == 'output_text'), {})
    annotations = text_content.get('annotations', [])
    text = text_content.get('text', '')

    citations = []
    for annotation in annotations:
        if annotation.get('type') == 'url_citation':
            citations.append({
                'url': annotation.get('url'),
                'text': text[annotation.get('start_index', 0):annotation.get('end_index', 0)],
                'start_index': annotation.get('start_index'),
                'end_index': annotation.get('end_index'),
            })

    return citations

result = response.json()
citations = extract_citations(result)
print(f'Found citations: {citations}')

جست‌وجوی وب در گفتگو

جست‌وجوی وب را در گفتگوهای چندنوبته بگنجانید:

const response = await fetch('https://app.asha-ai.ir/v1/responses', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <ASHA_API_KEY>',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'openai/o4-mini',
    input: [
      {
        type: 'message',
        role: 'user',
        content: [
          {
            type: 'input_text',
            text: 'What is the latest version of React?',
          },
        ],
      },
      {
        type: 'message',
        id: 'msg_1',
        status: 'in_progress',
        role: 'assistant',
        content: [
          {
            type: 'output_text',
            text: 'Let me search for the latest React version.',
            annotations: [],
          },
        ],
      },
      {
        type: 'message',
        role: 'user',
        content: [
          {
            type: 'input_text',
            text: 'Yes, please find the most recent information',
          },
        ],
      },
    ],
    tools: [ { type: 'web_search', parameters: { max_results: 2 } } ],
    max_output_tokens: 9000,
  }),
});

const result = await response.json();
console.log(result);
import requests

response = requests.post(
    'https://app.asha-ai.ir/v1/responses',
    headers={
        'Authorization': 'Bearer <ASHA_API_KEY>',
        'Content-Type': 'application/json',
    },
    json={
        'model': 'openai/o4-mini',
        'input': [
            {
                'type': 'message',
                'role': 'user',
                'content': [
                    {
                        'type': 'input_text',
                        'text': 'What is the latest version of React?',
                    },
                ],
            },
            {
                'type': 'message',
                'id': 'msg_1',
                'status': 'in_progress',
                'role': 'assistant',
                'content': [
                    {
                        'type': 'output_text',
                        'text': 'Let me search for the latest React version.',
                        'annotations': [],
                    },
                ],
            },
            {
                'type': 'message',
                'role': 'user',
                'content': [
                    {
                        'type': 'input_text',
                        'text': 'Yes, please find the most recent information',
                    },
                ],
            },
        ],
        'tools': [{'type': 'web_search', 'parameters': {'max_results': 2}}],
        'max_output_tokens': 9000,
    }
)

result = response.json()
print(result)

پیشرفت جست‌وجوی وب را با استریمینگ نظارت کنید:

const response = await fetch('https://app.asha-ai.ir/v1/responses', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <ASHA_API_KEY>',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'openai/o4-mini',
    input: [
      {
        type: 'message',
        role: 'user',
        content: [
          {
            type: 'input_text',
            text: 'What is the latest news about AI?',
          },
        ],
      },
    ],
    tools: [ { type: 'web_search', parameters: { max_results: 2 } } ],
    stream: true,
    max_output_tokens: 9000,
  }),
});

const reader = response.body?.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  const chunk = decoder.decode(value);
  const lines = chunk.split('n');

  for (const line of lines) {
    if (line.startsWith('data: ')) {
      const data = line.slice(6);
      if (data === '[DONE]') return;

      try {
        const parsed = JSON.parse(data);
        if (parsed.type === 'response.output_item.added' &&
            parsed.item?.type === 'message') {
          console.log('Message added');
        }
        if (parsed.type === 'response.completed') {
          const annotations = parsed.response?.output
            ?.find(o => o.type === 'message')
            ?.content?.find(c => c.type === 'output_text')
            ?.annotations || [];
          console.log('Citations:', annotations.length);
        }
      } catch (e) {
        // Skip invalid JSON
      }
    }
  }
}
import requests
import json

response = requests.post(
    'https://app.asha-ai.ir/v1/responses',
    headers={
        'Authorization': 'Bearer <ASHA_API_KEY>',
        'Content-Type': 'application/json',
    },
    json={
        'model': 'openai/o4-mini',
        'input': [
            {
                'type': 'message',
                'role': 'user',
                'content': [
                    {
                        'type': 'input_text',
                        'text': 'What is the latest news about AI?',
                    },
                ],
            },
        ],
        'tools': [{'type': 'web_search', 'parameters': {'max_results': 2}}],
        'stream': True,
        'max_output_tokens': 9000,
    },
    stream=True
)

for line in response.iter_lines():
    if line:
        line_str = line.decode('utf-8')
        if line_str.startswith('data: '):
            data = line_str[6:]
            if data == '[DONE]':
                break
            try:
                parsed = json.loads(data)
                if (parsed.get('type') == 'response.output_item.added' and
                    parsed.get('item', {}).get('type') == 'message'):
                    print('Message added')
                if parsed.get('type') == 'response.completed':
                    output = parsed.get('response', {}).get('output', [])
                    message = next((o for o in output if o.get('type') == 'message'), {})
                    content = message.get('content', [])
                    text_content = next((c for c in content if c.get('type') == 'output_text'), {})
                    annotations = text_content.get('annotations', [])
                    print(f'Citations: {len(annotations)}')
            except json.JSONDecodeError:
                continue

بهترین روش‌ها

  1. محدودکردن نتایج: برای تعادل بین کیفیت و سرعت، از max_results مناسب استفاده کنید.
  2. مدیریت حاشیه‌نویسی: حاشیه‌نویسی‌های استناد را برای ارجاع‌دهی صحیح پردازش کنید.
  3. دقت پرس‌وجو: برای نتایج بهتر، پرس‌وجوهای جست‌وجو را مشخص کنید.
  4. مدیریت خطا: مواردی را مدیریت کنید که جست‌وجوی وب ممکن است ناموفق باشد.
  5. محدودیت نرخ: به محدودیت‌های نرخ جست‌وجو توجه داشته باشید.

قدم‌های بعدی