Change an AI Model Without Redeploying

Use OpenRouter presets to switch your app's AI model without changing code.

Introduction

30 Second Summary

A small change to an AI assistant can produce a completely different answer. When its settings live inside your app, every experiment requires another code change.

In this project, you will move your AI configuration into an OpenRouter preset that a short script can call. A second run of the unchanged script proves that the dashboard update took effect.

What You'll Build

Picture an unchanged script printing a new style of reply seconds after you swap its model in a dashboard.

By the end of this project, you'll have:

  • A working AI script that calls a named preset. Its reply prints in your terminal.
  • A dashboard-controlled configuration where you can change the model. You can also update the system prompt without editing your script.
  • A verified activity history showing the model that served each request. You can also see the cost of each call.
  • Secret Mission: An optional challenge to push your skills further.

Are there any prerequisites?

You'll need an OpenRouter account plus an API key. You'll also need Python or Node with an HTTP client.

Before We Start

Changing a live model setting only proves something when your app can send a request before the change and after it.

Your browser gives you access to the OpenRouter dashboard.

Your local side needs Python 3. The Requests library gives your later script an HTTP client.

In this step, get ready to:
  • Prepare a browser tab for OpenRouter.
  • Verify that Python 3 is available in your terminal.
  • Prepare Requests for the project script.
Confirm your browser and terminal

The dashboard controls the remote preset. Your terminal runs the local script that uses it.

  • Open a new browser tab by pressing Cmd+T (macOS) or Ctrl+T (Windows).
  • Enter https://openrouter.ai in the address bar.
  • Press Enter to load the page.

You should see the OpenRouter website load in the new tab.

  • Open system search by pressing Cmd+Space (macOS) or the Windows key (Windows).
  • Enter terminal in system search.
  • Press Enter to open the matching terminal application.

You should now have the OpenRouter website in your browser. You should also have a terminal window ready for commands.

Check Python 3

The project script runs locally with Python. Checking the active major version prevents an older interpreter from causing confusing package errors.

  • Check the Python version available in your terminal by running this command:
python3 --version

What does this command check?

This command asks the active Python interpreter to print its version. The major version confirms whether the terminal can run this project's later script.

✔️ I see the required major version

That is your first setup check complete. Output that begins with Python followed by 3 confirms that your terminal has the required interpreter.

ⓧ I see an older major version

An older major version cannot run this project's Python script. The official installer adds a current Python 3 interpreter.

What to Expect From the Installer

Your operating system may show a permission prompt before the installer opens. The installer then guides you through its standard setup.

You should see the official downloads page for current Python releases.

  • Download the current Python 3 installer for your operating system.

Your browser should show the installer as a completed download.

  • Run the installer from your browser's downloads panel.
  • Approve the operating system permission request if one appears.

You should see the Python installer open.

  • Complete the installer using its default setup options.

You should see a completion screen when Python finishes installing.

  • Return to the terminal from earlier.
  • Confirm the new Python installation by running this command:
python3 --version

What does this second check prove?

The repeated version check confirms that your terminal can now find the newly installed interpreter. Output with major version 3 means Python is ready.

ⓧ Command not found

Your terminal cannot find a Python interpreter yet. The official installer adds Python 3 to your computer.

What to Expect From the Installer

Your operating system may show a permission prompt before the installer opens. The installer then guides you through its standard setup.

You should see the official downloads page for current Python releases.

  • Download the current Python 3 installer for your operating system.

Your browser should show the installer as a completed download.

  • Run the installer from your browser's downloads panel.
  • Approve the operating system permission request if one appears.

You should see the Python installer open.

  • Complete the installer using its default setup options.

You should see a completion screen when Python finishes installing.

  • Return to the terminal from earlier.
  • Confirm the Python installation by running this command:
python3 --version

What does this second check prove?

The repeated version check confirms that your terminal can now find the installed interpreter. Output with major version 3 means Python is ready.

Still Cannot Run Python?

Close the current terminal after installation. Open a fresh terminal so your operating system can refresh its available commands.

If the command still fails, confirm that the installer reached its completion screen.

Help me troubleshoot why my terminal cannot find Python after installation.

Install Requests

Requests handles the HTTP connection between your Python script and OpenRouter. Installing it now gives the later script everything it needs to send a request.

  • Install Requests in your terminal by running this command:
pip install requests

What does this command do?

The pip package installer downloads Requests with its required dependencies. Python can then import the library when your project script runs.

The terminal should finish with a successful installation message. A message explaining that the package is already installed also confirms that you can continue.

Requests Did Not Install?

If the terminal cannot find pip, close it after the Python installation. Open a fresh terminal before retrying the command.

