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:
- Collects message history from
state["messages"]to establish conversational context. - Formats a prompt using
transform_messages_into_research_topic_prompt(located insrc/open_deep_research/prompts.py), which instructs the LLM to distill the chat into a concrete research question. - Invokes the research model (
configurable_model) with a structured output schema calledResearchQuestion, expecting a single field namedresearch_brief. - 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_briefnode withinsrc/open_deep_research/deep_researcher.pyusing thetransform_messages_into_research_topic_prompttemplate. - Edit
src/open_deep_research/prompts.pyto permanently change formatting instructions, length constraints, or tone requirements. - Override prompts at runtime in
write_research_briefto support dynamic or user-specific brief formats. - Adjust model selection and parameters in
src/open_deep_research/configuration.pyto change generation quality without code modifications. - Post-process the
response.research_briefoutput 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →