[Roadmap] Implement: Allow users to customize full system prompt #11

Closed
opened 2026-02-16 08:19:25 -05:00 by yindo · 3 comments
Owner

Originally created by @shpeedle on GitHub (Aug 10, 2025).

[Roadmap] Allow users to customize full system prompt

Summary

The create_deep_agent method currently allows for an instructions parameter. That parameter is then concatenated on top of the base_prompt in the create_deep_agent method here.

If we allow the ability to customize this base prompt, then the full system prompt will be customizable. Developers will be able to provide a custom prompt for write_todos and the task tool task and any other future standard tools.

Next, we could provide support to pass in a customized write_todos tool and or a custom task tool.

Motivation

Being able to override the base_prompt, we can provide instruction to have our deepagent use tools we define and pass in, to reduce context usage. We can also customize the write_todos prompt, although I think the default one is pretty solid for now and have not experimented with customizing that yet.

Proposed Approach

Extract the base prompt into configurable parts

BASE_TOOLS_PROMPT = """You have access to a number of standard tools

## `write_todos`

{write_todos_prompt}

It is critical that you mark todos as completed as soon as you are done with a task. Do not batch up multiple tasks before marking them as completed.
## `task`

{task_assignments_list}."""

DETAULT_WRITE_TOOLS_PROMPT = """You have access to the `write_todos` tools to help you manage and plan tasks. Use these tools VERY frequently to ensure that you are tracking your tasks and giving the user visibility into your progress.
These tools are also EXTREMELY helpful for planning tasks, and for breaking down larger complex tasks into smaller steps. If you do not use this tool when planning, you may forget to do important tasks - and that is unacceptable."""

DEFAULT_TASK_ASSIGNMENTS = ["- When doing web search, prefer to use the `task` tool in order to reduce context usage."]

Add a base_prompt_override to the create_deep_agent method:

class BasePromptOverride(TypedDict):
    write_todos_prompt: str
    task_assignments: list[str]


def _make_base_prompt(base_prompt_override: Optional[BasePromptOverride]) -> str:
    _validate_base_prompt_override(base_prompt_override)

    write_tools_prompt = (
        base_prompt_override['write_todos_prompt']
        if base_prompt_override
        and 'write_todos_prompt' in base_prompt_override
        and base_prompt_override['write_todos_prompt']
        else DETAULT_WRITE_TOOLS_PROMPT
    )
    task_assignmnets_list = (
        base_prompt_override['task_assignments']
        if base_prompt_override
        and 'task_assignments' in base_prompt_override
        and base_prompt_override['task_assignments']
        else DEFAULT_TASK_ASSIGNMENTS
    )

    base_prompt = BASE_TOOLS_PROMPT.format(
        write_todos_prompt=write_tools_prompt,
        task_assignments_list="\n".join(task_assignmnets_list),
    )
    return base_prompt


def create_deep_agent(
    tools: Sequence[Union[BaseTool, Callable, dict[str, Any]]],
    instructions: str,
    base_prompt_override: Optional[BasePromptOverride] = None,
    model: Optional[Union[str, LanguageModelLike]] = None,
    subagents: list[SubAgent] = None,
    state_schema: Optional[StateSchemaType] = None,
):
    """Create a deep agent.

    This agent will by default have access to a tool to write todos (write_todos),
    and four file editing tools: write_file, ls, read_file, edit_file.

    Args:
        tools: The additional tools the agent should have access to.
        instructions: Additional instructions for the agent. Will be included in
            the system prompt.
        base_prompt_override: Optional dict to override base prompt components.
            Should have the following keys:
                - 'write_tools_prompt': str, prompt content for write tools.
                - 'task_assignments': list of str, task assignment instructions.
            If not provided, defaults will be used.
        model: The model to use.
        subagents: The subagents to use. Each subagent should be a dictionary with the
            following keys:
                - `name`
                - `description` (used by the main agent to decide whether to call the sub agent)
                - `prompt` (used as the system prompt in the subagent)
                - (optional) `tools`
        state_schema: The schema of the deep agent. Should subclass from DeepAgentState.
    """

    base_prompt = _make_base_prompt(base_prompt_override)
    prompt = instructions + base_prompt
    built_in_tools = [write_todos, write_file, read_file, ls, edit_file]
    if model is None:
        model = get_default_model()
    state_schema = state_schema or DeepAgentState
    task_tool = _create_task_tool(
        list(tools) + built_in_tools,
        instructions,
        subagents or [],
        model,
        state_schema
    )
    all_tools = built_in_tools + list(tools) + [task_tool]
    return create_react_agent(
        model,
        prompt=prompt,
        tools=all_tools,
        state_schema=state_schema,
    )

