Tavily Web Search
Tavily is a commercial web search API that is designed for LLMs and AI agents. Like a search engine, it takes a query and returns ranked web pages, but each result is returned as structured json (a title, a url, a snippet of the page’s content, and its publication date) rather than as a page of links for a person to read. This makes it a good fit for tool calling, where the LLM reads the results and cites them.
Smarter uses Tavily as one of the two web search APIs of the WebsearchPlugin. The other is the Brave Search API. Each WebsearchPlugin chooses its search API in its manifest.
Note
The WebsearchPlugin is experimental. See WebsearchPlugin.
How Smarter Uses Tavily
The WebsearchPlugin. A WebsearchPlugin gives an LLM one tool with two operations: search the
web, and read a web page. Only search uses Tavily. When the LLM sets a query, the plugin
sends it to the Tavily Search API, https://api.tavily.com/search, and returns the results to
the LLM in the same form as Brave’s, so that the LLM sees the same fields whichever API is
configured. Reading a web page, the fetch operation, is done by Smarter itself, not by Tavily.
The plugin’s manifest selects Tavily, and names the Smarter Secret that contains the Tavily API key:
spec:
websearchData:
search:
provider: tavily
apiKey: tavily_api_key # the name of a Smarter Secret, never the key itself
maxResults: 5
safeSearch: moderate
blockedDomains:
- pinterest.com
Each search request:
uses Tavily’s
basicsearch depth andgeneraltopic, and asks for no generated answer and no raw page content, only ranked results.passes the plugin’s
allowedDomainsandblockedDomainsto Tavily, as itsinclude_domainsandexclude_domains. Smarter also filters the results that Tavily returns by the same domain policy, so that the policy is enforced even if Tavily returns a result that it should not.passes
safeSearchas Tavily’ssafe_search, which is either on or off:moderateandstrictboth turn it on.passes
freshness(day, week, month or year) andlanguage. The plugin’scountryis not passed, because Tavily localizes by country name rather than by country code.
Search results are cached, per plugin, for the manifest’s cacheTtl seconds, keyed on the
query and its parameters. A repeated question does not call Tavily again until the cache
expires.
The implementation is
smarter.apps.llmtool.plugin.websearch_providers.TavilySearchProvider.
The sample WebsearchPlugin. smarter_project_websearch uses Tavily to find current
information about The Smarter Project on the web, from reputable sources. It is an example to
copy, and no example LLMClient uses it. Its manifest is in the source tree:
smarter/smarter/apps/llmtool/data/sample-plugins/websearch-smarter-project.yaml.
manage.py add_example_tools applies the sample plugins. Applying smarter_project_websearch
fails if its Secret tavily_api_key does not exist. The other plugins are not affected: each
manifest is applied in its own transaction, so a manifest that fails is rolled back entirely, and
is reported, and the command goes on to the next one.
Setup
Get an API key. Create an account at tavily.com, and copy an API key from its dashboard. Tavily keys begin with
tvly-.Set the environment variable. Set
TAVILY_API_KEY. As with every Smarter setting, the name may also be given theSMARTER_prefix,SMARTER_TAVILY_API_KEY: the two are the same setting. For local development, add it to.env, which.env.exampledocuments:SMARTER_TAVILY_API_KEY=tvly-...
Create the Secret.
manage.py initialize_providers, whichmanage.py initialize_platformruns, stores the key as the Smarter Secrettavily_api_key, owned by the smarter admin. It updates the Secret if it already exists, so running it again rotates the key.python manage.py initialize_providers
If
TAVILY_API_KEYis not set, or is still a placeholder, such asSET-ME-PLEASEorvalues.yaml’sSET-ME-IN-helm/charts/smarter/values.yaml, the command does not create the Secret, and lists the key in the[API KEYS NOT SET]console error that it logs at the end, with the other missing API keys. It never stores a placeholder as the key.Apply the sample plugins.
python manage.py add_example_tools
Other WebsearchPlugins can use the same Secret, by setting apiKey: tavily_api_key, or a
Secret of their own: apiKey is the name of any Secret that the plugin’s owner can read. See
the sample manifests in smarter/smarter/apps/llmtool/data/sample-plugins/websearch-*.yaml.
The environment variable is listed in Configuration.
CI/CD Considerations
GitHub repository secret. Both workflows read the key from the GitHub Actions repository
secret TAVILY_API_KEY. Add it in the repository’s Settings > Secrets and variables >
Actions. It is never committed: neither values.yaml nor any manifest contains the key.
Tests (.github/workflows/test.yml). The workflow passes TAVILY_API_KEY to the test
containers’ .env, with the other API keys. The unit tests do not call Tavily: they serve the
Tavily API from a fake web host, and create a test Secret, so they pass without the GitHub
secret.
Deployments (.github/workflows/deploy.yml). The workflow passes the GitHub secret to the
tavily-api-key input of .github/actions/deploy, which sets the Helm value
env.SMARTER_TAVILY_API_KEY. The chart’s init Job, templates/job-init.yaml, is a Helm
post-install and post-upgrade hook, so every deployment runs initialize_platform,
which creates or updates the Secret, and applies the sample plugins. Consequently:
Adding the key to an existing installation takes effect on the next deployment.
Rotating the key: update the GitHub secret, and deploy. The Secret is updated in place.
A deployment without the key completes, but the init Job logs that the
tavily_api_keySecret was not created, and thatsmarter_project_websearchcould not be applied. When the GitHub secret is not set, the deploy action passes no value, and Helm falls back to thevalues.yamlplaceholder, which the init command recognizes and ignores.Every environment that uses a Tavily WebsearchPlugin needs the key: local, alpha, beta and production. Each may use its own Tavily key, for separate usage and billing.
Cost and Limits
Tavily bills by API credits, and offers a free plan with a monthly allowance of credits; see the pricing on tavily.com. Smarter keeps usage low:
every search uses the
basicsearch depth, Tavily’s least expensive.results are cached for the plugin’s
cacheTtl.smarter_project_websearchcaches them for a day, because information about the project changes slowly.only search calls Tavily. Reading a web page does not.
Monitor usage in the Tavily dashboard. When Tavily refuses a search, for example because the key
is invalid or out of credits, the WebsearchPlugin returns an error to the LLM instead of search
results, and sends the websearch_failed signal.
Troubleshooting
the web search api key Secret tavily_api_key does not exist, or is not accessibleThe plugin was applied before the Secret existed, or by a user who cannot read it. Set
TAVILY_API_KEY, runmanage.py initialize_providers, and apply the plugin again.Plugin smarter_project_websearch not found for account ...An LLMClient that names the plugin was applied, but the plugin was not, almost always because of the missing Secret above. Fix the Secret, run
manage.py add_example_tools, and apply the LLMClient again.TAVILY_API_KEY is not set, andSMARTER_TAVILY_API_KEYin the[API KEYS NOT SET]console errorThe init command found no key, or only a placeholder. Set the environment variable, or, in a deployment, the GitHub secret
TAVILY_API_KEY.