【AIをAIから習って覚える】 第2話 :LLMを使ったシンプルなQ&Aアプリを作ってみる
【AIをAIから習って覚える】 第2話 :LLMを使ったシンプルなQ&Aアプリを作ってみる
概要
これは、僕がAIについて学び、試行錯誤していく過程を記録するシリーズの続きです。前回の記事では、AIを使ってどんなことができるか、そして何を学んでいくかの方針を、最終的に以下のような学習プランとしてまとめてみます。
前回記事: 【AIをAIから習って覚える】 第1話 - LLMを使いこなすには、人間様の的確な指示がキモだった件
次の記事を書くために、"課題1-1: シンプルなQ&Aアプリケーション"を開始しようと思います。
GitHub - taka4rest/learn-ai-1-1-1
リポジトリはこちらです。プログラミングをスタート
さて、前回立てた学習プランに沿って、いよいよ実際に手を動かしてみようと思う。
プランの最初のステップは 「1-1: シンプルなQ&Aアプリケーション」 だった。まずはここから取り組んでいきたい。
LLMの基本的な使い方を学びつつ、簡単なアプリケーションを構築する、という目的にはちょうど良いだろう。
実のところ、このレベルのものは、すでに幾つか作ってしまっていて知っているのだが、飛ばしちゃうといきなり中級編みたいになっちゃうので、それは避けたい。
どうせなら、AIを学び始めたばかりの人にも参考になれば嬉しい。
というわけで、テーマはもちろん「課題1-1: シンプルなQ&Aアプリケーション」開発だ。
言語は何を選ぶ?
まず考えるのは、どのプログラミング言語を使うかですね。
一番手軽そうなのは、やはり Python かな。
機械学習系のライブラリは圧倒的に揃っているのは知っている。
しかし、折角だから2025年初頭時点での流行も知っておきたい。
早速、gemini 2.5に聞いてみるよ。
```
https://zenn.dev/taka4rest/articles/8d387a81078462
次の記事を書くために、"課題1-1: シンプルなQ&Aアプリケーション"を開始しようと思います。
言語は何で作るのが良いかな?
pythonでシンプルなUIまで作っちゃって、ローカルで実行できるようにしてみようか?
他のいけてる言語があれば、最初にリコメンドして。
個人的にはGOエンジニアってイケてるイメージがあるが、コンパイル言語だから少し手間なのかなって思っているが、LLMを扱う上で覚えておいた方がよければやるよ。
```
ちょっと気になるのが Go言語。
パフォーマンスが良いって聞くし、静的型付けも堅牢な開発には魅力的だ。シングルバイナリで配布できるのも良い。「Goエンジニア」って、なんとなく響きも良いし(笑)。
ふむふむ、Geminiの回答を要約するとこんな感じか。
- Python: LLMライブラリのエコシステムが成熟していて、情報も多い。StreamlitやGradioを使えばUIも簡単に作れる。プロトタイピングや最初のステップには最適。
- Go: 実行速度や並行処理性能は高い。静的型付けもメリット。ただ、LLM関連のライブラリはPythonほど多くなく、UI作成もPythonほど手軽ではないかも。パフォーマンスが重要なバックエンドなどでは強力。
なるほど。僕の今の目的やスキルセットを考えると、まずは Python で始めるのが良さそうだ。Go言語は、ノリで聞いてみたけれど変なところでハマりそうだし今回はパスだな。
PythonでUIを作るなら?
Pythonで進めると決めたはいいが、問題はUIだ。
FlaskやFastAPIでAPIだけ作って、フロントエンドは別途HTML/CSS/JavaScriptで…というのは、今回の「サクッと作りたい」という目的からは少し重い。
もっとPythonだけで完結できるような、簡単なUI構築ツールはないものか…?
これもAIに聞いてみよう。
PythonでLLMを使う際に、ナウでヤングなみなさんが使っているのはどんなライブラリ?
FlaskとFastAPIなら使ったことがあるけど
ほう、Streamlit と Gradio というのが良さそうなのね。
名前は聞いたことがあるような気もするけど、詳しくは知らないな。ちょっと調べてみよう。
- Streamlit: Pythonスクリプトを上から実行するだけで、自動的にWebアプリのUIを生成してくれるらしい。データ分析系のダッシュボードや、簡単なWebアプリを高速で作るのに向いているようだ。ウィジェットもPythonの関数呼び出しで追加できると。これは手軽そうだ。
- Gradio: こちらは機械学習モデルのデモUI作成に特化しているみたいだ。モデル(関数)と入出力の形式を指定するだけで、インターフェースが作れると。Hugging Face社で作られているから当然 Huggin Face との連携も強いらしい。これもシンプルで良さそう。
なるほど、どちらも面白そうだ。Streamlitは汎用性が高そうだし、Gradioは特定のモデルを手早く試すのに特化している感じか。どちらを使うかは、作りたいものによるな。
今回の開発の進め方
せっかくだから、どちらも触るとするか。
ここでふと思ったんだけど、Hugging Faceの Transformers ライブラリって、Gradioとセットで使われることが多いらしいけど、Gradio専用なのかな?
Gemini、ちょっと確認なんだけど、Hugging FaceのTransformersライブラリって、Gradioがないと使えない?
thinking : こいつ何にも知らないんだな・・・教えてやらなきゃ。
「いえ、Transformersは独立したPythonライブラリなので、Streamlitでも、普通のPythonスクリプトでも利用できますよ」
シンキングモデルさん、僕を馬鹿にしているのが薄い文字で見えてます。
いいよいいよ。知らないのは事実だ。
よし、こんな進め方で両方のツールを試してみるのはどうだろう。学習プラン「1-1」の中でも、少し実験的な要素を加えてみよう。
- Gradio + Transformers: まずはGradioを使って、Transformersライブラリのモデル(例えば簡単なテキスト生成モデルとか)を動かすデモUIを作ってみる。これでGradioの基本的な使い方と、モデルをサッと試す手軽さを体験する。
- Streamlit + API連携: 次にStreamlitを使って、外部のLLM API(例えばOpenAIのAPIとGoogleのGemini API)を切り替えて使える簡単なQ&Aインターフェースを作ってみる。これでStreamlitのウィジェットの使い方や、もう少し汎用的なアプリの作り方を学ぶ。
うん、これなら両方のライブラリの特徴を掴めそうだ。実験としても面白い。
よし、方針は決まった。
学習プランの第一歩として、まずはこの2つの小さなアプリケーション開発を通じて、StreamlitとGradio、そしてLLM連携の基本を学んでいこう。
この方針決定までの思考プロセスも、記事の導入としてちょうど良さそうだ。
・・・眠い。
あ、明日頑張るよ!
gradio を使ってみるよ!
おはようございます!
ふむふむ。
gradio を使うと、えらい簡単にAIのプロトタイピングができるんだな。
```
import gradio as gr
def greet(name):
return "Hello " + name + "!!"
demo = gr.Interface(fn=greet, inputs="text", outputs="text")
demo.launch()
```
さて、実行してみるか。
```
(.venv) takaho@hatanakihonoMBP gradio % python gradio-1st.py
* Running on local URL: http://127.0.0.1:7860
```
URLにアクセスしてみると・・・
なるほど。
AIっぽいことをするなら・・・
- 画像分類デモ (Hugging Faceモデル利用)
- 簡単な翻訳ツール (Hugging Faceモデル利用)
- テキスト感情分析 (Hugging Faceモデル利用)
- GPT4Freeとlangchainを使って複数のモデルに跨った処理を試してみる
4は少し高度すぎるな。
Qiitaとかzennを gradioで検索すると、画像分類をしている人が多いな。
よし、2の翻訳ツールをやってみるか。
ライブラリをインストールしよう。
```
pip install gradio transformers torch<2 sentencepiece
```
んで、、、コードはこんな感じか?
```
import gradio as gr
from transformers import pipeline
# 1. Hugging Face の翻訳パイプラインをロード
try:
translator = pipeline("translation", model="Helsinki-NLP/opus-mt-en-jap")
print("翻訳モデルのロードに成功しました。")
except Exception as e:
print(f"モデルのロード中にエラーが発生しました: {e}")
print("インターネット接続を確認するか、モデル名が正しいか確認してください。")
exit() # エラー時は終了
# 2. テキストを翻訳する関数を定義
def translate_text(text_to_translate: str):
"""入力された英語テキストを日本語に翻訳する関数。"""
if not text_to_translate: # 入力が空の場合
return ""
try:
# パイプラインを使って翻訳を実行
# 結果は [{'translation_text': '翻訳されたテキスト'}] のようなリスト形式
result = translator(text_to_translate)
# リストの最初の要素から翻訳テキストを取り出す
translated_text = result[0]['translation_text']
return translated_text
except Exception as e:
print(f"翻訳中にエラーが発生しました: {e}")
return "翻訳中にエラーが発生しました。"
# 3. Gradioインターフェースを作成
iface = gr.Interface(
fn=translate_text, # 実行する関数
inputs=gr.Textbox(lines=3, placeholder="ここに英語のテキストを入力してください...", label="英文"), # 入力: 複数行入力可能なテキストボックス
outputs=gr.Textbox(label="和訳"), # 出力: テキストボックス
title="英語 -> 日本語 翻訳ツール",
description="Hugging Faceのモデル (Helsinki-NLP/opus-mt-en-jap) を使って英語を日本語に翻訳します。",
examples=[ # サンプルテキスト
["Hello, how are you?"],
["Gradio is a library for creating machine learning web apps."],
["This translation model is provided by Helsinki-NLP."]
]
)
# 4. デモを起動
if __name__ == "__main__":
print("Gradioインターフェースを起動します...")
try:
iface.launch()
print("インターフェースが http://127.0.0.1:7860 で起動しました。")
except Exception as e:
print(f"Gradioインターフェースの起動中にエラーが発生しました: {e}")
```
実行ポチッとな。
おぉぉぉ、なんかモデルを勝手にダウンロードしたりしている。
すげー
よし、試すぞ!
こんなんで翻訳ツールできちゃうの?
まじ?
あ、はい笑
なるほど。
まぁ、翻訳精度はともかく、AIモデルが使えたってことになるのかな。
ちょっと、別のモデルを試せないか調べてみよう。
facebook/nllb-200-distilled-600M というモデルが具合が良さそうなので試すことにします。
・・・何かおかしい。
今作業をしているのは intel macのGPU付きモデルだが、、、どうもうまく動かないようだ。
responceに空文字が入って返ってきている。GPUは15秒くらい仕事をしていたみたいだけど残念だ。
よし、せっかくだから実行環境を判別して、どんな環境でも実行できるようにしよう。
色々試してみたが、 intel macではGPUを使わないようが良さそうだ。 (実際のコードは github を参照してください)
コードはこんな感じになった。
ゴテゴテしてきたな。苦笑
```
# ライブラリのインポート
import gradio as gr
from transformers import pipeline
import torch
import sys # 標準エラー出力用
import platform # OS情報取得用
<中略>
selected_device = get_optimal_device()
# --- モデルのロード ---
# より多くの言語に対応し、品質も比較的高めなモデル
MODEL_NAME = "facebook/nllb-200-distilled-600M"
# Helsinkiモデル (軽量だが品質はNLLBに劣る場合がある)
# MODEL_NAME = "Helsinki-NLP/opus-mt-en-jap"
translator = None # グローバル変数として初期化
try:
print(f"\n翻訳モデル ({MODEL_NAME}) をロードしています... ({selected_device}を使用)")
print("初回実行時やモデル変更時はダウンロードに時間がかかることがあります。")
# NLLBモデルの場合、src_langとtgt_langが必要
if "nllb" in MODEL_NAME:
translator = pipeline(
"translation",
model=MODEL_NAME,
src_lang="eng_Latn", # 翻訳元言語: 英語 (NLLB言語コード)
tgt_lang="jpn_Jpan", # 翻訳先言語: 日本語 (NLLB言語コード)
device=selected_device # 自動選択したデバイスを指定
)
# Helsinkiモデルなど、他のモデルの場合は不要な場合がある
else:
translator = pipeline(
"translation",
model=MODEL_NAME,
device=selected_device
)
print("翻訳モデルのロードに成功しました。\n")
except Exception as e:
print(f"\n!!! エラー: モデル '{MODEL_NAME}' のロード中に問題が発生しました !!!", file=sys.stderr)
<中略>
sys.exit(1) # 致命的なエラーなので終了
# --- 翻訳実行関数 ---
def translate_text(text_to_translate: str):
"""
入力された英語テキストを日本語に翻訳する関数。
"""
# モデルがロードされていない場合(万が一)
if translator is None:
return "エラー: 翻訳モデルがロードされていません。"
# 入力が空文字列、または空白のみの場合は空文字列を返す
if not text_to_translate or not text_to_translate.strip():
return ""
print(f"翻訳を実行中... 入力: '{text_to_translate[:50]}...'")
try:
# max_lengthを設定して、長文でも翻訳できるようにする (デフォルトは短い場合がある)
# この値を大きくするとメモリ使用量が増える可能性あり
result = translator(text_to_translate, max_length=512)
translated_text = result[0]['translation_text']
print(f"翻訳完了: '{translated_text[:50]}...'")
return translated_text
except Exception as e:
print(f"!!! 翻訳中にエラーが発生しました: {e}", file=sys.stderr)
# ユーザーフレンドリーなエラーメッセージを返す
return f"翻訳エラーが発生しました。入力テキストを確認するか、少し待ってから再試行してください。 (詳細: {e})"
# --- Gradioインターフェース定義 ---
DESCRIPTION = f"""
英語のテキストを入力すると、日本語に翻訳します。
使用モデル: `{MODEL_NAME}`
実行デバイス: `{selected_device.upper()}` (自動検出)
- Windows, macOS, Linux で動作します。
- 利用可能なGPU (NVIDIA CUDA / Apple MPS) を自動検出し、高速化を図ります。
- GPUが利用できない場合はCPUで動作します。
"""
<中略>
# Gradioテーマ (見た目を少し変える)
# theme = gr.themes.Glass() # 他のテーマも試せます: Default, Monochrome, Soft, Glass, Base
theme = gr.themes.Soft()
iface = gr.Interface(
fn=translate_text, # 実行する関数
inputs=gr.Textbox(
lines=5, # 入力欄の高さ (行数)
placeholder="Enter English text here...", # 入力欄のプレースホルダー
label="English Text" # 入力欄のラベル
),
outputs=gr.Textbox(
label=f"Japanese Translation ({selected_device.upper()})", # 出力欄のラベル (デバイス情報を含む)
lines=5 # 出力欄の高さ
),
title="English to Japanese Translator (Cross-Platform)", # アプリのタイトル
description=DESCRIPTION, # アプリの説明
examples=EXAMPLES, # 例として表示する入力
theme=theme, # 見た目のテーマを適用
allow_flagging='never' # Hugging Face Spacesなどで不要なフラグ機能を無効化
)
# --- アプリケーション起動 ---
if __name__ == "__main__":
print("\nGradioインターフェースを起動します...")
try:
iface.launch(share=False)
# launch() は通常、Ctrl+Cで終了するまで実行をブロックします。
# print分の後に到達するのは、サーバーが停止した後です。
except Exception as e:
print(f"\n!!! Gradioインターフェースの起動中にエラーが発生しました: {e}", file=sys.stderr)
sys.exit(1)
```
ブラウザから適当な英文を翻訳してみる。
おぉぉぉ!!
それなりに翻訳してる!数年前のgoogle翻訳並みにはなっている気がする。
すごいなぁ。
どんなモデルがあるんだろう
なるほど。
かなり簡単にAIモデルを切り替えたりしながら遊べることがわかった。
目的に合わせて、既存のモデルを選択する知識や、自前で学習させたデータセットを使うノウハウが今後のお勉強課題になるんだな。
ざっくり、代表的なモデルをチェックしてみるとこんな感じ。
AI(特にディープラーニング)が得意なタスクごとに、代表的なモデルがあるみたいだ。
-
テキスト系 (自然言語処理 - NLP):
- テキスト生成: 文章の続きを書いたり、要約したり、詩を作ったり。有名なGPT系のモデル(GPT-2とか)や、日本語に特化したモデル(rinna/japanese-gpt2-medium とか)もある。ブログ記事の下書きとか、アイデア出しとかにも使えそう。
-
翻訳: 今回試した
facebook/nllb-200-distilled-600M
やHelsinki-NLP
シリーズが有名だけど、特定の言語ペア(例えば英語⇔ドイツ語)に超特化したモデルもたくさんある。 - テキスト分類: 文章がポジティブかネガティブか(感情分析)、スパムメールかどうか、ニュース記事のカテゴリ分けなど。カスタマーレビューの分析とかに使えそうだ。
- 質問応答 (QA): 長い文章やドキュメントを読み込ませて、それに関する質問に答えてくれるモデル。社内文書検索とか、マニュアルからの情報抽出とかに役立ちそう。BERT系のモデルがよく使われるらしい。
- 固有表現抽出 (NER): テキストの中から人名、地名、組織名などを抜き出すモデル。情報整理とかに便利。
-
画像系 (コンピュータビジョン):
- 画像分類: 写真に写っているのが「犬」なのか「猫」なのか、あるいは「車」なのかを当てる。基本的なタスクだけど、色々な応用がある。ResNet とか ViT (Vision Transformer) とかが有名。
- 物体検出: 画像の中にある物体の「位置」と「種類」(例: 左上に犬、右下に猫)を検出する。自動運転とか、画像内のアイテム検索とか。YOLOシリーズとかが有名かな?
- 画像生成: テキスト(プロンプト)から画像を生成するやつ。最近めちゃくちゃ話題の Stable Diffusion とか、DALL-E 2 とかもここに含まれる。まさに「絵を描くAI」。
-
音声系 (Audio):
- 音声認識 (Speech-to-Text): 人の話している声をテキストに変換する。会議の議事録作成とか、音声入力とか。OpenAI の Whisper が非常に高性能で有名。
- 音声合成 (Text-to-Speech, TTS): テキストを自然な話し声に変換する。オーディオブック作成とか、スマートスピーカーの応答とか。
軽くリストアップしてみたけれど、すごいボリュームだな。
Streamlitの実装もやってみようと思ったけれど、体力が切れた。
記事も長すぎるし別記事にしよう。
Discussion