Kong AI Gatewayで複数のAIのAPIを一元管理する

Kongが2月15日に[Kong AI Gatewayを発表した](https://konghq.com/blog/product-releases/announcing-kong-ai-gateway)。
AI系のAPIを統合管理するための機能で、提供される機能としてはざっくり以下となっている。
- 複数のLLMの統合：**同一APIで複数のLLM(OpenAI、Azure AI、Mistral、LLaMA等)が利用可能に**
- AIの認証情報を一元管理
- L7でのAIのメトリクスの収集
- コードレスでAIを統合
- プロンプトエンジニアリングの強化
- プロンプトのFirewallの提供
- AI用のEgressの提供およびトラフィック制御

AI系のサービスが乱立し始めている現在において、それらをまとめた管理するための機能がいい感じで揃っていそう。
利用前後の比較は以下のようになっていて、各アプリで個別にAIサービスを利用してサイロ化するのを防ぐことが出来るようにみえる。
![1708054044227.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/6be29d21-4eff-e5ac-8a2a-3ec34d07f084.png)
（[AI Gateway](https://docs.konghq.com/gateway/latest/get-started/ai-gateway/)より引用）

実装としては、従来のKong Gatewayに以下の6つのプラグインが追加で提供されるようになったものであり、ベースとなるアーキテクチャに変更があるようなものではなさそうだ。
- AI Proxy
- AI Request/Response Transformer
- AI Prompt Guard
- AI Prompt Template
- AI Prompt Decorator

ここでは、AI Proxyを味見してみた時のメモを残す。
実際に確認した環境の構成は以下となる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/39f705e0-7de6-2703-343c-a26b4c52de94.png)
基本的な構築・確認手順は[Get Started](https://docs.konghq.com/gateway/latest/get-started/ai-gateway/)に従う。

## Kong AI Gatewayの構築
検証用の環境を構築する。
お試し用にDockerを利用した構築スクリプトが用意されているので、今回はこれで構築する。
Dockerが使える環境なら多分どこでも動くはず。
以下の手順にて構築スクリプトを実行する。
```sh
curl -Ls https://get.konghq.com/ai | bash
```
スクリプトを実行すると最初にLLMプロバイダーのAPIキーを利用する旨が表示されるので `y`を選択して続行する。
```
In order for the AI Gateway to proxy requests, this tool must collect
API keys for each LLM provider that you wish to enable. These API keys
will be configured as environment variables for the locally running
Kong Gateway data plane only and will not be sent outside this host machine.

Do you want to continue? (y/n) y
```
次にAI GatewayのデータプレーンがローカルのDockerインスタンスとして起動し、コントロールプレーンはデフォルトでは[Kong Konnect(KongのSaaSのサービス)](https://konghq.com/kong-konnect)で動く旨が説明される。
ここではSaaSは利用しないので、次の問いかけには`n`で進める。
```
This CLI deploys the Kong AI Gateway data plane on a local Docker instance.
By default, Kong Konnect (https://konghq.com/kong-konnect) provides
a serverless control plane and many other advanced API management capabilities.

Optionally, you may choose to deploy the AI Gateway locally using Docker only,
but you will not have access to the additional Kong Konnect capabilities.

Do you want to deploy on Kong Konnect (y/n) n
```

次にLLMプロバイダのAPIキーを登録する。
登録できるプロバイダはOpenAI、Cohere、Azure、Anthropicとなっている。
ここでは試しにOpenAIとCohereを使ってみる。
APIの取得方法は割愛するが、OpenAIに関しては以前k8sgptを紹介した[こちら](https://qiita.com/ipppppei/items/e80af857b017d5d288fa#%E6%BA%96%E5%82%99)の記事が多少参考になるかも。
```
ℹ First we collect API Keys for hosted LLM providers, for example OpenAI.
  Provide a key for each provider you want to enable and press Enter.
  Not providing a key and pressing Enter will skip configuring that provider.

→ Enter API Key for OpenAI    : sk-cxxxxxxxxxxxxxxxxxx
→ Enter API Key for Cohere    : qIzGxxxxxxxxxxxxxxxxxx
→ Enter API Key for Azure     :
→ Enter API Key for Anthropic :
```
次にローカルで動くモデルの設定を行う。ここではMistralとLlama2が選べるので、どちらとも`y`で進めた。(実際に確認したのはMistralのみ)
```
ℹ Next, we configure local providers which are LLM models running on
  this host machine. These providers will be configured to access AI API
  endpoints on this host machine (http://host.docker.internal:11434).

  An example tool that can run models locally is Ollama.
   https://github.com/ollama/ollama

  If these local models are enabled on your host,
  enter 'y' to enable a provider, or 'n' to disable it.

→ Do you want to enable the local provider Mistral  ? (y/n): y
→ Do you want to enable the local provider Llama2   ? (y/n): y
```
以上で設定は終わりとなり、この後はスクリプト内でイメージをダウンロードしてGatewayを起動してくれる。
以下のメッセージが出れば起動完了となる。
```
⏲︎ Preparing Cohere API specification and decK configuration... ✔
⏲︎ Preparing Mistral API specification and decK configuration... ✔
⏲︎ Preparing Llama2 API specification and decK configuration... ✔
⏲︎ Merging decK files... ✔
⏲︎ Syncing Kong Gateway configuration... ✔
✔ AI Gateway Configured

🐵 Kong Gateway Ready 🐵
```
各種接続先は`/tmp/kong/ai-gateway/kong.env`で確認できる。
```sh:/tmp/kong/ai-gateway/kong.env
export KONG_PROXY=localhost:8000
export KONG_ADMIN_API=localhost:8001
export KONG_MANAGER=localhost:8002
export KONG_DEV_PORTAL=localhost:8003
export KONG_FILES_API=localhost:8004
```
Managerにブラウザで接続すると、各種AI系のプラグインが確認できる。
![1708322815950.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/915bb173-f015-4a0f-a01a-5415da85719b.png)

また、各LLMのエンドポイントはRoutesから確認できる。
![1708324273304.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/b995d6de-30ec-c7cd-9238-c28ea4dadee2.png)

## 動作確認
### OpenAI
先ほど確認したように、OpenAIのエンドポイントは`~/openai/chat$`となっているので、${KONG_PROXY}/openai/chatにリクエストを投げればOpenAIとやりとり出来るはずだ。
ここでは[Get Started](https://docs.konghq.com/gateway/latest/get-started/ai-gateway/)にあるcurlコマンドを拝借して叩いてみる。
```sh
curl -s -X POST localhost:8000/openai/chat \
  -H "Content-Type: application/json" -d '{
    "messages": [{
    "role": "user",
    "content": "What is Kong Gateway?"
  }] }'
```  
以下のエラーが返ってきた。
```json
{
    "error": {
        "message": "You exceeded your current quota, please check your plan and billing details. For more information on this error, read the docs: https://platform.openai.com/docs/guides/error-codes/api-errors.",
        "type": "insufficient_quota",
        "param": null,
        "code": "insufficient_quota"
    }
}
```
ChatGPT4を課金してたのだが、APIは別料金とのこと。
仕方ないので課金する。
なお、課金は前払いでオートチャージもOffに出来、過金額の上限も設定できるので、少額スタートかつ使いすぎ防止が出来、ハードルはそれほど高くない。
課金後、以下のように正常な出力を得ることが出来た。
```json
{
  "id": "chatcmpl-8traQNIrKQ6C2AHLSKqrc7LlJVVAe",
  "object": "chat.completion",
  "created": 1708324718,
  "model": "gpt-3.5-turbo-0125",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Kong Gateway is an open-source, cloud-native API gateway and microservices management layer. It provides a variety of features such as security, analytics, traffic control, load balancing, and more to help organizations manage and secure their APIs and microservices. Kong Gateway is designed to help improve the performance, reliability, and scalability of API-based applications."
      },
      "logprobs": null,
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 12,
    "completion_tokens": 69,
    "total_tokens": 81
  },
  "system_fingerprint": "fp_69829325d0"
}
```

### Cohere
Cohereの場合、デフォルト値では上手く動かない。
以下を投げてみる。
```sh
curl -s -X POST localhost:8000/cohere/chat \
  -H "Content-Type: application/json" --data-raw '{
    "messages": [{
    "role": "user",
    "content": "What is Kong Gateway?"
  }] }'
```
すると以下のようにエラーが返ってくる。
```json
{"message":"model 'model' not found, make sure the correct model ID was used and that you have access to the model."}
```
エラーメッセージを見るとModelが適切に設定されていないと出ている。
ManagerのUIから`Routes`->`cohere-api_cohere-chat`->`Plugins`
からAI ProxyのConfigurationを確認すると、ModelのNameが`Model`となっている。
ここを[AI ProxyのCohereの説明](https://docs.konghq.com/hub/kong-inc/ai-proxy/how-to/cohere/#set-up-route-and-plugin)で設定している`command`に変更してやる。
![1708329114148.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/f608483f-c864-0241-3b7a-eee7a3fec367.png)
そうすると、以下のように正常な出力が返ってくる。
```json
{"choices":[{"index":0,"message":{"role":"assistant","content":"Kong Gateway is an open-source API Gateway providing active mediation between services and API consumers. Kong allows developers to publish, manage, and secure APIs and microservices in modern architectures, including cloud-native environments, where APIs and services are widely distributed across domains.\n\nKey features of Kong Gateway are:\n- **API Routing** – Kong can dynamically route requests between different services versions or subsets, allowing changes and rolling updates with no downtime, and supporting smooth migration to new service versions without any impact on existing API implementations.\n- **API Gateway** – Kong controls who has access to APIs and how APIs are exposed, protecting your APIs from common security attacks, and enforcing the enterprise security and compliance policies.\n- **Security** – Kong enforces authentication and authorization, ensuring that only authenticated and authorized users have access to services. It supports various authentication mechanisms including OAuth 2.0, OIDC, and others. Additionally, Kong allows the usage of SSL/TLS certificates to encrypt data in transit.\n- **Service Discovery** – Kong enables the dynamic discovery of services, allowing for better resilience through service eviction/promotion processes. It handles service registry, health checking, and routing rules, taking advantage of a service registry solution to optimize the availability and latency of a service.\n- **Microservice Management** – Kong empowers teams to deploy, manage, and monitor thousands of APIs and microservices with consistency and confidence, allowing organizations to visualize their APIs and microservices in order to understand how they interact, and effectively identify and mitigate potential problems. \n\nThese are just a few of the many features Kong Gateway offers for handling APIs and microservices. \n\nIf you want to know more, I am happy to provide additional details and examples upon request."},"finish_reason":"stop"}],"usage":{"completion_tokens":353,"prompt_tokens":67,"total_tokens":420},"id":"a2b4b125-c3f8-4c7b-9837-ef7211819c3a","model":"command","object":"chat.completion"}
```

### ローカルLLM（Mistral）
ローカルLLMはLlama2とMistralでやることはそんなに違わないと思われるので、ここではMistralで確認した。
Mistralはlocalhost:7999でサービスを公開している。（起動方法は本メモの最後に載せている）
こちらもデフォルト値で動かすと、以下のエラーが出て弾かれる。
```json
{
  "message":"An invalid response was received from the upstream server",
  "request_id":"8027b7287773656e6ee0b16ebcf4941c"
}
```
構築時にローカルLLMのエンドポイントを指定する箇所がなかったので当然といえば当然だが、ローカルLLMのエンドポイントを指定する必要がある。
これについては以下の設定を行うことで動作することが確認できた。（ドキュメントを参照した訳ではなく試行錯誤で見つけたので、正確には少し違うかも）

1. Gateway Servicesのエンドポイントを変更
2. RoutesのPluginのUpstream URLを変更

1については以下のように`mistral-api`のHostを`host.docker.internal:7999`に変更した。
![1708346392634.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/1dbfdabe-f3d6-35e6-3b65-8bf148c13e00.png)
Mac上の`localhost`のサービスへのアクセスはコンテナ内からだと`host.docker.internal`になる点は注意。

2については`Routes`->`mistral-api_mistral-chat`->`Plugins`からAI ProxyをEditし、Upstream Urlを`http://host.docker.internal:7999/v1/chat/completions`に変更した。
![1708346642870.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/49425534-218e-c71d-f490-b57be34f6525.png)

この状態でcurlする。
```sh
curl -s -X POST localhost:8000/mistral/chat   -H "Content-Type: application/json" -d '{
    "messages": [{
    "role": "user",
    "content": "What is Kong Gateway?"
  }] }'
```
今度は正しい結果が得られた。
```json
{"id":"chatcmpl-f714c5ed-5823-418f-817f-c6eed38d77a6","object":"chat.completion","created":1708334471,"model":"mistral","choices":[{"index":0,"message":{"content":" Kong Gateway is an API management platform that enables businesses to create, secure, and manage APIs. It provides a comprehensive solution for building, deploying, and scaling APIs, allowing organizations to easily integrate with their existing systems and technologies.\n\nKong Gateway offers a range of features, including authentication and authorization, rate limiting, caching, load balancing, traffic routing, and monitoring. It also supports a wide range of protocols and technologies, including REST, GraphQL, WebSocket, and gRPC.\n\nOne of the key features of Kong Gateway is its ability to act as a reverse proxy, allowing developers to expose complex internal microservices or legacy applications as RESTful APIs. This can help simplify the integration of different services and improve the overall developer experience.\n\nOverall, Kong Gateway can help organizations streamline their API development and deployment processes, improve security and performance, and enable more efficient and scalable integration of different systems and technologies.","role":"assistant"},"finish_reason":"stop"}],"usage":{"prompt_tokens":17,"completion_tokens":205,"total_tokens":222}}
```
## まとめ
LLMのAPIのハブとしてKong Gatewayが使えることが確認できた。
認証・認可や流量制限などを組み合わせれば、ガバナンスを効かせた強力なハブとなり、AI関連のAPIの一元管理がかなり楽になりそうな手応えは得られた。
APIの発行回数で課金するモデルは管理が非常に重要になって来ると思われるので、AI関連に興味がある管理者とかは触っておいて損はなさそう。

## おまけ：llama.cppの起動
私の環境(Mac)では以下のコマンドでllama.cppをインストールした。
```sh
pip install llama-cpp-python
pip install uvicorn anyio starlette sse_starlette starlette_context fastapi pydantic_settings
```
次に、モデルを入手する。
[HuggingFaceのMistral](https://huggingface.co/mistralai)から適当なモデルを取得する。
ここではmistral-7b-instruct-v0.1.Q4_K_M.ggufをダウンロードした。
ローカルで起動する。デフォルトで8000ポートで動くが、これはKongが使っているのでポートを7999に変更して起動している。
```sh
python3 -m llama_cpp.server --model ./models/mistral-7b-instruct-v0.1.Q4_K_M.gguf --port 7999
```

動作確認する。
```sh
curl -s -X POST localhost:7999/v1/chat/completions \
  -H "Content-Type: application/json" --data-raw '{
    "messages": [{
    "role": "user",
    "content": "What is Kong Gateway?"
  }] }'
```
```json
{"id":"chatcmpl-4882f941-183d-4094-ad58-49c0546a09ef","object":"chat.completion","created":1708330859,"model":"./models/mistral-7b-instruct-v0.1.Q4_K_M.gguf","choices":[{"index":0,"message":{"content":" Kong Gateway is an open-source, API management platform that helps organizations to secure, monitor, and manage their APIs. It provides a scalable and flexible way to route, authenticate, authorize, and rate limit requests to and from APIs. Kong Gateway also supports various protocols like HTTP, MQTT, WebSocket, and gRPC, making it a versatile solution for managing APIs across different types of applications.","role":"assistant"},"finish_reason":"stop"}],"usage":{"prompt_tokens":17,"completion_tokens":92,"total_tokens":109}}
```
問題なさそうだ。

## おまけ2：Kong Konnect（SaaS版Kong Gateway）への展開
Quickstartのスクリプトを使っている場合、以下の質問で`y`を入力するとKong Konnect上に構築しようとする。
```shell
Do you want to deploy on Kong Konnect (y/n) y
```
この後、Personal Access Token（PAT）を求められるので、Konnectの[Personal Access Tokenのページ](https://cloud.konghq.com/global/account/tokens)に飛んで、`Generate Token`でTokenを生成する。

発行されたTokenを以下の質問の際にコピペする。
```shell
→ Enter your Konnect PAT : kpat_Qbze.....
```
以降は基本的にOSS版で進めるのと変わらない。
デプロイが完了すると、以下のようにKonnect上に`ai-gateway`というControl Planeが作成される。
![1709278342583.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/331b2124-8162-9a39-7008-ac63a699c5d0.png)
ということでKonnectユーザも簡単に試すことが出来るので、Konnectが使える人はこちらで確認してみてもよさそう。