
はじめに
DMM.博士通信の初回投稿です。DMM.博士については過去記事がありますので併せてお読みいただければと思います。ここでは簡潔な紹介に留めますが、DMMグループ内向けに提供中の、Slack上で動くChatGPT様式サービスをDMM.博士と呼んでいます。
過去記事の時点ではおしゃべりアプリに過ぎませんでしたが、DMMグループ従業員の方々にとって身近なコンパニオンアプリを目指して発展しています。今回はどのようにして業務フローをこなせるようになったのかを振り返りつつ説明します。
Azure OpenAI 外部関数呼び出し
既に1年前の出来事ですが、2023年7月20日にAzure OpenAIで関数呼び出しが可能になりました(参照記事)。これを利用して最初に追加した機能は、外部サイトの読み込みと、社内CMSコンテンツの読み込みでした。入力プロンプトにURLを与えて、「記事を要約して」と指示することで、社内会議の議事録などを要約することができるというものです。
この時点では当初構成を維持しており、Slackアプリとしての博士アプリと、OpenAIの2層構造のままです。変更点としては既存の博士アプリに関数呼び出しの要不要を判定するエージェント実装を追加し、呼び出し選択された関数を加えるだけのシンプルなものです。

エージェント実装のポイントとして、社内CMSコンテンツの読み込みは認証や設定された権限が必要になるため、外部サイト読み込みとは異なる関数を呼び出す必要があり、判定のヒントを定義します。例えば次のようなコードになります。
manifest.py
class HakaseFunctionManifest(object):
tools = [
{
"type": "function",
"function": {
"name": "open_url",
"description": "URLを開き内容を取得する",
"parameters": {
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "url (i.e. https://dmm.com)",
},
},
"required": ["url"],
},
},
},
{
"type": "function",
"function": {
"name": "open_confluence",
"description": "ConfluenceのURLを開き内容を取得する",
"parameters": {
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "url (i.e. https://confl.arms.dmm.com/)",
},
},
"required": ["url"],
},
},
},
]
単純な構成ですが、ここまでで次の3つの仕事をさせており、生成AIを業務フローに活かせるであろうことが想像できます。
- 何を入力情報として与えられたら
- それをどのように判定するか処理し呼び出す関数を決定する
- 関数実行結果を取得し次の判定を処理する(何もなければ利用者へ返す)
利用者の立場を理解する
業務フローに立ち入るには、依頼者が何者であるかを知る必要があります。上図の右側に外部システムとありますが、これを組織・従業員マスターAPIとすることで、利用者のSlackIDをキーに従業員自身や所属組織の情報を得て利用することができます。利用者へは「あなたが誰かを知っている」ことを示す挨拶文を返すことができます。

挨拶文はシンプルですが、このとき博士アプリとバックエンドにあるredisは利用者の詳細情報(社員コード、役職、所属、勤務地など)を保持しており、所属組織の責任者の情報を得ることもできます。
任せるべき業務フロー
最初のモデルケースとして、当社本社のある六本木グランドタワーの入館証発行を任せることにしました。生成AIでなければならない理由を追求すると、既存の手段でも十分である場合が結構あります。このモデルケースを選定したポイントは次の通りです。
- コロナ禍以降会社への往来がまばらで入館に必要な社員証を忘れるケースが多発し、総務部のコストが増えている
- 社外アクセスが必要(入館証が必要なときに社内アクセスのみ許可されたシステムでは使えない)
- 緊急時に自身の分のみ利用できる(他人の分を代理発行することは許容しない)
- 誰でもなんとなくでも利用できる(自然言語で指示して、対応してもらえる)
社外からスマートフォンのSlackアプリでDMM.博士に話しかけることができますし、博士は前述の通り、利用者の立場を理解しており、当社の従業員であるかどうか、また六本木グランドタワーに席があるかを理解しています。条件に該当しない利用者には指示の拒否や代替手段を提供するように実装することができます。
入館証発行対応アーキテクチャ
これを実現するための変更点として、既存の博士システムに新たにAPIsレイヤを加えた3層構造になります。博士アプリ側はどのAPIを呼び出すべきかのエージェント実装は残しますが、コールするAPI群はAzure Functionsを利用し、新たなサブシステムとして構築します。
詳細は省きますが、当該ビル管理会社のシステムへアクセスし、利用者の代理で博士がリクエスト送信する処理をAPI側で実装します。リクエストが正常に処理されると博士のメールボックスに入館証発行に必要なJANコードが届くので、博士は元の依頼者情報を照合してから、依頼者のSlackへダイレクトメッセージでJANコード画像と案内文を送信することができます。

自然言語による指示
ここまでのシステム設計の中でおそらく最も難しいのが、自然言語による指示の受付になると思います。安易に受け付けてしまっては良くないですし、ハルシネーションを発生させて受け付けたフリをされても困ります。しかし、この機能を2024年1月にリリースして以来、これまで運用してきた結果からいえば、この部分の精度調整は実用に耐える範囲で可能です。従業員の所属処理のバグに起因する不具合を除けば、エージェントの判定ミスはほとんど起きていません。

関数呼び出しエージェントには次のように定義を与えています。但しOpenAI Python SDK 0.28.x では一部ハードコードで制御する必要がありました。ハードコードに依存せずこの定義が期待通りの挙動を示すには 1.x へアップグレードが必要でした。
manifest.py
class HakaseFunctionManifest(object):
tools = [
{
"type": "function",
"function": {
"name": "admission_request_rgt",
"description": "六本木グランドタワーの入館要求に対応し入館証を発行する。",
"parameters": {
"type": "object",
"properties": {
"office": {
"type": "string",
"enum": ["六本木グランドタワー", "その他"],
"description": "入館対象となるオフィスビル名。推測禁止。その他の事業所については対応できない。確認必須。 e.g. 六本木グランドタワー, その他の事業所",
},
"confirm": {
"type": "string",
"enum": ["発行中止", "発行する"],
"description": "要求処理の最終確認。推測禁止。二重確認必須。確認方法:「六本木グランドタワーの入館証を発行してよろしいですか?」",
},
},
"required": ["office", "confirm"],
},
},
},
]
Function Callingの制御に関して役立った参照先を次に挙げておきます。
OpenAI Cookbook | How to call functions with chat models [Link]
openai-python | v1.0.0 Migration Guide [Link]
Azureのドキュメント | OpenAI Python API ライブラリ1.xへの移行 [Link]
おわりに
今回は2024年2月頃迄のDMM.博士の機能追加のうち、業務フロー組み込みの最初のモデルケースの成り立ちについて記載しました。
その後OpenAIから新モデルがリリースされたり、Anthropic Cluade 3の性能が話題になったりする中でDMM.博士の造りも変化していきます。
次回のDMM博士 通信 Vol.2ではRetrieval Augmented Generation(aka. RAG)について記載したいと思います。