Inside "Open Deep Research": A Technical Deep Dive

Inside "Open Deep Research": A Technical Deep Dive

Hello! The "Deep Research" scene has suddenly been heating up.

Today, we dive into Open Deep Research—announced just yesterday (February 5, 2025)—and walk through its architecture and implementation!


1. Introduction

OpenAI's "GPT Deep Research" has been making waves, and it seems likely that many companies—including those already in the field—will be competing fiercely in the "XX Deep Research" space going forward.

"Open Deep Research" is an open-source tool developed by Hugging Face that, as its name suggests, automates the kind of web research work that humans have traditionally done at their desks.

Today, we take a deep look at the tool's design philosophy—how does Deep Research actually work under the hood?

Please note that this article focuses strictly on how the system works; it is not a usage guide.

1.1. Background

In recent years, advances in information technology have dramatically increased the amount of information we can handle. When conducting web research at your desk, the work of extracting useful insights from vast amounts of information and organizing them clearly has become extremely important.

Naturally, it would be wonderful to automate this kind of work with AI, and commercial services such as Perplexity, Gemini Deep Research, and GPT Deep Research have been arriving one after another.
Following that trend, the Open Deep Research system (hereafter, OpenDeepResearch) was developed to automate the research process that humans used to perform manually, leveraging the latest large language models (LLMs)—and it was released as open source.

1.2. Background and Significance of the System

Our company also provides consulting services, and in consulting, research is the foundation of everything. It all starts with "desktop research"—gathering and organizing information collected primarily through web searches.

However, as the volume of information has exploded, the work of analysts and staff collecting data from multiple sources and organizing it by hand has become a heavy burden.


OpenDeepResearch appears to aim at leveraging the advanced comprehension capabilities of LLMs to automatically integrate information from multiple sources, achieving fast and accurate information organization.

1.3. Architecture Overview and Design Philosophy

OpenDeepResearch is designed to mimic the desktop research process that humans actually perform (collecting, comparing, analyzing, and integrating information), while automating and extending that work.

As engineers, what we really want to know is: "So how do you actually do that with IT and AI?"

Specialized components handle each stage of the process and coordinate through a multi-agent architecture, achieving overall efficiency and flexibility.

1.4 Architecture

The architecture is shown below. This article mainly walks through the code of the major components, but let's start with the big picture.

Main Components (and Their Interactions)

graph TB subgraph Core System RunPy[run.py - System Entry Point] Manager[Manager Agent] Reform[Reformulator] end subgraph Search & Analysis Browser[SimpleTextBrowser] TextInspector[TextInspectorTool] VisualQA[VisualQATool] Search[SearchInformationTool] Archive[ArchiveSearchTool] end subgraph Document Processing MDConv[MarkdownConverter] YouTubeConv[YouTubeConverter] PDFConv[PdfConverter] DocxConv[DocxConverter] XlsxConv[XlsxConverter] end subgraph File & Cache Management FileProc[File Processor] Cache[Cache System] end RunPy --> Manager Manager --> Reform Manager --> Browser Manager --> TextInspector Manager --> VisualQA Browser --> Search Browser --> Archive TextInspector --> MDConv MDConv --> YouTubeConv MDConv --> PDFConv MDConv --> DocxConv MDConv --> XlsxConv Search --> FileProc Archive --> FileProc FileProc --> Cache subgraph External Services SerpAPI[SerpAPI] WaybackMachine[Wayback Machine] IDEFICS[IDEFICS-2 Model] end Search --> SerpAPI Archive --> WaybackMachine VisualQA --> IDEFICS

Core System

  • Manager Agent: The central agent that oversees the entire system and controls all other components
  • Reformulator: Responsible for restructuring search and analysis results into the final answer format
  • run.py: The system's entry point, managing initial configuration and the execution flow

Search & Analysis

  • SimpleTextBrowser: A component that crawls and parses web pages
  • TextInspectorTool: A tool for detailed analysis and information extraction from text data
  • VisualQATool: Handles image understanding and visual question answering
  • SearchInformationTool: Runs web searches and organizes the results
  • ArchiveSearchTool: Searches and analyzes archives of past web pages

