Skip to the page

Tongyi DeepResearch

Run Tongyi DeepResearch's search and visit tools on SpecStream by changing the Serper host in tool_search.py and the Jina Reader address in tool_visit.py. One SpecStream key and one balance pay for every search and every page the agent reads. The model, the prompts and the summary model stay as they are.

SpecStream for Tongyi DeepResearchAgent frameworks & builders

What you need

  • Tongyi DeepResearch cloned from GitHub, with .env copied from .env.example as its README shows. The steps edit two files in its inference folder.
  • 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. Point the search tool at SpecStream

    Tongyi DeepResearch has no setting for its search address. The search tool in inference/tool_search.py opens a connection to google.serper.dev, posts each query to /search, and sends the key from SERPER_KEY_ID.

    From the repository root, change the host and the path to SpecStream's Serper route, and have the tool read its key from a variable of its own. The Scholar tool keeps SERPER_KEY_ID, as step 3 explains.

    Shell, in DeepResearch
    # On macOS, write sed -i '' in place of sed -i
    sed -i \
    -e 's#HTTPSConnection("google.serper.dev")#HTTPSConnection("api.specstream.ai")#' \
    -e 's#"POST", "/search"#"POST", "/serper/search"#' \
    -e "s#os.environ.get('SERPER_KEY_ID')#os.environ.get('SPECSTREAM_API_KEY')#" \
    inference/tool_search.py
  2. 2. Point the visit tool at SpecStream's Jina Reader route

    jina_readpage in inference/tool_visit.py reads a page by calling https://r.jina.ai/ followed by the page's address, with JINA_API_KEYS as a Bearer token. Change the prefix to SpecStream's Jina Reader route. The page's address stays on the end, and the key is sent as before.

    Shell, in DeepResearch
    sed -i 's#https://r.jina.ai/#https://api.specstream.ai/jina/#' inference/tool_visit.py
    grep -n "specstream" inference/tool_search.py inference/tool_visit.py
  3. 3. Set the keys in .env

    In .env, add SPECSTREAM_API_KEY and set JINA_API_KEYS to the same SpecStream key. run_react_infer.sh exports every line of .env before it starts the run, so both tools read them.

    Keep SERPER_KEY_ID as it was. The google_scholar tool in inference/tool_scholar.py still posts to Serper's /scholar with that key.

    .env
    SPECSTREAM_API_KEY=YOUR_SPECSTREAM_KEY
    JINA_API_KEYS=YOUR_SPECSTREAM_KEY
    SERPER_KEY_ID=YOUR_SERPER_KEY
  4. 4. Run the agent

    Set MODEL_PATH, DATASET and OUTPUT_PATH in .env as the README asks, then start the run. Each search query and each page the visit tool reads now goes through SpecStream, and each call is in your account's request log with its route as the endpoint.

    Shell, in DeepResearch
    cd inference
    bash run_react_infer.sh

What changes and what stays

Each SpecStream route answers in the shape the tools already read. The Serper route returns organic[] with title, link, snippet and position, with date when the page states one, and the search tool formats those into its numbered list. The tool still sends gl and hl: cn and zh-cn for a query in Chinese, us and en otherwise. SpecStream searches in that country and language. The tool names no count, so each query gets 10 results.

Called with no Accept header, as visit calls it, the Jina Reader route answers in Jina's text form: Title:, URL Source:, then the page's text as Markdown. visit passes that text to the summary model at API_BASE as before, so API_KEY, API_BASE and SUMMARY_MODEL_NAME stay as they are. The README's OpenRouter setup changes only the model calls in react_agent.py, so it works with these edits too.

What each call costs

  • Each query in a search call is one Search API call through a drop-in address: $1 per 1,000 searches of up to 10 results. The tool takes an array of queries, so a call with three queries is three searches. A search that returns no results costs nothing.
  • Each page visit reads is one Extract API page at $0.80 per 1,000 pages. A page that gives no text is not charged.
  • A page SpecStream cannot read answers 422 and costs nothing. visit tries such a page up to 24 times, 3 tries in each of 8 attempts, so a blocked page slows that step and adds nothing to the bill.
  • MAX_LLM_CALL_PER_RUN caps the model at 100 calls a question by default, and that bounds how many tool calls one question can make.
  • Calls come out of your balance with no quote and no approval, and every call, charged or not, is in your request log.

Why run Tongyi DeepResearch on SpecStream

The README asks for a Serper key for search and a Jina key for page reading, each with its own account and bill. On SpecStream one key and one balance pay for both, and one request log shows every query and every page a run made, which helps when you compare runs on a benchmark.

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. Scores and method are on the benchmarks page.

Limits and errors

  • With a wrong key the Serper route answers 401 with no organic field, and search tells the model No results found for the query. When every search comes back empty, check SPECSTREAM_API_KEY.
  • visit returns [visit] Failed to read page. once its tries run out. If it says that for every page, check JINA_API_KEYS.
  • When the account has used its calls for the minute, SpecStream answers 429 with Retry-After, and nothing is charged. search does not wait and reports no results for that query; visit tries again after half a second.

Go back

Run git checkout -- inference/tool_search.py inference/tool_visit.py, put your Jina key back in JINA_API_KEYS, and start the run again. Settings for other Serper and Jina clients are on Moving off Serper and Moving off Jina Reader. Questions: [email protected].

More

SpecStream for Tongyi DeepResearch covers what it does in Tongyi DeepResearch 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].