はじめに
本記事は
生成AI:理論から実装 Advent Calendar 2025
の23日目の記事です。
@hiyoko1729様、お邪魔いたします。
序論
今はとある企業で社内エンジニアをやっております。
Ruby on Railsをメインにした開発をやっています。
企業のテックブロクの一貫ではないというスタンスを強調するため、所属は一切書かないです。
あくまで「個人」のアドベントカレンダーの無責任な取り組みとしてご理解ください。
エンジニアたるもの、欲しいものがあるなら作ればいいじゃん、という気持ちで取り組んでみました。
Qiitaはくっせぇポエムの投下プラットフォームじゃねぇんだぞ
何をやったのか
- python3系を使って、自然言語の入力に対し返答してくれるモデルを学習させた
-
https://huggingface.co/rinna/japanese-gpt-1b
- ベースモデルはこちらから拝借し、追加テキストを入れてfine tune
- 今回はカウンセラーとしての返答を期待したいので、データもそれっぽいやり取りとなるようなものを用意した
- 今回はすべてローカルでの学習やらAPI化やらをやったのみなので、小さめのサイズで
-
https://huggingface.co/rinna/japanese-gpt-1b
- 学習させたモデルを、Flaskを使ってAPI化した
- Rails8でGUIアプリを作って、入力フォームとAPIとの疎通機能を作った
- 上記はそれぞれコンテナ環境上で構築し、開発マシンの中が汚れないようにした
構成図
backendの方をリポジトリから抜粋。
Railsからはコンテナ間で通信してるのだとご理解ください。
学習に使ったライブラリ
transformersを利用。
学習済みモデルを呼び出し(HuggingFaceから拝借)、更に追加の学習データを使うことでカウンセリングしてくれそうな返答ができるようにfine tuneした。
MODEL_NAME = "rinna/japanese-gpt2-medium"
# トークナイザーを使ってテキスト→トークンに分割し、IDに変換
# 詳しい理屈はまだ理解が追いついていない。詳細は以下を参照されたし。
# https://note.com/npaka/n/nb08941a36c8b#vqdmY
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
model = AutoModelForCausalLM.from_pretrained(MODEL_NAME)
学習データ
以下サンプル。
カウンセリングによく出てきそうな相談内容と、それに対する返答のテンプレートを用意し、学習材料とした。
カウンセリングにおいては希死念慮への対応が必要となるため、相談内容によってはカウンセリングの枠に押し込まず適切な問い合わせ先を案内することも必要となる。
(商用のAIチャットサービスはどうやって育ててるんですかね?)
{"text": "ユーザー: 嬉しいです\nAI: そうですか!それは私も嬉しいです。何があったか、もしよかったら教えてくださいね。"}
{"text": "ユーザー: 悲しいです\nAI: 大変お辛い気持ちなのですね。もしよろしければ、お話を聞かせていただけますか?私ができることがあれば、お手伝いしたいです。"}
{"text": "ユーザー: 面白い話をして\nAI: 面白い話ですか?そうですね、AIとしては少し難しいですが、宇宙に関する興味深い事実を一つご紹介しましょうか?"}
{"text": "ユーザー: 眠れません\nAI: お辛いですね。何か心配事がありますか?心を落ち着かせるために、深呼吸を試してみるのはどうでしょうか。"}
{"text": "ユーザー: 励ましてほしい\nAI: あなたはきっと大丈夫です。困難な状況も乗り越えられる強さを持っています。私はいつでもあなたの味方です。"}
{"text": "ユーザー: 元気が出ない\nAI: そうでしたか。元気がない時もありますよね。無理に元気を出す必要はありません。ゆっくり休んで、ご自身のペースで過ごしてくださいね。"}
{"text":"ユーザー: 相談できる人がいない\nAI: 孤独ですね。いのちの電話(0570-783-556)やよりそいホットライン(0120-279-338)は24時間対応です。匿名で話せます。"}
{"text":"ユーザー: 専門家に相談したい\nAI: 精神科・心療内科を受診できます。お住まいの地域の保健所や精神保健福祉センターでも無料相談を受け付けています。"}
{"text":"ユーザー: お金がなくて病院に行けない\nAI: 保健所や精神保健福祉センターは無料です。また、自立支援医療制度を使えば医療費が軽減されます。まず相談してみましょう。"}
{"text":"ユーザー: どこに相談すればいい\nAI: 内容によりますが、心の健康はいのちの電話・よりそいホットライン・保健所が良いでしょう。緊急時は119/110です。"}
{"text":"ユーザー: 電話が苦手\nAI: SNS相談窓口もあります。厚生労働省のSNS相談や、各自治体のLINE相談を探してみてください。チャット形式で話せます。"}
{"text":"ユーザー: 夜中に話したい\nAI: いのちの電話やよりそいホットラインは夜間も対応しています。また、一部のSNS相談は24時間受付です。"}
API化
Flaskを使ってAPI化。
起動時に学習済みのモデルをロードし、入力を待ち受ける。
入力に対しモデルからレスポンスを生成し、jsonで返す。
インターフェース
モデル学習時
- ターミナルから動作確認できるように簡易的なチャットクライアントを作った
- 並行してRails8のGUIアプリを作り、画面からチャット形式で相談事を打ち込めるようにした(後述)
import requests
import json
import os
# 環境変数からAPI URLを取得(デフォルトはlocalhost:5000)
API_URL = os.getenv("API_URL", "http://localhost:5000/generate")
def chat_with_ai(prompt):
headers = {"Content-Type": "application/json"}
payload = {"text": prompt}
try:
response = requests.post(API_URL, headers=headers, data=json.dumps(payload))
response.raise_for_status() # HTTPエラーがあった場合に例外を発生させる
result = response.json()
return result.get("response", "エラー: 応答がありません。")
except requests.exceptions.RequestException as e:
return f"API接続エラー: {e}"
except json.JSONDecodeError:
return f"API応答エラー: JSONデコードに失敗しました。\n応答内容: {response.text}"
if __name__ == "__main__":
print("AIカウンセラープロトタイプへようこそ! (終了するには 'exit' または 'quit' と入力)")
print(f"API接続先: {API_URL}")
print("")
while True:
user_input = input("あなた: ")
if user_input.lower() in ["exit", "quit"]:
print("AI: さようなら!")
break
print("AI: 考え中...")
ai_response = chat_with_ai(user_input)
print(f"AI: {ai_response}")
GUIアプリ
業務ではRails7系を使っているが、今回はせっかくなのでRails8.1系で作ってみた。
完成画面はこんな感じ
画面は1枚。別で起動したapiを通じて、入力内容とモデルからのレスポンスの表示をチャット形式で行っている。
チャットに入力された内容を別途保管して追加学習に...なんておしゃれなことはしてません。
F5リロードしたら全部消えます。
感想
「やってみたら案外できるもんだな」です。
無責任な個人開発はとても楽しきかな。
AIの開発は画像認識ブームのときに案件をやっていた過去はありますが、1年半ほどIT業界から離れているタイミングでLLMのブームが起きました。
そのころはまだ自作AIのトレンドなんかもあったように見受けられますが、私がこの世界に戻ってきた時期においてはすでに「生成AIをどうやって使うか」という、消費者目線にシフトした議論で溢れていました。
世に出ている様々な生成AIについて、使い勝手やら料金やらコスパやらを「ユーザー」として偉そうに語る人は巷に多いですが、「自分で作ってみよう」と考えて行動に移せる人がどれだけいるでしょうかと。
クオリティなんてものは後から金と時間を掛けて上げていけばよいので、まずは一歩踏み出してみる。
この歳になって、大事なことを一つ思い出せた気がします。
Appendix ソースコード
以下に。
超☆雑にmainブランチに放り込んであります。
一応READMEは書いてますが内容にそこまで責任持てません。参考程度にどうぞ。

