WORK

History Soul Matcher

顔写真を送るだけで、あなたに最も「魂が近い」歴史上の人物がわかるWebアプリ。AIが顔の特徴を自動分析し、200名の歴史人物データベースから最も相性のよい1名を判定して、その理由・歴史エピソード・名言を生成する。

ProductFullstackAI EngineerNext.jsReact 19TypeScriptClaude APITool UsePrompt CachingTailwind CSSZodUpstash RedisVercel
The Challenge

「顔から似た歴史上の人物を見つける」というSNSで話題化しやすい体験を入口に、Vision + Tool Use + 決定論的スコアリングの組み合わせが、LLMアプリで起きがちな『同じ人物に偏る』『リスト外の架空人物が出る』『判断根拠が再現性なくブレる』を構造的にどこまで抑え込めるかを検証するために立ち上げた個人プロジェクト。

What I Built

判定と物語生成を分離する3段パイプラインを設計・実装した。Stage 1はClaude APIのVision機能とTool Useを組み合わせ、顔特徴をfaceShape・jawline・eyeShape・eyeSpacing・noseShape・browShape・lipFullness・cheekbonesの8軸と印象タグに構造化抽出する。tool_choiceで特定ツールへの呼び出しを強制し、各軸を閉じたenumに制約することでスキーマ違反を表現不可能にした。また各軸に強度スコア(1〜10)を同時抽出し、マッチ表示の視覚的拡散に活用している。

画像アップロード画面

Stage 2は抽出した特徴プロフィールと200名の人物データセットに対して重み付き距離計算を純関数で実装。LLMは介在せず、同一入力は常に同一人物を返す決定論的な設計で、人物選定に起因するハルシネーションを構造的に排除した。Stage 3では上位3特徴の根拠を明示したうえで、理由・歴史エピソード・名言のナラティブ生成のみをClaudeに委ねる。抽出はtemperature: 0(再現性最大化)、ナラティブはtemperature: 0.7(表現の豊かさ)と意図的に使い分けた。

解析中の画面

固定systemプロンプトはPrompt CachingでephemeralキャッシュしAPI費用を抑制。画像はFormDataでサーバー送信しメモリ上でのみ処理する(サーバー保存なし)。Upstash RedisのスライディングウィンドウでIPごとに10 req/hのレート制限を設定。結果ページは@vercel/ogで動的OGP対応とし、SNSシェア体験まで含めて設計した。要件定義・データセット構築・実装・運用設計すべてソロ。

診断結果画面
Impact
200

登録歴史人物数(8カテゴリ)

3段

判定と物語生成を分離したパイプライン構成

8軸

Vision + Tool Useで構造化抽出する顔特徴

0件

サーバーに保存される画像データ

GitHubでソースを公開済み。Vercel上でのエンドツーエンド動作(画像アップロード→特徴抽出→スコアリング→ナラティブ生成→OGP付きシェア)まで動作確認済み。