- Search the live web with
/augment/search - Decide which of those results are worth reading
- Convert the selected pages to Markdown with
/augment/scrape - Ask a chat model to write the brief, citing sources by number
- Wire the four stages into one script
venice_parameters.enable_web_search on a chat completion instead. The Web Search and Scraping guide compares the two approaches.
Setup
You need Python 3.9 or newer, therequests package, and a Venice API key. See Generating an API Key if you do not have one.
research.py and start with the imports and a shared header block that every call reuses:
1. Search the web
/augment/search takes a query and returns up to 20 ranked results. Brave is the default provider and applies Zero Data Retention. Google is also available and is proxied through Venice, so the query is never linked to you.
content field arrives with HTML in it, because the provider wraps matched terms in <strong> tags. The HTML_TAG substitution above strips them so the snippet reaches the model as plain text.
The date field is frequently an empty string. Many pages publish no machine readable date, so treat date as a hint you can use when present rather than a field you can sort or filter on.
2. Choose which sources to read
Scraping all ten results would be slow, expensive, and largely redundant. Search engines return several pages from the same site, and documentation sites in particular return the same page in several languages, so the same content can appear three or four times under different URLs. Keeping only the highest ranked result per domain removes most of that duplication in a few lines:date. Every filter you apply here is a decision the model no longer has a chance to get wrong.
3. Scrape the selected pages
/augment/scrape fetches a public URL and returns it as Markdown. It first asks the site for a native Markdown representation and falls back to browser based extraction when there is none.
Some pages will fail, and a research tool should treat that as routine rather than fatal:
200 but hand back a cookie banner or an empty shell instead of an article.
Scrape failures return a plain
{"error": "..."} body with a readable message, for example X (formerly Twitter) blocks automated access to their content. X and Reddit are blocked outright. To include posts from X in an answer, use venice_parameters.enable_x_search on a chat completion instead.4. Write the brief
Now we hand the model the pages we collected, numbered, and ask for citations that refer to those numbers. The numbering in the prompt is what lets us turn a[2] in the output back into a URL later.
temperature keeps the wording close to the source text. Setting enable_web_search to off matches the default, but saying it out loud guarantees the model cannot quietly introduce a source that is missing from our reference list.
5. Put it together
The last piece runs the stages in order and appends the reference list that resolves the citation numbers:stderr, so you can redirect the brief on its own into a file:
Tuning the pipeline
Most of the wall clock time goes to the final chat completion, since four scraped pages add up to tens of thousands of tokens. These are the levers worth reaching for first:Next steps
The pipeline you now have is a foundation rather than a finished product. A few directions worth exploring:- Cache scraped Markdown by URL so repeated questions do not refetch the same pages.
- Store the Markdown as vectors with Embeddings and retrieve passages instead of whole pages.
- Let the model plan several queries before searching, as the Private Research Agent demo does.
- Read the brief out loud by piping it into Narrating Articles with Text-to-Speech.
Web Search and Scraping
Reference for the Search and Scrape endpoints.
Narrating Articles with Text-to-Speech
Turn the text you just generated into audio.
Embeddings
Index scraped Markdown instead of refetching it.
Private Research Agent
A larger agent that plans its own searches.