[ChatStream] クイックスタート

[ChatStream] クイックスタート

こんにちは! (株)Qualiteg プロダクト開発部 です!

まだまだ暑いですね!

早速、昨日発表しました ChatStream をつかったリアルタイムストリーミングチャットサーバーを作ってみたいと思います。

パッケージのインストール

早速 ChatStream パッケージのインストールをしていきます

pip install chatstream

必要パッケージのインストール

pip install torch torchvision torchaudio
pip install transformers
pip install "uvicorn[standard]" gunicorn 

ChatStream サーバーの実装

今回は RedPajamaINCITE をLLMとしてつかったストリーミングチャットサーバーを実装します。

chatstream_server.py

import torch
from fastapi import FastAPI, Request
from fastsession import FastSessionMiddleware, MemoryStore
from transformers import AutoTokenizer, AutoModelForCausalLM

from chatstream import ChatStream,ChatPromptTogetherRedPajamaINCITEChat as ChatPrompt

model_path = "togethercomputer/RedPajama-INCITE-Chat-3B-v1"
device = "cuda"  # "cuda" / "cpu"

tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForCausalLM.from_pretrained(model_path, torch_dtype=torch.float16)
model.to(device)

chat_stream = ChatStream(
    num_of_concurrent_executions=2,# 文章生成の最大同時実行数
    max_queue_size=5,# 待ち行列の大きさ
    model=model,
    tokenizer=tokenizer,
    device=device,
    chat_prompt_clazz=ChatPrompt,
)

app = FastAPI()

# ユーザーごとの ChatPrompt を HTTP セッションに保持するため、セッションミドルウェアを指定
app.add_middleware(FastSessionMiddleware,
                   secret_key="your-session-secret-key",
                   store=MemoryStore(),
                   http_only=True,
                   secure=False,
                   )


@app.post("/chat_stream")
async def stream_api(request: Request):
    # FastAPI の Request オブジェクトを `handle_chat_stream_request` に渡すだけで自動的にキューイング、同時実行制御します
    response = await chat_stream.handle_chat_stream_request(request)
    return response


@app.on_event("startup")
async def startup():
    # Webサーバー起動と同時に `start_queue_worker` を行い、キューイングシステムを開始します
    await chat_stream.start_queue_worker()

コンストラクターパラメータでパフォーマンス調整

num_of_concurrent_executions

num_of_concurrent_executions=2 は文章生成の最大同時実行数を表しています。この数字が大きいほど、複数の文章生成を並行実行することができます。ただし、大きすぎると、トークン生成速度(トークン/秒)が遅くなるため、GPUの性能にあわせて適切な値を設定してください。たとえば、GPUが A4000 x 1枚 程度の性能の場合は num_of_concurrent_executions=5~10 程度が「快適」と思える生成速度となります。

max_queue_size

max_queue_size=5 は、文章生成の同時実行が埋まっているときに、文章生成待ちをしているリクエストの最大数です。たとえば、上の例のように文章生成の同時実行数の最大数 num_of_concurrent_executions==2 に達しているとき、3番目のリクエストからは待ち行列に入ります。3番目から8番目までは、文章生成を待っている状態で、チャットUI上ではプログレスバーとなります。では、この状態で9番目のリクエストが来たらどうなるでしょうか。

その場合、9番目のリクエストには「現在、文章生成サーバーがBusyです」の旨UIに表示されます。

(ただしこのような状況はサービスとして好ましくないため、このような状況が発生しないよう複数のノードをあらかじめ準備しておくことができます。また、急遽想定以上のアクセスが発生したときに、新しいノードが立ち上がるように設定しておくこともできます。これにより、負荷が多くなったときに、新しいノードが立ち上がり、待ち時間の無いチャットサービスを提供することができます。これら、スケーリングに関する設定方法は別途投稿いたします。)

プロンプト処理クラス "ChatPrompt"を作る

ユーザーによる入力テキストをLLM用のフォーマットに書き換えるためのプロンプト処理クラスはChatPrompt クラスと呼びます。

Qualiteg では、新しい LLM が発表されるたび、そのモデル用の ChatPrompt クラスを作成・バンドルしていますが、自前で作成することもできます。

ここでは今回のサンプルで利用した RedpajamaIncite のモデル用の ChatPromptクラスをご紹介します

from chatstream import AbstractChatPrompt


class ChatPromptTogetherRedPajamaINCITEChat(AbstractChatPrompt):
    """
    togethercomputer/RedPajama-INCITE-7B-Chat
    """

    def __init__(self):
        super().__init__()  # Call the initialization of the base class
        self.set_requester("<human>")
        self.set_responder("<bot>")
        self.set_prefix_as_stop_str_enabled(True)  # enable requester's prompt suffix as stop str

    def get_stop_strs(self):
        return ['<|endoftext|>']

    def create_prompt(self, opts={}):
        """
        Build prompts according to the characteristics of each language model
        :return:
        """
        if self.chat_mode == False:
            return self.get_requester_last_msg()

        ret = self.system
        for chat_content in self.get_contents(opts):
            chat_content_role = chat_content.get_role()
            chat_content_message = chat_content.get_message()

            if chat_content_role:
                if chat_content_message:
                    merged_message = chat_content_role + ": " + chat_content_message + "\n"
                else:
                    merged_message = chat_content_role + ":"

                ret += merged_message

        return ret

    async def build_initial_prompt(self, chat_prompt):
        pass
        # If you want a common initial prompt for instructions, override this method and implement
        # chat_prompt.add_requester_msg("Do you know about the Titanic movie?")
        # chat_prompt.add_responder_msg("Yes, I am familiar with it.")
        # chat_prompt.add_requester_msg("Who starred in the movie?")
        # chat_prompt.add_responder_msg("Leonardo DiCaprio and Kate Winslet.")