Example Usage

agent = create_deep_agent(
    [internet_search],
    research_instructions,
    base_prompt_override={
        'write_todos_prompt': "my write todos prompt",
        'task_assignments': [
            "- my task assignment 1",
            "- my task assignment 2",
            "- my task assignment 3",
        ],
    },
    subagents=[critique_sub_agent, research_sub_agent],
).with_config({"recursion_limit": 100})
Originally created by @shpeedle on GitHub (Aug 10, 2025). # [Roadmap] Allow users to customize full system prompt ## Summary The `create_deep_agent` method currently allows for an `instructions` parameter. That parameter is then concatenated on top of the `base_prompt` in the `create_deep_agent` method [here](https://github.com/hwchase17/deepagents/blob/master/src/deepagents/graph.py#L14). If we allow the ability to customize this base prompt, then the full system prompt will be customizable. Developers will be able to provide a custom prompt for `write_todos` and the task tool `task` and any other future standard tools. Next, we could provide support to pass in a customized `write_todos` tool and or a custom `task` tool. ## Motivation Being able to override the `base_prompt`, we can provide instruction to have our deepagent use tools we define and pass in, to reduce context usage. We can also customize the `write_todos` prompt, although I think the default one is pretty solid for now and have not experimented with customizing that yet. ## Proposed Approach Extract the base prompt into configurable parts ```python BASE_TOOLS_PROMPT = """You have access to a number of standard tools ## `write_todos` {write_todos_prompt} It is critical that you mark todos as completed as soon as you are done with a task. Do not batch up multiple tasks before marking them as completed. ## `task` {task_assignments_list}.""" DETAULT_WRITE_TOOLS_PROMPT = """You have access to the `write_todos` tools to help you manage and plan tasks. Use these tools VERY frequently to ensure that you are tracking your tasks and giving the user visibility into your progress. These tools are also EXTREMELY helpful for planning tasks, and for breaking down larger complex tasks into smaller steps. If you do not use this tool when planning, you may forget to do important tasks - and that is unacceptable.""" DEFAULT_TASK_ASSIGNMENTS = ["- When doing web search, prefer to use the `task` tool in order to reduce context usage."] ``` Add a `base_prompt_override` to the `create_deep_agent` method: ```python class BasePromptOverride(TypedDict): write_todos_prompt: str task_assignments: list[str] def _make_base_prompt(base_prompt_override: Optional[BasePromptOverride]) -> str: _validate_base_prompt_override(base_prompt_override) write_tools_prompt = ( base_prompt_override['write_todos_prompt'] if base_prompt_override and 'write_todos_prompt' in base_prompt_override and base_prompt_override['write_todos_prompt'] else DETAULT_WRITE_TOOLS_PROMPT ) task_assignmnets_list = ( base_prompt_override['task_assignments'] if base_prompt_override and 'task_assignments' in base_prompt_override and base_prompt_override['task_assignments'] else DEFAULT_TASK_ASSIGNMENTS ) base_prompt = BASE_TOOLS_PROMPT.format( write_todos_prompt=write_tools_prompt, task_assignments_list="\n".join(task_assignmnets_list), ) return base_prompt def create_deep_agent( tools: Sequence[Union[BaseTool, Callable, dict[str, Any]]], instructions: str, base_prompt_override: Optional[BasePromptOverride] = None, model: Optional[Union[str, LanguageModelLike]] = None, subagents: list[SubAgent] = None, state_schema: Optional[StateSchemaType] = None, ): """Create a deep agent. This agent will by default have access to a tool to write todos (write_todos), and four file editing tools: write_file, ls, read_file, edit_file. Args: tools: The additional tools the agent should have access to. instructions: Additional instructions for the agent. Will be included in the system prompt. base_prompt_override: Optional dict to override base prompt components. Should have the following keys: - 'write_tools_prompt': str, prompt content for write tools. - 'task_assignments': list of str, task assignment instructions. If not provided, defaults will be used. model: The model to use. subagents: The subagents to use. Each subagent should be a dictionary with the following keys: - `name` - `description` (used by the main agent to decide whether to call the sub agent) - `prompt` (used as the system prompt in the subagent) - (optional) `tools` state_schema: The schema of the deep agent. Should subclass from DeepAgentState. """ base_prompt = _make_base_prompt(base_prompt_override) prompt = instructions + base_prompt built_in_tools = [write_todos, write_file, read_file, ls, edit_file] if model is None: model = get_default_model() state_schema = state_schema or DeepAgentState task_tool = _create_task_tool( list(tools) + built_in_tools, instructions, subagents or [], model, state_schema ) all_tools = built_in_tools + list(tools) + [task_tool] return create_react_agent( model, prompt=prompt, tools=all_tools, state_schema=state_schema, ) ``` ## Example Usage ```python agent = create_deep_agent( [internet_search], research_instructions, base_prompt_override={ 'write_todos_prompt': "my write todos prompt", 'task_assignments': [ "- my task assignment 1", "- my task assignment 2", "- my task assignment 3", ], }, subagents=[critique_sub_agent, research_sub_agent], ).with_config({"recursion_limit": 100}) ```
yindo closed this issue 2026-02-16 08:19:25 -05:00
Author
Owner

