Skip to main content
Glama

Context Engineering MCP Platform

template_manager.py20 kB
import logging import json import re from typing import Dict, List, Any, Optional, Tuple from datetime import datetime import google.generativeai as genai from pathlib import Path from context_models import PromptTemplate, PromptTemplateType, ContextElement, ContextWindow logger = logging.getLogger(__name__) class TemplateManager: """プロンプトテンプレート管理システム""" def __init__(self, gemini_api_key: str, storage_path: str = "templates"): genai.configure(api_key=gemini_api_key) self.model = genai.GenerativeModel('gemini-2.0-flash-exp') self.storage_path = Path(storage_path) self.storage_path.mkdir(exist_ok=True) self.templates: Dict[str, PromptTemplate] = {} self._load_templates() self._initialize_default_templates() def _load_templates(self): """保存されたテンプレートを読み込み""" template_files = self.storage_path.glob("*.json") for file_path in template_files: try: with open(file_path, 'r', encoding='utf-8') as f: data = json.load(f) template = self._dict_to_template(data) self.templates[template.id] = template except Exception as e: logger.error(f"Failed to load template from {file_path}: {str(e)}") def _save_template(self, template: PromptTemplate): """テンプレートを保存""" file_path = self.storage_path / f"{template.id}.json" try: with open(file_path, 'w', encoding='utf-8') as f: json.dump(self._template_to_dict(template), f, ensure_ascii=False, indent=2) except Exception as e: logger.error(f"Failed to save template {template.id}: {str(e)}") def _template_to_dict(self, template: PromptTemplate) -> Dict[str, Any]: """テンプレートを辞書に変換""" return { "id": template.id, "name": template.name, "description": template.description, "template": template.template, "variables": template.variables, "type": template.type.value, "category": template.category, "tags": template.tags, "usage_count": template.usage_count, "quality_score": template.quality_score, "created_by": template.created_by, "created_at": template.created_at.isoformat(), "updated_at": template.updated_at.isoformat() } def _dict_to_template(self, data: Dict[str, Any]) -> PromptTemplate: """辞書からテンプレートを作成""" return PromptTemplate( id=data["id"], name=data["name"], description=data["description"], template=data["template"], variables=data["variables"], type=PromptTemplateType(data["type"]), category=data["category"], tags=data["tags"], usage_count=data["usage_count"], quality_score=data["quality_score"], created_by=data["created_by"], created_at=datetime.fromisoformat(data["created_at"]), updated_at=datetime.fromisoformat(data["updated_at"]) ) def _initialize_default_templates(self): """デフォルトテンプレートの初期化""" if not self.templates: default_templates = [ { "name": "基本的な質問応答", "description": "シンプルな質問応答用テンプレート", "template": "質問: {question}\n\n以下の情報を参考に回答してください:\n{context}\n\n回答:", "type": PromptTemplateType.COMPLETION, "category": "qa", "tags": ["basic", "qa"] }, { "name": "専門家ロールプレイ", "description": "特定の専門分野の専門家として回答", "template": "あなたは{expertise}の専門家です。{years}年の経験があります。\n\n質問: {question}\n\n専門知識を活かして詳細に回答してください:", "type": PromptTemplateType.ROLEPLAY, "category": "expert", "tags": ["roleplay", "expert"] }, { "name": "段階的思考プロセス", "description": "ステップバイステップで問題を解決", "template": "問題: {problem}\n\n以下の手順で段階的に解決してください:\n1. 問題の理解\n2. 必要な情報の整理\n3. 解決方法の検討\n4. 最適解の選択\n5. 結論\n\n解答:", "type": PromptTemplateType.CHAIN_OF_THOUGHT, "category": "problem_solving", "tags": ["step_by_step", "analysis"] }, { "name": "Few-Shot学習", "description": "例を示して同様のタスクを実行", "template": "以下の例を参考に、同様のタスクを実行してください:\n\n{examples}\n\n新しいタスク: {task}\n回答:", "type": PromptTemplateType.FEWSHOT, "category": "learning", "tags": ["few_shot", "examples"] }, { "name": "コード生成", "description": "プログラミングコード生成用", "template": "言語: {language}\n要件: {requirements}\n\n以下の仕様でコードを生成してください:\n- {specifications}\n\nコード:\n```{language}\n{code}\n```\n\n説明:", "type": PromptTemplateType.COMPLETION, "category": "coding", "tags": ["code", "programming"] } ] for template_data in default_templates: template = PromptTemplate( name=template_data["name"], description=template_data["description"], template=template_data["template"], type=template_data["type"], category=template_data["category"], tags=template_data["tags"], created_by="system" ) template.variables = template.extract_variables() self.create_template(template) def create_template(self, template: PromptTemplate) -> str: """新しいテンプレートを作成""" template.variables = template.extract_variables() template.updated_at = datetime.now() self.templates[template.id] = template self._save_template(template) logger.info(f"Created template: {template.name} ({template.id})") return template.id def get_template(self, template_id: str) -> Optional[PromptTemplate]: """テンプレートを取得""" return self.templates.get(template_id) def list_templates(self, category: Optional[str] = None, tags: Optional[List[str]] = None) -> List[PromptTemplate]: """テンプレート一覧を取得""" templates = list(self.templates.values()) if category: templates = [t for t in templates if t.category == category] if tags: templates = [t for t in templates if any(tag in t.tags for tag in tags)] # 使用回数と品質スコアでソート templates.sort(key=lambda t: (t.usage_count, t.quality_score), reverse=True) return templates def search_templates(self, query: str) -> List[PromptTemplate]: """テンプレートを検索""" query_lower = query.lower() matching_templates = [] for template in self.templates.values(): score = 0 # 名前での一致 if query_lower in template.name.lower(): score += 3 # 説明での一致 if query_lower in template.description.lower(): score += 2 # タグでの一致 if any(query_lower in tag.lower() for tag in template.tags): score += 2 # カテゴリでの一致 if query_lower in template.category.lower(): score += 1 if score > 0: matching_templates.append((template, score)) # スコア順にソート matching_templates.sort(key=lambda x: x[1], reverse=True) return [template for template, score in matching_templates] def update_template(self, template_id: str, **updates) -> bool: """テンプレートを更新""" if template_id not in self.templates: return False template = self.templates[template_id] for key, value in updates.items(): if hasattr(template, key): setattr(template, key, value) template.updated_at = datetime.now() if 'template' in updates: template.variables = template.extract_variables() self._save_template(template) return True def delete_template(self, template_id: str) -> bool: """テンプレートを削除""" if template_id not in self.templates: return False template = self.templates[template_id] if template.created_by == "system": logger.warning(f"Cannot delete system template: {template_id}") return False del self.templates[template_id] # ファイルも削除 file_path = self.storage_path / f"{template_id}.json" if file_path.exists(): file_path.unlink() return True def render_template(self, template_id: str, variables: Dict[str, Any]) -> Optional[str]: """テンプレートをレンダリング""" template = self.get_template(template_id) if not template: return None # 使用回数を増加 template.usage_count += 1 template.updated_at = datetime.now() self._save_template(template) return template.render(variables) async def generate_template(self, purpose: str, examples: List[str] = None, constraints: List[str] = None) -> PromptTemplate: """AIでテンプレートを自動生成""" examples_text = "" if examples: examples_text = f"\n\n期待する出力例:\n" + "\n".join([f"- {ex}" for ex in examples]) constraints_text = "" if constraints: constraints_text = f"\n\n制約条件:\n" + "\n".join([f"- {c}" for c in constraints]) prompt = f""" 以下の目的のためのプロンプトテンプレートを作成してください: 目的: {purpose}{examples_text}{constraints_text} 以下の形式でJSON回答してください: {{ "name": "テンプレート名", "description": "テンプレートの説明", "template": "実際のテンプレート(変数は{{variable_name}}の形式)", "type": "completion|chat|instruct|fewshot|chain_of_thought|roleplay", "category": "カテゴリ名", "tags": ["タグ1", "タグ2"] }} テンプレートには適切な変数を含めてください。 """ try: response = self.model.generate_content(prompt) data = json.loads(response.text) template = PromptTemplate( name=data["name"], description=data["description"], template=data["template"], type=PromptTemplateType(data["type"]), category=data["category"], tags=data["tags"], created_by="ai_generated" ) template_id = self.create_template(template) logger.info(f"AI generated template: {template.name}") return template except Exception as e: logger.error(f"Template generation failed: {str(e)}") raise async def optimize_template(self, template_id: str) -> Dict[str, Any]: """テンプレートを最適化""" template = self.get_template(template_id) if not template: raise ValueError(f"Template {template_id} not found") prompt = f""" 以下のプロンプトテンプレートを分析し、改善提案を行ってください: 名前: {template.name} 説明: {template.description} テンプレート: {template.template} 以下の観点で分析してください: 1. 明確性 - 指示が明確で理解しやすいか 2. 完全性 - 必要な情報がすべて含まれているか 3. 効率性 - 無駄な記述がないか 4. 一貫性 - 用語や形式が一貫しているか 5. 柔軟性 - 様々な場面で使える汎用性があるか JSON形式で回答: {{ "current_score": {{ "clarity": 0.8, "completeness": 0.7, "efficiency": 0.9, "consistency": 0.8, "flexibility": 0.6 }}, "issues": ["問題点1", "問題点2"], "improvements": ["改善案1", "改善案2"], "optimized_template": "最適化されたテンプレート", "explanation": "最適化の説明" }} """ try: response = self.model.generate_content(prompt) result = json.loads(response.text) # 品質スコアを更新 scores = result["current_score"] overall_score = sum(scores.values()) / len(scores) template.quality_score = overall_score self._save_template(template) return result except Exception as e: logger.error(f"Template optimization failed: {str(e)}") raise def get_template_stats(self) -> Dict[str, Any]: """テンプレート統計情報を取得""" if not self.templates: return {} templates = list(self.templates.values()) # カテゴリ別集計 categories = {} for template in templates: if template.category not in categories: categories[template.category] = 0 categories[template.category] += 1 # タイプ別集計 types = {} for template in templates: type_name = template.type.value if type_name not in types: types[type_name] = 0 types[type_name] += 1 # 使用統計 usage_counts = [t.usage_count for t in templates] quality_scores = [t.quality_score for t in templates if t.quality_score > 0] return { "total_templates": len(templates), "categories": categories, "types": types, "total_usage": sum(usage_counts), "avg_usage_per_template": sum(usage_counts) / len(templates) if templates else 0, "avg_quality_score": sum(quality_scores) / len(quality_scores) if quality_scores else 0, "most_used_template": max(templates, key=lambda t: t.usage_count).name if templates else None, "highest_quality_template": max(templates, key=lambda t: t.quality_score).name if quality_scores else None } class ContextTemplateIntegrator: """コンテキストとテンプレートの統合""" def __init__(self, template_manager: TemplateManager): self.template_manager = template_manager def apply_template_to_context(self, context_window: ContextWindow, template_id: str, variables: Dict[str, Any]) -> ContextWindow: """テンプレートをコンテキストウィンドウに適用""" rendered = self.template_manager.render_template(template_id, variables) if not rendered: raise ValueError(f"Failed to render template {template_id}") # 新しいコンテキスト要素を作成 template_element = ContextElement( content=rendered, type=ContextType.SYSTEM, role="template", metadata={ "template_id": template_id, "variables": variables, "applied_at": datetime.now().isoformat() }, tags=["template", "generated"], priority=8 # テンプレートは高優先度 ) # コンテキストウィンドウに追加 success = context_window.add_element(template_element) if not success: raise ValueError("Failed to add template to context window (token limit exceeded)") context_window.template_id = template_id return context_window def extract_template_from_context(self, context_window: ContextWindow) -> Optional[PromptTemplate]: """コンテキストウィンドウからテンプレートを抽出""" if len(context_window.elements) < 2: return None # 要素の内容を分析してパターンを抽出 contents = [elem.content for elem in context_window.elements] # 共通パターンを見つけて変数化 # 実装は簡略化 template_content = "\n\n".join(contents) # 自動的に変数を検出(数値、固有名詞等を変数化) variables_detected = self._detect_variables(template_content) for var_name, var_values in variables_detected.items(): # 最初の値を変数プレースホルダーに置換 if var_values: template_content = template_content.replace(var_values[0], f"{{{var_name}}}") template = PromptTemplate( name="Extracted Template", description="コンテキストから抽出されたテンプレート", template=template_content, type=PromptTemplateType.COMPLETION, category="extracted", tags=["extracted", "auto_generated"], created_by="auto_extract" ) return template def _detect_variables(self, content: str) -> Dict[str, List[str]]: """コンテンツから変数候補を検出""" variables = {} # 数値パターン numbers = re.findall(r'\b\d+(?:\.\d+)?\b', content) if numbers: variables["number"] = numbers # 日付パターン dates = re.findall(r'\b\d{4}-\d{2}-\d{2}\b|\b\d{1,2}/\d{1,2}/\d{4}\b', content) if dates: variables["date"] = dates # メールアドレス emails = re.findall(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b', content) if emails: variables["email"] = emails # URL urls = re.findall(r'https?://[^\s]+', content) if urls: variables["url"] = urls return variables

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ShunsukeHayashi/context_engineering_MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server