Document Processing

  • MarkdownConverter: Converts documents of various formats into a unified format
  • YouTubeConverter: Extracts information from YouTube videos and processes transcripts
  • PdfConverter: Extracts text from PDF files and analyzes their structure
  • DocxConverter: Processes and analyzes Word documents
  • XlsxConverter: Processes data in Excel format

File & Cache Management

  • File Processor: Manages file I/O and format conversion
  • Cache System: Manages caches of search results and file-processing results to optimize performance

External Services

  • SerpAPI: An external API for retrieving Google search results
  • Wayback Machine: The Internet Archive's API for retrieving past web pages
  • IDEFICS-2 Model: An AI model for image understanding and generation

By working together, these components accomplish complex information retrieval and analysis tasks. In particular, the core system centered on the Manager Agent coordinates and integrates the components, enabling efficient information processing.

This article covers the five major components that make up the Open Deep Research architecture (Core System, Search & Analysis, Document Processing, File & Cache Management, and External Services) in the following order.

We start with TextInspectorTool, the heart of Search & Analysis, then cover the image-understanding component and the implementation of the web exploration system.

After that, we move on to the details of the multi-agent system, and finally discuss system evaluation and application examples.

So, let's begin with the implementation details of TextInspectorTool.


2. Implementation Details of Each Component

In this section, we explain the implementation of each major component of OpenDeepResearch, with concrete code examples.

To follow along properly, first clone the project from GitHub.

The license is Apache 2.0, and you can clone the repository from:

git clone https://github.com/huggingface/smolagents

Open Deep Research itself lives here:
https://github.com/huggingface/smolagents/tree/main/examples/open_deep_research

2.1. Implementation Details of TextInspectorTool

Now that we have the code, let's start with TextInspectorTool.

At the core of text processing is TextInspectorTool.

This tool uses MarkdownConverter to convert documents of various formats into a unified format, then extracts information and generates answers to questions based on the document's structure and context. It also has solid error handling; for image files, it prompts the use of an appropriate alternative tool.

class TextInspectorTool(Tool):
    def __init__(self, model: Model, text_limit: int):
        super().__init__()
        self.model = model
        self.text_limit = text_limit
        self.md_converter = MarkdownConverter()

    def forward(self, file_path, question: Optional[str] = None) -> str:
        result = self.md_converter.convert(file_path)

        if file_path[-4:] in [".png", ".jpg"]:
            raise Exception("Cannot use inspect_file_as_text tool with images: use visualizer instead!")

        if not question:
            return result.text_content

        messages = [
            {
                "role": MessageRole.SYSTEM,
                "content": [
                    {
                        "type": "text",
                        "text": "You will have to write a short caption for this file, then answer this question:" + question,
                    }
                ],
            },
            {
                "role": MessageRole.USER,
                "content": [
                    {
                        "type": "text",
                        "text": "Here is the complete file:\n### " + str(result.title) + "\n\n" + result.text_content[: self.text_limit],
                    }
                ],
            }
        ]

2.2. Technical Details of the Image-Understanding Component

VisualQATool is a component that uses the latest vision-language model, IDEFICS-2, to process images and question text in an integrated manner.
It works by base64-encoding images and combining them with text prompts to extract information from images. Automatic resizing is also implemented for large images. Hard to believe this was built in 24 hours.

def process_images_and_text(image_path, query, client):
    messages = [
        {
            "role": "user",
            "content": [
                {"type": "image"},
                {"type": "text", "text": query},
            ],
        },
    ]

    prompt_with_template = idefics_processor.apply_chat_template(
        messages, 
        add_generation_prompt=True
    )

    image_string = encode_local_image(image_path)
    prompt_with_images = prompt_with_template.replace(
        "<image>", 
        "![]({}) "
    ).format(image_string)

    payload = {
        "inputs": prompt_with_images,
        "parameters": {
            "return_full_text": False,
            "max_new_tokens": 200,
        },
    }

    return json.loads(client.post(json=payload).decode())[0]