@hwchase17 commented on GitHub (Aug 13, 2025):

but now BASE_TOOLS_PROMPT isnt modifiable... what if i want to do that?

i like this direction, but id prefer an approach that easily made EVERYTHING modifiable in some manner...

@hwchase17 commented on GitHub (Aug 13, 2025): but now `BASE_TOOLS_PROMPT` isnt modifiable... what if i want to do that? i like this direction, but id prefer an approach that easily made EVERYTHING modifiable in some manner...
Author
Owner

@shpeedle commented on GitHub (Aug 22, 2025):

but now BASE_TOOLS_PROMPT isnt modifiable... what if i want to do that?

i like this direction, but id prefer an approach that easily made EVERYTHING modifiable in some manner...

@hwchase17 thanks for the feedback!

Sorry for the late reply. Agreed, I see what you mean.

So think with make the BASE_TOOLS_PROMPT fully modifiable we could have:

prompts.py:

BASE_TOOLS_PROMPT = """You have access to a number of standard tools

## `write_todos`

You have access to the `write_todos` tools to help you manage and plan tasks. Use these tools VERY frequently to ensure that you are tracking your tasks and giving the user visibility into your progress.
These tools are also EXTREMELY helpful for planning tasks, and for breaking down larger complex tasks into smaller steps. If you do not use this tool when planning, you may forget to do important tasks - and that is unacceptable.

It is critical that you mark todos as completed as soon as you are done with a task. Do not batch up multiple tasks before marking them as completed.
## `task`

- When doing web search, prefer to use the `task` tool in order to reduce context usage."""

Then graph.py:

def create_deep_agent(
    tools: Sequence[Union[BaseTool, Callable, dict[str, Any]]],
    instructions: str,
    base_prompt_override: Optional[str] = None,
    model: Optional[Union[str, LanguageModelLike]] = None,
    subagents: list[SubAgent] = None,
    state_schema: Optional[StateSchemaType] = None,
    config_schema: Optional[Type[Any]] = None,
    checkpointer: Optional[Checkpointer] = None,
):
    """Create a deep agent.

    This agent will by default have access to a tool to write todos (write_todos),
    and then four file editing tools: write_file, ls, read_file, edit_file.

    Args:
        tools: The additional tools the agent should have access to.
        instructions: The additional instructions the agent should have. Will go in
            the system prompt.
        base_prompt_override: If provided, this will override the default base prompt.
            If not provided, the default base prompt will be used. Your base prompt should include
            the instructions for the `write_todos` tool and the `task` tool.
        model: The model to use.
        subagents: The subagents to use. Each subagent should be a dictionary with the
            following keys:
                - `name`
                - `description` (used by the main agent to decide whether to call the sub agent)
                - `prompt` (used as the system prompt in the subagent)
                - (optional) `tools`
        state_schema: The schema of the deep agent. Should subclass from DeepAgentState
        config_schema: The schema of the deep agent.
        checkpointer: Optional checkpointer for persisting agent state between runs.
    """
    base_prompt = base_prompt_override or BASE_PROMPT
    prompt = instructions + base_prompt
    
    built_in_tools = [write_todos, write_file, read_file, ls, edit_file]
    if model is None:
        model = get_default_model()
    state_schema = state_schema or DeepAgentState
    task_tool = _create_task_tool(
        list(tools) + built_in_tools,
        instructions,
        subagents or [],
        model,
        state_schema
    )
    all_tools = built_in_tools + list(tools) + [task_tool]
    return create_react_agent(
        model,
        prompt=prompt,
        tools=all_tools,
        state_schema=state_schema,
        config_schema=config_schema,
        checkpointer=checkpointer,
    )

