はじめに
先月に A2A で MAGI システムを作ろう、という記事を書きましたが、諸般の事情により、まずは OCI を使って、無料で作成できる MAGI的Webシステム を作成してみました。
MAGIシステムというのは、3つの独立した人格の AI が議論し、最終決議を下すというものですが、このプロセスを、無料で使える OCI のクラウド基盤と、WebUI を簡単に作成できる Streamlit を使い、無料枠の範囲で Gemini 2.5 Flash API を呼び出すという組み合わせで、完全無料で実現してみましたので、ご参考までに見てみてください。
動作環境の準備
① インスタンス準備
VM: VM.Standard.E2.1.Micro
(無料枠ではメモリが1GBしかない上記のインスタンスしか作成できませんでした・・)
OS: Ubuntu 22.04(メモリ消費が少ないため)
② メモリ不足対策
OCIの無料枠(1GBメモリ等)でもスワップ領域を確保することで、OSやアプリケーションを安定動作させることができます。
# 2GBのスワップ領域を確保
sudo fallocate -l 2G /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
③ 各種パッケージのインストール
pip の場所が不明になる問題を回避するため、仮想環境(venv)を構築します。
(こちらは Gemini3 に作成してもらったまま使用しております)
sudo apt update && sudo apt install -y python3-pip python3-venv
python3 -m venv venv
source venv/bin/activate
# langchain-google-genaiをインストール
pip install -U streamlit langchain-google-genai langchain-community chromadb
④ ネットワーク通信の開通
外部ブラウザからアクセス可能にするための設定です。
・サーバー内ファイアウォールの設定
sudo iptables -I INPUT -p tcp --dport 8501 -j ACCEPT
sudo netfilter-persistent save
・OCIセキュリティ・リストの設定
ソースCIDR: 0.0.0.0/0
宛先ポート範囲: 8501 (TCP) を許可
※本件では、かなり簡易的な設定を行っていますが、実際にはきちんとセキュリティ設定を行うことをお勧めします。
💡 Streamlit とは?
HTML/CSS/JavaScriptを一切書かずに、Pythonだけで Web UI を作成できます。
また機会がありましたら、Streamlit について詳しくご紹介します。
プログラムの実装
あらかじめ、Google Gemini APIキーの取得(無料)を行って起き、下記プログラムの
「YOUR_API_KEY_HERE」部分に、APIキーを設定してください。
(あくまで実験用のため直書きしていますが、ソースコードにAPIキーを直書きすることは避けてください)
import streamlit as st
import os
import time
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_core.messages import HumanMessage
# APIキーの設定
# 注: 本番運用時は環境変数等で管理することを推奨します
GEMINI_API_KEY = "YOUR_API_KEY_HERE"
# --- 画面設定とCSSハック (MAGI専用デザイン) ---
st.set_page_config(page_title="MAGI SYSTEM", layout="wide")
st.markdown("""
<style>
body { background-color: #000; }
.stApp { background-color: #000; }
.magi-card {
padding: 20px; border-radius: 5px; margin-bottom: 10px;
border: 1px solid #ff4b00; background-color: #0a0a0a;
color: #ff4b00; font-family: 'Courier New', monospace;
min-height: 250px; box-shadow: 0 0 10px #ff4b00;
}
.magi-header { font-weight: bold; font-size: 1.3em; border-bottom: 1px solid #ff4b00; margin-bottom: 10px; }
/* 最終決議用の点滅アニメーションと巨大文字 */
@keyframes blink { 0% { opacity: 1; } 50% { opacity: 0.3; } 100% { opacity: 1; } }
.final-decision-box {
padding: 40px; text-align: center; border: 5px double #ff4b00;
background-color: #000; margin-top: 20px;
}
.status-code {
font-size: 5em; font-weight: bold; animation: blink 0.8s infinite;
letter-spacing: 10px; margin: 20px 0;
}
.verdict-text {
font-size: 2em; border: 2px solid #ff4b00; display: inline-block; padding: 10px 30px;
}
</style>
""", unsafe_allow_html=True)
st.title("🔴 MAGI SYSTEM : STRATEGIC DECISION")
st.info("OCI Always Free x Gemini 2.5 Flash:3つの独立した人格による分散合議プロセス")
# モデル初期化
model = ChatGoogleGenerativeAI(model="gemini-2.5-flash", google_api_key=GEMINI_API_KEY)
# 3者のペルソナ定義
magi_config = {
"MELCHIOR-1": "科学者:論理的、効率的、技術的実現性を重視。感情を排した冷徹な判断を下す。",
"BALTHAZAR-2": "母:倫理、安全、社会への影響、長期的な保護を重視。リスクを極端に嫌う。",
"CASPER-3": "個人(女):直感、情熱、独自の美学、競争優位性を重視。時に大胆な賭けを支持する。"
}
if prompt := st.chat_input("審議事項を入力してください(例:新規事業へ投資すべきか?)"):
with st.chat_message("user"):
st.write(f"【諮問内容】: {prompt}")
results = {}
cols = st.columns(3)
# ステータス管理
with st.status("MAGI審議中... システム接続確認", expanded=True) as status:
for i, (name, persona) in enumerate(magi_config.items()):
with cols[i]:
st.markdown(f"🧬 **{name}** System Online...")
# レート制限(429)回避のリトライロジック
for attempt in range(5):
try:
time.sleep(i * 1.5)
sys_prompt = f"あなたはMAGIの{name}です。役割は{persona}です。諮問に対し150字程度で意見を述べ、最後に必ず【賛成】か【反対】か【条件付き賛成】を明記してください。"
response = model.invoke([HumanMessage(content=f"{sys_prompt}\n\n諮問: {prompt}")])
results[name] = response.content
st.markdown(f"""<div class='magi-card'>
<div class='magi-header'>{name} ANALYSIS</div>
{response.content}
</div>""", unsafe_allow_html=True)
break
except Exception as e:
st.caption(f"再試行中... ({attempt+1}/5)")
time.sleep(10)
status.update(label="審議完了。最終決議を生成中...", state="complete", expanded=False)
# --- 合意形成ロジック ---
votes = {"賛成": 0, "条件付き賛成": 0, "反対": 0}
for res in results.values():
if "条件付き賛成" in res: votes["条件付き賛成"] += 1
elif "賛成" in res: votes["賛成"] += 1
elif "反対" in res: votes["反対"] += 1
summary_prompt = f"以下の3者の意見を統合し、最終的な結論を250字程度で出力してください。多数決の結果を含めてください。\n\n{results}"
final_summary = model.invoke([HumanMessage(content=summary_prompt)])
# 判定とカラーリング
is_passed = (votes["賛成"] + votes["条件付き賛成"]) >= 2
code = "601" if is_passed else "602"
status_label = "PASSED (可決)" if is_passed else "REJECTED (否決)"
main_color = "#00ff00" if is_passed else "#ff0000"
# 最終決議の巨大表示
st.markdown(f"""
<div class="final-decision-box" style="border-color: {main_color};">
<div style="color: {main_color}; font-size: 1.5em;">MAGI FINAL DECISION</div>
<div class="status-code" style="color: {main_color};">CODE: {code}</div>
<div class="verdict-text" style="color: {main_color}; border-color: {main_color};">
{status_label}
</div>
</div>
""", unsafe_allow_html=True)
st.markdown(f"### 📢 最終報告サマリー\n{final_summary.content}")
st.bar_chart(votes)
いよいよ実行!!
OCI のコンソールより、下記を実行します。
python3 -m streamlit run magi.py
実行すると、下記の画面になります。
Collecting usage statistics. To deactivate, set browser.gatherUsageStats to false.
You can now view your Streamlit app in your browser.
Local URL: http://localhost:8501
Network URL: http://10.0.0.xxx:8501
External URL: http://138.2.60.xxx:8501
External URLに表示されている、「http://138.2.60.xxx:8501 」をダブルクリックします。
すると Webブラウザが立ち上がり、プロンプト入力画面になりますので、適当な審議事項(諮問)を入れてみてください。
実行結果
今回は、エヴァンゲリオンでおなじみ(?)の質問(諮問)をしてみました。

3者がそれぞれの判断で、賛成、反対、条件付き賛成を回答し、とりまとめを行って最終回答を行っています。
まとめ
今回は、OCI の Always Free を利用して。「MAGIシステム」的な仕組みを再現してみました。A2A のような完全なマルチエージェントではありませんが、意外とお手軽にこのようなアプリケーションを作成できますので、みなさんもチャレンジしてみてください!