HEROZ Tech Blog

日本将棋連盟公認「将棋ウォーズ」や、AIを活用したシステム企画・開発を行う、AI企業HEROZの公式テックブログです。

HEROZ ASKへのo1の導入

はじめに

昨年末の12/5に12 Days of OpenAIでついにo1が発表となりました。
また、Azure OpenAI Serviceでも、このo1が使用できるようになりましたので、HEROZ ASKへと組み込みました。
langchainを用いた組み込みで気になった点を書いていきます。

なお、このo1はHEROZ ASKで2025/1/24以降で使用可能です。

o1-preview時代からの共通項目

昨年9月にo1-previewがリリースされて以来、内部的にはo1-previewを組み込む試作を実施していました。
その時から注意点や気になった点は以下となります。

o1-previewやo1-miniはChatOpenAI()を用いてgpt-4oと同じように使おうとすると、以下が非対応のため修正が必要になります。

  • temperature: オプションの削除
  • ストリーミング(streaming): オプションの削除
  • SystemMessage: システムメッセージの除去

ストリーミングオプションを削除するとストリーミングを期待している時に何も出力されなくなるため、以下のようなラッピングクラスを用意しました。

コードを見る

class ChatOpenAI_o1(ChatOpenAI):
    def _generate(
        self,
        messages: List[BaseMessage],
        stop: Optional[List[str]] = None,
        run_manager: Optional[CallbackManagerForLLMRun] = None,
        **kwargs: Any,
    ) -> ChatResult:
        results = super()._generate(
            messages,
            stop,
            run_manager,
            *kwargs,
        )
        if run_manager is not None:
            # on_llm_new_tokenしないと結果が表示されない
            run_manager.on_llm_new_token("".join([g.text for g in results.generations]))
        return results

    async def _agenerate(
        self,
        messages: List[BaseMessage],
        stop: Optional[List[str]] = None,
        run_manager: Optional[AsyncCallbackManagerForLLMRun] = None,
        **kwargs: Any,
    ) -> ChatResult:
        results = super()._generate(
            messages,
            stop,
            run_manager,
            *kwargs,
        )
        if run_manager is not None:
            # on_llm_new_tokenしないと結果が表示されない
            await run_manager.on_llm_new_token(
                "".join([g.text for g in results.generations])
            )
        return results

また、ストリーミング時はstream_usageオプションを使用すると使用トークン数を取得できますが、これの出力トークン(completion tokens)に思考用のReasoning tokenも含まれており、助かりました。

o1での変更点

o1はo1-previewと比べると以下の点で変更となっています。

  • SystemMessageへの対応: roleはdeveloperとする
  • 画像入力: 数式の入力がやりやすくなります
  • Markdown出力: プロンプトにFormatting reenabledと追加すると、Markdownで出力できるようになります

SystemMessageについてはlangchainにおいてはSystemMessagePromptTemplateの呼び出しで、オプションにadditional_kwargs = { "__openai_role__": "developer" }を渡すことで対応できます。
確かにこの方法でSystemMessageの指定はできるようになったのですが、試してみる限りではgpt-4oのSystemMessageと比べて遵守率が低いように感じました。

一方で、o1は未だにコスト計算用の単価が書かれているopenai_info.pyやtiktokenのmodel.pyが対応していないので、テーブルを動的に上書きしない限りはトークンやコストの計算時にエラーが発生します。
これらのファイルについては早期に追加されることを期待します。

組み込み結果

早速、難解な数式を画像で入力して解かせたところ、無事に正解しました。

o1の実行結果

おわりに

gpt-4oより賢いと言われているo1をHEROZ ASKへ導入することができました。
o1は確かに込み入った数式のような問題には抜群の能力を発揮するのですが、普通の質問や知識を問う内容だとgpt-4oと回答が変わらず、o1は時間とコストだけがかかるので、使い所が難しいように思いました。
一般ユーザーを含めて導入することにより、その辺りのユースケースをもっと発掘していきたいと思います。