Deepgram Voice Agent web search
Give a Deepgram voice agent live web search. Define search_web in agent.think.functions and answer it from your own code with the SpecStream Search API. The agent speaks the answer and names the site that printed it.
What you need
- A Deepgram API key, and Python 3.10 or newer with websockets and httpx (
pip install "websockets>=14" httpx). - A SpecStream API key with a total spending limit. New accounts start with $10 of credit, no card. Create an account.
- 1
1. Create a SpecStream API key
In the SpecStream workspace, open API keys and click New key. Name it for the agent and choose Call the APIs under What the key can do. A key with that choice can search and read pages, which the two functions need.
Enter a Total spending limit, the most the agent may spend across all its calls, then click Create key. Copy the key from Copy your key now, because it is shown once. Set it as
SPECSTREAM_API_KEYon the server that runs the agent, besideDEEPGRAM_API_KEY. The functions run in your code, so the key stays on your server and Deepgram never sees it. - 2
2. Define search_web in the Settings message
Deepgram reads your functions from
agent.think.functionsin theSettingsmessage. A function without anendpointruns client side: Deepgram sends your code aFunctionCallRequest, and your code answers with aFunctionCallResponse.search_webtakes one parameter,q, the question in everyday words.read_pagetakes aurl, for a page the caller names or one a search returned. Put each block of this guide in one file,web_search_agent.py, in order:web_search_agent.py - 3
3. Call the Search API from each function
search_websendsGET /v1/web-searchwithqandnum=5. The reply'sdata.answerholds thevalueas the pages print it and thepageit was read on.data.sourcesholds the results in rank order, each with itstitle,site,snippetandurl. The function passes the agent only those fields, so its context stays short and the spoken answer comes quickly.read_pagesends the address to the Extract API,POST /v1/extract, and passes on the page's main text, cut at 4,000 characters:web_search_agent.py - 4
4. Answer each FunctionCallRequest
Each call in
functionshas anid, anameandargumentsas a JSON string. Run the matching function in its own task, so the socket keeps carrying audio. Then send back aFunctionCallResponsewith the sameidandnameand the result as a string incontent. A call that comes withthought_signature(some Gemini models send one) gets it back unchanged.Deepgram waits for that response, so every path sends one. A search with no reply in 20 seconds returns an error the agent can say aloud:
web_search_agent.py - 5
5. Connect and talk to it
Open the socket with your Deepgram key as
Tokenin theAuthorizationheader and sendSettingsfirst. This test types to the agent withInjectUserMessageand printsConversationText, so it runs without a microphone. In your own agent, stream the microphone as Deepgram's guide shows, and dropkeep_aliveandtype_to_agent. WhenFunctionCallCancelledarrives, the matching task stops and sends no response:web_search_agent.py - 6
6. Run it
Set
DEEPGRAM_API_KEYandSPECSTREAM_API_KEYand runpython web_search_agent.py. Ask about something from this week, such as a score, a price or an opening time. The agent callssearch_weband says the answer with the site it came from. Give it a page address and ask what the page says, and it callsread_page.
What the agent gets back
The Search API reads the live web at the moment of the call. When the pages agree on one value, answer.value is that value as they print it: a full name, a date with its year or a number with its unit. answer.page is the page it was read on. When no result prints a value that answers the question, answer is null, and the agent speaks from results or asks the caller to narrow the question.
The full reply also carries rows for a request that asks for many results, with the page and read time of each value, and price_usd, what the call cost. The Search API reference lists every field and parameter.
Calls sent before the caller finishes
Deepgram sends a function call as soon as the model asks for it, which can be before the caller has finished speaking. If the caller keeps talking, Deepgram sends FunctionCallCancelled and the code above stops the task without a response. A search that already reached SpecStream may still be charged.
To pay only for searches in confirmed turns, add "defer_until_eot": True to search_web in FUNCTIONS. The call then waits until the caller's turn ends, and that wait is added to the answer. Most agents leave search undeferred: a search changes nothing and costs a fraction of a cent.
Why the function runs in your code
Deepgram can also call a function on an address you name, when the function carries an endpoint with url, method and headers. That puts your SpecStream key in the Settings message Deepgram holds. Client side, the key stays in your process, you cut the reply down to what the agent needs to speak, and you choose what the agent says when a search fails.
If something doesn't work
| What you see | What to do |
|---|---|
An error with 401 | The key is unknown, expired or revoked. Create a new key and set it as SPECSTREAM_API_KEY. |
An error with 403 | The key can't search, or it reached its total spending limit. Create a key with Call the APIs, or raise the limit under API keys. |
An error with 402 | The balance is too low. Add balance in your SpecStream workspace. |
answer is null | No result printed a value that answers the question. The agent can speak from results, or ask the caller for a name, a place or a date. |
| The agent goes quiet after a function call | Deepgram waits for a FunctionCallResponse. Check that every path sends one with the call's id. |
Cost
Each search_web call is one Search API call at $5 per 1,000 searches of up to 10 results. num is 5, so every call is charged at that rate, and a search that returns no results costs nothing. Each read_page call reads one page at $0.80 per 1,000 pages, and a page with no text is not charged. Neither needs a quote or an approval. The key's total spending limit is the ceiling. New accounts start with $10 of credit, no card. The rates are on pricing, and balance and billing covers the rest.
Remove
Take search_web and read_page out of agent.think.functions. Then open API keys in your SpecStream workspace and revoke the key, which cuts the agent off at once. Browse the other tools SpecStream connects to, or write to [email protected] if a step here doesn't match what you see.
More
SpecStream for Deepgram Voice Agent web search covers what it does in Deepgram Voice Agent web search on one page. Every other tool has its guide in Connect your tools. You see the most a request can cost before it starts, and the matches are paid from your balance. Billing has the details. For help, email [email protected].