AIエンジニアの探求

計算論的神経科学で博士号取得後、AIエンジニアとして活動中。LLMの活用や脳とAIの関係などについて記事を書きます。

OpenAIのfunction callingでタスクの自動管理に挑戦

ChatGPTの新機能であるfunction callingが話題になっています。

このfunction callingを使えばChatGPTが自然言語の入力から関数への引数を自動で設定してくれるようになるということで、先日簡単に試してみました。

このツイートでは自然言語でタスクを設定するとよしなにタスクの内容、開始日、終了日を定めてくれることを確認しました。これにより、例えばGASを叩くことでガントチャートなどにタスクを登録できるようになります。

タスクの設定は様々な形式で行うことができ、例えば以下のようなパターンに対して正しく引数を定義できました。

  • 6/12から7/3まで参考文献調査をする
  • 6/14から要件定義を行う。締切は6月21日
  • ストーリーラインの作成。7月上旬から始めて7月中旬までに完了させる

「これは便利そうだ」と思ったものの、同時に「結構使い所が難しいな」という印象を持ちました。というのも、ガントチャートにタスクを登録する際は素直にタスクの内容、開始日、終了日を定められたフォーマットで(人間が)記入すれば良く、わざわざ自然言語で登録したい場面がなかなか思い浮かばなかったためです。

しかし、人が登録するのではなくシステムが自動で登録するようなシチュエーションではかなり重宝しそうです。 そういった、function callingに関する需要と供給がマッチしそうな場面がないか考えた結果、「slackからタスクの自動登録」はかなりポテンシャルがあるのでは・・?と思い至りました。

slackのメッセージからのタスクの自動登録

slack上では、日々様々なメッセージが飛び交っており、その中でタスクの依頼を受けるケースも少なくありません。

slackメッセージの一例(データはダミーです)

その中で、「依頼してもらったタスクを見逃す/忘れてしまう」ケースが往々にしてあると思います。 そこでタスクを依頼してもらった時に自動でガントチャート(なりバックログなり)に登録する機能があれば便利そうです。 また、タスクの依頼方法は人によってまちまちなので、function callingの「様々な入力形式を受け付けて、正しい引数に変換してくれる」機能の本領が発揮されそうです。

登録すべきタスクの判定

上述したようにslack上のメッセージは全てタスクの依頼というわけではないので、まず「登録すべきタスクかどうか」を判定する必要があります。 基本的な考え方としては「お願いします」「ご確認いただけると幸いです」などのような依頼文になっているかで判断する形で良いと思いますが、例えば

すみません、前のmtgが伸びていて遅れそうなので、先にmtg始めていただけると助かります。

などのように依頼文ではあるもののタスクとして登録するのがふさわしくないメッセージもあります。

この判定を行うために、以下のようなCoT(Chain of Thought) promptingを活用しました(初期的な検証に利用したものなので、改善の余地は大いにあるものと思われます)。

## 背景
slack上でのやり取りから、slack上で依頼された事項を見逃してしまったり忘れてしまうという課題を解決するために、タスクとしてガントチャートに登録することで一元的に管理しようとしています。
しかしslack上での送られるメッセージが全てタスク化すべき依頼事項というわけではないので、まずメッセージがタスク化すべき依頼事項(=ガントチャートに登録すべきタスク)かどうかを判定する必要があります。

## 指示
slack上で送られたメッセージが与えられるので、ガントチャートに登録すべきタスクかどうかを判定してください。ガントチャートに登録すべきタスクでない場合は、「タスクではない」と出力してください。ガントチャートに登録すべきタスクの場合は、
・タスクの内容
・開始日
・終了予定日
を出力してください。ただし、開始日は特に指定がない場合は送信日を開始日とみなしてください。また、終了予定日が分からない場合は出力しなくて良いです。

## 制約
- タスクの具体的な内容が抽象的であっても、問題ありません。「タスクの内容」として出力してください
- 依頼文の形であっても、習慣の変更や「今この瞬間に」実施すべきことについてはガントチャートに登録する必要はないです

## 例
- slack message:
送信日: 2023/6/25
@Kohei Ichikawa 追加検証していた実験についてアップデートしたので、お手隙の際にご確認いただけると幸いです! 
https://tripdancer0916.hatenablog.com/entry/llamaindex_agent
- 出力:
「ご確認いただけると幸いです!」という依頼文の形であるため、何らかのタスクが依頼されている可能性が高い。また記事のリンクが貼られていることから、このリンクの記事のレビューをタスクとして実施することが望ましいと考えられる。よって、
・タスクの内容: https://tripdancer0916.hatenablog.com/entry/llamaindex_agent の記事のレビュー
・開始日: 2023/6/25

