1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

node.js練習でMAGIシステムを作ろう【個人用メモ】

Last updated at Posted at 2026-01-18

開発の経緯

ある日YouTubeを眺めていたら、面白い動画がおすすめに出てきました。

マギシステムをつくりVtuberの彼氏公表をマギに問う月ノ美兎【にじさんじ/切り抜き】

Vtuberの月ノ美兎さんが、ChatGPTに「人格を3つ」作らせて、エヴァのMAGIみたいに多数決させていたんです。
これを見て「複数視点で意思決定するAIの使い方」としてかなり良いアイデアだと思い、node.jsの練習も兼ねて再現してみました。

利用した技術・サービス

  • JavaScript(フロント:ネイティブ)
  • Node.js / Express(バックエンド)
  • OpenAI API(今回は手間だったので省いたが、人格ごとにgemini,openAI,deepseekのようにサービスを変えたらより中立的な判断が下せるかも?)
  • Vercel(デプロイ)

Webアプリ開発の経験がほとんど無かったので、今回はReactなどのフレームワークは使わず、フロントはネイティブJSで組みました。

デモ

MAGI System
待機画面
スクリーンショット 2026-01-18 113932.png

回答画面
スクリーンショット 2026-01-18 114026.png

機能の紹介

  1. 質問を入力すると、3つのAI(MELCHIOR / BALTHASAR / CASPER)に同時送信
  2. 各AIが「可決 or 否決 + 理由(JSON)」で返答
  3. 多数決で最終決定(2/3以上で承認)

仕組み(ざっくり)

  • フロント:入力→ /ask-magi にPOST
  • バックエンド:3つのOpenAI呼び出しを Promise.all で並列実行
  • 最後に多数決して、結果をJSONで返す

環境構築

Dockerで開発環境作成

Dockerfile / docker-compose.yml / package.json を用意して、コンテナ上でNodeを動かしました。

docker-compose up -d --build #コンテナ作成
docker-compose exec magi-system npm install #パッケージインストール
#node_modules は空に見えるが、仮想環境にパッケージがインストされている。

備忘録

フロントとバックエンドの分離

  • require, express, openAI の設定はサーバー用ファイルに格納する。
  • ユーザーが通信を見れてしまうのでhtml側ではフロント側スクリプトのみ参照
<script src="script.js"></script>

公開範囲の設定

以下をサーバー側に書いたら、publicフォルダにユーザーに見られて問題ないファイルを入れる(=html,css,フロント側ロジック)


app.use(express.static('public'));

開発中のサーバー起動

Live Serverではなく、ExpressがlistenしているURLで動作確認する。

vercelでのデプロイ

//環境変によってローカルかどうか判断させる
if (process.env.NODE_ENV !== 'production') {
  const PORT = process.env.PORT || 3000;
  app.listen(PORT, () => {
    console.log(`MAGI System Online: http://localhost:${PORT}`);
  });
}
module.exports = app;

.env はGitHubに上げないように .gitignore に追加し、Vercel側の環境変数に設定する。

node.js学習メモ

//モジュール読み込みと公開設定
const express = require('express'); //ライブラリを読み込む
const app = express(); //サーバー本体(app)を作成
const dotenv = require('dotenv'); //.envから環境変数読み込み
dotenv.config(); //.env を読んで process.env.XXXX に入れる
app.use(express.json()); //POSTの本文がJSONの場合に req.body として読めるようにする
app.use(express.static('public')); //public フォルダをWeb公開する
//async awaitで非同期処理(結果が返るまで次の処理を待機)
async function askMagiCore(config, userMessage, API_KEY) {
  try {
    const response = await API_KEY.chat.completions.create({
      model: "gpt-4o-mini",
      messages: [
        { role: "system", content: `...` },
        { role: "user", content: userMessage }
      ],
      response_format: { type: "json_object" }//JSONでのレスポンスを強制
    });
    //文字列レスポンスをオブジェクト変換
    const answer = JSON.parse(response.choices[0].message.content);
    return { ... };
  } 
}
//エンドポイント
//ブラウザがPOST /ask-magi に { "message": "..." } を送る
app.post('/ask-magi', async (req, res) => {
	//サーバーは req.body.message を取り出す
  const { message } = req.body;
  //3つのAI問い合わせを 同時に走らせる
  const results = await Promise.all([
    askMagiCore(...MELCHIOR...),
    askMagiCore(...BALTHASAR...),
    askMagiCore(...CASPER...),
  ]);
  //全部返ってきたら多数決して、JSONでブラウザへ返す
  res.json({
    finalDecision: calculateDecision(results),
    results: results,
  });
}),

振り返り

開発の流れを「環境構築 → バックエンド → 簡易フロント → UI/デザイン」の順で踏めたのは良かったです。
一方で、UIの細部調整に時間を使いすぎた感があり、MAGIっぽさを十分に出しきれませんでした。

次はReactやTailwindも触ってみると、UI構築の効率が上がるかもしれません。
また、OpenAI APIを3回呼ぶのでコストや失敗時の扱い(タイムアウト、リトライ、1つエラーでも多数決するか等)も改善ポイントとして残りました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?