2.3. Implementation of Web Exploration and Information Gathering

SimpleTextBrowser evolves the traditional web crawler, with functionality that mimics human browsing behavior through management of page history and the viewport.

class SimpleTextBrowser:
    def __init__(self, start_page: Optional[str] = None,
                 viewport_size: Optional[int] = 1024 * 8,
                 downloads_folder: Optional[Union[str, None]] = None,
                 serpapi_key: Optional[Union[str, None]] = None):
        self.start_page = start_page if start_page else "about:blank"
        self.viewport_size = viewport_size
        self.downloads_folder = downloads_folder
        self.history = []
        self.page_title = None
        self.viewport_current_page = 0
        self.viewport_pages = []
        self.serpapi_key = serpapi_key
        self._mdconvert = MarkdownConverter()

2.4. Implementation Details of the Multi-Agent System

OpenDeepResearch adopts a multi-agent architecture in which each component plays its own role while cooperating with the others.
For example, it implements a mechanism in which an information-retrieval agent and a manager agent work together.

def create_agent_hierarchy(model: Model):
    text_limit = 100000
    ti_tool = TextInspectorTool(model, text_limit)
    browser = SimpleTextBrowser(**BROWSER_CONFIG)

    WEB_TOOLS = [
        SearchInformationTool(browser),
        VisitTool(browser),
        PageUpTool(browser),
        PageDownTool(browser),
        FinderTool(browser),
        FindNextTool(browser),
        ArchiveSearchTool(browser),
        TextInspectorTool(model, text_limit),
    ]

    text_webbrowser_agent = ToolCallingAgent(
        model=model,
        tools=WEB_TOOLS,
        max_steps=20,
        verbosity_level=2,
        planning_interval=4,
        name="search_agent",
        description="""A team member that will search the internet to answer your question.
        Ask him for all your questions that require browsing the web."""
    )

    manager_agent = CodeAgent(
        model=model,
        tools=[visualizer, ti_tool],
        max_steps=12,
        verbosity_level=2,
        managed_agents=[text_webbrowser_agent]
    )

The information-retrieval agent (text_webbrowser_agent) and the manager agent (manager_agent) operate in a hierarchical structure. Specifically, manager_agent oversees everything as a CodeAgent, with text_webbrowser_agent placed under its management.

In this configuration, text_webbrowser_agent specializes in web-related tasks such as web search, page browsing, and navigation. Using web tools such as SearchInformationTool, VisitTool, and PageUpTool, this agent provides capabilities like running Google searches, browsing web pages, searching within pages, and searching archived pages.

Meanwhile, manager_agent is responsible for overall task management and coordination. It has code-execution capabilities and can directly use the visualizer and TextInspectorTool. It also has the authority to delegate tasks to text_webbrowser_agent as needed.

def answer_single_question(example, model_id, answers_file, visual_inspection_tool):
    model = LiteLLMModel(
        model_id,
        custom_role_conversions=custom_role_conversions,
        max_completion_tokens=8192,
        reasoning_effort="high",
    )
    
    agent = create_agent_hierarchy(model)
    
    augmented_question = """You have one question to answer...""" + example["question"]
    
    # Run the agent
    final_result = agent.run(augmented_question)
    
    # Format the results
    agent_memory = agent.write_memory_to_messages(summary_mode=True)
    final_result = prepare_response(augmented_question, agent_memory, reformulation_model=model)

In terms of the actual flow, manager_agent starts execution upon receiving a question, and delegates the task to text_webbrowser_agent when a web search is needed. text_webbrowser_agent runs the search and returns the results to manager_agent, which then integrates the information and generates the final answer.

The key point in this process is the flow: when a question comes in, manager_agent receives it first and delegates work to text_webbrowser_agent as needed. Execution results are stored in agent_memory and finally formatted by prepare_response.

Communication between agents is handled through the capabilities of ToolCallingAgent.

