操作
バグ #265
未完了RAG機能プラグイン化検討: 設定ベース制御 vs 動的プラグインシステム
ステータス:
新規
優先度:
通常
担当者:
-
開始日:
2025-06-05
期日:
進捗率:
0%
予定工数:
説明
RAG機能プラグイン化検討: Redmine カスタムUIのモジュラー設計¶
🔍 現状分析¶
現在のアーキテクチャ¶
task2.call2arm.com
├── Redmine UI (React SPA) → 固定統合
├── Redmine API → dev.call2arm.com (プロキシ)
└── RAG API → task2-api:3002 (固定統合)
発見事項¶
- UI統合: RedmineカスタムUIにAIアシスタント機能が固定実装
- API統合: RAG機能がserver.jsに直接組み込み
- プラグイン機能: 現状では未実装 (enable/disable機能なし)
- 機能一覧: vector検索、Multi-LLM、チャット、ドキュメント処理
🎯 プラグイン化の必要性と利点¶
なぜプラグイン化が必要か?¶
1. 運用柔軟性
- 🔄 RAG機能の停止/再開: メンテナンス時やリソース制限時
- ⚡ 段階的導入: 小規模テスト → 本格運用
- 🛡️ 障害分離: RAG問題がRedmine機能に影響しない
2. ライセンス・コスト管理
- 💰 OpenAI API: 使用量課金のコスト制御
- 📊 リソース管理: ベクトルDB、Redis、Meilisearchの選択利用
- 🔒 セキュリティ: AI機能の一時的無効化
3. 開発・テスト効率
- 🧪 独立テスト: Redmine機能とRAG機能の分離テスト
- 🔧 部分更新: RAG機能のみのアップデート
- 📈 段階的機能追加: 新しいAI機能の安全な導入
🏗️ 提案するプラグイン化アーキテクチャ¶
レベル1: 設定ベース制御(推奨・即座実装可能)¶
環境変数による機能制御¶
# .env 設定例
ENABLE_RAG=true # RAG機能全体の有効/無効
ENABLE_AI_CHAT=true # チャット機能
ENABLE_VECTOR_SEARCH=true # ベクトル検索
ENABLE_DOCUMENT_PROCESSING=true # ドキュメント処理
ENABLE_LLM_INTEGRATION=true # LLM統合
# 外部サービス制御
OPENAI_API_ENABLED=true
CLAUDE_API_ENABLED=false
DEEPSEEK_API_ENABLED=false
サーバー側実装例¶
// app/api/src/middleware/FeatureToggle.js
class FeatureToggle {
static requireFeature(featureName) {
return (req, res, next) => {
const enabled = process.env[`ENABLE_${featureName.toUpperCase()}`] === 'true';
if (!enabled) {
return res.status(503).json({
status: 'disabled',
message: `Feature '${featureName}' is currently disabled`,
feature: featureName
});
}
next();
};
}
static isEnabled(featureName) {
return process.env[`ENABLE_${featureName.toUpperCase()}`] === 'true';
}
}
// 使用例
app.use('/api/embeddings', FeatureToggle.requireFeature('RAG'), embeddingsRouter);
app.use('/api/chat', FeatureToggle.requireFeature('AI_CHAT'), chatRouter);
UI側制御例¶
// RedmineUI での機能表示制御
const features = {
aiAssistant: await checkFeature('AI_CHAT'),
vectorSearch: await checkFeature('VECTOR_SEARCH'),
documentProcessing: await checkFeature('DOCUMENT_PROCESSING')
};
// 機能が無効な場合は非表示
{features.aiAssistant && <AIAssistantPanel />}
{features.vectorSearch && <VectorSearchBox />}
レベル2: モジュラープラグインシステム(高度実装)¶
プラグインマネージャー¶
// app/api/src/plugins/PluginManager.js
class PluginManager {
constructor() {
this.plugins = new Map();
this.loadedPlugins = new Set();
}
registerPlugin(name, plugin) {
this.plugins.set(name, plugin);
}
async loadPlugin(name) {
const plugin = this.plugins.get(name);
if (plugin && !this.loadedPlugins.has(name)) {
await plugin.initialize();
this.loadedPlugins.add(name);
console.log(`Plugin '${name}' loaded`);
}
}
async unloadPlugin(name) {
const plugin = this.plugins.get(name);
if (plugin && this.loadedPlugins.has(name)) {
await plugin.shutdown();
this.loadedPlugins.delete(name);
console.log(`Plugin '${name}' unloaded`);
}
}
isLoaded(name) {
return this.loadedPlugins.has(name);
}
}
RAGプラグイン実装¶
// app/api/src/plugins/RAGPlugin.js
class RAGPlugin {
async initialize() {
// ベクトルDB接続
this.vectorDB = await connectVectorDB();
// Redis接続
this.redis = await connectRedis();
// Meilisearch接続
this.search = await connectMeilisearch();
console.log('RAG Plugin initialized');
}
async shutdown() {
await this.vectorDB?.close();
await this.redis?.quit();
await this.search?.close();
console.log('RAG Plugin shutdown');
}
getRoutes() {
return {
'/api/embeddings': embeddingsRouter,
'/api/chat': chatRouter,
'/api/search': searchRouter
};
}
getUIComponents() {
return {
aiAssistant: '/plugins/rag/ai-assistant.js',
vectorSearch: '/plugins/rag/vector-search.js'
};
}
}
📊 実装優先度と段階的導入¶
Phase 1: 設定ベース制御(即座実装)¶
所要時間: 2-3時間
メリット: 即座にon/off制御可能
# 実装手順
1. .env にフィーチャーフラグ追加
2. FeatureToggle ミドルウェア作成
3. 既存ルートに適用
4. UI側で機能チェック実装
5. 管理画面で設定変更UI追加
Phase 2: 動的プラグインシステム(高度実装)¶
所要時間: 1-2週間
メリット: 完全なプラグイン分離
# 実装手順
1. PluginManager 実装
2. RAGPlugin 分離
3. 動的ルート管理
4. UI コンポーネント動的ロード
5. 管理画面でリアルタイム制御
🔧 即座実装案: 設定ベース制御¶
1. 環境変数設定¶
# /var/docker/task2-service/.env 追記
# ========== RAG機能制御 ==========
ENABLE_RAG=true
ENABLE_AI_CHAT=true
ENABLE_VECTOR_SEARCH=true
ENABLE_DOCUMENT_PROCESSING=true
ENABLE_LLM_INTEGRATION=true
OPENAI_API_ENABLED=true
CLAUDE_API_ENABLED=false
2. FeatureToggle実装¶
// app/api/src/middleware/FeatureToggle.js
// 上記コード実装
3. 既存ルート修正¶
// app/api/server.js
const FeatureToggle = require('./src/middleware/FeatureToggle');
// RAG機能にフィーチャーフラグ適用
if (FeatureToggle.isEnabled('RAG')) {
app.use('/api/embeddings', FeatureToggle.requireFeature('RAG'), require('./src/routes/embeddings'));
app.use('/api/chat', FeatureToggle.requireFeature('AI_CHAT'), chatRouter);
app.use('/api/search', FeatureToggle.requireFeature('VECTOR_SEARCH'), searchRouter);
}
4. 管理UI追加¶
// 設定画面でリアルタイム制御
const toggleRAG = async (enabled) => {
await fetch('/api/admin/features', {
method: 'POST',
body: JSON.stringify({ feature: 'RAG', enabled }),
headers: { 'Content-Type': 'application/json' }
});
// UI更新
location.reload();
};
📋 実装メリット・デメリット¶
設定ベース制御の場合¶
✅ メリット¶
- ⚡ 即座実装: 2-3時間で完成
- 🛡️ 安全性: コンテナ再起動で確実に制御
- 🔧 シンプル: 理解しやすい実装
- 💰 コスト制御: API使用量の即座制御
❌ デメリット¶
- 🔄 再起動必要: 設定変更時にコンテナ再起動
- 🔒 静的制御: リアルタイム変更不可
- 📊 粗い制御: 機能単位での制御
動的プラグインシステムの場合¶
✅ メリット¶
- 🔄 リアルタイム: 無停止での機能切り替え
- 🎯 細かい制御: 機能詳細レベルでの制御
- 🚀 拡張性: 新プラグイン簡単追加
- 📈 運用性: 本格的なエンタープライズ対応
❌ デメリット¶
- ⏱️ 実装時間: 1-2週間必要
- 🧩 複雑性: アーキテクチャが複雑化
- 🐛 バグリスク: 動的制御による潜在的問題
🎯 推奨実装案¶
即座対応: 設定ベース制御¶
理由: Phase B完了後の即座実装で最大効果
長期計画: 動的プラグインシステム¶
理由: Phase C/D完了後の本格運用対応
⚡ 今すぐ実行可能なRAG制御¶
# RAG機能を一時停止
cd /var/docker/task2-service
echo "ENABLE_RAG=false" >> .env
docker-compose restart task2-api
# RAG機能を再開
echo "ENABLE_RAG=true" >> .env
docker-compose restart task2-api
現在のRAG機能はRedmineカスタムUIに密結合していますが、提案する設定ベース制御により、柔軟な運用制御が実現できます。
表示するデータがありません
操作