VWork バイブコーディングフレームワーク

日本株を複数のAIエージェントが議論して判断するOSS TradingAgents-JP を、マルチユーザーのWEBサービスに作り替えました。名前は Kurage TradingAgents(コード名 ktajp)です。

この記事は「動く個人ツールを、他人が使えるサービスにする」ときに実際どこで詰まるかの記録です。認証・課金・LLMの3か所で刺さりました。

何が変わったか

  旧 TradingAgents-JP 新 Kurage TradingAgents
利用者 自分だけ(APIトークン1本) Xアカウントごとのテナント
判断の頭脳 ローカルLLM or ルール Kurage Brain(ksbrain)系に接続、一般ユーザーはDeepSeek
課金 なし 1分析ごとに支払い(x402 / URLAI / PayPal)
履歴 単一DB ユーザーごとに分離

エンジン部分(担当AIの独立評価 → 強気/弱気の討論 → リスク審査 → 最終判断)はそのままです。変えたのは周りだけで、エンジンは vendor/ に固定コミットで抱えています。

1. 認証:自前で持たない

テナント境界を作るとき、最初に決めたのは「認証を自前で実装しない」ことでした。パスワードもセッションも持ちたくありません。

Kurageシリーズにはすでに X(旧Twitter)のOAuth2共通ログインがあるので、入口のPHPが認証を確定し、検証済みのXユーザー名をヘッダでバックエンドに渡す構成にしました。

ブラウザ → kurage.exbridge.jp/ktajp.php (共通Xログインで認証確定)
             ↓  X-Ktajp-User: <username> + 共有トークン
          バックエンド :18337(セッションを持たない)

共有トークンを付けているのは、バックエンドを直接叩いて任意のユーザー名を名乗られるのを防ぐためです。バックエンド側は「トークンが一致したヘッダだけ信用する」だけでよく、認証コードがゼロ行になりました。1テナント = 1 Xアカウントという定義も、これで自然に決まります。

2. 課金:3つの支払い方法と、まとめ買いの計算

有料化で決めたのは「無料で使わせない。ただし支払い手段は選べる」でした。

ここで一度計算を間違えました。「x402 $0.05 ≒ 7.5円だから、200円なら25回分」としたのですが、これは為替を$1=150円で仮置きし、PayPal手数料を無視していました。実勢(約161円/ドル)と手数料(3.6% + 40円)を入れるとこうなります。

  実質受取 x402換算 付与
x402 $0.05 8.1円/回 1回
PayPal 200円 152.8円 18.9回 20回
URLAI 20,000(=200円) 200円(手数料なし) 24.8回 25回

オンチェーン決済は手数料が乗らないぶん、そのまま利用者に還元される形になりました。決済手段ごとの実質コストを揃えるだけで、トークンを使う動機が自然に生まれるのは発見でした。

3. 販売面は「1つの窓口」に寄せる

最初、この分析機能をx402マーケットプレイスに独立サービスとして登録しました。これは設計として間違いでした。

Kurageには判断APIの家族(暗号資産の kcbrain / FXの kfxbrain / 日本株の ksbrain)があり、機械向けの売り口はここに集約しています。新機能ごとにサービスを増やすと、買い手から見て「どれを買えばいいのか」が分からなくなります。

そこで、マルチエージェント分析は ksbrain のスキルとして 売る形に変えました。

POST https://x402.bankr.bot/0x…/ksbrain/agents/analyze
{"symbol": "7203", "username": "<任意>"}

実装上はゲートウェイのハンドラでこのパスだけ分析エンジン側へルーティングしています。販売面の一貫性は、実装の都合より優先するという整理です。人間はブラウザから、AIエージェントはこのエンドポイントから、同じ機能を同じ課金レールで使えます。

4. 推論型モデルで踏んだ罠(本題)

一般ユーザーの分析はDeepSeek(deepseek-v4-flash)で走らせています。ここで2つ刺さりました。

4.1 content が空で返る

finish_reasonstop なのに message.content が空文字で、reasoning_content だけ入っている応答が間欠的に返ります。JSONを期待している側は「LLM応答にJSONオブジェクトがありません」で落ちます。

原因は max_tokens が小さすぎたことでした。推論型モデルは推論トークンも同じ枠を消費するため、1800では推論だけで枯れて本文が出ません。

"max_tokens": int(os.environ.get("..._MAX_TOKENS", "8192")),  # 1800 では推論で枯れる

あわせて、空応答・JSON無しは即失敗にせず3回リトライするようにしました。このとき、JSON抽出の失敗が独自の例外型で飛んでいたため最初の実装ではリトライに入りませんでした。捕捉する例外に自前の例外型を含めるまで直りませんでした。

4.2 遅くて決済ゲートウェイのタイムアウトに当たる

修正後、分析は通るようになりましたが1回74秒かかり、x402ゲートウェイが504を返しました。担当AIの評価を直列に回していたためです。

担当同士は独立なので、まとめて投げれば済みます。

return list(await asyncio.gather(*(evaluate(b) for b in baselines)))

これで 74秒 → 27秒。ゲートウェイの制限内に収まり、実際に$0.05を支払って完全な分析が返ることを確認できました。

マルチエージェント構成は「独立に評価する」建付けなのに、実装が直列だと待ち時間だけが積み上がります。 並列化は速度改善というより、従量課金の同期APIとして成立させるための必須要件でした。

まとめ

コードは ktajp(サービス本体)と TradingAgents-JP(分析エンジン)で公開しています。実際の画面は tajp.exbridge.jp からどうぞ。

関連書籍

こうした「AIと対話しながら金融システムを作る」進め方(バイブコーディング×バイブトレーディング)を、VPS契約とAI環境構築から、ボット実装、バックテスト、過学習対策、運用監視まで全49章に分解した入門書を出しています。

『AIと作る自動取引ボット入門 — バイブコーディング×バイブトレーディングで暗号資産・FX戦略を育てる』(小嶋 篤・Kindle)

Kindle Unlimitedなら追加料金なしで読めます。本記事のような「個人ツールをサービスにする」段階の、その手前の土台づくりに使えます。


※本記事で紹介したサービスは情報提供のみを目的とし、投資助言ではありません。投資は自己責任で行ってください。