- slack message:
送信日: 2023/4/8
りんごをオレンジに置き換えることで画像認識タスクの精度が3%上がったそう。参考になるかもです
- 出力:
このメッセージは参考情報としてシェアしているものであり、特に何か依頼内容が含まれているわけではない。よって、
タスクではない

(例が続く)

これにより、入力されるメッセージに対して以下のようにタスクの判定が行われることを確認しました(以下はCoTの例として与えていないサンプルに対する結果です)。

例1

  • slack message: 送信日: 2023/4/8 PR作成しました!レビューお願いします!
  • 出力: メッセージに「レビューお願いします」という依頼文があり、タスクが依頼されていると考えられます。よって、

・タスクの内容: PRのレビュー

・開始日: 2023/4/8

例2

  • slack message: 送信日: 2023/5/13 充電器を貸していただいても良いでしょうか?
  • 出力: このメッセージは充電器の貸し借りについての依頼であり、タスクとしてガントチャートに登録するような内容ではありません。よって、 タスクではない

例3

  • slack message: 送信日: 2023/6/4 next action: ストーリーラインの作成(6/11まで)
  • 出力: 「next action: ストーリーラインの作成(6/11まで)」という文があることから、依頼が含まれています。また、「6/11まで」という締切が指定されています。よって、

・タスクの内容: ストーリーラインの作成

・開始日: 2023/6/4

・終了予定日: 2023/6/11

このように、様々な形式のメッセージに対して正しく登録すべきタスクの判定ができていることを確認できました。

外部関数に与える引数への変換

出力結果を見るとタスクの内容、開始日、終了予定日が抽出されているので登録すべき情報は出揃いました。しかしCoTで出力させた推論プロセスも出力されてしまっているので、出力する情報を絞る必要があります。

そこでfunction callingの出番です。

冒頭のツイートにある関数の引数に関するプロンプトを再活用します(ただし差分として、nullを許容するようにしました)。

functions = [
    {
        'name': 'register_task',
        'description': 'タスクをガントチャートに登録する',
        'parameters': {
            'type': 'object',
            'properties': {
                'task': {
                    'type': 'string',
                    'description': '実施するタスク名。ただし、タスクではない場合や判断できない場合nullとする。例: 画像認識手法サーベイ、アブストラクト執筆、モデルファインチューニング',
                },
                'start_date': {
                    'type': 'string',
                    'description': '実施するタスクの開始日。半角でyyyymmdd形式とする。年の指定がない場合、デフォルトは2023年。ただし、タスクではない場合や判断できない場合nullとする。例: 20230619, 19950908',
                },
                'end_date': {
                    'type': 'string',
                    'description': '実施するタスクの終了予定日。半角でyyyymmdd形式とする。年の指定がない場合、デフォルトは2023年。また、指定しなくてもよい。指定しない場合nullとする。例: 20230619, 19950908',
                },
            },
            'required': ['task', 'start_date', 'end_date'],
        },
    }
]

そして入力として、先ほどのタスク判定関数の返り値を与えます。 結果は以下のようになりました。

例1

{
"task": "PRのレビュー",
"start_date": "20230408",
"end_date": null
}

例2

関数呼び出しなし

例3

{
  "task": "ストーリーラインの作成",
  "start_date": "20230604",
  "end_date": "20230611"
}

これにより、いい感じにslackのメッセージからタスクだけを抽出してガントチャートに登録することができそうです。

今回はfunction callingの検証がメイン目的でしたが、需要がありそうなら実際にslackとspread sheetを連携させてタスク自動管理を実行するところまで挑戦してみたいと思います。

まとめ

  • function callingの有効な使い所として、「slackのメッセージからのタスクの自動登録」が良さそうと考え、検証してみました。
  • 「メッセージからタスクかどうか・その内容の判定を実施→得られた結果をガントチャートに登録できる形に自動フォーマッティング」という一連の流れの中で、後半部分におけるfunction callingの有効性を確かめることができました。
    • 前半の判定部分もやってみるとなかなか奥が深そうだったので、掘り下げてみても面白そうです。
  • 一般的な示唆として、「Chain of Thoughtで得られた結果をいい感じにフォーマットする」際にfunction callingが便利そうであることが分かりました。