工作と競馬2

電子工作、プログラミング、木工といった工作の記録記事、競馬に関する考察記事を掲載するブログ

小型LLM Bonsai-8B を OpenWebui を動かす(playwright-cli と組み合わせ、Webブラウザを操作してみる)

概要

小型のLLM Bonsai-8BをOpenWebuiで動かすことができた。




背景と目的

以前より、ローカルでLLMを動かして遊んできた。

dekuo-03.hatenablog.jp

dekuo-03.hatenablog.jp

今回は、

Bonsai-8B

というモデルを試してみる。このモデルは、

  • 1ビット量子化前提で作られている

というのが特徴で、パラメータ数が少なく(2,3B)、量子化ビット数が3,4ビットあるものと比較してビット数は小さいがパラメータが多いことで、精度と速度のバランスが良いと評判なので、ぜひ試してみたい。



詳細

0. 環境

  • CPU: Core-i5 14400F
  • GPU: RTX4060 8GB
  • RAM: DDR5-4800 16GB
  • Windows11


1. Bonsai-8B セットアップ~起動

まず、以下のサイトからclone。

github.com

Windowsのセットアップ方法に従い、以下を実行。8Bのモデルがダウンロードされる。

.\setup.ps1

次に、起動するのだが、Windows向けは、LinuxやMacと異なりスクリプトが用意されていない。bin/cudaというところに、llama-cliやllama-serverというexeファイルが用意されているので、それらを利用する。llama-cli.exeを用いれば、直接チャット画面が現れるが、今回はOpenWebuiから利用するため、以下のようなバッチファイルを作成し、サーバーモードで動作させ、OpenAI 互換 API経由でリクエストを待ち構える状態にする。ポートは8081とした。

cd /d %~dp0
.\bin\cuda\llama-server.exe --model .\models\gguf\8B\Bonsai-8B.gguf --port 8081 --host 0.0.0.0


2. OpenWebui セットアップ~起動

OpenWebuiは、Windows環境ではWSL Linux上でDockerコンテナとして実行することが推奨されているが、Linux(Docker)側からWindows側で待ち構えているAPI(1で起動したもの)にアクセスするための設定周りが面倒なので、Windows側で完結する。すなわち、

python -m venv
call venv\Scripts\activate
pip install openwebui

インストールが完了したら、以下を実行。ここでは、8085ポートを使用する。

open-webui serve --port 8085

で起動する。Webブラウザで、localhost:8085にアクセスすると、OpenWebuiの画面が出てくる。


3. playwright-cliを用いたツールの作成

Bonsai-8Bは、function calling(Tool calling)に対応している。そのため、OpenWebuiのツールを設定することで、ツールを使用したチャットのやり取りができる。そこで、Webブラウザの操作用ツールを作成して、Bonsai-8Bから呼び出してみたい。

方法としては、

  • playwright-cli

を呼び出すPythonスクリプトとする。playwright-cliは、Webブラウザを操作するAPIを提供するplaywrightというフレームワークのCLI版である。CLIを叩くには、Pythonのsubprocessモジュールを使ってコマンドを組み立ててあげるようにすればよい。したがって、以下の例のように、

    def open_browser(self) -> str:
        """ブラウザを起動。"""

        cli_command = ["playwright-cli", "open", "--headed"]

        resp = subprocess.run(
            cli_command,
            shell=True,
            check=True,
            text=True,
            encoding="utf-8",
            errors="ignore",
            capture_output=True,
        )

        return "ブラウザを起動しました."

ツールを実装することで動くはずである。


4. 動作確認

ブラウザを起動、終了、URLへ移動、スナップショット(アクセシビリティツリーを取得)など、基本的なものをいくつか実装し、

https://????/に移動してスナップショットを取得

というようなプロンプトを入力したところ、

うまくツールを呼び出してブラウザ起動し、当該URLへ移動してアクセシビリティツリーを取得することができた。

しかも、トークンの出力速度は 80token/秒 程度となっていて、他の小型といわれるような2,3Bで3,4ビット量子化クラスのLLMに比べてもかなり体感的に速い。そして、プロンプトに対してツール呼び出しが正確に行えている印象である。

したがって、この小さなモデルとツールを組み合わせれば、ストレスなくブラウザの操作ができてしまう、ということがわかった。



まとめと今後の課題

小型LLM Bonsai-8B を OpenWebui + playwright-cli で動かし、Webブラウザを操作できることがわかった。定型的な操作を自動化したり、他にもツールのバリエーションを増やすことでローカルでいろいろな操作に活用してみたい。


アクセスキー使用時のMFA認証強制 & 一定期間MFA再認証抑制で安全と使い勝手を確保する

概要

自分用メモ。




背景と目的

AWSリソースを使いながら動くLambda関数をローカルでテストしておきたい、というような場合に、IAMユーザーに紐づくアクセスキーをローカル保存して使用することがある。しかし、アクセスキーの漏洩の危険性からただ単にローカル保存することは望ましくなく、

  • ①目的の権限を持ったロールを引き受けるようにする
  • ②MFA認証を強制する
  • ③IAM Identity CenterのSSOを使用する

ということが対策として言われたりする。

①は単独ではほとんど意味をなさないと思う。なぜなら、結局のところ権限を引き受けられるので、もともと権限があることとあまり変わらないから。②と併用することで効果的といえる。①で当該ユーザーそのものには権限を与えないようにしておき、MFA認証したうえでロールを切り替えて初めてAWSの操作ができるようになるから。(ただ、個人的には①は要るのだろうか?と思っていたりする。)ただ、②を導入すると使用するたびにMFA認証を要求され使い勝手が悪い。

