# How to Add a New AI Provider to Bella OpenAPI by Implementing IProtocolAdaptor

> Learn to add a new AI provider to Bella OpenAPI by implementing IProtocolAdaptor. Follow Spring integration steps for seamless API extension and enhanced functionality.

- Repository: [Ke Technologies/bella-openapi](https://github.com/lianjiatech/bella-openapi)
- Tags: how-to-guide
- Published: 2026-03-06

---

**To add a new AI provider to Bella OpenAPI, implement the `IProtocolAdaptor` interface (or a specialized sub-interface like `CompletionAdaptor`), create a property DTO extending `IProtocolProperty`, and annotate the class with `@Component` so Spring auto-registers it with the `AdaptorManager`.**

The [lianjiatech/bella-openapi](https://github.com/lianjiatech/bella-openapi) repository uses a pluggable adapter pattern to integrate diverse AI services. By implementing the generic `IProtocolAdaptor` interface, you can route requests to any external LLM or embedding service without modifying core controller logic. This guide walks through the concrete implementation steps using actual source paths from the codebase.

## Understanding the Bella OpenAPI Adapter Architecture

Bella OpenAPI delegates all provider-specific logic to implementations of `IProtocolAdaptor`. At startup, [`BellaAutoConf`](https://github.com/lianjiatech/bella-openapi/blob/develop/api/server/src/main/java/com/ke/bella/openapi/configuration/BellaAutoConf.java) collects every Spring bean implementing this interface and registers them with the singleton [`AdaptorManager`](https://github.com/lianjiatech/bella-openapi/blob/develop/api/server/src/main/java/com/ke/bella/openapi/protocol/AdaptorManager.java). When a request arrives, [`EndpointService`](https://github.com/lianjiatech/bella-openapi/blob/develop/api/server/src/main/java/com/ke/bella/openapi/service/EndpointService.java) looks up the appropriate adaptor by endpoint and protocol, then delegates execution.

The framework provides specialized sub-interfaces for common tasks:

- **`CompletionAdaptor<T>`** for chat and text completion
- **`EmbeddingAdaptor<T>`** for vector embeddings

## Step-by-Step Implementation Guide

### 1. Create a Property DTO

Define a class that implements `IProtocolProperty` (or a specific variant like `CompletionProperty`) to hold provider-specific configuration such as API keys, model IDs, and base URLs.

```java
package com.ke.bella.openapi.protocol.myprovider;

import com.ke.bella.openapi.protocol.IProtocolProperty;

public class MyProviderCompletionProperty implements IProtocolProperty {
    public String apiKey;
    public String model;
    public String baseUrl;
}

```

Store this file at [`api/sdk/src/main/java/com/ke/bella/openapi/protocol/myprovider/MyProviderCompletionProperty.java`](https://github.com/lianjiatech/bella-openapi/blob/main/api/sdk/src/main/java/com/ke/bella/openapi/protocol/myprovider/MyProviderCompletionProperty.java).

### 2. Implement the Adaptor Interface

Create a class that implements the appropriate sub-interface. For chat completions, extend `CompletionAdaptor<T>` where `T` is your property class. Implement the `completion()` and `streamCompletion()` methods to translate between Bella's request/response format and the provider's API.

```java
package com.ke.bella.openapi.protocol.myprovider;

import com.ke.bella.openapi.protocol.Callbacks;
import com.ke.bella.openapi.protocol.completion.CompletionAdaptor;
import com.ke.bella.openapi.protocol.completion.CompletionRequest;
import com.ke.bella.openapi.protocol.completion.CompletionResponse;
import okhttp3.*;
import org.springframework.stereotype.Component;
import java.io.IOException;

@Component
public class MyProviderCompletionAdaptor implements CompletionAdaptor<MyProviderCompletionProperty> {

    private final OkHttpClient http = new OkHttpClient();

    @Override
    public CompletionResponse completion(CompletionRequest request,
                                        String url,
                                        MyProviderCompletionProperty property) {
        Request.Builder builder = authorizationRequestBuilder(property);
        builder.url(property.baseUrl != null ? property.baseUrl : "https://api.myprovider.com/v1/chat/completions")
               .post(RequestBody.create(MediaType.parse("application/json"),
                        request.toJson(property.model)));

        try (Response resp = http.newCall(builder.build()).execute()) {
            if (!resp.isSuccessful()) {
                throw new IOException("Unexpected code " + resp);
            }
            return CompletionResponse.fromJson(resp.body().string());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void streamCompletion(CompletionRequest request,
                                 String url,
                                 MyProviderCompletionProperty property,
                                 Callbacks.StreamCompletionCallback callback) {
        // Implement Server-Sent Events or WebSocket streaming logic here
        // Call clearLargeData(...) for huge responses to prevent memory issues
    }

    @Override
    public String endpoint() {
        return "/v1/chat/completions";
    }

    @Override
    public String getDescription() {
        return "Adapter for MyProvider chat completion API";
    }

    @Override
    public Class<?> getPropertyClass() {
        return MyProviderCompletionProperty.class;
    }
}

```

Place this implementation at [`api/server/src/main/java/com/ke/bella/openapi/protocol/myprovider/MyProviderCompletionAdaptor.java`](https://github.com/lianjiatech/bella-openapi/blob/main/api/server/src/main/java/com/ke/bella/openapi/protocol/myprovider/MyProviderCompletionAdaptor.java).

**Key implementation details:**

- Use the inherited `authorizationRequestBuilder()` method from `IProtocolAdaptor` to construct the `Authorization` header.
- The `endpoint()` method must return the exact path used by the frontend (e.g., `/v1/chat/completions`).
- The `@Component` annotation triggers automatic discovery—no manual registration required.

### 3. Configure Provider Credentials

Add provider-specific settings to [`application.yml`](https://github.com/lianjiatech/bella-openapi/blob/main/application.yml) or externalize them via environment variables. The adaptor receives these values through the property object passed in the request.

```yaml
myprovider:
  api-key: ${MY_PROVIDER_API_KEY}
  base-url: https://api.myprovider.com
  model: gpt-4-my

```

### 4. (Optional) Register Cost and Model Metadata

If your provider uses custom pricing or model capabilities, implement `IPriceInfo` for billing integration with `CostCounter`, or `IModelFeatures`/`IModelProperties` to expose model-specific behaviors.

### 5. Test the Adaptor

Use the mock network utilities provided in the SDK to write isolated unit tests. The [`MockNetworkIO`](https://github.com/lianjiatech/bella-openapi/blob/develop/api/sdk/src/main/java/com/ke/bella/openapi/mock/MockNetworkIO.java) class stubs HTTP interactions without external calls.

```java
package com.ke.bella.openapi.protocol.myprovider;

import com.ke.bella.openapi.protocol.completion.CompletionRequest;
import com.ke.bella.openapi.protocol.completion.CompletionResponse;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class MyProviderCompletionAdaptorTest {

    @Test
    void testCompletion() {
        MyProviderCompletionAdaptor adaptor = new MyProviderCompletionAdaptor();
        CompletionRequest req = new CompletionRequest();
        MyProviderCompletionProperty prop = new MyProviderCompletionProperty();
        prop.apiKey = "test-key";
        prop.model = "gpt-4-my";
        prop.baseUrl = "http://localhost:8080/mock";

        CompletionResponse resp = adaptor.completion(req, null, prop);
        assertNotNull(resp);
    }
}

```

Run the test suite with:

```bash
mvn test -pl server -Dtest=MyProviderCompletionAdaptorTest

```

## Critical Source Files for Reference

- **Core Interface:** [`IProtocolAdaptor`](https://github.com/lianjiatech/bella-openapi/blob/develop/api/server/src/main/java/com/ke/bella/openapi/protocol/IProtocolAdaptor.java) — Base contract all adaptors must implement.
- **Chat Completion Sub-interface:** [`CompletionAdaptor`](https://github.com/lianjiatech/bella-openapi/blob/develop/api/server/src/main/java/com/ke/bella/openapi/protocol/completion/CompletionAdaptor.java) — Specialized contract for LLM chat endpoints.
- **Central Registry:** [`AdaptorManager`](https://github.com/lianjiatech/bella-openapi/blob/develop/api/server/src/main/java/com/ke/bella/openapi/protocol/AdaptorManager.java) — Singleton that maps endpoints to adaptor instances.
- **Auto-Registration:** [`BellaAutoConf`](https://github.com/lianjiatech/bella-openapi/blob/develop/api/server/src/main/java/com/ke/bella/openapi/configuration/BellaAutoConf.java) — Spring configuration that injects all `IProtocolAdaptor` beans into the manager.
- **Request Routing:** [`EndpointService`](https://github.com/lianjiatech/bella-openapi/blob/develop/api/server/src/main/java/com/ke/bella/openapi/service/EndpointService.java) — Service layer that resolves adaptors at runtime.
- **Reference Implementation:** [`OpenAiAdaptor`](https://github.com/lianjiatech/bella-openapi/tree/develop/api/server/src/main/java/com/ke/bella/openapi/protocol/openai) — Working example of a production provider integration.

## Summary

- **Implement `IProtocolAdaptor`** (or `CompletionAdaptor<T>`) to handle provider-specific protocol translation.
- **Create a property class** extending `IProtocolProperty` to encapsulate API keys, models, and endpoints.
- **Annotate with `@Component`** to enable Spring's auto-discovery and registration via `BellaAutoConf`.
- **Override `endpoint()`** to define the URL path that routes requests to your adaptor.
- **Use `MockNetworkIO`** for unit testing HTTP interactions without live network calls.

Once deployed, Bella OpenAPI automatically routes matching requests to your implementation through the `AdaptorManager`, enabling immediate integration with the new AI provider.

## Frequently Asked Questions

### What is the difference between `IProtocolAdaptor` and `CompletionAdaptor`?

`IProtocolAdaptor` is the generic base interface for all protocol adapters in Bella OpenAPI. `CompletionAdaptor<T>` is a specialized sub-interface specifically for chat completion and text generation endpoints. When adding a new LLM provider, you should implement `CompletionAdaptor<T>` rather than the base interface to inherit default methods like `authorizationRequestBuilder()` and ensure type safety with your property class.

### How does Bella OpenAPI discover my new adaptor without explicit configuration?

The framework uses Spring's dependency injection and component scanning. According to [`BellaAutoConf`](https://github.com/lianjiatech/bella-openapi/blob/develop/api/server/src/main/java/com/ke/bella/openapi/configuration/BellaAutoConf.java), any bean implementing `IProtocolAdaptor` is automatically injected into the `adaptorManager()` method, which registers each instance under the endpoint returned by its `endpoint()` method. Simply adding `@Component` to your class completes the registration.

### Can I add multiple endpoints for the same provider?

Yes. Implement separate adaptor classes for each endpoint (for example, one for `/v1/chat/completions` and another for `/v1/embeddings`), ensuring each implements the appropriate sub-interface (`CompletionAdaptor` vs `EmbeddingAdaptor`). Each class should return a unique endpoint string and be annotated with `@Component`. The `AdaptorManager` stores both registrations independently.

### How do I handle streaming responses from my AI provider?

Implement the `streamCompletion()` method in your `CompletionAdaptor`. Use OkHttp's WebSocket or Server-Sent Events (SSE) to consume the provider's streaming API, and invoke the provided `Callbacks.StreamCompletionCallback` for each chunk. If processing large payloads, call `clearLargeData()` on the response object to prevent memory exhaustion, as indicated in the interface contracts.