If the download cannot start, confirm that your computer has an internet connection before retrying.

Help me troubleshoot why pip cannot install Requests.

Before you verify, what package details do you expect the terminal to return?

  • Confirm that pip can find the installed Requests package by running this command:
pip show requests

What does this final check prove?

This command reads the installed package metadata. Seeing the package details proves that pip can find Requests in your local Python environment.

You should see package information that includes the installed Requests version and its location. Your local toolkit is ready to support the project script.

No Requests Details?

Confirm that the installation command completed in the same terminal environment. Retry the installation if that earlier command stopped with an error.

Help me find why pip cannot show Requests after installation.

Your browser and local Python toolkit are ready. Next, you will create your OpenRouter account without writing any project code yet.

Create Your OpenRouter API Key

Every request in this project needs a secure way to identify your OpenRouter account. An API key provides that identity without exposing your account login.

You also need a clean Activity baseline before the first model call. This lets you prove later that every recorded request came from your script.

In this step, get ready to:
  • Create an OpenRouter account.
  • Create an API key for the project.
  • Confirm that the Activity page shows zero requests.
Set up your OpenRouter account

OpenRouter keeps API keys under your account. It also records your request history there.

You should see the API Keys page for your signed-in account. That account is now the home for the credential you use throughout this project.

Having trouble signing in?

  • Allow the authentication window if your browser blocks it.
  • Reload the API Keys page after completing account verification.

Ask for help with the exact point where the account flow stops: help me troubleshoot the OpenRouter account registration or sign-in flow.

Generate your OpenRouter API key

An API key is a bearer credential that authorizes future requests. Anyone who has the key can send requests through your account.

This credential appears in plaintext only once. The current terminal session gives it a temporary home outside your project files.

  • Use the key creation control on the API Keys page.
  • Enter NextWork Preset Demo as the key name.
  • Submit the form to create the key.
  • Copy the plaintext key when the one-time display appears.

The key is a live credential, so keep it out of screenshots. You place it only in an environment variable for the current terminal session.

The command differs between shell families. Use the tab that matches your terminal.

macOS

  • Replace sk-or-v1-YOUR-API-KEY in the command below with the key you copied.
  • Store the key in the current terminal session by running the edited command:
export OPENROUTER_API_KEY="sk-or-v1-YOUR-API-KEY"

What does this command do?

The export command adds your key to OPENROUTER_API_KEY for the current shell. Your later script can read the credential without storing it in a project file.

  • Confirm that the terminal returns to its prompt without an error.
  • Keep this terminal session open for the later steps.

Windows

  • Replace sk-or-v1-YOUR-API-KEY in the command below with the key you copied.
  • Store the key in the current PowerShell session by running the edited command:
$env:OPENROUTER_API_KEY="sk-or-v1-YOUR-API-KEY"

What does this command do?

The $env: prefix adds your key to OPENROUTER_API_KEY for the current PowerShell session. Your later script can read the credential without storing it in a project file.

  • Confirm that PowerShell returns to its prompt without an error.
  • Keep this PowerShell session open for the later steps.

Did the export command fail?

  • Use the tab that matches the shell running in your terminal.
  • Paste the key again if any characters were omitted.
  • Preserve the quotation marks around the key.

Share the shell name without sharing the credential when you ask for help with the environment variable.

  • Return to the OpenRouter API Keys page from earlier.
  • Dismiss the one-time key display.

You should see NextWork Preset Demo listed without its full secret value. Your project credential is ready without being stored in a project file.

Confirm your zero-request baseline

The Activity page is your audit trail for API usage. A clean baseline makes each later request easy to identify.

Before you check, do you expect the Activity page to contain a request?

You should see Requests at 0. This confirms that no model calls have been made from your new account.

That's your clean baseline confirmed. Any request that appears next has a clear starting point.

Your OpenRouter account is ready. Next, you'll turn the model configuration into a named preset.

Create an AI Preset

Your OpenRouter account is ready. Its Activity page still shows zero requests.

The next call needs a model choice plus behavior rules that can change without a code edit. An OpenRouter preset keeps that configuration in the dashboard under one reusable slug.

In this step, get ready to:
  • Open the preset editor in your OpenRouter dashboard.
  • Store an initial model plus a system prompt in a named preset.
  • Confirm the generated slug without making an AI request.
Open the preset editor

The preset editor gives your AI configuration a home outside your future script. This is where dashboard changes can reach every new request that uses the saved slug.

You're in the right place. The preset editor is ready to collect the configuration your future script will reuse.

Configure the model and prompt