③は、近年最も推奨される方法だが、会社などで組織としてAWSアカウントが管理されている場合に自由に使えなかったりする。

①+②+認証キャッシュ使用

の方法で一定期間再認証抑制で安全と使い勝手を確保する方法を調べ、メモしておく。



詳細

0. 前提条件

  • IAMユーザーにMFAデバイス登録済み

1. 流れの確認

ここでは、AWS SDK(Python)すなわちboto3での活用を目指す。

目的の権限を持つロールを作成
↓
ユーザーのポリシー編集
↓
CLIのプロファイル設定
↓
プロファイルを参照、認証キャッシュを利用

2. 目的の権限を持つロールを作成

IAMコンソールで、目的の権限(S3がいじりたければS3FullAccessなど)を付与したロールを作成しておく。その際、信頼ポリシーには、MFA認証済みであることを条件としてロール引き受けを許可するように設定。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::{accound_id}:user/{iam_user_name}"
            },
            "Action": "sts:AssumeRole",
            "Condition": {
                "Bool": {
                    "aws:MultiFactorAuthPresent": "true"
                }
            }
        }
    ]
}

3. ユーザーのポリシー

IAMユーザー側のインラインポリシーで、目的の権限を持つロールARNの引き受けができるようにしておく。それ以外のロールは一切アタッチしない。つまり、AWSサービスの操作はできない状態。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::{accound_id}:role/{目的の権限を持つロールARN}"
        }
    ]
}

4. CLIのプロファイル設定

base-userプロファイルと目的のロール引き受け用設定を保持するtargetプロファイルを記載。

4.1 ~/.aws/config

[profile base-user]
output = json
region = ap-northeast-1

[profile target]
output = json
region = ap-northeast-1
source_profile = base-user
mfa_serial = {登録済みMFAデバイスのARN}
role_arn = {引き受けたい目的の権限を持つロールARN}

4.2 ~/.aws/credentials

base-userプロファイルとして、IAMユーザーのアクセスキーを記入。このアクセスキーが万が一漏洩しても、MFA認証を強制されるため、ローカルに保存しても安全。

[base-user]
aws_access_key_id = {アクセスキーID}
aws_secret_access_key = {シークレットアクセスキー}

5. boto3でプロファイルを参照、認証キャッシュを利用

以下は、S3のバケット一覧を取得する例。 boto3では、targetプロファイルを使ってセッションを作成する。ここで、MFA認証後一定期間再認証を要求されないようにするには、認証キャッシュを読み出せるようにしておく必要がある。そこで、一連の処理を行ってboto3.Sessionを取得する専用の関数boto3_session_from_cli_cacheを用意しておく。

import os
from pathlib import Path
import boto3
import botocore.session


def boto3_session_from_cli_cache(profile_name: str, cache_dir: str | None = None) -> boto3.Session:
    botocore_session = botocore.session.Session()
    botocore_session.set_config_variable('profile', profile_name)

    if cache_dir is None:
        cache_dir = Path.home() / '.aws' / 'cli' / 'cache'
    cache = botocore.credentials.JSONFileCache(cache_dir)

    resolver = botocore_session.get_component('credential_provider')
    assume_role_provider = resolver.get_provider('assume-role')
    assume_role_provider.cache = cache

    return boto3.Session(botocore_session=botocore_session)


if __name__ == "__main__":
    session = boto3_session_from_cli_cache("target")
    s3_client = session.client("s3")
    print(s3_client.list_buckets())

6. 結果

上記のスクリプトを実行すると、以下のようにMFAのコード入力を要求される。

Enter MFA code for arn:aws:iam::{account_id}:mfa/{登録MFAデバイス名}: 

正しく入力すると、ロール引き受けが走り、スクリプトにおいて目的の権限を持つ操作が可能。今回ではS3のバケット一覧が無事取得できた。

さらに、もう一度スクリプトを実行すると、今度はキャッシュを読み出すことでMFA認証の要求をされずそのままスクリプトが実行された。

ということで、「安全と使い勝手を確保」することができた。



まとめと今後の課題

目的の動作をさせることができた。簡易な処理なので、スクリプトに差し込んで使おうと思う。


3Dプリンターで、ギアを作ってみる(2) ステッピングモータ 28BYJ-48 の増速

概要

3Dプリンターで作ったギアをステッピングモータ 28BYJ-48 に装着して動かすことができた。




背景と目的

前回、3Dプリンターでギアを印刷できた。今回は、モータやシャフトを支持する部分を印刷し、組み上げて動かしてみる。



詳細

1. ギアボックスの組み立て

以下の3部品を印刷した。形状、サイズは別の機器に組み込んで使う想定で作ったので、動作確認のためだけなら無駄な部分が多い。

  • モータ取り付け部+増速側軸受

  • 増速側軸受2

軸受はボールベアリングなどでよりスムーズに動かせるようにするのが本来はベストだがひとまず、動作確認のためこれでよい。

  • 増速側軸ストッパー

軸方向にズレないように、軸の端に取り付ける。

2. 動かした様子

組み立てて動かした様子。

モータ軸に取り付けられた大きいほうのギアよりも、増速側の軸がそれより速く回っていることが分かる。動かし始めたときは少しギアのかみ合う音が気になったが手持ちのシリコンスプレーを吹きかけたところ、結構音が抑えられ、気にならないレベル。 増速した分トルクが小さくなっているので、増速側の軸を無理に手で抑えれば当然脱調するが、ひとまずちゃんと増速の動作ができている。


www.youtube.com



まとめと今後の課題

3Dプリンターで、ギアを作り、ステッピングモータ 28BYJ-48 の増速をすることができた。これを基に機器に組み込んで目的の速度で動かせるようにしたい。