多くの開発者がOSSライブラリをスター数や更新日で選びがちですが、その選択には見えない「運用負債」が潜んでいます。「依存天秤」は、この曖昧なリスクをAIが定量スコアに変換し、2つの選択肢を天秤にかけるという全く新しい比較体験を提供します。単なるデータ表示と違い、最終的にどちらを選ぶべきかという「根拠ある選択」まで導く点がユニークです。GitHubの公開情報から保守性や依存関係の健全性を読み解きスコア化するアプローチは、LLMによる定性・定量分析のトレンドを開発者の意思決定支援に応用した好例と言えるでしょう。
依存天秤 (Dependency Balance)
2つのOSSライブラリ運用負債をAIが比較採点
2つのOSSライブラリのGitHub URLを入力し比較すると、AIが各ライブラリの運用負債をスコア化します。結果はスコアボードで表示され、最適なライブラリの選択をサポートします。
今後は、現在は静的なサンプルデータですが、将来的には実際のGitHub APIと連携し、あらゆる公開リポジトリをリアルタイムで比較できるようにしたいです。スコアリングロジックもより高度化させ、コミュニティ内で共有できる「比較レポート」のエクスポート機能を追加することで、チームの技術選定における定番ツールを目指したいです。
使い方
この作品の使い方と、画面で確認するポイントをまとめて表示します。
OSSライブラリ選定で迷う際、運用負債の観点から客観的な比較スコアと推奨を得られます。
比較したいOSSライブラリのURLを入力
比較したい2つのOSSライブラリのGitHub URLをそれぞれ指定します。例として、`https://github.com/facebook/react`と`https://github.com/vuejs/vue`が入力されます。
指定されたライブラリの情報を収集
入力されたGitHub URLに基づき、各OSSライブラリの名称、説明、スター数、フォーク数、オープンイシュー数、ライセンス、最終コミット日、コントリビューター数などの情報が収集されます。
AIが運用負債をスコアリング
収集されたリポジトリデータに基づき、AIモデルが各ライブラリの運用負債を1〜10のスケールで採点する設計です。評価軸は安定性、保守性、セキュリティ、依存関係の健全性、コミュニティ活動です。例えば、Reactは安定性9、保守性8、セキュリティ8、依存関係の健全性7、コミュニティ活動9と評価されます。
比較結果と推奨理由を出力
両ライブラリの運用負債スコアが比較され、総合スコアが高い方が推奨ライブラリとして選定されます。推奨ライブラリの名称と、その選定理由が明確に提示されます。例として、Reactが推奨され、「Reactは、より活発で大規模なコミュニティと堅牢なメンテナンス体制を持っており、長期的なプロジェクトにおいて安定性が高いと評価されました。
制作メモ
この作品でAIが重視した制作方針を、公開向けに整理して表示します。
コメント
この作品に対するコメントとAIレビューをまとめて表示します。
運用負債までスコア化して天秤にかける、この視点は面白いですね。一般的なライブラリ比較ツールがスター数や更新日といった表面的なデータに終始する中で、これなら意思決定の質が格段に上がりそうです。AIが「根拠ある選択」まで示唆してくれるのは、特に判断に迷う場面で頼りになるだろうなと感じました。
ソース
この作品で保存されているコードと確認用ファイルをまとめて表示します。
主要ファイル
コードプレビュー
"use client";
import { useState, useEffect } from 'react';
import { sampleTrace, FinalOutput } from '../data/sample-trace';
import { sampleInput } from '../data/sample-input';
const pipelineSteps = [
{ name: 'リポジトリ情報分析', key: 'step1_analyzeRepositories_output' },
{ name: '運用負債スコアリング', key: 'step2_scoreDebt_output' },
{ name: '比較と推奨生成', key: 'step3_generateRecommendation_output' },
];
export default function DependencyBalancePage() {
const [currentStep, setCurrentStep] = useState(-1);
const [outputs, setOutputs] = useState<Record<string, any>>({});
const handleReplay = () => {
setCurrentStep(0);
};
useEffect(() => {
if (currentStep >= 0 && currentStep < pipelineSteps.length) {
const timer = setTimeout(() => {
const stepKey = pipelineSteps[currentStep].key;
setOutputs(prev => ({ ...prev, [stepKey]: (sampleTrace as any)[stepKey] }));
setCurrentStep(currentStep + 1);
}, 500);
return () => clearTimeout(timer);
}
}, [currentStep]);
const finalOutput: FinalOutput | null = outputs.step3_generateRecommendation_output || null;
const ScoreCard = ({ title, scores }: { title: string; scores: any }) => (
<div style={{ border: '1px solid #ddd', padding: '16px', borderRadius: '8px', width: '300px' }}>
<h3 style={{ marginTop: 0 }}>{title}</h3>
{scores && Object.entries(scores).map(([key, value]) => (
<div key={key} style={{ display: 'flex', justifyContent: 'space-between' }}>
<span>{key.charAt(0).toUpperCase() + key.slice(1)}</span>
<strong>{value as number}</strong
...