text_webbrowser_agent can use web tools such as the following.

class SearchInformationTool(Tool):
    name = "web_search"
    description = "Perform a web search query (think a google search) and returns the search results."
    
    def forward(self, query: str, filter_year: Optional[int] = None) -> str:
        self.browser.visit_page(f"google: {query}", filter_year=filter_year)
        header, content = self.browser._state()
        return header.strip() + "\n=======================\n" + content

Using these tools, text_webbrowser_agent gathers the necessary information and returns the results to manager_agent, which integrates them to generate the final answer.

This architecture achieves an efficient division of labor: specific tasks such as web search and information gathering are delegated to the information-retrieval agent, while overall control and final decision-making remain with manager_agent. Each agent has a toolset specialized for its own domain, and by combining them appropriately, the system is able to handle complex tasks.

2.5. Implementation of the Execution System

The operation of the entire system is centrally managed by the run.py module, which automates everything from task assignment to saving results. This is, in effect, the main class of the system.

def main():
    args = parse_args()
    print(f"Starting run with arguments: {args}")

    answers_file = f"output/{SET}/{args.run_name}.jsonl"
    tasks_to_run = get_examples_to_answer(answers_file, eval_ds)

    with ThreadPoolExecutor(max_workers=args.concurrency) as exe:
        futures = [
            exe.submit(answer_single_question, example, args.model_id, answers_file, visualizer)
            for example in tasks_to_run
        ]
        for f in tqdm(as_completed(futures), total=len(tasks_to_run)):
            f.result()

3. System Optimization and Operations Management

This section covers the techniques used for stabilizing, optimizing, and operating the system.

3.1. Performance Optimization and System Tuning

The OpenDeepResearch system appears to achieve smooth operation by optimizing its document-processing pipelines.


For example, the MarkdownConverter class implements a mechanism for efficiently converting between various formats.

class MarkdownConverter:
    def __init__(self, requests_session: Optional[requests.Session] = None, 
                 mlm_client: Optional[Any] = None,
                 mlm_model: Optional[Any] = None):
        self._requests_session = requests_session or requests.Session()
        self._mlm_client = mlm_client
        self._mlm_model = mlm_model
        self._page_converters = []
        
        self.register_page_converter(PlainTextConverter())
        self.register_page_converter(HtmlConverter())
        self.register_page_converter(WikipediaConverter())
        self.register_page_converter(YouTubeConverter())
        self.register_page_converter(DocxConverter())
        self.register_page_converter(XlsxConverter())

3.2. Error Handling and Robustness

Unexpected errors are common in real-world operation, but the system implements mechanisms that avoid interrupting processing when errors occur, preserving as much information as possible and attempting to recover.
For example, here is one example of its error handling.

def answer_single_question(example, model_id, answers_file, visual_inspection_tool):
    try:
        model = LiteLLMModel(
            model_id,
            custom_role_conversions=custom_role_conversions,
            max_completion_tokens=8192,
            reasoning_effort="high",
        )
        
        agent = create_agent_hierarchy(model)
        final_result = agent.run(augmented_question)
        
    except Exception as e:
        print(f"Error processing question: {e}")
        output = None
        intermediate_steps = []
        raise_exception = True
        
    finally:
        append_answer({
            "agent_name": model.model_id,
            "question": example["question"],
            "prediction": output,
            "error": str(e) if raise_exception else None,
        }, answers_file)

3.3. Concurrency and Scalability

To process large numbers of tasks efficiently, the system incorporates concurrency and task-management techniques.
By properly tracking tasks that have already been processed, it enables smooth operation even after restarts.

def get_tasks_to_run(data, total: int, base_filename: Path, tasks_ids: list[int]):
    f = base_filename.parent / f"{base_filename.stem}_answers.jsonl"
    done = set()
    if f.exists():
        with open(f, encoding="utf-8") as fh:
            done = {json.loads(line)["task_id"] for line in fh if line.strip()}

    tasks = []
    for i in range(total):
        task_id = int(data[i]["task_id"])
        if task_id not in done:
            if tasks_ids is not None and task_id in tasks_ids:
                tasks.append(data[i])

