Skip to the page

Agents Deep Research

Run Agents Deep Research, the deep-researcher package, on SpecStream's Search API with two lines in .env. Its SearXNG client is already in the code under the name searchxng, so there is no Serper key to buy and no SearXNG server to host.

SpecStream for Agents Deep ResearchAgent frameworks & builders

What you need

  • Agents Deep Research 0.0.11 or later, from pip install deep-researcher or a clone of github.com/qx-labs/agents-deep-research, with a model key set in .env as its README describes.
  • A SpecStream key. Get your key on the Search API screen of your SpecStream workspace. New accounts start with $10 of credit, no card.
  1. 1. Set the provider and the address in .env

    In the .env file, set SEARCH_PROVIDER to searchxng, spelled as the code spells it, and set SEARCHXNG_HOST to SpecStream's SearXNG address with your key in it. The client adds /search itself and sends no header, so the key goes in the address. SERPER_API_KEY is no longer read.

    The comment in .env.example lists only serper and openai, and the README names the same two. The code accepts a third: llm_config.py lists searchxng as a search provider, and web_search.py builds a SearchXNGClient for it.

    .env
    SEARCH_PROVIDER=searchxng
    SEARCHXNG_HOST=https://api.specstream.ai/searxng/YOUR_SPECSTREAM_KEY
  2. 2. Run a research from the command line

    Start a research as the README shows. Each search the agents make now goes to SpecStream. The parser names the flag --model, and Python's argparse takes the README's --mode as its short form, so both work.

    Terminal
    deep-researcher --mode deep --query "Provide a comprehensive overview of quantum computing" --max-iterations 3 --max-time 10 --verbose
  3. 3. Or set the provider in Python

    LLMConfig takes the provider at runtime and overrides SEARCH_PROVIDER. The address still comes from SEARCHXNG_HOST, which the client reads when the researcher is created.

    Python
    import asyncio
    from deep_researcher import DeepResearcher, LLMConfig
    llm_config = LLMConfig(
    search_provider="searchxng",
    reasoning_model_provider="openai",
    reasoning_model="o3-mini",
    main_model_provider="openai",
    main_model="gpt-4o",
    fast_model_provider="openai",
    fast_model="gpt-4o-mini",
    )
    researcher = DeepResearcher(max_iterations=3, max_time_minutes=5, config=llm_config)
    report = asyncio.run(researcher.run("Provide a comprehensive overview of quantum computing"))
    print(report)

What changes and what stays

SearchXNGClient sends GET to the address plus /search with q and format=json, and reads results[] with url, title and content. SpecStream answers in that SearXNG shape, so the client runs unchanged.

Each search returns up to 10 results. The app's filter agent, on your reasoning model, keeps up to 5 that fit the query, and the app then fetches those pages itself, as it did with Serper. Your models, the planner, the writer and the crawler tool stay as they are.

The Serper address is a constant in SerperClient, https://google.serper.dev/search, so that client cannot be pointed anywhere else. SEARCH_PROVIDER=openai uses OpenAI's hosted web search tool, and the app refuses it unless the fast model runs on OpenAI's own API. The searchxng branch works with every model provider the app supports, Anthropic, Gemini, DeepSeek, OpenRouter and local models included.

SpecStream's Search API scores 97.9 F-score on all 1,000 SimpleQA Verified questions and 64.0 item F1 on all 200 WideSearch tasks on its default tier. Scores and method are on the benchmarks page.

What each search costs

Each call of the app's web_search tool is one search through the SearXNG address, on SpecStream's fast tier: $1 per 1,000 searches of up to 10 results, a fifth of the default search's $5 per 1,000. The client names no result count, so each call gets 10 results at the base price. A search that returns no results costs nothing.

Calls come out of your balance with no quote and no approval, and every call is in your account's request log under the SearXNG route. Your model calls stay on your model provider's bill.

Check the address before a run

This is the call the client sends. It makes one search on your key:

Keep the key in the address private

SEARCHXNG_HOST carries your key, so keep .env out of git and out of shared logs. Give this app a key of its own with a spending limit, made under Agents & API in your workspace. A key that searches needs the finds:spend scope and a limit above 0.

Limits and errors

  • Leave the DR_ prefix off SEARCHXNG_HOST. The app reads most settings with or without it, but the SearXNG client reads SEARCHXNG_HOST by that exact name. DR_SEARCH_PROVIDER=searchxng works.
  • AttributeError: 'NoneType' object has no attribute 'endswith' when the researcher starts means SEARCHXNG_HOST is not in the environment.
  • When a search fails, the tool returns a message that starts with Sorry, I encountered an error while searching: and the research goes on. A 401 in it means the key in the address is missing or wrong.
  • When the account has used its calls for the minute, or search is busy, SpecStream answers 429 with Retry-After, and nothing is charged. The client does not retry.
  • The app skips result addresses that contain .pdf, .doc, .xls and other file extensions, and reads each page with an 8 second timeout. That fetch runs in the app, not on SpecStream.

Go back

Set SEARCH_PROVIDER back to serper and put your Serper key in SERPER_API_KEY, or point SEARCHXNG_HOST at your own SearXNG instance. To stop the SpecStream key working everywhere, revoke it under Agents & API in your workspace. Questions go to [email protected].

More

SpecStream for Agents Deep Research covers what it does in Agents Deep Research 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].