# Connect your AI

> Connect one or more language model providers, decide which models your team may use, and set the models for search, dictation and reading aloud. This guide walks the whole setup, from the API key to the first answer from the AI Assistant.

nexxus does not come with a language model of its own. You bring the model: a cloud provider such as IONOS or OpenAI, or a model that runs on your own server. Each workspace (tenant) keeps its own keys and its own model list, so one company's keys never reach another.

Connecting a provider is only half the job. The other half is deciding what your people see. A provider like OpenAI offers dozens of models, and you probably want your team to choose between two or three of them, under names that make sense to them ("Fast answers", "Thorough analysis"), at prices you know. That is what this page is about.

Take Brandt & Söhne, a 60-person installation company. Their admin, Jana Brandt, connects IONOS for everyday questions, because the data stays in a German data centre, and OpenAI for image generation. Employees see two models in the AI Assistant's model picker, called "Standard" and "Thorough". Nobody sees the technical model ids, and Jana sees what each answer cost.

## How a model gets to your team

A model goes through four states before anyone can chat with it. The provider must be connected and switched on. You load the provider's models into nexxus. You switch on the models the AI Assistant may use. And you publish the ones your team should see.

<Flow
  steps={[
    { icon: 'key-round', title: 'Connect', text: 'Enter the API key and switch the provider on.' },
    { icon: 'refresh-cw', title: 'Sync models', text: 'nexxus loads the list of models from the provider.', tone: 'cyan' },
    { icon: 'toggle-right', title: 'Activate', text: 'The AI Assistant may use the model. Admins can already pick it.', tone: 'lavender' },
    { icon: 'users', title: 'Publish', text: 'Everyone sees it in the model picker, under a public name.' },
  ]}
  caption="Only published models appear for your team. The technical model id stays hidden from them."
/>

A provider delivers more than chat models. nexxus sorts every synced model into one of four kinds and uses one model per kind for the whole workspace:

<Hub
  inputsLabel="Providers"
  inputs={[
    { icon: 'globe-lock', title: 'European clouds', text: 'IONOS Inference, Scaleway Generative API' },
    { icon: 'cloud', title: 'Other clouds', text: 'OpenAI, Anthropic, Google Gemini, Moonshot AI, Inceptron' },
    { icon: 'server', title: 'Your own servers', text: 'Ollama, vLLM, LM Studio, LiteLLM, a company proxy' },
  ]}
  core={{
    title: 'AI settings of your workspace',
    text: 'One page per provider, one model per purpose',
    items: ['Chat', 'Embeddings', 'Speech-to-text', 'Text-to-speech'],
  }}
  outputsLabel="Used for"
  outputs={[
    { icon: 'message-square-text', title: 'AI Assistant', text: 'Answers, tools, proposals' },
    { icon: 'search', title: 'Search by meaning', text: 'Knowledge and document content' },
    { icon: 'mic', title: 'Voice', text: 'Dictation and reading answers aloud' },
  ]}
  caption="All AI calls go through the nexxus AI gateway, which fetches your workspace's keys and models from nexxus for each request."
/>

## Which provider to choose

nexxus offers eight provider types. Seven are fixed services with a known address. The eighth, **OpenAI-kompatibel (eigene URL)** (OpenAI-compatible, own URL), connects anything that speaks the OpenAI API, which covers most self-hosted model servers. The provider names come from the AI gateway and read the same in every app language.

| Provider type in the app | Address used by default | API key | Can be added more than once |
|---|---|---|---|
| OpenAI | `https://api.openai.com/v1` | required | no |
| Anthropic (Claude) | `https://api.anthropic.com` | required | no |
| Scaleway Generative API | `https://api.scaleway.ai/v1` | required | no |
| IONOS Inference | `https://openai.inference.de-txl.ionos.com/v1` | required | no |
| Google Gemini | `https://generativelanguage.googleapis.com` | required | no |
| Moonshot AI (Kimi) | `https://api.moonshot.ai/v1` | required | no |
| Inceptron | `https://openrouter.inceptron.io/v1` | required | no |
| OpenAI-kompatibel (eigene URL) | none, you enter it | optional | yes, one entry per endpoint |