The model determines which AI handles each request. The system prompt gives that model a standing instruction for every new response.

  • Enter nextwork-configurable-ai as the preset name.
  • Select openai/gpt-4o-mini as the default model.

The editor now shows your preset name. It also shows the selected model.

  • Enter You are a concise helpful assistant. Reply in one sentence. as the system prompt.
  • Save the preset using the save control in the preset editor.

That's the separation in place. Your future script's AI configuration now lives in the dashboard.

Preset Did Not Save?

  • Confirm that the preset name contains nextwork-configurable-ai.
  • Clear the model search if the picker has no matching result.
  • Search again using the complete model ID openai/gpt-4o-mini.

Ask for help with the values visible in your preset editor. Never include your API key when sharing the issue.

help me troubleshoot why my OpenRouter preset is not saving

Verify the saved preset

The generated slug is the stable reference your script will use. Recording it now keeps the next request tied to the preset you just saved.

Before you inspect the saved preset, consider whether its summary will match every value you entered.

  • Confirm that the saved preset name is nextwork-configurable-ai.
  • Confirm that the selected model is openai/gpt-4o-mini.
  • Confirm that the system prompt is You are a concise helpful assistant. Reply in one sentence..
  • Record the displayed preset slug here: your dashboard-generated preset slug.
  • Return to the Activity page from earlier to confirm that it still shows zero requests.

The saved preset shows nextwork-configurable-ai as its name. It shows openai/gpt-4o-mini as its model.

The full system prompt matches the text you entered. The page also shows the generated slug you recorded as your dashboard-generated preset slug.

The Activity page still shows zero requests. Creating a preset stores configuration without calling the model.

Your model configuration now lives in the dashboard. Next, you'll call it from a script using the slug you recorded.

Call Your Preset from Python

Your saved OpenRouter preset already holds the model choice and system prompt. That separation becomes useful when your application calls the preset instead of a direct model ID.

In this step, you will create a Python script that reads your existing API key from an environment variable. The script will send a message through your preset and print the reply.

In this step, get ready to:
  • Capture the dashboard-generated slug for your saved preset.
  • Create a Python script that calls the preset through the OpenRouter API.
  • Confirm the reply in your terminal and the request on the Activity page.
Capture your preset slug

The API model field uses @preset/ followed by the preset's dashboard-generated slug. You only need to capture the slug because the script supplies the prefix.

The slug is easy to confuse with the preset's display name. Focus on the generated slug shown for the saved preset.

  • Switch back to the saved preset page in the OpenRouter dashboard.
  • Copy the dashboard-generated slug shown for nextwork-configurable-ai.
  • Record the slug here: your dashboard-generated preset slug.

Why use the slug?

The slug gives your code a stable reference to the preset. OpenRouter resolves that reference to the model and system prompt saved in the dashboard.

Build the preset-backed script

The script keeps the secret in your terminal environment. It also leaves the direct model ID inside the preset.

  • Select the New File control in the code editor you use for Python.
  • Paste this code into the new file:
import os
import requests

# Read the key from the terminal environment to keep the secret out of this file.
api_key = os.environ["OPENROUTER_API_KEY"]

# Send the user message through the dashboard-managed preset.
response = requests.post(
    "https://openrouter.ai/api/v1/chat/completions",
    headers={
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    },
    json={
        "model": "@preset/[[PRESET_SLUG=\"your dashboard-generated preset slug\"]]",
        "messages": [
            {
                "role": "user",
                "content": "Explain why configuration presets are useful.",
            }
        ],
    },
)

# Print the assistant's text from the chat completion response.
print(response.json()["choices"][0]["message"]["content"])

What does this code do?

  • The os.environ lookup reads OPENROUTER_API_KEY from the current terminal session. The secret never enters preset_call.py.
  • The requests.post() call sends a JSON request to the OpenRouter chat-completions endpoint.
  • The model field points to your preset through the @preset/ prefix. The script contains no direct model ID.
  • The messages list carries the user question. The final line selects the assistant's text from the response.
  • Save the file as preset_call.py in the folder shown by your current terminal prompt.

You'll see preset_call.py in your editor's file list.

Can't find the script from your terminal?

Check that you saved preset_call.py in the folder shown by the current terminal prompt. Move the file into that folder if your editor saved it elsewhere.

Ask for help if the editor and terminal are pointing at different folders: help me locate preset_call.py from my current terminal folder.

✔️ Awesome, I've got everything!

Your saved preset_call.py reads the key from the environment. Its model field points to your preset slug.

ⓧ I'd like to double check the full code

import os
import requests

# Read the key from the terminal environment to keep the secret out of this file.
api_key = os.environ["OPENROUTER_API_KEY"]

