# OSS Deep Research

This is a "Deep Research" agent, adapted from the LangChain version (which was inspired by
the OpenAI "Deep Researcher" product).
The LangChain code is here: https://github.com/langchain-ai/open_deep_research. All
credit to LangChain for the original.

See 'oss_deep_research.prompts.yaml' for all the agent prompts.

This agent is a prototype for a "deterministic orchestration" agent where the orchestration
of the process is written in code, rather than determined solely by the LLM.

## Install and Running

Start by installing the Agentic project:

    git clone git@github.com:supercog-ai/agentic.git
    uv venv --python 3.12
    source .venv/bin/activate
    uv pip install -e "./agentic[all-tools,dev]"

You need a `TAVILY_API_KEY`, and the API key for whatever model you are using, like `OPENAI_API_KEY`
or `ANTHROPIC_API_KEY`.
Set these in your environment or use the CLI command `agentic secrets set KEY_NAME=<key_value>` to set them.

Now run from the command line:

    python examples/deep_research/oss_deep_research.py

Or serve the FastAPI API and use the web UI:

    (terminal 1):
    agentic serve examples/deep_research/oss_deep_research.py

    (terminal 2):
    agentic dashboard start

### Some example prompts

"A report on the history of golden retrievers and their presence in popular culture"

"A product comparison for e-foils, including popular manufacturers and models, plus customer reviews. Focus on the mid-market of quality products with reasonable prices."

### Getting page content

By default the agent relies on the `raw_result` value from Tavily search to include the page
content of search results. However, we have added `Playwright` support that will use browser
automation to download pages that aren't returned by Tavily.

To use this, you need to install Playwright and a driver:

    pip install playwright
    playwright install chromium

and then enable playwrite in the Agent config part:

    self.playwright_fallback: bool = True

With that setting the agent will fallback to using Playwright to grab page content.
This relies on the [PlaywrightTool](../../src/agentic/tools/playwright.py).

## How it works

The workflow for this agent is quite interesting. This is an example of a 
[plan and execute](https://www.promptlayer.com/glossary/plan-and-execute-agents) 
agent, where the LLM creates a `plan` and then the execution of that plan is managed
separately (and orchestrated in code).

The basic workflow looks like this:

```
.. User enters their research topic
... LLM generates "initial web search queries" which give it "some context" about the topic
... using initial search results, LLM generates a "report plan" list of topic sections to cover
..... looping over each section, we follow this process:
....... ask LLM to generate web queries for this section
....... execute web queries and retrieve results
....... ask LLM to draft THIS section of our report
..... once all section drafts are generated, we loop over each section **again**
....... ask LLM to _rewrite_ the section based on the entire draft report
..... finally, we generate a list of "important sources" and append them to the report
... we return the completed report
```  

I find the "final section writing" part is the most interesting part of the process. All
the raw content of the report has been generated, but in separate sections. This final
phase has the agent rewrite each section of the report with the full context of
_all the other sections_. This results in a stronger narrative and cohesive report rather
than just a bunch of separate sections.

### Reading the code

The main orchestration is in the `DeepResearchAgent` class. It constructs a set of [ReAct](https://www.promptingguide.ai/techniques/react)
agents to handle the processing. Each agent has a prompt, you can find them in 
execution order in [oss_deep_research.prompts.yaml](./oss_deep_research.prompts.yaml).

The class constructor has a `# CONFIG` section with various settings. The main
ones are the `num_queries` property which determines how many web searches to process.

The agent is run via the `next_turn` method, which executes our process flow. It
invokes each ReAct agent in turn, saving the results from one agent and feeding them
in as data to the next. To invoke a sub-agent we call the `final_result` method
which "runs" the agent for a complete run until it stops, and then returns the
final result from the sub-agent.

As our agent runs it `yields` events about its progress. These can be text messages
or other types of events. When we run sub-agents we do `yield from agent.final_result`
which has the result of yielding events generated by the sub-agent. Our client
application (either the command line REPL or an API client like our dashboard) can
examine the `depth` of each event to decide how to show it (or hide it) to the user.

The looping over sections is all handled in code. Also, once the initial plan is
executed, we publish a `WaitForInput` event to wait for the human to review or
modify the research plan.

This agent uses `Agent.result_model` which allows us to specify a Pydantic model
that the result of running our ReAct agent should conform to. This uses _structured outputs_
from our LLM to force the agent result to match our schema.

## Agent orchestration

There are two common approaches to building AI agents these days: simple _ReAct_ agents which
rely on the LLM to determine the process steps, and "workflow agents" which rely on deterministic
code to drive the process.

This agent demonstrates "orchestration in code". The _Agentic_ framework itself isn't really
involved - it simply defines the top-level API (`next_turn`) and set of publishable events.

Contrast this with the _LangGraph_ implementation which relies on building a _graph_ and
orchestrating the ReAct agets from the graph. I am wildy unconvinced that the graph offers
much advantage over our simpler approach.

An area for research is how to enhance our framework to support _plan and execute_ style
agents in a more standardized way. Please read the [pipeline problem](./pipeline_problem.md) for a litte more discussion
on this topic.

## Further work

Checkout some of the example reports in this folder to get a sense of the output
from the agent. And if you generate a cool prompt and report - please share it!

* Using Playwright fallback definitely produces more content and detail, although
results vary by topic.

* Some other projects are including support for other search APIs beyond Tavily, and
for specialized content access like **https://arxiv.org/**. These would all be 
good additions.

* I think a good improvement would be re-ranking the search results to use the most
"authoritative" sources. Currently the agent just takes result links in source order
and accumulates text content until a cap, so we are relying on the search engine ranking
to get the best source context.

* Another great improvement would be to introduce a "Go further" agent which takes over
once the report is produced. It could support follow-up questions or branching to 
produce additional reports.

* An obvious improvement would be "report templates" that direct more specific styles
for different types of reports, like financial analysis, trip planning, etc...