単純なモデルの場合は、LLMに入力するプロンプトテキストは、テンプレートマッチングだけで表現できますが、複雑な処理が必要な場合には、このようにChatPromptクラスとして実装したほうが柔軟な処理ができます。


Read more

大企業のAIセキュリティを支える基盤技術 - 今こそ理解するActive Directory 第5回 ブラウザ設定と認証

大企業のAIセキュリティを支える基盤技術 - 今こそ理解するActive Directory 第5回 ブラウザ設定と認証

こんにちは、今回はシリーズ第5回「ブラウザ設定と認証」について解説いたします! さて、前回(第4回)では、プロキシサーバーをドメインに参加させることで、ChatGPTやClaudeへのアクセスを「誰が」行ったかを確実に特定する仕組みを解説しました。「信頼の連鎖」の概念や、Windows版Squidなら1時間で構築できる環境、Negotiate/NTLM/Basicという3段階の認証フォールバック機構について理解いただけたかと思います。 しかし、せっかくサーバー側で完璧な統合Windows認証環境を構築しても、ブラウザ側の設定が適切でなければ、ユーザーには毎回パスワード入力ダイアログが表示されてしまいます。 「Edgeだと自動でログインできるのに、Chromeだとパスワードを聞かれる」 「同じサーバーなのにURLの書き方で動作が違う」 これらはヘルプデスクに寄せられる典型的な問い合わせです。(ただ、業務に好きなブラウザ使っていいよ、という企業はそんなに多くはないとおもいます) 今回は、統合Windows認証がブラウザでどのように動作するのか、その仕組みから各ブラウザ(Edge/

By Qualiteg AIセキュリティチーム, Qualiteg コンサルティング
スライドパズルを解くAIから学ぶ、「考える」の正体

スライドパズルを解くAIから学ぶ、「考える」の正体

こんにちは! 「このパズル、AIの教科書に載ってるらしいよ」 子供の頃に遊んだスライドパズル。いや、大人が遊んでも楽しいです。 数字のタイルをカチャカチャ動かして揃えるあれです。実はこのシンプルなパズルが、AI研究の出発点のひとつだったって知ってました? 今回は、このパズルを題材に「AIがどうやって考えているのか」を解き明かしていきます。しかも、ここで使われている手法は、Google Mapsの経路探索からChatGPTまで、現代の様々な技術のベースになっているんです。 まず遊んでみよう 理屈の前に、まずは感覚を思い出してみてください。 最初に shuffle をクリックすると、配置がシャッフルされゲームを開始できます。 ちなみに必ず解くことができるようになっていますが、慣れていないとそれなりに難しいかもしれません。 どうでしょう? 何手でクリアできましたか? クリアできなくても大丈夫です。記事後半で、実際にAIが解いてくれる機能つきゲームも掲載しています^^ 以下は動画です。本ブログで紹介するアルゴリズムで実際にパズルを解く様子をご覧いただけます

By Qualiteg 研究部
楽観的ロック vs 悲観的ロック:実際のトラブルから学ぶ排他制御

楽観的ロック vs 悲観的ロック:実際のトラブルから学ぶ排他制御

こんにちは! Qualitegプロダクト開発部です! 「楽観的ロックを実装したのに、まだ競合エラーが出るんですけど...」 これは私たちが実際に経験したことです。 本記事では、楽観的ロックと悲観的ロックの違いを、実際に発生したトラブルを通じて解説します。 抽象的な説明ではなく、 「なぜそれが必要なのか」「どんな問題を解決できるのか」 を実感できる内容を目指します。 目次 1. 問題の背景:並列処理で謎のエラー 2. ロックなしの世界:なぜ競合が起きるのか 3. 楽観的ロックの導入:期待と現実 4. 楽観的ロックの限界:解決できなかった問題 5. 悲観的ロックによる解決 6. 実装時のハマりポイント 7. どちらを選ぶべきか:判断基準 8. まとめ 1. 問題の背景:並列処理で謎のエラー 1.1 システムの概要 私たちが開発していたのは、 複数のワークスペースを切り替えて使用するAPIサーバー でした。 当社AI関係のプロダクトの一部だったのですが、結合テスト兼負荷テストを実行すると、まれに発生してしまっていました。 ユーザーは複数のワーキン

By Qualiteg プロダクト開発部
企業セキュリティはなぜ複雑になったのか? 〜AD+Proxyの時代から現代のクラウド対応まで〜

企業セキュリティはなぜ複雑になったのか? 〜AD+Proxyの時代から現代のクラウド対応まで〜

こんにちは! ChatGPTやClaudeといった生成AIサービスが業務に浸透し始めた今、 「AIに機密情報を送ってしまうリスク」 が新たなセキュリティ課題として浮上しています。 この課題に向き合う中で、私たちは改めて「企業のセキュリティアーキテクチャはどう変遷してきたのか」を振り返る機会がありました。 すると、ある疑問が浮かんできます。 「なんでこんなに複雑になってるんだっけ?」 企業のセキュリティ担当者なら、一度は思ったことがあるのではないでしょうか。 アルファベット3〜4文字の製品が乱立し、それぞれが微妙に重複した機能を持ち、設定は複雑化し、コストは膨らみ続けています。 当社ではAIセキュリティ関連プロダクトをご提供しておりますが、AI時代のセキュリティを考える上でも、この歴史を理解することは重要ではないかと考えました。 本記事では、企業ネットワークセキュリティの変遷を振り返りながら、「なぜこうなったのか」を整理してみたいと思います。 第1章:観測点を集約できた時代 ― オンプレAD + Proxy(〜2010年代前半) 統制しやすかったモデル かつ

By Qualiteg コンサルティング, Qualiteg AIセキュリティチーム