# Send the user message through the dashboard-managed preset.
response = requests.post(
    "https://openrouter.ai/api/v1/chat/completions",
    headers={
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    },
    json={
        "model": "@preset/[[PRESET_SLUG=\"your dashboard-generated preset slug\"]]",
        "messages": [
            {
                "role": "user",
                "content": "Explain why configuration presets are useful.",
            }
        ],
    },
)

# Print the assistant's text from the chat completion response.
print(response.json()["choices"][0]["message"]["content"])
Run and confirm the request

This first run tests the full path from your script to the saved preset. The preset should control the reply without exposing its model configuration in the file.

Before you run it, what kind of reply do you expect from the preset's current instructions?

  • Send the first preset-backed request by running this command:
python3 preset_call.py

What should I see?

You should see a concise reply printed in your terminal. The reply should explain why configuration presets are useful in one sentence.

This proves that OpenRouter accepted your environment-based API key. It also proves that the preset reference resolved successfully.

No model reply in your terminal?

An error mentioning a missing environment variable means the current terminal session cannot access OPENROUTER_API_KEY. Return to the terminal session where you exported the key.

A request failure can also come from an incomplete preset reference. Confirm that the model value starts with @preset/ and ends with the exact dashboard-generated slug.

If the call still fails, help me troubleshoot my preset-backed OpenRouter request.

  • Switch back to the OpenRouter Activity page from earlier.
  • Refresh the Activity page.

You'll see a new request entry on the Activity page. That's the separation working: preset_call.py produced a reply without storing the API key or a direct model name.

Your Python script now calls a dashboard-managed preset and leaves the underlying model configuration outside the code. Next, you'll change that configuration while keeping this exact script untouched.

Update the Preset Configuration

Your first preset-backed request printed a reply in the terminal. That proves preset_call.py can reach OpenRouter through the saved slug.

A hard-coded AI model would force a code edit plus another deployment. Keeping configuration in the dashboard removes that delay.

In this step, you will update the dashboard configuration. You will rerun the untouched script to prove the same slug picks up the changes.

In this step, get ready to:
  • Swap the preset to google/gemini-2.5-flash.
  • Give the preset an enthusiastic two-sentence system prompt.
  • Rerun the untouched script to confirm its response changes.
Swap the preset model

The model selection lives inside the saved preset. Changing that selection affects new requests that use the same slug.

  • Return to the OpenRouter presets page from earlier.
  • Select the preset named nextwork-configurable-ai.
  • Open the model selector in the preset editor.
  • Search for google/gemini-2.5-flash.
  • Select google/gemini-2.5-flash from the results.

You should now see google/gemini-2.5-flash as the preset's selected model.

Rewrite the system prompt

A system prompt controls how the model approaches every request. This new prompt gives the response a visible tone plus a strict length.

  • Select the existing text in the preset editor's system prompt field.
  • Replace the selected text with You are an enthusiastic technical teacher. Reply in exactly two short sentences..
  • Keep the dashboard-generated slug unchanged.
  • Save the updated preset version with the editor's save control.

You should see google/gemini-2.5-flash as the model. You should also see the new two-sentence system prompt while the slug remains unchanged.

Why does the slug stay the same?

Saving an edit creates a new preset version. OpenRouter makes that version active for new requests.

The existing slug resolves to the active configuration. Your application can pick up model or prompt updates without a code change.

You have now changed the live configuration while leaving the application file untouched.

Rerun the unchanged script

The script still sends the same preset slug plus the same user message. A fresh request resolves the active dashboard configuration.

  • Keep preset_call.py untouched.
  • Switch back to the current terminal session.

Before you run it again, do you expect the reply to keep the first response's tone or length?

  • Run the exact same script again with this command:
python3 preset_call.py

What does this command prove?

  • The python3 command executes the same preset_call.py file as before.
  • OpenRouter resolves the same preset slug to its newly active configuration.
  • The new request still uses Explain why configuration presets are useful. as its user message.
  • Compare the new reply with the first terminal output from earlier.

You should see exactly two short sentences. The tone should sound noticeably more enthusiastic than the first reply.

That is the proof. Your application's behavior changed through dashboard configuration alone.

Reply still looks unchanged?

  • Confirm the preset editor shows google/gemini-2.5-flash as the selected model.
  • Confirm the system prompt field contains You are an enthusiastic technical teacher. Reply in exactly two short sentences..
  • Save the preset version with the editor's save control.
  • Run the same terminal command again to send a fresh request.

Help me diagnose why my unchanged preset-backed script still returns the earlier response style.

