How to Customize Research Brief Generation from User Messages in Open Deep Research

You can customize the research brief generation in the Open Deep Research agent by modifying the prompt template in src/open_deep_research/prompts.py, swapping prompts at runtime within the write_research_brief node, adjusting model configuration settings, or post-processing the output before it enters the graph state.

The Open Deep Research agent converts conversational user messages into structured research directives through a specialized LangGraph workflow. When you need to tailor how the system interprets user intent, enforces formatting constraints, or selects models for this transformation, you must customize the research brief generation pipeline that transforms state["messages"] into the state["research_brief"] field.

Understanding the Research Brief Generation Flow

The brief generation occurs in the write_research_brief node defined in src/open_deep_research/deep_researcher.py. According to the langchain-ai/open_deep_research source code, the node executes four distinct operations:

  1. Collects message history from state["messages"] to establish conversational context.
  2. Formats a prompt using transform_messages_into_research_topic_prompt (located in src/open_deep_research/prompts.py), which instructs the LLM to distill the chat into a concrete research question.
  3. Invokes the research model (configurable_model) with a structured output schema called ResearchQuestion, expecting a single field named research_brief.
  4. Persists the result into the graph state at state["research_brief"], making it available to the supervisor node for downstream research orchestration.

Because the brief derives entirely from a prompt template and model invocation, you have four distinct extension points for customization.

Modifying the Prompt Template

The most direct way to customize research brief generation is to edit the transform_messages_into_research_topic_prompt variable in src/open_deep_research/prompts.py. This string template accepts {messages} and {date} placeholders and dictates tone, format, and constraints.

To enforce a specific output structure—such as requiring Markdown headings or bullet lists—modify the template definition:


# src/open_deep_research/prompts.py

transform_messages_into_research_topic_prompt = """You will be given a set of messages that have been exchanged so far between yourself and the user.
Your job is to translate these messages into a concise research brief that will guide the subsequent research.

**Requirements**
- Begin the brief with a level-2 Markdown heading: `## Research Brief`

- Limit the brief to *no more than 150 words*.
- Preserve any user-specified constraints (e.g., preferred sources, language).

The messages that have been exchanged so far between yourself and the user are:
<Messages>
{messages}
</Messages>

Today's date is {date}.

Return **only** the brief text, without any additional explanation.
"""

After restarting the agent, the write_research_brief node automatically uses this updated template, producing briefs that follow your new formatting rules.

Swapping the Prompt at Runtime

For dynamic customization without modifying source files, override the prompt within the write_research_brief function in src/open_deep_research/deep_researcher.py. This approach lets you load templates from external files or environment variables based on runtime conditions.


# src/open_deep_research/deep_researcher.py

async def write_research_brief(state, config):
    # ... existing setup code ...

    
    # Load a custom template from a file or environment variable

    custom_prompt = Path("custom_prompt.txt").read_text()
    prompt_content = custom_prompt.format(
        messages=get_buffer_string(state.get("messages", [])),
        date=get_today_str()
    )
    
    # Invoke model with custom prompt

    response = await research_model.ainvoke([
        SystemMessage(content=prompt_content)
    ])
    return {"research_brief": response.research_brief}

This method is ideal for multi-tenant deployments where different users require distinct brief formats.

Adjusting Model Configuration

You can change which model generates the brief—or its generation parameters—via src/open_deep_research/configuration.py. The Configuration class exposes fields that the write_research_brief node uses to initialize the configurable_model.


# src/open_deep_research/configuration.py

class Configuration(BaseSettings):
    research_model: str = "gpt-4o-mini"   # Change to Claude, Gemini, etc.

    research_model_max_tokens: int = 1024
    research_model_temperature: float = 0.2

Adjusting these values alters the brief's creativity, length, and reasoning characteristics without changing the prompt logic.

Post-Processing the Output

To apply additional transformations—such as adding metadata tags, trimming whitespace, or injecting citations—modify the write_research_brief function after the model invocation but before returning the state update:


# src/open_deep_research/deep_researcher.py

async def write_research_brief(state, config):
    # ... prompt setup and invocation ...

    response = await research_model.ainvoke([...])
    
    # Post-process the generated brief

    processed_brief = response.research_brief.strip()
    processed_brief = f"[Generated on {get_today_str()}]\n\n{processed_brief}"
    
    return {"research_brief": processed_brief}

This technique allows you to enforce length constraints programmatically or append system metadata that the raw LLM output might omit.

Key Files for Customization

File Role Key Component
src/open_deep_research/prompts.py Stores LLM prompt templates transform_messages_into_research_topic_prompt
src/open_deep_research/deep_researcher.py Implements LangGraph nodes write_research_brief function
src/open_deep_research/state.py Defines graph state schema research_brief field
src/open_deep_research/configuration.py Runtime model settings Configuration class fields

Summary

  • The research brief is generated in the write_research_brief node within src/open_deep_research/deep_researcher.py using the transform_messages_into_research_topic_prompt template.
  • Edit src/open_deep_research/prompts.py to permanently change formatting instructions, length constraints, or tone requirements.
  • Override prompts at runtime in write_research_brief to support dynamic or user-specific brief formats.
  • Adjust model selection and parameters in src/open_deep_research/configuration.py to change generation quality without code modifications.
  • Post-process the response.research_brief output before returning it to the state to inject metadata or enforce programmatic constraints.

Frequently Asked Questions

Where exactly is the research brief generated in the codebase?

The brief is generated in the write_research_brief async function inside src/open_deep_research/deep_researcher.py. This LangGraph node extracts messages from the state, formats them using the prompt template, and invokes the configured research model with the ResearchQuestion structured output schema.

What is the structure of the research brief output?

The brief is stored as a string in state["research_brief"]. The LLM is constrained by the ResearchQuestion Pydantic model (referenced in deep_researcher.py), which expects a single field named research_brief containing the distilled research directive. You can enforce specific formats—such as Markdown headings or bullet lists—by editing the prompt template instructions.

Can I use a different model specifically for brief generation?

Yes. The model used for brief generation is controlled by the research_model field in src/open_deep_research/configuration.py. Changing this configuration value switches the LLM used in the write_research_brief node. You can also adjust research_model_max_tokens and temperature settings to fine-tune output characteristics.

How do I access the generated brief in downstream research nodes?

The brief is automatically persisted to the graph state at the key research_brief (defined in src/open_deep_research/state.py). Subsequent nodes, including the supervisor, access this value via state["research_brief"] to guide query generation, source selection, and synthesis operations.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →