From 6e5e5fe6e9a74fdf5de2d53bcb1c1b943fe8a47d Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:15:09 +0200 Subject: [PATCH] feat: add a Tavily search depth setting (#31308) Tavily web search always ran at Tavily's default depth (basic), because the search request never sent `search_depth`. The only Tavily depth control in Admin > Settings > Web Search, "Tavily Extract Depth", applies to the Extract API used by the web loader, never to search. This adds `TAVILY_SEARCH_DEPTH` (env var and persisted setting, default `basic`) and a "Tavily Search Depth" select (ultra-fast, fast, basic, advanced) under the Tavily search engine settings. The value is sent as `search_depth` on every Tavily search request, so admins can set search and extract depth independently, for example fast search with advanced extraction. The default matches Tavily's own default, so existing setups keep the same behaviour until the setting is changed. Fixes #29891 --- backend/open_webui/config.py | 3 +++ backend/open_webui/retrieval/web/tavily.py | 4 +++- backend/open_webui/routers/retrieval.py | 6 ++++++ src/lib/components/admin/Settings/WebSearch.svelte | 14 ++++++++++++++ src/lib/i18n/locales/en-US/translation.json | 4 ++++ 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index 897618247a..cc38281c4b 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1302,6 +1302,8 @@ TAVILY_API_KEY = os.getenv('TAVILY_API_KEY', '') TAVILY_EXTRACT_DEPTH = os.getenv('TAVILY_EXTRACT_DEPTH', 'basic') +TAVILY_SEARCH_DEPTH = os.getenv('TAVILY_SEARCH_DEPTH', 'basic') + STAAN_API_KEY = os.getenv('STAAN_API_KEY', '') STAAN_MARKET = os.getenv('STAAN_MARKET', 'en-us') @@ -2998,6 +3000,7 @@ DEFAULT_CONFIG = { 'web.search.sougou_api_sk': SOUGOU_API_SK, 'web.search.tavily_api_key': TAVILY_API_KEY, 'web.search.tavily_extract_depth': TAVILY_EXTRACT_DEPTH, + 'web.search.tavily_search_depth': TAVILY_SEARCH_DEPTH, 'web.search.staan_api_key': STAAN_API_KEY, 'web.search.staan_market': STAAN_MARKET, 'web.search.staan_max_snippets': STAAN_MAX_SNIPPETS, diff --git a/backend/open_webui/retrieval/web/tavily.py b/backend/open_webui/retrieval/web/tavily.py index 7bf15a1e62..a0403787b5 100644 --- a/backend/open_webui/retrieval/web/tavily.py +++ b/backend/open_webui/retrieval/web/tavily.py @@ -14,6 +14,7 @@ def search_tavily( query: str, count: int, filter_list: list[str] | None = None, + search_depth: str = 'basic', # **kwargs, ) -> list[SearchResult]: """Search using Tavily's Search API and return the results as a list of SearchResult objects. @@ -22,6 +23,7 @@ def search_tavily( api_key (str): A Tavily Search API key query (str): The query to search for count (int): The maximum number of results to return + search_depth (str): Tavily search depth Returns: A list of SearchResult objects. @@ -31,7 +33,7 @@ def search_tavily( 'Content-Type': 'application/json', 'Authorization': f'Bearer {api_key}', } - data = {'query': query, 'max_results': count} + data = {'query': query, 'max_results': count, 'search_depth': search_depth} response = requests.post(url, headers=headers, json=data) response.raise_for_status() diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index e5a959f663..401eeb079a 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -387,6 +387,7 @@ RETRIEVAL_CONFIG_KEYS = { 'STAAN_MAX_SNIPPETS': 'web.search.staan_max_snippets', 'TAVILY_API_KEY': 'web.search.tavily_api_key', 'TAVILY_EXTRACT_DEPTH': 'web.search.tavily_extract_depth', + 'TAVILY_SEARCH_DEPTH': 'web.search.tavily_search_depth', 'TEXT_SPLITTER': 'rag.text_splitter', 'TIKA_SERVER_URL': 'rag.tika_server_url', 'TIKA_SERVER_VERSION': 'rag.tika_server_version', @@ -773,6 +774,7 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)): 'FIRECRAWL_API_BASE_URL': config.FIRECRAWL_API_BASE_URL, 'FIRECRAWL_TIMEOUT': config.FIRECRAWL_TIMEOUT, 'TAVILY_EXTRACT_DEPTH': config.TAVILY_EXTRACT_DEPTH, + 'TAVILY_SEARCH_DEPTH': config.TAVILY_SEARCH_DEPTH, 'EXTERNAL_WEB_SEARCH_URL': config.EXTERNAL_WEB_SEARCH_URL, 'EXTERNAL_WEB_SEARCH_API_KEY': config.EXTERNAL_WEB_SEARCH_API_KEY, 'EXTERNAL_WEB_LOADER_URL': config.EXTERNAL_WEB_LOADER_URL, @@ -856,6 +858,7 @@ class WebConfig(BaseModel): FIRECRAWL_API_BASE_URL: str | None = None FIRECRAWL_TIMEOUT: str | None = None TAVILY_EXTRACT_DEPTH: str | None = None + TAVILY_SEARCH_DEPTH: str | None = None EXTERNAL_WEB_SEARCH_URL: str | None = None EXTERNAL_WEB_SEARCH_API_KEY: str | None = None EXTERNAL_WEB_LOADER_URL: str | None = None @@ -1386,6 +1389,7 @@ async def update_rag_config(request: Request, form_data: ConfigForm, user=Depend config.EXTERNAL_WEB_LOADER_URL = form_data.web.EXTERNAL_WEB_LOADER_URL config.EXTERNAL_WEB_LOADER_API_KEY = form_data.web.EXTERNAL_WEB_LOADER_API_KEY config.TAVILY_EXTRACT_DEPTH = form_data.web.TAVILY_EXTRACT_DEPTH + config.TAVILY_SEARCH_DEPTH = form_data.web.TAVILY_SEARCH_DEPTH config.YOUTUBE_LOADER_LANGUAGE = form_data.web.YOUTUBE_LOADER_LANGUAGE config.YOUTUBE_LOADER_PROXY_URL = form_data.web.YOUTUBE_LOADER_PROXY_URL request.app.state.YOUTUBE_LOADER_TRANSLATION = form_data.web.YOUTUBE_LOADER_TRANSLATION @@ -1535,6 +1539,7 @@ async def update_rag_config(request: Request, form_data: ConfigForm, user=Depend 'FIRECRAWL_API_BASE_URL': config.FIRECRAWL_API_BASE_URL, 'FIRECRAWL_TIMEOUT': config.FIRECRAWL_TIMEOUT, 'TAVILY_EXTRACT_DEPTH': config.TAVILY_EXTRACT_DEPTH, + 'TAVILY_SEARCH_DEPTH': config.TAVILY_SEARCH_DEPTH, 'EXTERNAL_WEB_SEARCH_URL': config.EXTERNAL_WEB_SEARCH_URL, 'EXTERNAL_WEB_SEARCH_API_KEY': config.EXTERNAL_WEB_SEARCH_API_KEY, 'EXTERNAL_WEB_LOADER_URL': config.EXTERNAL_WEB_LOADER_URL, @@ -2721,6 +2726,7 @@ async def search_web(request: Request, engine: str, query: str, user=None) -> li query, config.WEB_SEARCH_RESULT_COUNT, config.WEB_SEARCH_DOMAIN_FILTER_LIST, + search_depth=config.TAVILY_SEARCH_DEPTH, ) else: raise Exception('No TAVILY_API_KEY found in environment variables') diff --git a/src/lib/components/admin/Settings/WebSearch.svelte b/src/lib/components/admin/Settings/WebSearch.svelte index ce9690a83d..674e02ca47 100644 --- a/src/lib/components/admin/Settings/WebSearch.svelte +++ b/src/lib/components/admin/Settings/WebSearch.svelte @@ -579,6 +579,20 @@ /> + +
+
+
+ {$i18n.t('settings.admin.web.tavilySearchDepth.label')} +
+ + + + + + +
+
{:else if webConfig.WEB_SEARCH_ENGINE === 'staan'}
diff --git a/src/lib/i18n/locales/en-US/translation.json b/src/lib/i18n/locales/en-US/translation.json index c5aa62d0df..ee7dba23b5 100644 --- a/src/lib/i18n/locales/en-US/translation.json +++ b/src/lib/i18n/locales/en-US/translation.json @@ -285,6 +285,7 @@ "Base Model (From)": "", "Base Model is required.": "", "Base Models": "", + "Basic": "", "Basic text only": "", "Basics": "", "Bearer": "", @@ -1000,6 +1001,7 @@ "Failed to update webhook": "", "Failed to upload background image.": "", "Failed to upload file.": "", + "Fast": "", "Features Permissions": "", "February": "", "Feedback": "", @@ -2706,6 +2708,7 @@ "settings.admin.web.sougouSearchApiSk.label": "Sougou Search API SK", "settings.admin.web.tavilyApiKey.label": "Tavily API Key", "settings.admin.web.tavilyExtractDepth.label": "Tavily Extract Depth", + "settings.admin.web.tavilySearchDepth.label": "Tavily Search Depth", "settings.admin.web.timeout.description": "Maximum time to wait while loading web content.", "settings.admin.web.timeout.label": "Timeout", "settings.admin.web.title": "Web Search", @@ -3319,6 +3322,7 @@ "Type Hugging Face Resolve (Download) URL": "", "Type your answer": "", "Uh-oh! There was an issue with the response.": "", + "Ultra-fast": "", "Unarchive": "", "Unarchive Chat": "", "Unassigned": "",