4. Advanced Information Integration and Processing

This section covers data integration from multiple sources and the advanced processing capabilities for search and analysis.

4.1. Advanced Information Integration

The system integrates data obtained from multiple sources and generates the final response based on the dialogue between agents.

def prepare_response(original_task: str, inner_messages, reformulation_model: Model):
    messages = [
        {
            "role": MessageRole.SYSTEM,
            "content": [
                {
                    "type": "text",
                    "text": f"Earlier you were asked: {original_task}\nYour team then worked diligently to address that request. Read below a transcript of that conversation."
                }
            ]
        }
    ]
    
    try:
        for message in inner_messages:
            if not message.get("content"):
                continue
            message = copy.deepcopy(message)
            message["role"] = MessageRole.USER
            messages.append(message)
    except Exception:
        messages += [{"role": MessageRole.ASSISTANT, "content": str(inner_messages)}]

This part is quite interesting.

The prepare_response function organizes the exchanges between agents and prepares for generating the final answer. Let's look at what it actually does.

  1. First, it creates a new conversation context
messages = [
    {
        "role": MessageRole.SYSTEM,
        "content": [
            {
                "type": "text",
                "text": f"Earlier you were asked: {original_task}\nYour team then worked diligently to address that request. Read below a transcript of that conversation."
            }
        ]
    }
]

This system message presents the original question (original_task) and explains that the exchange that follows is a record of the work done on that question.

2. Next, it processes the exchanges between agents (inner_messages)

try:
    for message in inner_messages:
        if not message.get("content"):
            continue
        message = copy.deepcopy(message)
        message["role"] = MessageRole.USER
        messages.append(message)

The processing here is as follows.

  • Loop over each message in inner_messages
  • Skip messages with empty content
  • Create a deep copy of each message to protect the original
  • Normalize the role of all messages to USER
  • Append the processed messages to the new conversation context

3. Error handling:

except Exception:
    messages += [{"role": MessageRole.ASSISTANT, "content": str(inner_messages)}]

If an error occurs while processing the messages, the entire inner_messages is collapsed into a single message as a string.

In short, the main purpose of this function is to convert the complex exchanges among multiple agents into a well-organized conversation history. This allows the model to understand all the relevant information in the proper context when generating the final answer.

Also, by converting every message to the User role, the model treats each message as fresh input and can analyze them holistically. This serves to integrate the different perspectives and information from multiple agents into a final answer.

4.2. Real-Time File Processing System

The system can process files of various formats in real time, enriching web-based research. The appropriate processing method is selected automatically based on the file extension.

def get_single_file_description(file_path: str, question: str, visual_inspection_tool, document_inspection_tool):
    file_extension = file_path.split(".")[-1]
    if file_extension in ["png", "jpg", "jpeg"]:
        file_description = f" - Attached image: {file_path}"
        file_description += f"\n     -> Image description: {get_image_description(file_path, question, visual_inspection_tool)}"
        return file_description
    elif file_extension in ["pdf", "xls", "xlsx", "docx", "doc", "xml"]:
        file_description = f" - Attached document: {file_path}"
        image_path = file_path.split(".")[0] + ".png"
        if os.path.exists(image_path):
            description = get_image_description(image_path, question, visual_inspection_tool)
        else:
            description = get_document_description(file_path, question, document_inspection_tool)
        file_description += f"\n     -> File description: {description}"
        return file_description

class PdfConverter(DocumentConverter):
    def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]:
        extension = kwargs.get("file_extension", "")
        if extension.lower() != ".pdf":
            return None

        text_content = pdfminer.high_level.extract_text(local_path)
        
        layout = extract_layout(local_path)
        sections = analyze_document_structure(layout)
        
        metadata = extract_pdf_metadata(local_path)
        
        return DocumentConverterResult(
            title=metadata.get('Title'),
            text_content=format_content(text_content, sections)
        )

