製造業の中小企業が社内用ChatGPTをLibreChatで構築した話

# きっかけ

私は地方にある製造業の中小企業に勤めています．数ヶ月前に，ChatGPTを事務系の社員が使えるような環境を整えたいが，ChatGPTのTeamsプランでは費用が高いので，より安く実現できないか，という内容の相談を受けました．ChatGPTのような大規模言語モデルを業務で利用することに可能性を感じてはいるものの，まずはコストを抑えつつ実験的に導入してみたい，ということでした．社員からChatGPTを使えるようにしてほしいという要望が出たというよりは，経営陣が社員にChatGPTを使ってもらいたいというトップダウン的な側面が強く，導入したとしても実際に利用する社員がどのくらい出てくるのかわからない，という問題もありました．

つまり社内ChatGPTには次のようなことが求められます：

- 業務に利用可能であること
    - 公式のChatGPTは無料でも利用できますが，入力したデータがAIモデルの改善等に利用される可能性があります[^openai-data-usage]．入力したデータが利用されないようにするには，TeamsまたはEnterpriseプランに加入する必要があります．
- 安価であること
    - 公式のChatGPTのTeamsプランは$25/月（年払い）です[^chatgpt-pricing]．今回想定している利用者数はざっくり100人程度なので，30万円/月程度はかかります．
- 早く提供できること

これらの要求を満たす解決策として，LibreChatとOpenAI APIを利用することに決めました．


# LibreChat
LibreChatはフリーでオープンソースなチャットAI用のウェブインターフェイスです[^librechat]．ChatGPTのクローンを目指して開発されており，ChatGPTにそっくりなUIになっています[^librechat-ui-image]．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320225/1188b9a2-31aa-ac99-a8a8-8c5477ad4402.png)

機能が豊富で，ChatGPTにはない機能も提供しています[^librechat-features]．（逆にChatGPTにしかない機能もありますが）

- 直感的なUI：ChatGPTに似たインターフェース，ダークモード，リアルタイムストリーミング
- 多様なAIモデル選択：OpenAI，Azure OpenAI，BingAI，Anthropic（Claude）など
- カスタムプリセット：設定の保存と共有が可能
- 会話の編集と分岐：メッセージの編集，再送信，会話の分岐が可能
- マルチモーダルチャット：画像分析と文書対話機能
- 多言語UI：日本語を含む多数の言語をサポート
- 音声対話：音声認識と音声合成機能
- 会話のインポートとエクスポート：複数の形式に対応
- 検索機能：Meilisearchを使用した高度な検索
- プラグインとエクステンション：ウェブアクセス，画像生成など
- マルチユーザー認証：セキュアなユーザー管理

# OpenAI API

ChatGPTではなくOpenAI APIを利用することで，従量課金制での支払いになります．利用者全員が相当使い込まない限り，ChatGPTよりもコストを抑えることができるはずです．

またOpenAI APIに送信したデータはAIモデルの改善等には利用されません[^openai-enterprise-privacy]．ただし利用規約違反などを取り締まるために30日間データを保持するようです．

https://openai.com/enterprise-privacy/

# インフラ

AWS EC2にLibreChatをホストしています．公式のデプロイ手順[^librechat-docker-linux]に従って，DockerでLibreChatのコンテナを実行しています．

インフラの構成は非常にシンプルで，パブリックサブネットにEC2（`t3.small`）を１台置き，ALBなどは利用せずに直接インターネットからEC2にアクセスします．そのためユーザー認証やSSL証明書の発行・管理もEC2で行われます．同様にユーザーのチャット履歴やアップロードしたファイルなどのデータもすべてEC2内に保管されます．ウェブサービス構築のベストプラクティスからは逸脱した構成ですが，ユーザー数が最大100人程度の内部用サービスであるため，目的を十分果たすことができています．

# ユーザー管理・認証

LibreChatにはユーザー管理機能が組み込まれており，チャット履歴やアップロードしたファイルなどのデータをユーザーごとに分離することができます[^librechat-auth]．LibreChat上でアカウントを発行することもできるようですが，100人分のアカウント発行・管理を行うのは非常に手間がかかります．そこで今回は会社で契約しているMicrosoft 365とOpenID Connectで連携することで，MicrosoftアカウントでLibreChatにログインできるように設定しています[^librechat-auth-azure]．

# 費用

主にAWSとOpenAI APIに利用料金が発生します．

AWSの利用料金は数千円/月程度で，ほとんどがEC2インスタンスの料金です．従量課金制ではありますが，こちらの料金はあまり変動しないと考えて良いと思います．

変動が大きいのがOpenAI APIの利用料金です．従量課金制なので，利用者の数や利用頻度がそのまま料金に反映されます．

OpenAI APIのダッシュボードで詳細な利用量と料金を確認できます[^openai-api-usage]．遅くても次の日には前日までの利用が反映されているので，公開直後は一応毎日確認していました．

またOpenAI APIの設定からAPIの利用料金に上限を設定することもできます[^openai-api-limit]．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320225/a7c726e3-6131-27c6-febd-da39b4edc66e.png)

OpenAI APIの料金は利用状況や為替よって変動しますが，今のところ2~5万円/月程度で推移しています．ChatGPT Teamsプランの10分の1程度で抑えられています．


# 利用状況の確認

OpenAI APIのダッシュボードではLibreChat全体の利用状況を確認することはできますが，ユーザーごとの利用状況などのような，より細かい情報を確認することはできません．LibreChatのチャット履歴等はすべてデータベース（Mongo DB）に保存されており，データベースを直接見ることで細かい利用状況を確認できます．具体的にはMongoDBのコンテナのポートを開放し，SSHトンネルでローカルPCのMondoDB CompassからMongoDBに接続しています．

