---
question: How do I add OpenAI or Ollama as a provider?
kind: task
via_web: na
via_cli: na
via_python: available
via_api: na
via_config: available
ref_python: ModelDefinition
ref_config: modules:
next:
  - /capabilities/build/models/choose-the-default-model
  - /capabilities/build/agents/edit-prompt-and-model
---

# Add a provider

A provider is a module that registers models. The marketplace ships one per vendor under `naas_abi_marketplace.ai` (Anthropic, OpenAI, Gemini, Mistral, OpenRouter, Ollama, and others): enable it in `config.yaml` with its key. For a provider the marketplace does not have, write a module whose `models/` folder declares the models.

## Web UI

Not applicable. Nexus does not enable modules: Settings › Models lists every marketplace provider's models, **Not configured** until you enable the module on the Config tab.

## CLI

Not applicable. There is no `abi new model` command: a provider is a module enabled in `config.yaml`, on the Config tab, and `abi config validate --modules` checks it.

## Python

### Scaffold a module

```bash
abi new module my_llm src --in-engine
```

List it under `modules:` in `config.yaml`, with a `config:` value for its key, and declare that field on its `Configuration` (`api_key: str`).

### Declare a model

Create a `models/` folder in the module. Each file in it holds one `ModelDefinition` subclass. The module registers them when it loads, under their `CANONICAL_ID`:

```python title="src/my_llm/models/my_chat.py"
from langchain_openai import ChatOpenAI
from my_llm import ABIModule
from naas_abi_core.models.Model import ChatModel, ModelDefinition
from pydantic import SecretStr


class MyChatModel(ModelDefinition):
    CANONICAL_ID = "my-chat"
    MODEL_ID = "my-chat-v1"
    PROVIDER = "my_llm"

    model: ChatModel = ChatModel(
        model_id=MODEL_ID,
        provider=PROVIDER,
        name="My chat",
        context_window=32768,
        model=ChatOpenAI(
            model=MODEL_ID,
            base_url="https://models.example.com/v1",
            api_key=SecretStr(ABIModule.get_instance().configuration.api_key),
        ),
    )
```

`model` is any LangChain chat model. An embedding model is an `EmbeddingModel`, the same way.

### Build models on demand

To accept any model id of the provider without a file per model, register a factory in the module's `on_load`, after `super().on_load()`:

```python title="src/my_llm/__init__.py"
def on_load(self):
    super().on_load()

    def chat_factory(provider_model_id: str):
        return ChatOpenAI(model=provider_model_id, base_url="https://models.example.com/v1")

    self.engine.services.model_registry.register_chat_provider("my_llm", chat_factory)
```

Callers then ask `registry.get_chat_model("<any id>", provider="my_llm")`.

## REST API

Not applicable. There is no REST endpoint that registers a model provider: a provider is a module, and the default model is `services.model_registry` in `config.yaml`.

## Config

### Install the module's extra

The marketplace modules need their package extra. For Anthropic:

```bash
uv add "naas-abi-marketplace[ai-claude]"
```

OpenRouter needs none. See [Marketplace install](/user-guide/build/modules/marketplace/marketplace-install).

### Enable the module

Add it under `modules:` with its key, read from the secret service:

```yaml title="config.yaml"
modules:
  - module: naas_abi_marketplace.ai.anthropic
    enabled: true
    config:
      anthropic_api_key: "{{ secret.ANTHROPIC_API_KEY }}"
```

The key field is named after the vendor: `openai_api_key`, `gemini_api_key`, `mistral_api_key`, `openrouter_api_key`, and so on. Ollama needs no key: see [Run models locally](/user-guide/build/models/run-models-locally).

### Store the key

```bash title=".env"
ANTHROPIC_API_KEY=sk-ant-...
```

### Check and restart

```bash
abi config validate --modules
```

It imports every enabled module and validates its config. Restart the engine: Settings › Models then marks that module's models **Configured**, and agents can ask for them by canonical id.

## The default model

The engine checks `default_chat_model` and `default_embedding_model` after the modules load, and stops when one is not registered. Before you disable a provider, move the defaults, and any agent model pinned in a module's config, to models another enabled module provides. See [Choose the default model](/user-guide/build/models/choose-the-default-model).