4.3. Query Optimization Engine

A query optimization engine is implemented to convert user questions into effective search queries and improve the precision of information gathering.

class ArchiveSearchTool(Tool):
    def forward(self, url, date) -> str:
        no_timestamp_url = f"https://archive.org/wayback/available?url={url}"
        archive_url = no_timestamp_url + f"&timestamp={date}"
        response = requests.get(archive_url).json()
        response_notimestamp = requests.get(no_timestamp_url).json()
        
        if "archived_snapshots" in response and "closest" in response["archived_snapshots"]:
            closest = response["archived_snapshots"]["closest"]
        elif "archived_snapshots" in response_notimestamp and "closest" in response_notimestamp["archived_snapshots"]:
            closest = response_notimestamp["archived_snapshots"]["closest"]
        else:
            raise Exception(f"URL {url} was not archived")
            
        target_url = closest["url"]
        header, content = self.browser._state()
        
        return f"Web archive for url {url}, snapshot taken at date {closest['timestamp'][:8]}\n=======================\n{content}"

ArchiveSearchTool is a tool for searching and viewing past versions of specific web pages using the Wayback Machine (Internet Archive).

The process first makes two types of requests to the Wayback Machine API: one to look for a snapshot on the specified date, and another to find the closest snapshot without a date restriction. This way, even if no archive exists for the specified date, it can retrieve the closest available snapshot.

It checks the API response and, if an archived snapshot exists, obtains its URL. It first checks the result for the specified date, and if that does not exist, uses the result of the date-unrestricted search. If neither method finds an archive, it raises an error saying the URL has not been archived.

When an accessible archive is found, it retrieves the page content and returns it along with the URL and the capture date (displaying only the date, using the first 8 characters of the timestamp). This lets users see what a specific web page looked like at some point in the past—useful mainly for tracking the historical evolution of web pages or referencing the content of pages that no longer exist.

4.4. Advanced Context Management

In multi-turn dialogue, it is important to integrate new information in light of past exchanges. This mechanism is used to manage the dialogue history properly and generate optimal responses.

First, it receives the original question (original_task) and the agents' work history (inner_messages), and restructures them into a properly formatted conversation history. It starts by creating a system message that sets the context of the original question and makes clear that the conversation that follows is a record of the work on that question.

Next, it processes the agents' work history. It loops over each message and extracts those with non-empty content. In doing so, it creates deep copies so the original messages are not modified, and normalizes the role of every message to the user role. This is so the model treats each message as new information and can analyze it more objectively.

The purpose of this processing is to organize the complex working process of multiple agents into a format the model can easily understand.

When you unpack it, the idea is essentially to reduce everything to a dialogue between a user and the AI.

This allows the model to understand all relevant information in the proper context and generate a more accurate and comprehensive final answer. Also—call it a constraint of LLMs if you like—every message from every agent is treated as the user role. This prevents the model from being biased toward any particular agent's perspective; no favoritism arises based on which agent the information came from, so the model can ultimately evaluate the information from an objective standpoint.

def prepare_response(original_task: str, inner_messages, reformulation_model: Model) -> str:
    messages = [
        {
            "role": MessageRole.SYSTEM,
            "content": [
                {
                    "type": "text",
                    "text": f"Earlier you were asked: {original_task}\nYour team then worked diligently to address that request. Read below a transcript of that conversation."
                }
            ]
        }
    ]

    try:
        for message in inner_messages:
            if not message.get("content"):
                continue
            message = copy.deepcopy(message)
            message["role"] = MessageRole.USER
            messages.append(message)
    except Exception:
        messages += [{"role": MessageRole.ASSISTANT, "content": str(inner_messages)}]


5. Applications and Advanced Data Processing

This section introduces application examples of the OpenDeepResearch system and its advanced data-processing capabilities.

5.1. Use as an Information Research Support System

Now, partly as a review, let's think about how the system can be put to use.