If your data should stay in Europe, IONOS (Germany) and Scaleway (France) are the European providers in the list. If it should not leave your network at all, run the model yourself and connect it as an OpenAI-compatible endpoint (see [Models on your own server](#models-on-your-own-server)).

A few things only work with a particular provider today. Keep them in mind when you plan:

- **Image generation** (the connector <Ui>Image</Ui>) always uses the OpenAI provider of your workspace with the model `gpt-image-1`. Without an OpenAI provider, the AI Assistant cannot create images.
- **Embeddings** and **speech-to-text** fall back to OpenAI models when you select none (details in [One model per purpose](#one-model-per-purpose)).

## Before you start

- You hold the admin role, or a role with the permission block <Ui>AI Providers</Ui> set to <Ui>Write</Ui>. With <Ui>Read (management)</Ui> alone you can open the page but not save, test or sync.
- You have an API key from the provider. For an own endpoint that needs no key, you need its address instead.
- The nexxus AI gateway is running. If it is not, the provider list stays empty (see [When something goes wrong](#when-something-goes-wrong)).

The AI Assistant belongs to every workspace. In the setup step <Ui>Areas</Ui> it is listed under <Ui>Always included</Ui> as <Ui>AI assistant</Ui> and cannot be switched off. What leaves your workspace, you control through the provider you choose, the connectors and the embeddings switch (see [Data protection and consent](#data-protection-and-consent)).

:::tip[The quick route]
On a fresh installation, the setup wizard asks for one provider, one key and one chat model in its step <Ui>AI</Ui>, and sends a test message through. That is enough to start. Come back to this page when you want more than one model, prices or voice. See [First run](/setup/first-run/).
:::

## Add a provider

<Screenshot src={shot_ai_providers_list} url="/ai-providers" alt={"The AI Settings page with three providers"} caption={"Each card shows how many models are active and how many are published."} />

<Steps>

1. Open <MenuPath to="AI > Set up AI > AI Providers" />. The page is titled <Ui>AI Settings</Ui> and lists the providers you have connected, each with a switch <Ui>Provider active</Ui>.

2. Click <Ui>New provider</Ui> at the bottom of the page. A menu <Ui>Choose provider type</Ui> opens with every type you have not connected yet. Pick one, for example <Ui>IONOS Inference</Ui>.

   <Screenshot src={shot_ai_provider_new_menu} url="/ai-providers" alt={"The provider type menu opened from New provider"} caption={"Only types you have not connected yet appear. The OpenAI-compatible type is always offered."} />

3. The provider page opens. Switch to the tab <Ui>Credentials</Ui> and paste the key into <Ui>API key</Ui>. Leave <Ui>Base URL</Ui> empty unless you route the provider through a proxy: nexxus then uses the address from the table above.

   <Screenshot src={shot_ai_provider_credentials} url="/ai-providers/openai" alt={"The Credentials tab of a provider with a stored key"} caption={"The key is stored encrypted and never shown again."} />

4. In the panel on the right, turn on <Ui>Provider active</Ui>. As long as it is off, the AI Assistant cannot use any model of this provider.

5. Optional: click <Ui>Test connection</Ui>. nexxus asks the provider for its model list with your key. A green message such as "Authenticated. 42 models reachable." means the key works.

6. Click <Ui>Synchronise models</Ui>. nexxus loads all models of the provider into the tab <Ui>Chat models</Ui> and **saves the provider in the same step**. The message <Ui>Models synchronised and saved</Ui> confirms it. New models arrive switched off.

   <Screenshot src={shot_ai_provider_actions} url="/ai-providers/openai" alt={"The status and actions panel of a provider"} caption={"Synchronise models loads the provider's models and saves in the same step."} />

7. On <Ui>Chat models</Ui>, turn on <Ui>Active</Ui> for each model the AI Assistant may use. Then turn on <Ui>Published</Ui> for the models your team should see, and give each a public name and a one-line description. The next section explains every column.

   <Screenshot src={shot_ai_provider_chat_models} url="/ai-providers/ionos" alt={"The chat model table with active and published models and prices"} caption={"Active lets the AI Assistant use a model, published shows it to everyone under its public name."} />

8. Click <Ui>Save</Ui>. The message <Ui>Saved</Ui> confirms it.

9. Open the AI Assistant with the button at the top right and click the model button in the input area. Your published models are listed under their public names. Ask a first question.

</Steps>

To change a provider later, click its card in the list. The switch <Ui>Provider active</Ui> on the card takes effect immediately, without opening the provider.

## Decide what your team sees

The table on <Ui>Chat models</Ui> has one row per model and these columns:

| Column | What it does |
|---|---|
| <Ui>Model</Ui> | The technical model id, with the context size when the provider reports it (for example "128k context"). |
| <Ui>Active</Ui> | The AI Assistant may use the model. Turning it off also unpublishes it. |
| <Ui>Published</Ui> | Everyone in the workspace sees the model in the picker. Only possible for an active model. |
| <Ui>Vision</Ui> | The model can see images. For models nexxus knows, this is fixed and greyed out. For models behind your own endpoint or proxy, you set it. |
| <Ui>Price (USD per 1M tokens)</Ui> | What the model costs, so nexxus can calculate the cost of each answer. See [Costs](#costs). |
| <Ui>Public name & description (for users)</Ui> | The name and one-line description your team sees. Only shown for published models. |

What the two switches mean for different people:

| | Admins | Everyone else |
|---|---|---|
| Active, not published | sees the model in the picker | does not see it |
| Active and published | sees it | sees it, under its public name |
| Not active | does not see it | does not see it |

That makes "active, not published" a good state for trying out a new model yourself before you hand it to the team.

A published model without a public name is saved with its technical id as name. Give it a real name: your colleagues choose by that name, and the hover card in the picker shows your description.

:::note[Vision matters for attachments]
When someone attaches an image while a model without <Ui>Vision</Ui> is selected, the AI Assistant warns that the model cannot see images and offers to switch to one that can. Set <Ui>Vision</Ui> correctly for your own models so that warning is right.
:::

## The model a conversation starts with

nexxus has no separate "default model" setting. A new conversation starts with the model the person picked last time (their browser remembers it). If they never picked one, it starts with the model marked <Ui>Recommended</Ui> in the picker. The AI gateway chooses that one: the first published chat model of your active providers, unless your operator has set an installation-wide default model that is also active for your workspace.

If you want everyone to start with one particular model, publish only that one at first and keep the others active but unpublished until your team knows its way around.

## One model per purpose

Besides chat models, providers offer models for embeddings, speech-to-text and text-to-speech. The AI gateway recognises them by their id when you sync (for example `text-embedding-3-small`, `whisper-1`, `tts-1`), and nexxus lists them on their own tabs. The tabs only appear when the provider has such models.

| Tab | Purpose | If you select nothing |
|---|---|---|
| <Ui>Embeddings</Ui> | Turns knowledge entries and document content into vectors for search by meaning. Must produce 1536 dimensions. | OpenAI `text-embedding-3-small`, through your OpenAI provider |
| <Ui>Speech-to-text</Ui> | Turns dictation in the chat into text. | OpenAI `gpt-4o-transcribe`, through your OpenAI provider |
| <Ui>Text-to-speech</Ui> | Reads the AI Assistant's answers aloud. | the browser's built-in voice, at no cost |

Each tab has a switch <Ui>Use</Ui> per model. Your workspace uses **exactly one model per purpose**, across all providers. If another provider already holds the selection, the tab says so: "Currently selected: ... from ... Selecting one here replaces it." Saving here takes the selection away from the other provider.

Changing the embedding model has a consequence: every stored vector has to be calculated again. nexxus asks before it does that. The full story is on [Search by meaning](/setup/embeddings/). Dictation and reading aloud are covered in [Voice](/setup/voice/).

## Models on your own server

Ollama, vLLM, LM Studio, LiteLLM and most company proxies offer an OpenAI-compatible API. You connect each of them as its own entry of the type **OpenAI-kompatibel (eigene URL)**, and you can add as many as you like.

<Steps>

1. Click <Ui>New provider</Ui> and pick <Ui>OpenAI-kompatibel (eigene URL)</Ui>. The page opens directly on <Ui>Credentials</Ui>.

   <Screenshot src={shot_ai_provider_own_endpoint} url="/ai-providers/openai-compatible" alt={"A new OpenAI-compatible endpoint for a local Ollama server"} caption={"The base URL must be reachable from the AI gateway, not only from your browser."} />

2. Enter a <Ui>Name</Ui>, for example "Ollama (office)". Your team sees it next to the models, so make it recognisable.

3. Enter the <Ui>Base URL</Ui> including `/v1`, for example `http://host:11434/v1`.

4. Leave <Ui>API key</Ui> empty if the server needs no key. nexxus then sends no authorisation header at all.

5. Turn on <Ui>Provider active</Ui>, click <Ui>Save</Ui>, then <Ui>Synchronise models</Ui>, and continue as for any other provider.

</Steps>

:::caution[The address must be reachable from the AI gateway]
The AI gateway calls your endpoint, not your browser. An address like `http://localhost:11434/v1` points at the gateway's own machine. Use an address that the gateway's server can reach, and if your model server sits in your company network, make sure that network path exists.
:::

Two limits apply to own models. nexxus cannot always tell whether such a model sees images, so set <Ui>Vision</Ui> yourself. And for embeddings, the model must deliver vectors with 1536 dimensions. Many small embedding models deliver 768 or 1024, and nexxus refuses them when you save.

## Costs

AI costs money per token, and nexxus can show you what each answer cost, per person, per model and per month. For that it needs the prices.

### Enter prices

In the column <Ui>Price (USD per 1M tokens)</Ui> each active model has four fields, all in US dollars per million tokens, the way providers publish their price lists:

| Field | Meaning |
|---|---|
| <Ui>In</Ui> | Input tokens: what the AI Assistant sends to the model. |
| <Ui>Out</Ui> | Output tokens: what the model writes back. |
| <Ui>C-Rd</Ui> | Tokens read from the provider's prompt cache. |
| <Ui>C-Wr</Ui> | Tokens written into the prompt cache. |

Two rules keep the numbers honest:

- **An empty field means "not maintained", not "free".** Answers from a model without a price are counted in tokens, and the usage page says that a price is missing. It does not book them as zero.
- **Cache prices are charged on top of input.** nexxus receives input, cache reads and cache writes as separate counts. If your provider charges for cached tokens and you leave the cache fields empty, the total comes out too low. (OpenAI charges for cache reads only.)

The cost of each answer is calculated when the answer is recorded, at the price valid at that moment. Changing a price later does not rewrite past answers.

### Show costs in euros

Prices stay in dollars because providers publish them that way. To see euros on the usage page, set an exchange rate in <MenuPath to="Administration > Operations > System configuration" />, section <Ui>AI costs</Ui>, field <Ui>Rate: euros per US dollar</Ui>, for example 0.92. Leave it empty or set 0 to go back to dollars.

### Who sees what

<Screenshot src={shot_ai_answer_meta} url="/dashboard" alt={"The cost and model line under an answer, expanded"} caption={"Only admins see this line. Without a price for the model it says so instead of an amount."} />

- **Admins** see a line under every finished answer in the AI Assistant's column with the duration, the number of tool calls, the cost and the model. Clicking it shows the tokens (input, from cache, output) and the cost in detail. Nobody else sees this line.
- **Everyone else** sees a <Ui>Usage cost</Ui> scale in the model picker: <Ui>Low</Ui>, <Ui>Medium</Ui>, <Ui>High</Ui> or <Ui>Very high</Ui>. nexxus mixes three parts input price and one part output price per million tokens: under 1 dollar is low, up to 5 medium, up to 15 high, above that very high. A model without a price has no scale.
- The page <MenuPath to="AI > Set up AI > AI usage" /> (admins only) breaks down the costs of the last 7, 30 or 90 days or the last year by person, model, skill, origin (chat, schedule, skill) and the most expensive sessions. If prices are missing, it says how many models lack one and marks totals as a lower bound.

<Screenshot src={shot_ai_usage_page} url="/ai-usage" alt={"The AI usage page with turns, tokens and a missing price"} caption={"A missing price turns the total into a lower bound, and the page says so."} />

## Data protection and consent

What leaves your workspace, and when:

- **The conversation goes to the provider you connected.** The AI Assistant sends the question, the page context and whatever tools found to the chat model you selected. There is no extra confirmation for this step: choosing the provider is your decision as admin. Pick a European provider or your own server if the data must stay in Europe or in house.
- **Names and identifiers can go out as placeholders.** With pseudonymisation on, the gateway replaces them by table and pattern before the request leaves and puts them back in the answer, without a model. See [Pseudonymisation](/setup/pseudonymisation/).
- **Other external services ask first.** When the AI Assistant wants to use a tool that sends data to another service, the conversation pauses and the person sees a dialog <Ui>Allow external service?</Ui> For image generation the text comes from the server in German: "Für das Bild geht die Beschreibung an den Bilddienst des eingerichteten KI-Anbieters (standardmäßig OpenAI, außerhalb der EU). Einverstanden?" (the image description goes to the image service of the configured AI provider, OpenAI outside the EU by default; do you agree?). The answer counts for the rest of that conversation.
- **Connector actions that change something elsewhere** are confirmed one by one, on a card with <Ui>Confirm</Ui> and <Ui>Decline</Ui>.
- **Search by meaning can be switched off.** If no text should go to an embedding provider, turn off embeddings in the system configuration. See [Search by meaning](/setup/embeddings/#turn-embeddings-off).

How this looks from a user's side is described in [Working with the AI Assistant](/use/assistant/#the-ai-assistant-proposes-you-approve).

## Check that everything works

- On the provider page, the panel <Ui>Status</Ui> shows <Ui>Connected</Ui> when the provider is active and holds a key (or needs none). This is not a live check. Use <Ui>Test connection</Ui> for that.
- In <MenuPath to="Administration > Operations > Setup" />, the step <Ui>AI</Ui> has a button <Ui>Save and test</Ui> that sends a real message through the AI gateway and back. It shows three checks, <Ui>Provider and model</Ui>, the gateway check and <Ui>Model answers</Ui>, plus the answer itself.
- If the AI gateway stops responding, the menu entry <Ui>AI Providers</Ui> gets a red dot. Hover it to see the reason.

<Screenshot src={shot_ai_setup_step} url="/einrichtung" alt={"The AI step of the setup"} caption={"Save and test sends a real message through the AI gateway and back, then the test run card shows three checks."} />

The card <Ui>AI Gateway</Ui> at the top of the provider list shows which gateway generation your workspace uses. Leave the switch <Ui>Use v1</Ui> as it is unless your operator asks you to change it.

## What happens behind the scenes

- **Keys are encrypted.** nexxus stores API key, base URL and model filter of each provider encrypted with AES-256-GCM and never shows the key again. The form only says <Ui>••• Saved</Ui> with a button <Ui>Change</Ui>. Tests and syncs use the stored key when you do not type a new one.
- **The AI gateway holds no keys of its own.** For each request it asks nexxus for the active providers of your workspace and their keys, and caches them for about 30 seconds. Saving or deleting a provider clears that cache at once.
- **Model kinds come from the model id.** When you sync, the AI gateway sorts each model by its name: ids containing "embed" go to embeddings, "whisper" or "transcribe" to speech-to-text, "tts" to text-to-speech. Image, audio and moderation models are hidden. Everything else is a chat model.
- **Several own endpoints** each get their own internal id, built from the type and the name you gave (for example `openai-compatible-ollama-office`). Renaming is not possible in the setup wizard; use the provider page.
- **Deleting a provider** with <Ui>Delete provider</Ui> removes it from the list and from the AI Assistant. If it held the embedding model, nexxus recalculates all vectors with the fallback model, and the delete dialog says so.

## When something goes wrong

The validation messages come from the server and are German in every app language.

| Message or symptom | Cause and fix |
|---|---|
| "Für diesen Provider ist ein API-Key erforderlich." (an API key is required for this provider) | Every type except the OpenAI-compatible one needs a key when you create it. Enter the key on <Ui>Credentials</Ui>. |
| "Bitte einen Namen für den Endpunkt angeben." (please name the endpoint) | A new OpenAI-compatible endpoint needs a <Ui>Name</Ui>. |
| "Bitte die Basis-URL des Endpunkts angeben, z. B. http://host:11434/v1." (please enter the base URL) | A new OpenAI-compatible endpoint needs its address. |
| "Die Basis-URL muss eine http(s)-Adresse sein, z. B. http://host:11434/v1." (the base URL must be an http(s) address) | The address must start with `http://` or `https://` and contain a host. |
| <Ui>Synchronisation failed</Ui> followed by `missing_api_key` | No key is stored or typed. Add it on <Ui>Credentials</Ui>. |
| <Ui>Synchronisation failed</Ui> followed by `http_401` or `http_403` | The provider rejected the key. Check it at the provider. |
| <Ui>Synchronisation failed</Ui> followed by `Gateway HTTP` and a number | The AI gateway could not handle the request. Ask your operator to check the gateway. |
| Test result "API key is required." | Same as `missing_api_key`. |
| Test result "HTTP 404 from" followed by an address | The base URL is wrong. For OpenAI-compatible endpoints it must end with `/v1`. |
| The list says <Ui>The gateway is not reporting any providers. Is it running?</Ui> | You have not connected a provider yet, or the AI gateway does not answer. If <Ui>New provider</Ui> shows no types, it is the gateway. |
| Red dot on <Ui>AI Providers</Ui>, tooltip <Ui>Gateway unreachable</Ui> | The AI gateway is down or unreachable from nexxus. Your operator needs to look at it. |
| A colleague cannot find a model in the picker | The model is active but not published, or the provider is switched off. |
| <Ui>New provider</Ui> is greyed out | All provider types are connected already. The OpenAI-compatible type stays available, so this only happens when the gateway sends no catalog. |
| The setup test says "Kein Anbieter mit eingeschaltetem Modell." (no provider with an active model) | No active provider has an active chat model. Activate one on <Ui>Chat models</Ui>. |
| Saving the embedding model fails with "returns 768 dimensions, the vector store needs 1536" | The model produces vectors of the wrong size. Choose a model with 1536 dimensions. See [Search by meaning](/setup/embeddings/#when-something-goes-wrong). |

## For operators

If you run nexxus yourself, these settings belong to the AI setup:

| Setting | Purpose |
|---|---|
| `NEXXUS_SECRETS_KEY` | Base64 key of 32 bytes for encrypting provider keys and other secrets. Create one with `openssl rand -base64 32`. Required: without it nexxus refuses to start. Only a developer machine (`./gradlew bootRun`, or the profile `local`, `dev` or `test`) falls back to a built-in development key. |
| `AI_GATEWAY_URL`, `AI_GATEWAY_V0_URL`, `AIASSISTANT_GATEWAY_URL` | Address of the AI gateway. Several parts of nexxus read different names, so set all three to the same value, as the reference Kubernetes setup does. |
| `AI_GATEWAY_TOKEN`, `AI_GATEWAY_V0_TOKEN`, `AIASSISTANT_GATEWAY_TOKEN` | The shared token between nexxus and the gateway, in both directions. Same value in all three. It must match the entry for this installation in the gateway's project list. |
| `AI_GATEWAY_AUTH_MODE` | `token` (default) or `jwt`. Decides which gateway generation workspaces use unless an admin switches it on the provider page. |
| `AI_GATEWAY_V0_AUTH` | `token` (default) or `jwt`. With `jwt` every call to the static-token generation carries a short-lived signed token instead of the shared token. The gateway then takes the workspace and the person from that token and refuses a request that names others. The installation's entry in the gateway's project list needs the same secret as `jwtSecret`. |
| `NEXXUS_AI_GATEWAY_JWT_SECRET` | Shared signing secret for the JWT gateway generation and for `AI_GATEWAY_V0_AUTH=jwt`. At least 32 characters. |
| `AI_GATEWAY_V1_URL` | Address of the JWT gateway generation. |
| `AI_EMBEDDINGS_ENABLED` | `false` locks search by meaning off for every workspace. |

The AI gateway calls back into nexxus for keys, tools and knowledge, so it must be able to reach the nexxus backend. Its own defaults for embeddings (`EMBEDDING_PROVIDER`, `EMBEDDING_MODEL`) and an optional installation-wide chat model (`DEFAULT_CHAT_MODEL`, written as `provider/model`) live in the gateway's configuration.

## Next steps

<CardGrid>
  <LinkCard title="Search by meaning" description="Choose the embedding model and keep knowledge and documents searchable." href="/setup/embeddings/" />
  <LinkCard title="Voice" description="Dictation in the chat and answers read aloud." href="/setup/voice/" />
  <LinkCard title="Working with the AI Assistant" description="What your team sees once the models are published." href="/use/assistant/" />
</CardGrid>