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.plugin.plugin.websearch_providers.TavilySearchProvider.
The smarter LLMClient. The platform’s built-in smarter LLMClient, the Smarter sales
agent, uses the built-in WebsearchPlugin smarter_project_websearch to find current
information about The Smarter Project on the web, from reputable sources. It complements the
documentation and source code that its smarter_project_github MCPClients read. Its manifests are in
the source tree:
smarter/smarter/apps/llmclient/data/plugins/plugin-smarter-websearch.yamlsmarter/smarter/apps/llmclient/data/llm-clients/llmclient-smarter.yaml
manage.py deploy_builtin_llmclients applies the built-in plugins, and then the built-in
LLMClients. Applying an LLMClient fails if any plugin that it names does not exist, and applying
smarter_project_websearch fails if its Secret tavily_api_key does not exist. An
installation without a Tavily API key therefore cannot deploy the smarter LLMClient. The other
built-in plugins and LLMClients are not affected: the command applies each manifest 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. An existing smarter LLMClient keeps its previous version.
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 as.env.example’sSET-ME-PLEASEorvalues.yaml’sSET-ME-IN-helm/charts/smarter/values.yaml, the command logs a warning and does not create the Secret. It never stores a placeholder as the key.Deploy the built-in LLMClients.
python manage.py deploy_builtin_llmclients --account_number 3141-5926-5359
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/plugin/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 then deploy_builtin_llmclients. 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_websearch, and therefore thesmarterLLMClient, could not be applied. The other built-in LLMClients are applied as usual. 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 deploys the built-in LLMClients 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 ...The smarter LLMClient was applied, but its WebsearchPlugin was not, almost always because of the missing Secret above. Fix the Secret, and run
manage.py deploy_builtin_llmclients, which reports each manifest that it fails to apply asFailed to apply manifest ....initialize_tavily: TAVILY_API_KEY is not setThe init command found no key, or only a placeholder. Set the environment variable, or, in a deployment, the GitHub secret
TAVILY_API_KEY.