As a tool that automates traditional desktop web research, OpenDeepResearch has a wide range of applications.
For example, it can be used to collect and organize information on a specific topic from multiple sources to build a complete picture.

5.2. Integrated Processing of Multimodal Data

Open Deep Research does more than just search web text: by integrating and processing data of different types—text, images, and audio—it can produce richer insights.
It extracts features from each type of data, and after integration, generates the final insights.

def integrate_multimodal_data(text_data, image_data, audio_data):
    text_features = self.text_processor.extract_features(text_data)
    visual_features = self.visual_processor.process_images(image_data)
    audio_features = self.audio_processor.analyze_audio(audio_data)
    
    integrated_features = self.feature_integrator.combine_features(
        text_features,
        visual_features,
        audio_features
    )
    
    return self.analyzer.generate_insights(integrated_features)

The integrate_multimodal_data function provides key functionality for integrating different types of data (text, images, audio) to perform comprehensive analysis.

The main purpose of this function is to combine information from multiple modalities (data types) in a meaningful way and analyze their features. Specifically, it first extracts linguistic features from text data, visual features from images, and acoustic features from audio, each with a dedicated processor. These different kinds of features are processed in ways specialized to each modality.

Next, it integrates these different features using feature_integrator. This integration process means more than simple concatenation: it takes into account the interrelationships and complementary relationships between modalities. For example, it becomes possible to check the consistency between what the text states and the visual information the image shows, or to relate the tone of the audio to the emotional content of the text.

Finally, the integrated features are passed to an analyzer to generate the final insights. At this stage, information from multiple modalities is interpreted holistically, enabling deeper understanding and new discoveries.

This kind of multimodal integration approach is especially important in areas such as sentiment analysis, content understanding, and anomaly detection. It enables the understanding of subtle nuances and context that are easily missed with a single data type, providing more accurate and reliable analysis results. We are also working hard on this modality-integration technology in the AI humans and digital humans we develop.

5.3. Time-Series Data Analysis and Tracking

By tracking changes to a target topic over time, it is possible to grasp trends from the past to the present. A mechanism for extracting particularly important points of change is implemented.

class TemporalAnalyzer:
    def analyze_temporal_changes(self, topic: str, start_date: str, end_date: str):
        timeline = []
        current_date = start_date
        
        while current_date <= end_date:
            snapshot = self.archive_tool.get_snapshot(topic, current_date)
            
            changes = self.change_detector.analyze(
                previous_snapshot=timeline[-1] if timeline else None,
                current_snapshot=snapshot
            )
            
            if changes.is_significant():
                timeline.append({
                    'date': current_date,
                    'snapshot': snapshot,
                    'changes': changes.get_description()
                })
            
            current_date = self.increment_date(current_date)
        
        return self.summarize_timeline(timeline)

Here, the system first performs sequential analysis over the period from the specified start date to the end date. At each point in time, it uses archive_tool to retrieve a snapshot of the topic (its state at that time). This could be, for example, a past version of a web page or database records at a specific point in time.

Each retrieved snapshot is compared with the previous one using change_detector. This comparison detects changes between the two points in time and evaluates their significance—for example, substantial rewrites of text, additions or deletions of important information, or notable shifts in numerical data.

When a significant change is detected (when changes.is_significant() returns True), information about the change is recorded on the timeline. Each record includes the date, the snapshot at that time, and a description of the detected change. This makes it possible to track the key points in a topic's evolution over time.

Finally, the summarize_timeline method summarizes the entire timeline, presenting the topic's evolution over time in an easily digestible form. This technique is particularly useful for analyzing information that changes over time, such as the development of news stories, a company's product development history, or the course of policy changes. By extracting only the important change points from large volumes of time-series data, it enables efficient understanding of the information.

5.4. Building and Using Knowledge Graphs

To visually grasp the relationships among the collected pieces of information, the system implements functionality to structure them as a knowledge graph.
By representing relationships between entities on a graph, new insights can be obtained.