MongoDBにAggregation[^mongo-aggregation]という集計機能があり，例えばユーザーごと，日毎のメッセージ数を調べたりすることができます．また集計結果をJSONやCSVで出力できるので，データをある程度まで整形・集計してからPythonでプロットしています．MongoDBはほとんど使ったことがなかったので，LibreChatに聞いて集計のクエリを生成してもらいました．

MongoDBにはLibreChatのすべてのデータが保管されているため，すべてのユーザーのすべてのチャット履歴を見ることができてしまいます．業務利用とはいえ，他人に自分のチャット履歴や利用頻度を見られるのはあまり良い気分がしません．そのため，データの集計の際にはユーザー名などの個人を判別できる情報やチャットの文章を排除するようにクエリを設定しています．

# 発生した問題や課題

## 突然Banされる

LibreChatにアクセスすると，次のようなメッセージがブラウザに表示されて利用できない，ということがありました．

```json
{"message":"Your account has been temporarily banned due to violations of our service."}
```

これはLibreChatのModeration機能[^librechat-moderation]が原因です．Moderation機能にリミッターがあり，大量のメッセージ送信やログイン試行を制限することでLibreChatを守ることができるのですが，このうちのIPアドレスごとのメッセージ送信制限[^librechat-ip-limiter]に引っかかりました．インターネットから見ると社内ネットワークからのアクセスはすべて同じIPアドレスに見えるため，同時に利用するユーザーが増えると同じIPアドレスから大量のメッセージ送信が行われているように見えてしまうようです．

LibreChatの設定ファイルでIPアドレスごとのメッセージ送信制限を無効にすることでこの問題は解決しました．

## 安価なモデルばかり使われる

LibreChatを始動させた時点では，OpenAI APIが提供しているモデルには大まかに`gpt-3.5-turbo`と`gpt-4`がありました．`gpt-3.5-turbo`は安価で高速だが性能はそこそこ，`gpt-4`は性能は非常に高いが高価で遅い，というような特徴があります．最初の頃は利用者が目的のタスクに応じてモデルを使い分けることを想定し，`gpt-3.5-turbo`と`gpt-4`の両方を提供していました．

しかし実際には，利用者が高価な`gpt-4`を使うのを遠慮して`gpt-3.5-turbo`ばかり使われるという状態になっていました．コストを抑えたい気持ちは確かにありますが，大規模言語モデルを業務で活用する方法を模索することのほうがより重要です．そのためにも遠慮せずに`gpt-4`を使ってもらう必要があります．そこで思い切ってモデルの選択肢を減らし，`gpt-4`（現在は`gpt-4o`に変更）しか使えないように設定することにしました．

## EC2が応答しなくなる

EC2がそもそも応答しなくなることがありました．`t3.small`というスペックの低いインスタンスで実行しているため，利用が集中したときの負荷に耐えられないのかもしれません．SSH接続もできなかったので，EC2を再起動してみたら正常に動作し始めました．

必要に応じてより性能の高いインスタンスに移行します．

## 利用頻度の偏り

チャット履歴からLibreChatの利用状況を調べたところ，全体の利用量のほとんどを少数（十数人）のヘビーユーザーが占め，それ以外の大多数のユーザーはたまに使う，あるいは全く使っていない，という分布になっていることがわかりました．

おそらく利用頻度の低い利用者は，LibreChatをどう活用したらよいのかわからずに使えていないのだと考えています．ヘビーユーザーが存在することを考えると，LibreChatを活用できる業務が存在しないというわけではなさそうです．つまりLibreChatを業務で活用するためのノウハウをヘビーユーザーからライトユーザーにどう広めてもらうか，という点が会社全体でLibreChatを活用するための鍵になりそうです．


# 参考になる記事

同じようにLibreChatを社内で利用している事例を参考にさせていただきました．

https://techblog.a-tm.co.jp/entry/2024/05/31/165049

https://techblog.asahi-net.co.jp/entry/2024/01/11/105358

[^openai-data-usage]: https://help.openai.com/en/articles/7039943-data-usage-for-consumer-services-faq
[^openai-enterprise-privacy]: https://openai.com/enterprise-privacy/
[^chatgpt-pricing]: https://openai.com/chatgpt/pricing/
[^librechat]: https://www.librechat.ai/
[^librechat-ui-image]: 元画像：https://www.librechat.ai/_next/image?url=https%3A%2F%2Fgithub.com%2Fdanny-avila%2FLibreChat%2Fassets%2F32828263%2Fa03ee02d-5099-4220-95b0-bfa2d3b00b4d&w=1080&q=75
[^librechat-features]: https://www.librechat.ai/docs/features
[^openai-api-docs]: https://platform.openai.com/docs/overview
[^librechat-docker-linux]: https://www.librechat.ai/docs/remote/docker_linux
[^librechat-auth]: https://www.librechat.ai/docs/user_guides/authentication
[^librechat-auth-azure]: https://www.librechat.ai/docs/configuration/authentication/OAuth2-OIDC/azure
[^openai-api-usage]: https://platform.openai.com/organization/usage
[^openai-api-limit]: https://platform.openai.com/settings/organization/limits
[^librechat-moderation]: https://www.librechat.ai/docs/configuration/mod_system
[^librechat-ip-limiter]: https://www.librechat.ai/docs/configuration/mod_system#message-rate-limiting-per-ip
[^mongo-aggregation]: https://www.mongodb.com/docs/manual/aggregation/