会社のハッカソンイベントに参加して作品を作ったので紹介します。
世界の拠点からエンジニアが集まったグローバルなイベントで、開発時間は24時間でした。

※イベント自体は2024年9月開催で、公開許可をいただいたのでブログに書いています。

作品

DEMO動画 (一部編集済み)

AIが生活に欠かせなくなってきている昨今、普段使っているMacの操作もAIにやってもらったら面白いのでは?と思い、macOSを自動操作するAIエージェント「あざらしすたんと」を作りました。詳しくはDEMO動画をご覧ください。

古の時代に “お前を消す方法”で有名なイルカ がいました。現代のAIがあれば、某イルカは真に便利なアシスタントになりそうですね。
今回はデザイナーのアイデアによりイルカではなくあざらしとして生まれ変わることになりました。名前は「らしたん」です。

技術

このアイデアで行くと決めた後、チームメンバーのAIエンジニアに「LangChain Agents」というものがあることを教えてもらい、それを使って実現することにしました。

らしたんを表示したいのでSwiftUIでmacOSアプリを作り、内部でLangChain Agentsを利用して、AIを実行しました。

自分はmacOSアプリと AIエージェントに自律的に行動してもらうための仕組み の部分を実装したので、そのあたりの技術について紹介します。

デスクトップマスコットの実装

古の時代にデスクトップマスコットと呼ばれるものがありました。ウィンドウ等を表示せずにデスクトップにキャラクターを表示 (常駐) させるアプリです。
これにはタイトルバーを消す実装やウィンドウの背景を透明にする実装、最前面に表示する実装などが必要になります。

SwiftUIでは下記でタイトルを消すことはできます。

1
2
3
4
5
WindowGroup {
    ContentView()
}
.windowResizability(.contentSize)
.windowStyle(.hiddenTitleBar)

タイトルなし

ただ、タイトルバーの領域自体を消したり、閉じるボタンなどを消したりするのはXcode 15 (開発時の環境) では不可能だったため、一部はAppKitを利用しました。

1
2
3
4
5
6
func configure(_ window: NSWindow) {
    window.standardWindowButton(.zoomButton)?.isHidden = true
    window.standardWindowButton(.closeButton)?.isHidden = true
    window.standardWindowButton(.miniaturizeButton)?.isHidden = true
    window.styleMask = [.borderless, .fullSizeContentView]
}

タイトルバーなし

背景色を消して透明なウィンドウを作成したり、最前面に表示するためには下記のようにします。

1
2
3
4
window.isOpaque = false
window.backgroundColor = .clear
window.level = .screenSaver
window.isMovableByWindowBackground = true

透明なウィンドウ

isMovableByWindowBackgroundtrueにすると、背景をドラッグしてウィンドウを移動できるようになります。

AIエージェントの実装

LangChainは特定のLLMに依存せず汎用的なAI実装を実現したり、再利用可能な実装やプロンプトのベストプラクティスが詰まったフレームワークです。

今回はその中でも LangChain Agents というAIエージェントを実装するための機能を利用しました。

AIエージェントというのは一般的に、目的を達成するために必要な行動をAI自身が考え、自律的に選択して行動するものを指します。
これによってユーザー視点ではシンプルな命令 (プロンプト) で複雑な目的を達成することができます。

macOSの自動操作

macOSはセキュリティ的な理由から制限が厳しいです。ハッカソンの時間内で実現できる方法を考えた結果、AppleScriptを利用することにしました。AppleScriptはシステム設定で許可をすれば、多くの操作を自動化できます。

動作ロジックとしては以下の通りです。

  1. ユーザーの命令からLLMでAppleScriptのコードを生成
  2. 生成したコードに破壊的な動作が含まれるかをLLMで判定
    ・含まれる場合はユーザーに許可を求める
  3. AppleScriptを実行
  4. もしエラーが起きた場合はエラーメッセージをLLMに伝え、AppleScriptを再生成し、2に戻る

LLM自体はmacOSを操作できませんが、AppleScriptのコードは生成できるので、それを実行することでAIにmacOSを操作させることができます。

ただ、ファイルをすべて削除するなど危険な行為をされては困るので、生成したコードに破壊的な動作が含まれるかをLLMで判定することで、最低限の安全性を確保しました。

また、AppleScriptの生成は学習データセットが少ないのか、試してみると意外とうまくいかないことが多いので、システムプロンプトなどで実装方法のドキュメントなどを記載しておく必要があります。
それでもうまくいかないことがあるので、エラーメッセージをLLMに伝えて自己修復を繰り返すことで、安定性が大きく向上しました。

ごはん中のらしたん

ごはん中のらしたん

ツールの実装

LLMでできるのはテキストを生成することですが、AppleScriptの例のように生成させたものを利用して何かを実行することで様々な事ができるようになります。

OpenAIでいうと「Tool calling (Function calling)」という機能があります。これはAIに呼び出してほしい関数のインターフェースなどのドキュメントを渡すと、AIが必要なときにその関数呼び出しに必要な情報を提供してくれるようになる機能です。

例えば、「helloと書かれたテキストファイルを作成して」という命令が来た時に createFile("file.txt", "hello") というような情報を返してくれるようにできます。
AppleScriptの生成と実行もLangChain AgentsのToolの仕組みを使って実現しています。

1
2
3
4
5
6
7
8
9
@tool
def run_applescript(script: str) -> dict[str, Any]:
    """AppleScriptを実行
    <いろいろな説明を記述>
    """
    # LLMで破壊的な動作が含まれるか判定
    # ...
    # AppleScriptを実行
    return _run_applescript(script)

ハッカソンの終盤は時間の許す限りToolの追加をしました。
例えば、画像を生成する機能らしたん自身のプロフィールに関する情報を取得する機能、必要な情報をランタイムでIn-Context Learningするための機能などを実装しました。

エビフライになるらしたん

らしたんはたまにエビフライになります(?)

感想

AIエージェントは面白い!

このハッカソンで初めてAIエージェントを実装しましたが、短時間の開発でもかなり色々なことができると実感して、AI開発の視野がかなり広がりました。

最近はLangChain Agentsの後続となるLangGraphを触っていますが、複数のAIエージェントを組み合わせることでチームを組んだ人間のように、大きなタスクを達成できたりと、とても面白いです。

日々進化しているAI技術をいろいろ触ってみて、面白いものが作れないか考えていきたいです。

今回の作品「あざらしすたんと」の作品情報はここでも見れます。よかったら見てください。