# How OpenCTI Integrates with AI/ML Models Such as Mistral AI: A Technical Deep Dive

> Discover how OpenCTI integrates with AI ML models like Mistral AI. Explore its unified layer for natural language querying and text summarization via GraphQL. A technical deep dive.

- Repository: [OpenCTI Platform/opencti](https://github.com/opencti-platform/opencti)
- Tags: deep-dive
- Published: 2026-02-19

---

**OpenCTI integrates with Mistral AI through a unified AI layer that reads runtime configuration, instantiates provider-specific clients, and exposes streaming capabilities via GraphQL mutations for features like natural language querying and text summarization.**

The **OpenCTI-Platform/opencti** repository implements a provider-agnostic AI architecture that supports Mistral AI, OpenAI, and Azure OpenAI through a consistent abstraction layer. This **OpenCTI AI/ML integration** enables cybersecurity teams to leverage large language models for automated threat intelligence processing without modifying core business logic.

## Configuration-Driven AI Provider Setup

OpenCTI uses the **nconf** configuration system to manage AI runtime settings. The platform reads AI parameters from [`config.yml`](https://github.com/OpenCTI-Platform/opencti/blob/main/config.yml) or environment variables to determine which provider to instantiate.

Key configuration parameters include:
- `ai:enabled` – Boolean flag to activate the AI layer
- `ai:type` – Provider identifier (`mistralai`, `openai`, or `azureopenai`)
- `ai:endpoint` – API base URL (e.g., `https://api.mistral.ai`)
- `ai:token` – Authentication API key
- `ai:model` – Model name (e.g., `mistral-large`)

In [`opencti-platform/opencti-graphql/src/database/ai-llm.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/opencti-platform/opencti-graphql/src/database/ai-llm.ts) (lines 18–27), the platform retrieves these values:

```typescript
const AI_ENABLED = conf.get('ai:enabled');
const AI_TYPE    = conf.get('ai:type');
const AI_ENDPOINT = conf.get('ai:endpoint');
const AI_TOKEN    = conf.get('ai:token');
const AI_MODEL    = conf.get('ai:model');

```

## Client Initialization and Provider Selection

The integration supports both official Mistral endpoints and OpenAI-compatible interfaces (such as vLLM). The provider selection logic in [`ai-llm.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/ai-llm.ts) (lines 30–61) dynamically instantiates the appropriate client and chat wrapper.

For **Mistral AI**, the implementation creates a `Mistral` client from the `@mistralai/mistralai` SDK and selects between `ChatMistralAI` (official API) or `ChatOpenAI` (OpenAI-compatible endpoints):

```typescript
if (AI_ENABLED && AI_TOKEN) {
  switch (AI_TYPE) {
    case 'mistralai':
      client = new Mistral({
        serverURL: isEmptyField(AI_ENDPOINT) ? undefined : AI_ENDPOINT,
        apiKey: AI_TOKEN,
      });

      if (AI_ENDPOINT?.includes('https://api.mistral.ai')) {
        nlqChat = new ChatMistralAI({ 
          model: AI_MODEL, 
          apiKey: AI_TOKEN, 
          temperature: 0 
        });
      } else {
        nlqChat = new ChatOpenAI({
          model: AI_MODEL,
          apiKey: AI_TOKEN,
          temperature: 0,
          configuration: { baseURL: `${AI_ENDPOINT}/v1` },
        });
      }
      break;
  }
}

```

## Streaming Query Implementation

The `queryMistralAi` function in [`ai-llm.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/ai-llm.ts) (lines 104–132) handles streaming chat completions. It constructs a `ChatCompletionStreamRequest`, sends it to the Mistral client, and processes the response stream chunk by chunk:

```typescript
export const queryMistralAi = async (
  busId: string | null,
  systemMessage: string,
  userMessage: string,
  user: AuthUser,
) => {
  if (!client) throw UnsupportedError('Incorrect AI configuration');
  
  const request: ChatCompletionStreamRequest = {
    model: AI_MODEL,
    temperature: 0,
    messages: [
      { role: 'system', content: systemMessage },
      { role: 'user', content: truncate(userMessage, AI_MAX_TOKENS, false) },
    ],
  };
  
  const response = await (client as Mistral)?.chat.stream(request);
  let content = '';
  
  for await (const chunk of response) {
    if (chunk.data.choices[0].delta.content !== undefined) {
      content += chunk.data.choices[0].delta.content;
      if (busId !== null) {
        await notify(BUS_TOPICS[AI_BUS].EDIT_TOPIC, { bus_id: busId, content }, user);
      }
    }
  }
  return content;
};

```

This implementation supports real-time updates through OpenCTI's internal event bus when a `busId` is provided.

## Unified AI Query Interface

The `queryAi` function (lines 184–195) serves as the unified entry point for all AI operations. It routes requests to provider-specific implementations based on the `AI_TYPE` configuration:

```typescript
export const queryAi = async (
  busId: string | null,
  developerMessage: string | null,
  userMessage: string,
  user: AuthUser,
) => {
  const finalDeveloperMessage = developerMessage
    || 'You are an assistant helping a cyber threat intelligence analyst …';
    
  switch (AI_TYPE) {
    case 'mistralai':
      return queryMistralAi(busId, finalDeveloperMessage, userMessage, user);
    case 'azureopenai':
    case 'openai':
      return queryChatGpt(busId, finalDeveloperMessage, userMessage, user);
    default:
      throw UnsupportedError('Not supported AI type', { type: AI_TYPE });
  }
};

```

## GraphQL API Exposure

High-level AI features in [`opencti-platform/opencti-graphql/src/modules/ai/ai-domain.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/opencti-platform/opencti-graphql/src/modules/ai/ai-domain.ts) consume the unified interface. Functions like `fixSpelling`, `summarize`, and `generateNLQresponse` call `queryAi` (or `queryNLQAi` for natural language queries) and expose capabilities through GraphQL mutations.

For example, the spell-checking resolver (lines 57–74) constructs a prompt and streams the correction:

```typescript
export const fixSpelling = async (context, user, id, content, format = Format.Text) => {
  const prompt = `...${content}`;
  const response = await queryAi(id, SYSTEM_PROMPT, prompt, user);
  return response;
};

```

Clients invoke these capabilities via GraphQL mutations:

```graphql
mutation FixSpelling($id: ID!, $content: String!, $format: Format) {
  fixSpelling(id: $id, content: $content, format: $format)
}

```

## Practical Configuration for Mistral AI

To enable **OpenCTI Mistral AI integration**, configure your [`config.yml`](https://github.com/OpenCTI-Platform/opencti/blob/main/config.yml) as follows:

```yaml
ai:
  enabled: true
  type: mistralai
  endpoint: https://api.mistral.ai
  token: ${MISTRAL_API_KEY}
  model: mistral-large
  max_tokens: 2048

```

Set the API key via environment variable:

```bash
export MISTRAL_API_KEY=your-mistral-api-key

```

After restarting the platform, AI-powered mutations become available through the GraphQL API.

## Summary

- OpenCTI implements a **provider-agnostic AI layer** supporting Mistral AI, OpenAI, and Azure OpenAI through unified configuration keys in [`ai-llm.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/ai-llm.ts).
- The platform dynamically selects between `ChatMistralAI` and `ChatOpenAI` wrappers based on endpoint URL patterns, enabling both official APIs and OpenAI-compatible deployments.
- **Streaming responses** are handled through `queryMistralAi`, which processes chunks from the Mistral client and optionally pushes updates through the internal event bus.
- GraphQL resolvers in [`ai-domain.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/ai-domain.ts) expose AI capabilities (spelling correction, summarization, natural language queries) without hardcoding provider logic.
- All AI features route through the `queryAi` dispatcher, ensuring consistent error handling and system prompt management across providers.

## Frequently Asked Questions

### How do I configure OpenCTI to use a self-hosted Mistral model via vLLM?

Set `ai:type` to `mistralai` and point `ai:endpoint` to your vLLM server URL. The code in [`ai-llm.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/ai-llm.ts) detects non-official endpoints and automatically uses `ChatOpenAI` with a custom `baseURL` instead of the native `ChatMistralAI` client, allowing OpenAI-compatible API access to your local model.

### What GraphQL mutations are available for AI features in OpenCTI?

Available mutations include `fixSpelling` for text correction, `summarize` for content condensation, and `generateNLQresponse` for natural language querying. These reside in [`ai-domain.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/ai-domain.ts) and accept parameters like entity IDs, content strings, and output formats, returning AI-generated responses streamed from your configured provider.

### Where does OpenCTI handle AI authentication and token management?

Authentication tokens are read from the **nconf** configuration system in [`ai-llm.ts`](https://github.com/OpenCTI-Platform/opencti/blob/main/ai-llm.ts) (lines 18–27) via `conf.get('ai:token')`. The platform passes these tokens directly to provider SDKs (`Mistral`, `OpenAI`) without logging or exposing them in error messages, ensuring secure credential handling.

### Can OpenCTI stream AI responses to connected clients in real-time?

Yes. When a `busId` is provided to `queryMistralAi`, the function calls `notify()` on the internal event bus (`BUS_TOPICS[AI_BUS].EDIT_TOPIC`) for each content chunk received from the Mistral stream. This enables live updates in the OpenCTI web interface or other subscribed clients during long-running AI operations.