# Prompt engineering

Enhance results with prompt engineering strategies.

With the OpenAI API, you can use a
[large language model](https://platform.openai.com/docs/models) to generate text
from a prompt, as you might using ChatGPT. Models can generate almost any kind
of text responseâlike code, mathematical equations, structured JSON data, or
human-like prose.

Here's a simple example using the
[Responses API](https://platform.openai.com/docs/api-reference/responses).

```javascript
import OpenAI from "openai";
const client = new OpenAI();

const response = await client.responses.create({
  model: "gpt-5",
  input: "Write a one-sentence bedtime story about a unicorn.",
});

console.log(response.output_text);
```

```python
from openai import OpenAI
client = OpenAI()

response = client.responses.create(
    model="gpt-5",
    input="Write a one-sentence bedtime story about a unicorn."
)

print(response.output_text)
```

```bash
curl "https://api.openai.com/v1/responses" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $OPENAI_API_KEY" \
    -d '{
        "model": "gpt-5",
        "input": "Write a one-sentence bedtime story about a unicorn."
    }'
```

An array of content generated by the model is in the `output` property of the
response. In this simple example, we have just one output which looks like this:

```json
[
  {
    "id": "msg_67b73f697ba4819183a15cc17d011509",
    "type": "message",
    "role": "assistant",
    "content": [
      {
        "type": "output_text",
        "text": "Under the soft glow of the moon, Luna the unicorn danced through fields of twinkling stardust, leaving trails of dreams for every child asleep.",
        "annotations": []
      }
    ]
  }
]
```

**The `output` array often has more than one item in it!** It can contain tool
calls, data about reasoning tokens generated by
[reasoning models](https://platform.openai.com/docs/guides/reasoning), and other
items. It is not safe to assume that the model's text output is present at
`output[0].content[0].text`.

Some of our [official SDKs](https://platform.openai.com/docs/libraries) include
an `output_text` property on model responses for convenience, which aggregates
all text outputs from the model into a single string. This may be useful as a
shortcut to access text output from the model.

In addition to plain text, you can also have the model return structured data in
JSON format - this feature is called
[Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs).

## Choosing a model

A key choice to make when generating content through the API is which model you
want to use - the `model` parameter of the code samples above.
[You can find a full listing of available models here](https://platform.openai.com/docs/models).
Here are a few factors to consider when choosing a model for text generation.

- **[Reasoning models](https://platform.openai.com/docs/guides/reasoning)**
  generate an internal chain of thought to analyze the input prompt, and excel
  at understanding complex tasks and multi-step planning. They are also
  generally slower and more expensive to use than GPT models.
- **GPT models** are fast, cost-efficient, and highly intelligent, but benefit
  from more explicit instructions around how to accomplish tasks.
- **Large and small (mini or nano) models** offer trade-offs for speed, cost,
  and intelligence. Large models are more effective at understanding prompts and
  solving problems across domains, while small models are generally faster and
  cheaper to use.

When in doubt, [gpt-4.1](https://platform.openai.com/docs/models/gpt-4.1) offers
a solid combination of intelligence, speed, and cost effectiveness.

## Prompt engineering

**Prompt engineering** is the process of writing effective instructions for a
model, such that it consistently generates content that meets your requirements.

Because the content generated from a model is non-deterministic, prompting to
get your desired output is a mix of art and science. However, you can apply
techniques and best practices to get good results consistently.

Some prompt engineering techniques work with every model, like using message
roles. But different model types (like reasoning versus GPT models) might need
to be prompted differently to produce the best results. Even different snapshots
of models within the same family could produce different results. So as you
build more complex applications, we strongly recommend:

- Pinning your production applications to specific
  [model snapshots](https://platform.openai.com/docs/models) (like
  `gpt-4.1-2025-04-14` for example) to ensure consistent behavior
- Building [evals](https://platform.openai.com/docs/guides/evals) that measure
  the behavior of your prompts so you can monitor prompt performance as you
  iterate, or when you change and upgrade model versions

Now, let's examine some tools and techniques available to you to construct
prompts.

## Message roles and instruction following

You can provide instructions to the model with differing levels of authority
using the `instructions` API parameter or **message roles**.

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.

```javascript
import OpenAI from "openai";
const client = new OpenAI();

const response = await client.responses.create({
  model: "gpt-5",
  reasoning: { effort: "low" },
  instructions: "Talk like a pirate.",
  input: "Are semicolons optional in JavaScript?",
});

console.log(response.output_text);
```

```python
from openai import OpenAI
client = OpenAI()

response = client.responses.create(
    model="gpt-5",
    reasoning={"effort": "low"},
    instructions="Talk like a pirate.",
    input="Are semicolons optional in JavaScript?",
)

print(response.output_text)
```

```bash
curl "https://api.openai.com/v1/responses" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $OPENAI_API_KEY" \
    -d '{
        "model": "gpt-5",
        "reasoning": {"effort": "low"},
        "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:

```javascript
import OpenAI from "openai";
const client = new OpenAI();

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

console.log(response.output_text);
```

```python
from openai import OpenAI
client = OpenAI()

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

print(response.output_text)
```

```bash
curl "https://api.openai.com/v1/responses" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $OPENAI_API_KEY" \
    -d '{
        "model": "gpt-5",
        "reasoning": {"effort": "low"},
        "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](https://platform.openai.com/docs/guides/conversation-state)
with the `previous_response_id` parameter, the `instructions` used on previous
turns will not be present in the context.

The OpenAI model spec describes how our models give different levels of priority
to messages with different roles.

| `developer`                                                                                                        | `user`                                                                                             | `assistant`                                                |
| ------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| `developer` messages are instructions provided by the application developer, prioritized ahead of `user` messages. | `user` messages are instructions provided by an end user, prioritized behind `developer` messages. | Messages generated by the model have the `assistant` role. |

A multi-turn conversation may consist of several messages of these types, along
with other content types provided by both you and the model. Learn more about
[managing conversation state here](https://platform.openai.com/docs/guides/conversation-state).

You could think about `developer` and `user` messages like a function and its
arguments in a programming language.

- `developer` messages provide the system's rules and business logic, like a
  function definition.
- `user` messages provide inputs and configuration to which the `developer`
  message instructions are applied, like arguments to a function.

## Reusable prompts

In the OpenAI dashboard, you can develop reusable [prompts](/chat/edit) that you
can use in API requests, rather than specifying the content of prompts in code.
This way, you can more easily build and evaluate your prompts, and deploy
improved versions of your prompts without changing your integration code.

Here's how it works:

1.  **Create a reusable prompt** in the [dashboard](/chat/edit) with
    placeholders like `{{customer_name}}`.
2.  **Use the prompt** in your API request with the `prompt` parameter. The
    prompt parameter object has three properties you can configure:
    - `id` â Unique identifier of your prompt, found in the dashboard
    - `version` â A specific version of your prompt (defaults to the "current"
      version as specified in the dashboard)
    - `variables` â A map of values to substitute in for variables in your
      prompt. The substitution values can either be strings, or other Response
      input message types like `input_image` or `input_file`.
      [See the full API reference](https://platform.openai.com/docs/api-reference/responses/create).

String variables

```javascript
import OpenAI from "openai";
const client = new OpenAI();

const response = await client.responses.create({
  model: "gpt-5",
  prompt: {
    id: "pmpt_abc123",
    version: "2",
    variables: {
      customer_name: "Jane Doe",
      product: "40oz juice box",
    },
  },
});

console.log(response.output_text);
```

```python
from openai import OpenAI
client = OpenAI()

response = client.responses.create(
    model="gpt-5",
    prompt={
        "id": "pmpt_abc123",
        "version": "2",
        "variables": {
            "customer_name": "Jane Doe",
            "product": "40oz juice box"
        }
    }
)

print(response.output_text)
```

```bash
curl https://api.openai.com/v1/responses \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5",
    "prompt": {
      "id": "pmpt_abc123",
      "version": "2",
      "variables": {
        "customer_name": "Jane Doe",
        "product": "40oz juice box"
      }
    }
  }'
```

Variables with file input

```javascript
import fs from "fs";
import OpenAI from "openai";
const client = new OpenAI();

// Upload a PDF we will reference in the prompt variables
const file = await client.files.create({
  file: fs.createReadStream("draconomicon.pdf"),
  purpose: "user_data",
});

const response = await client.responses.create({
  model: "gpt-5",
  prompt: {
    id: "pmpt_abc123",
    variables: {
      topic: "Dragons",
      reference_pdf: {
        type: "input_file",
        file_id: file.id,
      },
    },
  },
});

console.log(response.output_text);
```

```python
import openai, pathlib

client = openai.OpenAI()