Your unchanged script has now produced replies under two configurations. Next, you will use the Activity page to trace what happened behind each request.

Review Model Usage and Cost

The unchanged preset_call.py script has now produced a different reply after your dashboard update. You still need a record that ties each reply to the configuration that served it.

The OpenRouter Activity page records the serving model for each request. It also records each request's cost.

In this step, get ready to:
  • Find both preset-backed requests on the Activity page.
  • Match each request to the model that served it.
  • Compare each request's cost.
Find both preset-backed requests

Each script run created its own Activity entry. Finding both entries gives you a record of the original preset configuration plus the updated configuration.

  • Switch back to the OpenRouter dashboard in your browser.
  • Select Activity from the dashboard navigation.
  • Refresh the Activity page to load the latest requests.

You should see both calls from your two runs of preset_call.py. The earlier entry represents the original preset configuration.

Why Activity Evidence Matters

Generated wording can vary between calls. The Activity record ties each individual request to the model that actually served it.

Compare the serving models and costs

Before you inspect the request details, which two serving models do you expect the calls to show?

  • Use the timestamps to identify the earlier request.
  • Read the serving model shown for the earlier request.
  • Read the cost shown for the earlier request.
  • Use the timestamps to identify the later request.
  • Read the serving model shown for the later request.
  • Read the cost shown for the later request.

The earlier request shows openai/gpt-4o-mini as its serving model. Its entry also displays the cost of that request.

The later request shows google/gemini-2.5-flash as its serving model. Its entry displays the cost of the second request.

You have the full proof now: the script stayed unchanged while the dashboard controlled the serving model. The Activity page gives you a cost trail for every call.

Can't See Both Calls?

  • Refresh the Activity page once more.
  • Confirm that you are viewing the same OpenRouter account that ran both requests.
  • Check that the Activity page has no filters hiding one of the calls.

Help me find both preset-backed requests on the OpenRouter Activity page.

Secret mission

Audit Your Preset for Configuration Drift

Complete a three-part configuration drift audit. Trace the unchanged script to the saved preset. Use Activity to prove which model served each call.

Clean Up Your Resources

Clean Up Your Resources

Your experiment is complete, so choose whether to keep, pause, or remove its access. Future OpenRouter model calls can create new usage costs.

Resources you used:

  • OpenRouter API key exposed as OPENROUTER_API_KEY in the current terminal session. The secret value is not stored in preset_call.py.

Your saved preset nextwork-configurable-ai plus preset_call.py remain reusable learning artifacts. Neither sends a request until you run the script.

Keep everything running

No action is needed. Choose this option if you plan to keep testing dashboard configuration changes.

  • Keep the API key active for future model calls.
  • Keep preset_call.py as the unchanged client for the preset.
  • Keep nextwork-configurable-ai saved in OpenRouter so you can change its model or system prompt later.

Your preset does not make requests by itself. Usage only changes when you run the script again.

Pause - I'll come back to this later

A pause removes the temporary credential from your current session. Your preset stays ready for another day.

  • Close the current terminal session so OPENROUTER_API_KEY is no longer available there.
  • Stop running preset_call.py until you are ready to resume.
  • Leave nextwork-configurable-ai saved in OpenRouter for your next session.

Your preset remains available. A future terminal session needs the API key exported again before the script can authenticate.

Delete - I don't want to use this again

Remove the API key if you do not plan to make more requests. Keep the preset plus the script as reusable examples from this project.

Your Preset Stays Saved

Deleting the API key removes the credential used by the script. Your nextwork-configurable-ai preset survives without it.

  • Switch back to the OpenRouter dashboard from earlier.
  • Use the dashboard account settings to return to the API key management page you used in Step 1.
  • Locate the API key you created for this project.
  • Use that key's deletion control to remove it.
  • Confirm the deletion when OpenRouter asks.
  • Refresh the API key management page to verify the deleted key is no longer listed.
  • Close the current terminal session to clear the now-invalid OPENROUTER_API_KEY value.

That cleanup closes the only active credential from this project. Your preset plus your script remain available as reusable examples.

Nice Work!

Nice Work!

Great work! You built a Python script that calls an OpenRouter preset while the dashboard controls its model configuration.

You've learned how to:

  • Protect your OpenRouter API key with the OPENROUTER_API_KEY environment variable.
  • Build a named preset that controls the model configuration used by preset_call.py.
  • Prove that dashboard edits change the response from the unchanged preset_call.py script. Trace each request to its serving model and cost on the Activity page.
  • Extend the preset-driven workflow through the optional Secret Mission.

Your app can now change AI behavior without a code edit or redeployment.

Ready to quiz yourself?