> ## Documentation Index
> Fetch the complete documentation index at: https://docs.decimal.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 3. Run it in your code

> Run order-support from your own code, in Colab or on your machine. Your code picks up the skill you changed on the page, and the next change reaches it with no redeploy.

So far this has been a made-up shop with stand-in tools, running on our servers. Next, you'll run the same agent from your own code, where its tools can reach your own systems.

> [card] [I already have an agent](https://docs.decimal.ai/quickstart.md)
>
> Add a registry skill to the agent you already run, and compare its answers with and without it.

> [card] [I don't have one yet](#run-it-in-colab)
>
> Keep going on this page and run `order-support`.

You need an API key for your SDK's model, and your copy of `order-support` from [Part 1's step 4](https://docs.decimal.ai/tutorials/support-agent/try-it.md). Parts 3 and 4 work on every tab below. Part 5's `evaluate()` takes OpenAI Agents SDK agents only, so choose that tab to run Part 5 as written.

## Run it in Colab

Nothing to install. Open the notebook for your SDK: [OpenAI Agents SDK](https://colab.research.google.com/github/decimal-labs/decimalai-python/blob/main/examples/tutorial/order_support_openai_agents.ipynb), [Claude Agent SDK](https://colab.research.google.com/github/decimal-labs/decimalai-python/blob/main/examples/tutorial/order_support_claude_agent_sdk.ipynb), [OpenAI SDK](https://colab.research.google.com/github/decimal-labs/decimalai-python/blob/main/examples/tutorial/order_support_openai.ipynb) or [Anthropic API](https://colab.research.google.com/github/decimal-labs/decimalai-python/blob/main/examples/tutorial/order_support_anthropic.ipynb). LangChain has no notebook yet: use the steps below.

Add two keys as Colab **Secrets** (the key icon in its sidebar): your model provider's key, and `DECIMAL_API_KEY`, which is filled in here when you're signed in:

Run the notebook. Then skip to [step 5](#5-change-the-fee-again).

## Or run it on your machine

You need Python 3.10 or later. Pick your SDK in step 1 and the tabs below follow it.

> [accordion] Let your coding agent set it up
>
> Paste this into Claude Code, Cursor or another coding agent:
>
> ```text theme={null}
> Set up the DecimalAI tutorial agent in a new folder called order-support.
>
> 1. Read https://docs.decimal.ai/tutorials/support-agent/run-it-in-your-code.md and follow steps 1 and 2, on the OpenAI Agents SDK tab.
> 2. Create a .env file with OPENAI_API_KEY= and DECIMAL_API_KEY= left blank, and ask me to fill them in. Don't ask me to paste keys into this chat.
> 3. Once I say they're in, run main.py and show me the reply.
> ```

## 1. Install

```bash theme={null}
mkdir order-support && cd order-support
python3 -m venv .venv && source .venv/bin/activate
```

Then install your tab's packages, and replace `sk-...` with your model provider's key:

```bash OpenAI Agents SDK theme={null}
pip install "decimalai[openai-agents]"
echo 'OPENAI_API_KEY=sk-...' >> .env
```

```bash Claude Agent SDK theme={null}
pip install "decimalai[claude-agent-sdk]"
echo 'ANTHROPIC_API_KEY=sk-ant-...' >> .env
```

```bash OpenAI SDK theme={null}
pip install "decimalai[openai]"
echo 'OPENAI_API_KEY=sk-...' >> .env
```

```bash Anthropic API theme={null}
pip install "decimalai[anthropic]"
echo 'ANTHROPIC_API_KEY=sk-ant-...' >> .env
```

```bash LangChain theme={null}
pip install "decimalai[langchain]" langchain-openai
echo 'OPENAI_API_KEY=sk-...' >> .env
```

`decimalai` reads `.env` when it is imported.

## 2. Save the program

This is the program from Part 1, complete with its four tools. Save it as `main.py`:

```python OpenAI Agents SDK theme={null}
from agents import Agent, Runner, function_tool
from decimalai.openai_agents import agent_config

ORDERS = {
    "ORD-1001": {"item": "electric kettle", "status": "delivered 2026-10-20", "charges": ["$49.00 on 2026-10-15"]},
    "ORD-1002": {"item": "mechanical keyboard", "status": "delivered 2026-10-18", "charges": ["$129.00 on 2026-10-12", "$129.00 on 2026-10-12"]},
}


# Your tools. lookup_order reads your orders; the other three stand in for actions the
# agent's skills call for, and report what they would do.
@function_tool
def lookup_order(order_id: str) -> str:
    """Look up an order by its id, for example ORD-1001."""
    return str(ORDERS.get(order_id, "No order with that id."))


@function_tool
def flag_for_billing(order_id: str, note: str) -> str:
    """Flag an order's charges for the billing team. Call before claiming billing will follow up."""
    if order_id not in ORDERS:
        return "No order with that id."
    return f"Flagged {order_id} for the billing team: {note}"


@function_tool
def lock_account() -> str:
    """Lock the customer's account: nobody can sign in or change it until they finish recovery or deletion."""
    return "Locked the account."


@function_tool
def start_account_deletion() -> str:
    """Send the deletion confirmation link. Call before claiming it was sent; this does not delete the account."""
    return "Sent the deletion confirmation link to the email on file."


TOOLS = [lookup_order, flag_for_billing, lock_account, start_account_deletion]


support = agent_config(
    "order-support",
    fallback=(
        "You are Acme's order support agent. Look the order up before you answer. You cannot issue "
        "refunds or change orders yourself. For a verified duplicate charge, call flag_for_billing "
        "before saying the billing team will follow up. Only describe an action as done after "
        "its tool succeeds; a failed or missing tool call means it has not happened."
    ),
)

agent = Agent(
    name=support.name,
    instructions=support.instructions,  # the prompt and a menu of skills
    tools=[*TOOLS, *support.tools],     # your tools, then load_skill
)

if __name__ == "__main__":
    question = "I opened my kettle from ORD-1001 and it works, but I don't want it. How much do I get back if I return it?"
    result = Runner.run_sync(agent, question)
    print(result.final_output)
```

```python Claude Agent SDK theme={null}
import asyncio
import inspect

from claude_agent_sdk import ClaudeAgentOptions, ResultMessage, create_sdk_mcp_server, tool
from decimalai.claude_agent_sdk import agent_config

ORDERS = {
    "ORD-1001": {"item": "electric kettle", "status": "delivered 2026-10-20", "charges": ["$49.00 on 2026-10-15"]},
    "ORD-1002": {"item": "mechanical keyboard", "status": "delivered 2026-10-18", "charges": ["$129.00 on 2026-10-12", "$129.00 on 2026-10-12"]},
}


# Your tools. lookup_order reads your orders; the other three stand in for actions the
# agent's skills call for, and report what they would do.
def lookup_order(order_id: str) -> str:
    """Look up an order by its id, for example ORD-1001."""
    return str(ORDERS.get(order_id, "No order with that id."))


def flag_for_billing(order_id: str, note: str) -> str:
    """Flag an order's charges for the billing team. Call before claiming billing will follow up."""
    if order_id not in ORDERS:
        return "No order with that id."
    return f"Flagged {order_id} for the billing team: {note}"


def lock_account() -> str:
    """Lock the customer's account: nobody can sign in or change it until they finish recovery or deletion."""
    return "Locked the account."


def start_account_deletion() -> str:
    """Send the deletion confirmation link. Call before claiming it was sent; this does not delete the account."""
    return "Sent the deletion confirmation link to the email on file."


TOOLS = [lookup_order, flag_for_billing, lock_account, start_account_deletion]


def as_tool(fn):
    """A Claude Agent SDK tool from a function: its name, its docstring, string arguments."""
    async def handler(arguments):
        return {"content": [{"type": "text", "text": fn(**arguments)}]}
    return tool(fn.__name__, fn.__doc__, {name: str for name in inspect.signature(fn).parameters})(handler)


support = agent_config(
    "order-support",
    fallback=(
        "You are Acme's order support agent. Look the order up before you answer. You cannot issue "
        "refunds or change orders yourself. For a verified duplicate charge, call flag_for_billing "
        "before saying the billing team will follow up. Only describe an action as done after "
        "its tool succeeds; a failed or missing tool call means it has not happened."
    ),
)
options = ClaudeAgentOptions(
    model="claude-haiku-5-5",
    mcp_servers={"support": create_sdk_mcp_server("support", tools=[*map(as_tool, TOOLS)])},
    allowed_tools=[f"mcp__support__{fn.__name__}" for fn in TOOLS],  # your tools; run.query() adds load_skill
    tools=[],               # none of Claude Code's own tools: no shell, no files
    setting_sources=[],     # nothing from this machine's Claude settings
    verbatim_prompts=True,  # a customer's "@file" or "/command" stays text
)


async def main():
    question = "I opened my kettle from ORD-1001 and it works, but I don't want it. How much do I get back if I return it?"
    async with support.run(question) as run:
        async for message in run.query(options=options):
            if isinstance(message, ResultMessage):
                reply = message.result
    print(reply)


asyncio.run(main())
```

```python OpenAI SDK theme={null}
import inspect
import json

from openai import OpenAI
from decimalai.openai import agent_config

ORDERS = {
    "ORD-1001": {"item": "electric kettle", "status": "delivered 2026-10-20", "charges": ["$49.00 on 2026-10-15"]},
    "ORD-1002": {"item": "mechanical keyboard", "status": "delivered 2026-10-18", "charges": ["$129.00 on 2026-10-12", "$129.00 on 2026-10-12"]},
}


# Your tools. lookup_order reads your orders; the other three stand in for actions the
# agent's skills call for, and report what they would do.
def lookup_order(order_id: str) -> str:
    """Look up an order by its id, for example ORD-1001."""
    return str(ORDERS.get(order_id, "No order with that id."))


def flag_for_billing(order_id: str, note: str) -> str:
    """Flag an order's charges for the billing team. Call before claiming billing will follow up."""
    if order_id not in ORDERS:
        return "No order with that id."
    return f"Flagged {order_id} for the billing team: {note}"


def lock_account() -> str:
    """Lock the customer's account: nobody can sign in or change it until they finish recovery or deletion."""
    return "Locked the account."


def start_account_deletion() -> str:
    """Send the deletion confirmation link. Call before claiming it was sent; this does not delete the account."""
    return "Sent the deletion confirmation link to the email on file."


TOOLS = [lookup_order, flag_for_billing, lock_account, start_account_deletion]
BY_NAME = {fn.__name__: fn for fn in TOOLS}


def schema(fn):
    """A Responses API tool definition from a function: its name, its docstring, string arguments."""
    names = list(inspect.signature(fn).parameters)
    return {"type": "function", "name": fn.__name__, "description": fn.__doc__,
            "parameters": {"type": "object", "properties": {name: {"type": "string"} for name in names},
                           "required": names, "additionalProperties": False}}


client = OpenAI()
support = agent_config(
    "order-support",
    fallback=(
        "You are Acme's order support agent. Look the order up before you answer. You cannot issue "
        "refunds or change orders yourself. For a verified duplicate charge, call flag_for_billing "
        "before saying the billing team will follow up. Only describe an action as done after "
        "its tool succeeds; a failed or missing tool call means it has not happened."
    ),
)

question = "I opened my kettle from ORD-1001 and it works, but I don't want it. How much do I get back if I return it?"
with support.run(question) as run:
    items = [run.message]
    while True:
        response = client.responses.create(
            model="gpt-5.4-mini",
            instructions=run.system,
            input=items,
            tools=[*map(schema, TOOLS), *run.response_tools],  # your tools, then load_skill
        )
        items += response.output
        calls = [item for item in response.output if item.type == "function_call"]
        if not calls:
            break
        for call in calls:
            items.append(run.tool_result(call) or {   # load_skill answers itself
                "type": "function_call_output",
                "call_id": call.call_id,
                "output": BY_NAME[call.name](**json.loads(call.arguments)),
            })
print(response.output_text)
```

```python Anthropic API theme={null}
import anthropic
from anthropic import beta_tool
from decimalai.anthropic import agent_config

ORDERS = {
    "ORD-1001": {"item": "electric kettle", "status": "delivered 2026-10-20", "charges": ["$49.00 on 2026-10-15"]},
    "ORD-1002": {"item": "mechanical keyboard", "status": "delivered 2026-10-18", "charges": ["$129.00 on 2026-10-12", "$129.00 on 2026-10-12"]},
}


# Your tools. lookup_order reads your orders; the other three stand in for actions the
# agent's skills call for, and report what they would do.
@beta_tool
def lookup_order(order_id: str) -> str:
    """Look up an order by its id, for example ORD-1001."""
    return str(ORDERS.get(order_id, "No order with that id."))


@beta_tool
def flag_for_billing(order_id: str, note: str) -> str:
    """Flag an order's charges for the billing team. Call before claiming billing will follow up."""
    if order_id not in ORDERS:
        return "No order with that id."
    return f"Flagged {order_id} for the billing team: {note}"


@beta_tool
def lock_account() -> str:
    """Lock the customer's account: nobody can sign in or change it until they finish recovery or deletion."""
    return "Locked the account."


@beta_tool
def start_account_deletion() -> str:
    """Send the deletion confirmation link. Call before claiming it was sent; this does not delete the account."""
    return "Sent the deletion confirmation link to the email on file."


TOOLS = [lookup_order, flag_for_billing, lock_account, start_account_deletion]


client = anthropic.Anthropic()
support = agent_config(
    "order-support",
    fallback=(
        "You are Acme's order support agent. Look the order up before you answer. You cannot issue "
        "refunds or change orders yourself. For a verified duplicate charge, call flag_for_billing "
        "before saying the billing team will follow up. Only describe an action as done after "
        "its tool succeeds; a failed or missing tool call means it has not happened."
    ),
)

question = "I opened my kettle from ORD-1001 and it works, but I don't want it. How much do I get back if I return it?"
with support.run(question) as run:
    runner = client.beta.messages.tool_runner(
        model="claude-haiku-5-5",
        max_tokens=4096,
        system=run.system,
        tools=[*TOOLS, *run.tools],        # your tools, then load_skill
        messages=[{"role": "user", "content": question}],
    )
    answer = runner.until_done()
reply = "".join(block.text for block in answer.content if block.type == "text")
print(reply)
```

```python LangChain theme={null}
from langchain.agents import create_agent
from langchain.tools import tool
from decimalai.langchain import agent_config

ORDERS = {
    "ORD-1001": {"item": "electric kettle", "status": "delivered 2026-10-20", "charges": ["$49.00 on 2026-10-15"]},
    "ORD-1002": {"item": "mechanical keyboard", "status": "delivered 2026-10-18", "charges": ["$129.00 on 2026-10-12", "$129.00 on 2026-10-12"]},
}


# Your tools. lookup_order reads your orders; the other three stand in for actions the
# agent's skills call for, and report what they would do.
@tool
def lookup_order(order_id: str) -> str:
    """Look up an order by its id, for example ORD-1001."""
    return str(ORDERS.get(order_id, "No order with that id."))


@tool
def flag_for_billing(order_id: str, note: str) -> str:
    """Flag an order's charges for the billing team. Call before claiming billing will follow up."""
    if order_id not in ORDERS:
        return "No order with that id."
    return f"Flagged {order_id} for the billing team: {note}"


@tool
def lock_account() -> str:
    """Lock the customer's account: nobody can sign in or change it until they finish recovery or deletion."""
    return "Locked the account."


@tool
def start_account_deletion() -> str:
    """Send the deletion confirmation link. Call before claiming it was sent; this does not delete the account."""
    return "Sent the deletion confirmation link to the email on file."


TOOLS = [lookup_order, flag_for_billing, lock_account, start_account_deletion]


support = agent_config(
    "order-support",
    fallback=(
        "You are Acme's order support agent. Look the order up before you answer. You cannot issue "
        "refunds or change orders yourself. For a verified duplicate charge, call flag_for_billing "
        "before saying the billing team will follow up. Only describe an action as done after "
        "its tool succeeds; a failed or missing tool call means it has not happened."
    ),
)

agent = create_agent(
    "openai:gpt-5.4-mini",
    tools=TOOLS,                      # your tools; the middleware adds load_skill
    middleware=[support.middleware],  # the prompt and a menu of skills
)

if __name__ == "__main__":
    question = "I opened my kettle from ORD-1001 and it works, but I don't want it. How much do I get back if I return it?"
    result = agent.invoke({"messages": [{"role": "user", "content": question}]})
    print(result["messages"][-1].text)
```

## 3. Add your DecimalAI key

Add this line to the same `.env`. It's filled in when you're signed in:

The tutorial key lasts 30 days. For a project you'll keep running, create your own key under **Settings → API keys** and use that instead.

## 4. Run it

```bash theme={null}
python main.py
```

Real output (the model's wording varies from run to run):

```text theme={null}
For ORD-1001, since the kettle was opened and works, you can return it with a 10% restocking fee.

- Purchase: $49.00
- Fee: $4.90
- Refund: **$44.10**

Start at acme.example/returns using your order number. Your refund should reach the card within 5 business days after Acme receives it.
```

That's the answer from the end of Part 1, because `agent_config("order-support")` read your copy from DecimalAI:

* **The skills and prompt** are the ones saved on your copy, including the skill you forked. Your code doesn't list them.
* **`fallback=`** is used only if the agent has no saved prompt, or DecimalAI can't be reached when the program starts.
* **Your tools are yours.** `lookup_order` reads a dictionary here and your database in your app. The other three stand in for actions the skills call for: they report what they would do and change nothing.
* **Every run is traced**: the model calls, your tools' calls, the skills it opened, and the versions it ran on. [Part 4](https://docs.decimal.ai/tutorials/support-agent/see-what-it-did.md) reads them.

A model can say it did something without doing it, so don't take its word for an action: [Part 5](https://docs.decimal.ai/tutorials/support-agent/measure-it.md) checks what the tools really returned.

## 5. Change the fee again

Your fork is on DecimalAI, so you can change it without touching your code.

1. Open [`acme-returns-policy`](https://app.decimal.ai/skills/acme-returns-policy) and, under **Manage it in DecimalAI**, click **Open copy**.
2. On its **Settings** tab, in **Body (Markdown)**, change `10%` to `5%`.
3. Click **Save Changes**, then **Publish (affects 1 agent)**. This makes a new version of your copy for your agent. It stays private: nothing goes to the public registry.

Run `python main.py` again, or run the notebook's question cell again:

```text theme={null}
For ORD-1001, you’d receive **$46.55** after the 5% restocking fee ($2.45). Start the return at **acme.example/returns** using your order number. The refund reaches your card within 5 business days after Acme receives the kettle.
```

$44.10 became $46.55 and your code didn't change. `agent_config()` reads your copy each time a program starts, and a program that stays running picks up a change within about a minute. The wording varies from run to run, and now and then the reply gives the percentage without the amount. If yours does, run it again.

> [accordion] No DecimalAI account? Run it with local skills
>
> Do [step 1](#1-install) and [step 2](#2-save-the-program) in a new folder, then add the four skills: `billing-dispute-resolution`, `account-deletion-verification-policy`, `diagnostic-triage-questions` and `acme-returns-policy`. No account is needed:
>
> ```bash theme={null}
> decimalai skills add billing-dispute-resolution
> decimalai skills add account-deletion-verification-policy
> decimalai skills add diagnostic-triage-questions
> decimalai skills add acme-returns-policy
> ```
>
> Each one writes the skill's files to `.agents/skills/` and lists it in `.decimal/skills.toml`. Run `python main.py`. Real output (the model's wording varies from run to run):
>
> ```text theme={null}
> decimalai: no DECIMAL_API_KEY, so agent 'order-support' runs keyless: no traces, and its skills are the ones .decimal/skills.toml lists (`decimalai skills add <name>` adds one). Add DECIMAL_API_KEY to connect it.
> For ORD-1001, since the kettle is opened and working, you'll receive **$41.65** after the 15% restocking fee (**$7.35**).
>
> Start the return at **acme.example/returns** using your order number. Your refund reaches the card within 5 business days after Acme receives it.
> ```
>
> Nothing here was sent to DecimalAI. The prompt is your `fallback=` text and the skills are the registry's originals, so the fee is the original 15%.
>
> Don't add your DecimalAI key to this folder if you forked a skill in Part 1: connecting a project copies its local skills onto your agent, beside your fork. Use a new folder and follow the steps above instead.

> [card] [Next: 4. See what it did](https://docs.decimal.ai/tutorials/support-agent/see-what-it-did.md)
>
> Read order-support's traces, change its prompt, and compare runs from before and after.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.