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

# RUN YOUR AGENT AS THE MAIN MODEL IN PI

> Serve your fine-tuned tool-calling model from Oumi and use it as the model inside the pi agent harness

An agent that you train on Oumi can run outside Oumi. [pi](https://pi.dev) is one of the most popular open-source [agent harnesses](https://docs.oumi.ai/reference/agent-harnesses.md) for the terminal. It sends your prompt to a model, runs the tools that the model calls, and sends the tool results back until the model answers. You deploy your fine-tuned model on Oumi, implement its tools as a pi extension, and add a custom model to pi that points to your Oumi deployment.

You do not write or maintain an agent loop of your own. pi supplies the loop, the terminal interface, and the session history, and your small fine-tuned model supplies the tool-calling behavior at a fraction of the cost and latency of a frontier model.

In this guide, your model is the main model of the pi session and sees only the tools and system prompt from its training data. To keep your usual model in pi and call your agent only when you need it, [run it as a subagent](https://docs.oumi.ai/guides/agents/run-your-agent/pi/subagent.md) instead.

This guide uses a stock lookup agent as its example. The agent has two tools: `search_company` finds the ticker symbol for a company name, and `get_stock_price` returns the latest price for a ticker.

***

## HOW THE PIECES CONNECT

![The pi agent loop on your machine sends messages and tools to your Oumi deployment, runs each tool call in your pi extension, and returns the final reply to you](https://mintcdn.com/oumi/up4xn2fDkJQDzAD6/images/pi-connection-light.svg?fit=max\&auto=format\&n=up4xn2fDkJQDzAD6\&q=85\&s=10e9a10ac215c75ae1d4c1d509faf335)

Oumi serves the model. pi runs everything else on your machine, including your tool code, so your tools can reach real data that Oumi cannot.

***

## BEFORE YOU START

You will need:

* An Oumi project.
* pi, installed on your machine by following the [pi quickstart](https://pi.dev) instructions.
* A personal Oumi API key from **User Settings > API Keys**.

***

**1. Train a tool-calling model**

Ask FAiE to help you build the agent, or follow the [agents workflow](https://docs.oumi.ai/guides/agents.md#a-typical-workflow) yourself:

1. [Create a tool](https://docs.oumi.ai/guides/agents/tools.md) for each function that your agent calls. For the example, create `search_company` and `get_stock_price`.
2. Give each tool a [tool implementation](https://docs.oumi.ai/guides/agents/tool-implementations.md). A simulated implementation is enough to generate training data. pi calls your real code later.
3. Collect the prompts that your agent must handle, and [generate training conversations](https://docs.oumi.ai/guides/synthesis/how-it-works.md#add-tools-and-a-simulated-user) with a strong teacher model.
4. [Train](https://docs.oumi.ai/guides/training.md) a base model that [supports tool calling](https://docs.oumi.ai/guides/training/model-selection.md#tool-use) on the best conversations.
5. [Evaluate](https://docs.oumi.ai/guides/evaluations/running.md#add-tools-and-a-simulated-user) the trained model against the teacher with your tools attached.

Keep a copy of the system prompt from your training data. You use it again in pi.

**2. Deploy the model**

[Deploy your trained model](https://docs.oumi.ai/guides/deployment/deploy-a-model.md) and wait until the deployment is `Active`. Copy its model path from the deployment page. The model path has the form `projects/{project_id}/deployments/{deployment_id}`.

Save your Oumi API key in a file, for example `~/.config/oumi/api.key`, and make it readable only by you:

```bash theme={null}
chmod 600 ~/.config/oumi/api.key
```

**3. Implement the tools in pi**

During training or evaluation on the Oumi platform, a [tool implementation](https://docs.oumi.ai/guides/agents/tool-implementations.md) answered each tool call. In pi, an extension answers it. An extension is a TypeScript file in `~/.pi/agent/extensions/` that registers the tools your model knows how to call.

The model learned your tools from their Oumi definitions. Make each pi tool match its Oumi tool:

* **Name:** The same `toolName`, for example `search_company`. If the names differ, the model calls a tool that pi does not have.
* **Parameters:** The same parameter names, types, and required fields.
* **Description:** The same text, or text that is very close to it.

Create `~/.pi/agent/extensions/stock-tools.ts`:

```typescript stock-tools.ts theme={null}
import { Type } from "@earendil-works/pi-ai";
import { defineTool, type ExtensionAPI } from "@earendil-works/pi-coding-agent";

const API = "https://api.example-stocks.com";

// The model reads `content`. pi stores `details` in the session.
function result(text: string, details: Record<string, unknown>) {
	return { content: [{ type: "text" as const, text }], details };
}

const searchCompany = defineTool({
	name: "search_company",
	label: "Search Company",
	description: "Find a company's stock ticker symbol by company name. Call this before get_stock_price.",
	parameters: Type.Object({
		name: Type.String({ description: "Company name, e.g. 'Apple'." }),
	}),

	async execute(_toolCallId, params, signal) {
		const res = await fetch(`${API}/search?q=${encodeURIComponent(params.name)}`, { signal });
		if (res.status === 404) return result(`No company found matching "${params.name}".`, { found: false });
		if (!res.ok) throw new Error(`Search returned HTTP ${res.status}`);

		const { ticker, name } = (await res.json()) as { ticker: string; name: string };
		return result(`Found ${name} (ticker: ${ticker}).`, { found: true, ticker, name });
	},
});

const getStockPrice = defineTool({
	name: "get_stock_price",
	label: "Get Stock Price",
	description: "Get the latest stock price for a ticker symbol returned by search_company.",
	parameters: Type.Object({
		ticker: Type.String({ description: "Stock ticker symbol, e.g. 'AAPL'." }),
	}),

	async execute(_toolCallId, params, signal) {
		const res = await fetch(`${API}/quote/${encodeURIComponent(params.ticker)}`, { signal });
		if (res.status === 404) return result(`No price found for "${params.ticker}".`, { found: false });
		if (!res.ok) throw new Error(`Quote returned HTTP ${res.status}`);

		const { price, currency } = (await res.json()) as { price: number; currency: string };
		return result(`${params.ticker}: ${price} ${currency}.`, { found: true, price, currency });
	},
});

export default function (pi: ExtensionAPI) {
	pi.registerTool(searchCompany);
	pi.registerTool(getStockPrice);
}
```

A tool that finds no match returns a result that says so. A tool whose data source fails throws an error, and pi shows that error to the model as a failed tool call. Neither path invents a value.

> [!TIP]
>
> You can have pi write the extension for you. Start pi with a frontier model, paste the JSON of each Oumi tool from its detail page, and ask: "Write a pi extension in `~/.pi/agent/extensions/` that implements these tools with the same names and parameters. Use `<your data source>` to answer them." Review the code before you load it, because an extension runs with your user's permissions.

pi loads the extensions in `~/.pi/agent/extensions/` when it starts. If pi is already running, run `/reload`.

**4. Add the deployment to pi**

Add an `oumi` provider to `~/.pi/agent/models.json`. Create the file if it does not exist. If it exists, add the `oumi` entry inside `providers`.

```json ~/.pi/agent/models.json theme={null}
{
  "providers": {
    "oumi": {
      "baseUrl": "https://inference.oumi.ai/v1",
      "api": "openai-completions",
      "apiKey": "!cat /Users/you/.config/oumi/api.key",
      "name": "Oumi",
      "models": [
        {
          "id": "projects/{project_id}/deployments/{deployment_id}",
          "name": "Oumi Stock Lookup",
          "input": ["text"],
          "contextWindow": 32768,
          "maxTokens": 4096,
          "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
        }
      ]
    }
  }
}
```

| Field | Value |
| - | - |
| `baseUrl` | `https://inference.oumi.ai/v1`. Your deployment's endpoint is [OpenAI-compatible](https://docs.oumi.ai/guides/deployment/calling-your-endpoint.md). |
| `api` | `openai-completions`, so that pi sends requests in the OpenAI chat completions format. |
| `apiKey` | Your Oumi API key. A value that starts with `!` is a shell command that pi runs for each request, so the key stays out of the file. You could also use `$OUMI_API_KEY` to read an environment variable. |
| `models[].id` | The model path of your deployment, exactly as the deployment page shows it. |
| `models[].name` | The label that pi shows in its model picker. |
| `contextWindow`, `maxTokens` | Limits that are within those of your trained model. pi uses them to decide when to compact the conversation. |
| `cost` | Zeros. Oumi bills your deployment, and pi uses these values only to show a cost estimate. |

**5. Select the model and run the agent**

Start pi with your model, only your tools, and the system prompt from your training data, so that the model gets the same context as in your evaluations:

```bash theme={null}
pi --provider oumi \
  --model "projects/{project_id}/deployments/{deployment_id}" \
  --tools search_company,get_stock_price \
  --system-prompt ./stock-agent-system-prompt.md
```

> [!WARNING]
>
> By default, pi also gives the model its own coding tools (`read`, `bash`, `edit`, and `write`) and a system prompt for coding work. If your model did not see these during training, you may want to consider starting pi with `--tools` and `--system-prompt`, as in the command above. Otherwise, the model can call a coding tool instead of your tools, or answer without calling a tool.

Then ask a question such as "How is Nucor doing today?". The model calls `search_company` to find the ticker `NUE`, calls `get_stock_price` with that ticker, and answers with the price that the tool returned. pi shows each tool call and its result in the transcript.

***

## TROUBLESHOOTING

* **`429` with "Deployment is warming up":** Your deployment uses [scale-to-zero](https://docs.oumi.ai/guides/deployment/deploy-a-model.md#autoscaling-and-cost-custom-models) and has no warm replica. Wait a few minutes and send the prompt again. To prevent cold starts, set min replicas to 1.
* **`400` with "Invalid model format":** The `id` in `models.json` is not a model path. Set `id` to `projects/{project_id}/deployments/{deployment_id}` and put the label in `name`.
* **The model does not appear in `/model`:** pi cannot get an API key for the provider. Run the `apiKey` command yourself, for example `cat ~/.config/oumi/api.key`, and make sure it prints your key.
* **The model calls a tool that pi does not have:** A tool name in your extension does not match the `toolName` in Oumi. Rename the pi tool, then run `/reload`.
* **The model answers without calling tools, or calls the coding tools:** Start pi with `--tools` and `--system-prompt` as shown in the last step, so that the model sees the same tools and instructions as in training.

***

## WHAT'S NEXT

> **[Run your agent as a subagent](https://docs.oumi.ai/guides/agents/run-your-agent/pi/subagent.md)**
>
> Keep your usual model in pi and give it your agent as a tool.

> **[Calling your endpoint](https://docs.oumi.ai/guides/deployment/calling-your-endpoint.md)**
>
> Call your deployment from your own code with the OpenAI or Anthropic SDKs.

> **[Inference logs](https://docs.oumi.ai/guides/deployment/inference-logs.md)**
>
> Review the requests that pi sent to your deployment.

> **[Compounding intelligence](https://docs.oumi.ai/guides/deployment/compounding-intelligence.md)**
>
> Find where your deployed model struggles, and retrain it on targeted data.

> **[Tools](https://docs.oumi.ai/guides/agents/tools.md)**
>
> Write tool definitions that a model calls correctly.


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