class KnowledgeGraphBuilder:
    def build_knowledge_graph(self, research_data):
        graph = nx.DiGraph()
        
        for item in research_data:
            entities = self.entity_extractor.extract(item.content)
            relationships = self.relationship_analyzer.analyze(entities)
            
            for entity in entities:
                graph.add_node(entity.id, 
                             type=entity.type,
                             properties=entity.properties)
            
            for rel in relationships:
                graph.add_edge(rel.source, 
                             rel.target,
                             type=rel.type,
                             properties=rel.properties)
        
        return self.optimize_graph_structure(graph)

5.5. Advanced Information Verification System

To evaluate the reliability of collected information from multiple angles, a system combining several verification techniques is implemented.
Through source evaluation and cross-reference checks, it aims to deliver highly accurate information.

class InformationVerifier:
    def __init__(self, model: Model):
        self.model = model
        self.fact_checker = FactCheckingTool()
        self.source_analyzer = SourceAnalyzer()
        self.cross_referencer = CrossReferenceSystem()

    def verify_information(self, content: str, sources: List[str]) -> VerificationResult:
        source_credibility = self.source_analyzer.evaluate_sources(sources)
        cross_references = self.cross_referencer.find_corroborating_sources(content)
        fact_check_results = self.fact_checker.verify_claims(content)
        verification_summary = self.integrate_verification_results(
            source_credibility,
            cross_references,
            fact_check_results
        )
        
        return self.generate_verification_report(verification_summary)

The main purpose of KnowledgeGraphBuilder is to systematically organize information collected from the web and build it into an interconnected knowledge graph.

Specifically, the data gathered through web research includes the following.

  • Web search results
  • Web page content
  • News articles
  • Social media posts
  • Histories of archived web pages

For example, when you run a web search on a specific topic and collect information from multiple web pages, the build_knowledge_graph method will

  • Extract important concepts and terms (entities) from each web page
  • Analyze the relationships among them (e.g., one web page references another, or pages offer different perspectives on the same topic)
  • Structure this information as a directed graph

Building a knowledge graph in this way organizes large amounts of web information and clarifies the relationships among pieces of information, enabling more effective understanding and use.


6. System Evaluation, Search, and Report Generation

This section covers overall system evaluation, search optimization, report generation, and operational monitoring.

6.1. System Evaluation and Performance Analysis

To evaluate system performance from multiple angles, mechanisms are implemented to measure various metrics such as response speed, accuracy, and resource usage.

6.2. Advanced Search Optimization

Advanced search optimization algorithms are implemented to support efficient research, including semantic analysis of search queries, optimization of search scope, and planning of parallel search strategies.

6.3. Report Generation System

To effectively summarize research results and output them as clear reports, the system implements features such as data visualization, citation management, and report structure generation.

6.4. Production Operation and Monitoring

For stable operation, a monitoring system is implemented that collects various metrics and performs performance analysis, anomaly detection, resource optimization, and logging.


7. Conclusion and Outlook

Now, let's wrap up!

OpenDeepResearch appeared just one day after the announcement of GPT Deep Research. Yet as the code makes clear, it is not a mere aggregation of search results like RAG—it makes generous use of the components required of a research-oriented agent. Development toward further feature expansion and performance improvements will likely continue.

Many improvements can be expected: more advanced natural language understanding (in particular, for Japanese support, using an engine specialized for Japanese expressions such as BERT could further improve insight extraction), stronger multimodal data integration, better real-time performance, improved scalability, and an optimized user interface. We will probably see many custom Deep Research systems built on this foundation!

Thank you very much for reading this article to the end. At Qualiteg, we provide our own AI services, along with cutting-edge expertise in generative AI—including the Deep Research and LLM technologies introduced today—and training and consulting on creating new AI-driven businesses. If you are interested, or if you have any specific needs, please feel free to contact us through the inquiry form here.

We also offer a popular workshop for those who want to master the steps of new business creation. The training focuses on having each participant think about the business from an executive's perspective, and the content is designed not only for planning staff but also for their counterpart engineers, designers, and marketers.


navigation

Read more