Then, I think we'd want to have the ability to override the built_in_tools and the task_tool that we instruct and describe in the base_prompt_override.

I'm still tinkering with that concept locally.

Is that more aligned with the goal of customizing the full system prompt?

@shpeedle commented on GitHub (Aug 22, 2025): > but now `BASE_TOOLS_PROMPT` isnt modifiable... what if i want to do that? > > i like this direction, but id prefer an approach that easily made EVERYTHING modifiable in some manner... @hwchase17 thanks for the feedback! Sorry for the late reply. Agreed, I see what you mean. So think with make the BASE_TOOLS_PROMPT fully modifiable we could have: `prompts.py`: ```python BASE_TOOLS_PROMPT = """You have access to a number of standard tools ## `write_todos` You have access to the `write_todos` tools to help you manage and plan tasks. Use these tools VERY frequently to ensure that you are tracking your tasks and giving the user visibility into your progress. These tools are also EXTREMELY helpful for planning tasks, and for breaking down larger complex tasks into smaller steps. If you do not use this tool when planning, you may forget to do important tasks - and that is unacceptable. It is critical that you mark todos as completed as soon as you are done with a task. Do not batch up multiple tasks before marking them as completed. ## `task` - When doing web search, prefer to use the `task` tool in order to reduce context usage.""" ``` Then `graph.py`: ```python def create_deep_agent( tools: Sequence[Union[BaseTool, Callable, dict[str, Any]]], instructions: str, base_prompt_override: Optional[str] = None, model: Optional[Union[str, LanguageModelLike]] = None, subagents: list[SubAgent] = None, state_schema: Optional[StateSchemaType] = None, config_schema: Optional[Type[Any]] = None, checkpointer: Optional[Checkpointer] = None, ): """Create a deep agent. This agent will by default have access to a tool to write todos (write_todos), and then four file editing tools: write_file, ls, read_file, edit_file. Args: tools: The additional tools the agent should have access to. instructions: The additional instructions the agent should have. Will go in the system prompt. base_prompt_override: If provided, this will override the default base prompt. If not provided, the default base prompt will be used. Your base prompt should include the instructions for the `write_todos` tool and the `task` tool. model: The model to use. subagents: The subagents to use. Each subagent should be a dictionary with the following keys: - `name` - `description` (used by the main agent to decide whether to call the sub agent) - `prompt` (used as the system prompt in the subagent) - (optional) `tools` state_schema: The schema of the deep agent. Should subclass from DeepAgentState config_schema: The schema of the deep agent. checkpointer: Optional checkpointer for persisting agent state between runs. """ base_prompt = base_prompt_override or BASE_PROMPT prompt = instructions + base_prompt built_in_tools = [write_todos, write_file, read_file, ls, edit_file] if model is None: model = get_default_model() state_schema = state_schema or DeepAgentState task_tool = _create_task_tool( list(tools) + built_in_tools, instructions, subagents or [], model, state_schema ) all_tools = built_in_tools + list(tools) + [task_tool] return create_react_agent( model, prompt=prompt, tools=all_tools, state_schema=state_schema, config_schema=config_schema, checkpointer=checkpointer, ) ``` Then, I think we'd want to have the ability to override the `built_in_tools` and the `task_tool` that we instruct and describe in the `base_prompt_override`. I'm still tinkering with that concept locally. Is that more aligned with the goal of customizing the full system prompt?
Author
Owner

@vtrivedy commented on GitHub (Dec 29, 2025):

closing as linked PR is closed

@vtrivedy commented on GitHub (Dec 29, 2025): closing as linked PR is closed
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/deepagents#11