Response Endpoint: Instructions Parameter vs Developer Role

Hey all, I know this has been discussed and there is extensive information in the guides, but there seems to be some lack of clarity on instructions parameter vs developer role.

I’m trying to determine if I use the responses memory to create chains, how instructions and developer roles are prioritised. I’ve read the chain of command guide as well but there they use the term ‘instructions’ without mentioning whether its for the parameter or for developer roles so it’s confusing for me.

For the sake of clarity I will refer to ‘instructions parameter’ and ‘developer role inputs’.

What I know

  • I know that instruction parameter does not get carried forward; and that developer role inputs do.

What I don’t know
If I create a chain and how do instruction parameter and developer role input work together.

I’ve tested it with a bunch of different simple options. Ones that clearly compete (e.g. ‘all answers must be ‘apple’’ vs ‘all answers must be ‘pear’’) and those that can be used simultaneously (e.g. ‘all answers must be ‘apple’’ and 'all answers must be in ‘caps’)

When I use developer roles throughout it seems to react as you would expect. If it can satisfy both the current messages developer role input and the developer role input from chat history, it does so. And if they compete, it chooses the latest one. [This makes sense to me]

It’s when I throw in the instructions parameter that it doesn’t always behave as expected. E.g. if I put a developer role in the first message and then use an instruction in the third message I would expect that the instruction parameter takes precedence (regardless if it competes with previous developer role inputs). But it doesn’t seem to behave that way and when I test it I get mixed results, sometimes adhering to instructions, sometimes not.

E.g. I ran two calls: first one uses developer role input to say all answers must be ‘apple’. Second has an instruction parameter that all answers must be in ALL CAPS. I ran this and 8 times out of 10 it made sure the answer was ‘APPLE’ (correct). But there were at least 2 times that the answer was outputted as a lowercase ‘apple’.

If I put both in one message (instructions and developer role input) it seems to favour the developer role. Which is strange because there is a line in the guide somewhere that instructions parameter takes precedence over input. But then the example they show uses a simple input message and not roles - which could change things.

I know this might be overkill, but I feel like there is some nice synchronisation you can have by using developer role inputs for more project wide “instructions” while the instructions parameter can add some unique things for specific calls. But based on how I see irregularity here I’m not that comfortable trusting it. It might be that I’m making them too similar…like the fact that I told it to make the answer ‘pear’ and then tell it to put it in ALL CAPS could be seen as a competing statement even though I didn’t specify ‘pear’ needs to be lowercase, it would just copy it exactly as I had inputted it.

Sorry for the rambling, hopefully someone smarter than me can explain this to me :smiley: Thanks a lot!

  • GR

This is what the official documentation says:

The instructions parameter gives the model high-level instructions on how it should behave while generating a response, including tone, goals, and examples of correct responses. Any instructions provided this way will take priority over a prompt in the input parameter.

response = client.responses.create(
    model="gpt-4.1",
    instructions="Talk like a pirate.",
    input="Are semicolons optional in JavaScript?",
)

The example above is roughly equivalent to using the following input messages in the input array:

response = client.responses.create(
    model="gpt-4.1",
    input=[
        {
            "role": "developer",
            "content": "Talk like a pirate."
        },
        {
            "role": "user",
            "content": "Are semicolons optional in JavaScript?"
        }
    ]
)

Note that the instructions parameter only applies to the current response generation request. If you are managing conversation state with the previous_response_id parameter, the instructions used on previous turns will not be present in the context.

For more details:

Yes, I saw you post this on another thread relating to this as well. I have already read all the documentation regarding this, including what you have linked.

However, have you actually ran tests? Because I have - even though they are very simple - and my results are not conclusive.

For example. If you put an ‘instructions parameter’ with ‘developer role input’ simultaneously, I find it 100% obeys the developer role input over the instructions. Which is directly against what the documentation says above.

As I mention in my first message, that situation refers to the input parameter without roles and I’m wondering if that effects the situation.

I am trying to understand how can one use instructions parameters and developer rules togther and in what preference do they take. I’d appreciate responses that have been tested because these documentations are far from perfect regarding this situation.

E.g. Run this code:

response1 = client.responses.create(
    model="gpt-4.1-nano",  
    instructions="Always answer my questions with \"Apple\" and nothing else.",
    input=[
        {
            "role": "developer",
            "content": [
                {
                    "type": "input_text",
                    "text": "Always answer my questions with \"Pear\" and nothing else."
                }
            ]
        },
        {
            "role": "user",
            "content": [
                {
                    "type": "input_text",
                    "text": "Hi, how are you?"
                }
            ]
        }
    ],   
)

You will see the answer is ‘pear’. Which directly contradicts the documentation you are sending.

Yes, actually out of curiosity I did run a few tests.

The point here though is, when developing an app the end user should not have access to any form of developer roles, only user roles.

Why you would create conflicting instructions anywhere (in the same request)? As an exploration like you are doing now it is fine, but I think it doesnt have any practical use.

Yes, role takes priority over instructions. That’s all there is that is not in the docs (although it never said it is the same as the developer role, it says ‘roughtly’ the same, to not delve in too many complicated details.

TL;DR:

  • role takes priority over instructions
  • instructions apply only for the current request.
  • If you need permanent rules, use a developer role.

What is the big oversight here:

You can put a message with developer/system role name into “input” messages anywhere, either at the start, or adding more later.

Whether the models specifies that you must send “developer” or “system”, that is absolutely equivalent to the role name priority of “instructions”.

If you use “instructions”, you are placing an additional developer role message right before the one that comes from input (and any input message is persisted in a server-side response ID reuse). It is a per-call insertion.

  • An initial “system” that is part of the input, or a per-call “instructions” parameter: they are identical in internal name and identical in function.

You can choose one or the other. If you use both, “instructions” will be placed first, followed by input messages, and “instructions” can be changed per-call.

Any “instruction hierarchy” is out of your control - what that part of the model spec means is that your “developer” message, as the only name you can place internally on reasoning models, isn’t as important or respected as “system”, which is now reserved for OpenAI (because you are untrustworthy.)

I did find something interesting through looking into this though, which is due to the fact instructions disappear from the conversation in the next request, it explains a case where someone was failing to activate prompt caching when using the instructions parameter.

The point here though is, when developing an app the end user should not have access to any form of developer roles, only user roles.

I don’t agree with you here. It depends on your use case. We use a two-part developer prompt. The first part is a generic “hidden” developer prompt:

Identity

You are a valued assistant. Embody the role of the most qualified subject matter expert.

Instructions

  • Exclude personal ethics or morals unless explicitly relevant.
  • Provide a unique, non-repetitive response.
  • Address the core of each question to understand intent.
  • Break down complexities into smaller steps with clear reasoning.
  • Offer multiple viewpoints or solutions.
  • Do not exibit sycophancy. Unless otherwise specified, keep the tone serious and academic.
  • Ensure the response is in plain text without any Markdown or special formatting. Avoid bullet points, asterisks, hash marks, or any symbols that indicate structured text.
  • Ensure that the text is properly punctuated using the punctuation and grammatical rules of the language.
  • The response must be in the specified language.

The user does not see this part of the developer prompt. However, the user may want to format the output of the response. Example:

  • The response must be in standard paragraph format.
  • A heading must be created for each paragragh describing the paragrapgh.
  • Prepend headings only with large Roman numerals.
  • Separate the heading and paragraph with a blank line.
  • Create a title for the response above the first paragraph heading and separate with a blank line.

We allow users to optionally input a format prompt (shown above) which is then appended to the hidden developer prompt.

The user also has the option to export the response output to a PDF, Word, or RTF document.

Of course, this is best achieved with chat completions endpoints.

@jeffvpace It was in the context that the user doesn’t choose its role, and as the developer it doesn’t make sense to deliberately add a system role and a instruction parameter in the same single request.

But, it’s not that you can’t, it is your choice.

1 Like

…it doesn’t make sense to deliberately add a system role and a instruction parameter in the same single request.

I agree.

Thank you for the replies and delving deeper. While I don’t disagree that the use cases are niche, I find it important to understand the priorities and how to chain instructions whether they be developer roles or otherwise. But I agree with you, for the most part I will just use the Dev role.

In my specific use case I was trying to create a chain of messages, with a basic set of dev role instructions that applied to all, but then I wanted the option to be able to temporarily override those instructions for a specific call that I wanted to be able to recall the previous conversation, but ultimately I didn’t want it to be affected by the same dev role instructions that I had applied from the beginning…

I hope that makes sense. But either way, I think I’m satisfied.

Appreciate it!

1 Like

Ultimate control that you need is not using the “instruction” parameter, and not using the server side state by reusing a response ID.

Instead, send the complete messages you want as input each time.


Responses does not meet your need:

  • The “instructions” API parameter must be used on every call, otherwise it is simply not present and the AI loses its guidance.
  • A past “developer” role message used in the first input turn is permanently part of the chat history that is re-supplied.
  • You should not continue to send other “developer” messages as input messages with previous response ID use, as they will continue to be added conversationally after the most recent messages and AI response.

The closest you could do is not “override”, but “amend” or “prefix” an initial input system message sent at conversation instantiation with a cache-breaking occasional insertion of “instructions”, which is placed before all the role messages of a chat history.

Context to a non-reasoning model looks like:

system: (OpenAI’s jamming up the AI with unwanted things like a cutoff date, a message about vision being enabled, 250 tokens of vision prohibitions, etc)
system: (per-call instruction insertion by you)

Followed by input (messages)

Then messages with the exact roles you place, such as these you could send at the start of a session that persist with response_id:

system: “You are a helpful OpenAI API developer support agent, specializing in OpenAI product knowledge, and denying other uses of the AI assistant.”
system: (more unwanted OpenAI injection before the most recent user message, like “the user uploaded files” when file_search is active)
user: “What is an API?”