Llama 3.2 3B Instruct を使って Slack を「賢く検索」するアプリを作ろうとしてみた話（タイトル詐欺）

## はじめに

すみません賢く検索してません。

Llama 3.2 1B、3B で軽量でデータを外部に公開することなく気軽に生成 AI 使えるらしい！

最近 Slack で検索がめんどくさい！なんかだれか言っていたような、という内容をすぐに探し出したい！

やってみて、アドベントカレンダーにしよう！

前日までに完成しなかった！ので途中までやったことを書こう！

初めて Chat GPT 以外の生成 AI 触ってみました。

# この記事で少し分かること

- Python で Llama をローカルで使用する
- なんかよく見る JSON の形式と役割

## ゴール

「Slack の random チャンネルで田中さんが先週話していた ‘楽しかった’ という内容を知りたい」という質問に対して、以下のステップで回答を導き出すアプリを目指しました。

	1.	ユーザーの質問から 必要な検索要素を抽出（やってみた）
        - 例: チャンネル名、対象ユーザー、時期、キーワード
	2.	抽出した情報をもとに Slack API を呼び出し、関連するメッセージを取得（やってない）
	3.	取得したメッセージを Llama に渡し、質問に対する適切な回答を生成（やってない）

## 事前準備

- AccessToken 取得
    - Hugging Face に登録
    - 使用するモデル [meta-llama/Llama-3.2-3B-Instruct](https://huggingface.co/meta-llama/Llama-3.2-3B-Instruct) の画面指示に従いライセンスに同意
    - アクセストークン取得
- Python 環境

## 実装概要

### 1.	ユーザーの質問から 必要な検索要素を抽出

まず、Llama 3.2 3B Instruct を使い、ユーザーの質問を解析して検索に必要な情報を抽出することを試みました。Transformers を使用します。

``` python
import json

import torch
from huggingface_hub import login
from transformers import pipeline


def extract_search_words(question):
    model_id = "meta-llama/Llama-3.2-3B-Instruct"

    pipe = pipeline(
        "text-generation", model=model_id, torch_dtype=torch.bfloat16, device_map="auto"
    )

    message = question

    input = [
        {
            "role": "system",
            "content": "You are an extractor of search phrases for creating queries to use with the Slack message API.",
        },
        {
            "role": "user",
            # 以下投げる内容
            "content": f"""Given the question ‘{message}’, create a JSON object with the following structure:
    •    If there is information about the channel, include it under the key in.
    •    If there is information about who made the statement, include it under the key from.
    •    If there is information about the search keyword, include it under the key target.
    •    If there is information about the date, include it under the key on as a range in the format yyyy-MM-dd ~ yyyy-MM-dd.
If there are multiple pieces of such information, create a list of objects with this structure, each containing the keys in, from, target, and on where applicable. If any key has no value, remove it entirely from the JSON object. Only return the JSON object as the output, without any additional explanation or text.""",
        },
    ]
    result = pipe(
        input,
        max_new_tokens=256,
    )
    res = result[0]["generated_text"][-1]
    print(
        json.dumps(
            json.loads(res["content"].strip("```json").strip("```").strip()),
            indent=4,
            ensure_ascii=False,
        )
    )


def login_hugging_face():
    login(token="hogefugahogefuga") # 自分のアクセストークンに置き換えてください。


login_hugging_face()
extract_search_words(
    "Someone mentioned going to Okayama in random channel last week, but who was it?"
)

```

引数で受けた文言から色々抜き出してみてくれ、json でくれ、と言うためにプロンプトはこんなかんじか。

``` text
Given the question ‘{message}’, create a JSON object with the following structure:
    •    If there is information about the channel, include it under the key in.
    •    If there is information about who made the statement, include it under the key from.
    •    If there is information about the search keyword, include it under the key target.
    •    If there is information about the date, include it under the key on as a range in the format yyyy-MM-dd ~ yyyy-MM-dd.
If there are multiple pieces of such information, create a list of objects with this structure, each containing the keys in, from, target, and on where applicable. If any key has no value, remove it entirely from the JSON object. Only return the JSON object as the output, without any additional explanation or text.
```

質問 `Someone mentioned going to Okayama in random channel last week, but who was it?` に対して実行結果は

```json
{
    "in": {
        "channel": "random channel"
    },
    "from": {
        "user": "unknown"
    },
    "target": "Okayama",
    "on": {
        "start": "last week",
        "end": "2023-12-12 ~ 2023-12-18"
    }
}
```

なんか惜しい、、、

頑張れば行けるのでしょうか、修行が足りないのでわからない。

## この input の JSON 何

初心者は、なにこの JSON よく見るけど規格とかあるのか？と思ったのですが、そんなことはなく、Open AI とかが使ってるから流行ってるという感じらしい。ファインチューニングとかでもこの形。

サンプル形式

```json
[
  {
    "role": "system",
    "content": "You are a helpful assistant."
  },
  {
    "role": "user",
    "content": "What is the capital of France?"
  },
  {
    "role": "assistant",
    "content": "The capital of France is Paris."
  }
]
```

キーの説明
- role:
    - 対話の役割を示します
	- 代表的な値：
    	- "system": モデルの指示を設定（例: モデルの性格や目標）
    	- "user": ユーザーの入力
    	- "assistant": モデルの応答
- content:
    - 実際のメッセージ内容

という感じでした。

## まとめ

思ってたよりもできそうでできなそうかも、という感想です。

続きを作って記事にしたいと思います（やれたらやるなのでやらない）