🔄 Migration from Legacy Systems¶
Leitfaden für die Migration von Legacy-Systemen zu Keiko Personal Assistant.
🏗️ Legacy-System-Unterstützung¶
Unterstützte Legacy-Systeme¶
graph TB
subgraph "Legacy Systems"
CUSTOM[Custom AI Systems]
LANGCHAIN[LangChain Apps]
OPENAI[OpenAI Assistants]
AZURE[Azure Bot Framework]
RASA[Rasa Chatbots]
end
subgraph "Migration Tools"
EXTRACTOR[Data Extractor]
TRANSFORMER[Data Transformer]
VALIDATOR[Migration Validator]
end
subgraph "Keiko v2.0"
AGENTS[Keiko Agents]
TASKS[Task System]
MCP[MCP Integration]
end
CUSTOM --> EXTRACTOR
LANGCHAIN --> EXTRACTOR
OPENAI --> EXTRACTOR
AZURE --> EXTRACTOR
RASA --> EXTRACTOR
EXTRACTOR --> TRANSFORMER
TRANSFORMER --> VALIDATOR
VALIDATOR --> AGENTS
VALIDATOR --> TASKS
VALIDATOR --> MCP
🤖 OpenAI Assistants Migration¶
OpenAI Assistant zu Keiko Agent¶
# migration/openai_migrator.py
import openai
from keiko.core.agent import Agent, AgentConfig
from keiko.migration.base import BaseMigrator
class OpenAIMigrator(BaseMigrator):
"""Migriert OpenAI Assistants zu Keiko Agents."""
def __init__(self, openai_api_key: str):
self.openai_client = openai.OpenAI(api_key=openai_api_key)
super().__init__()
async def extract_assistants(self) -> List[Dict[str, Any]]:
"""Extrahiert OpenAI Assistants."""
assistants = []
# Alle Assistants abrufen
response = self.openai_client.beta.assistants.list()
for assistant in response.data:
assistant_data = {
'id': assistant.id,
'name': assistant.name,
'description': assistant.description,
'instructions': assistant.instructions,
'model': assistant.model,
'tools': [tool.type for tool in assistant.tools],
'file_ids': assistant.file_ids,
'metadata': assistant.metadata,
'created_at': assistant.created_at
}
assistants.append(assistant_data)
return assistants
async def transform_assistant_to_agent(self, assistant: Dict[str, Any]) -> AgentConfig:
"""Transformiert OpenAI Assistant zu Keiko Agent."""
# Capabilities aus Tools ableiten
capabilities = []
for tool in assistant.get('tools', []):
if tool == 'code_interpreter':
capabilities.extend(['code_execution', 'data_analysis'])
elif tool == 'retrieval':
capabilities.extend(['document_search', 'knowledge_retrieval'])
elif tool == 'function':
capabilities.append('function_calling')
# Agent-Konfiguration erstellen
config = AgentConfig(
name=assistant['name'] or f"Migrated Assistant {assistant['id']}",
type='specialist',
capabilities=capabilities,
description=assistant.get('description', ''),
# Konfiguration
timeout_seconds=300,
max_concurrent_tasks=1,
# Externe Konfiguration
external_config={
'openai_model': assistant.get('model', 'gpt-4'),
'instructions': assistant.get('instructions', ''),
'migrated_from': 'openai_assistant',
'original_id': assistant['id'],
'migration_date': datetime.utcnow().isoformat()
}
)
return config
async def migrate_assistant_files(self, assistant: Dict[str, Any]) -> List[str]:
"""Migriert Assistant-Dateien."""
migrated_files = []
for file_id in assistant.get('file_ids', []):
try:
# Datei von OpenAI herunterladen
file_info = self.openai_client.files.retrieve(file_id)
file_content = self.openai_client.files.content(file_id)
# In Keiko-Storage speichern
local_path = f"/data/migrated_files/{file_info.filename}"
with open(local_path, 'wb') as f:
f.write(file_content.read())
migrated_files.append(local_path)
except Exception as e:
print(f"Fehler beim Migrieren der Datei {file_id}: {e}")
return migrated_files
# Verwendung
async def migrate_openai_assistants():
"""Migriert alle OpenAI Assistants."""
migrator = OpenAIMigrator(openai_api_key="your-api-key")
# Assistants extrahieren
assistants = await migrator.extract_assistants()
print(f"Gefunden: {len(assistants)} OpenAI Assistants")
# Jeden Assistant migrieren
for assistant in assistants:
try:
# Agent-Konfiguration erstellen
agent_config = await migrator.transform_assistant_to_agent(assistant)
# Dateien migrieren
migrated_files = await migrator.migrate_assistant_files(assistant)
# Agent in Keiko erstellen
agent = Agent(agent_config)
await agent_service.create_agent(agent)
print(f"Assistant '{assistant['name']}' erfolgreich migriert")
except Exception as e:
print(f"Fehler beim Migrieren von Assistant '{assistant['name']}': {e}")
🦜 LangChain Migration¶
LangChain Chain zu Keiko Agent¶
# migration/langchain_migrator.py
from langchain.chains import LLMChain, ConversationChain
from langchain.agents import AgentExecutor
from keiko.core.agent import Agent, AgentConfig
class LangChainMigrator(BaseMigrator):
"""Migriert LangChain Chains zu Keiko Agents."""
async def extract_chain_config(self, chain) -> Dict[str, Any]:
"""Extrahiert Konfiguration aus LangChain Chain."""
config = {
'chain_type': type(chain).__name__,
'llm_model': getattr(chain.llm, 'model_name', 'unknown'),
'prompt_template': None,
'tools': [],
'memory': None
}
# Prompt-Template extrahieren
if hasattr(chain, 'prompt'):
config['prompt_template'] = chain.prompt.template
# Tools extrahieren (für Agent-Chains)
if hasattr(chain, 'tools'):
config['tools'] = [
{
'name': tool.name,
'description': tool.description,
'func': tool.func.__name__ if hasattr(tool, 'func') else None
}
for tool in chain.tools
]
# Memory extrahieren
if hasattr(chain, 'memory') and chain.memory:
config['memory'] = {
'type': type(chain.memory).__name__,
'return_messages': getattr(chain.memory, 'return_messages', False)
}
return config
async def transform_chain_to_agent(self, chain_config: Dict[str, Any]) -> AgentConfig:
"""Transformiert LangChain Chain zu Keiko Agent."""
# Capabilities basierend auf Chain-Typ bestimmen
capabilities = []
if chain_config['chain_type'] == 'LLMChain':
capabilities.extend(['text_generation', 'conversation'])
elif chain_config['chain_type'] == 'ConversationChain':
capabilities.extend(['conversation', 'memory_management'])
elif 'Agent' in chain_config['chain_type']:
capabilities.extend(['tool_usage', 'reasoning', 'planning'])
# Tools zu Capabilities hinzufügen
for tool in chain_config.get('tools', []):
if 'search' in tool['name'].lower():
capabilities.append('web_search')
elif 'calculator' in tool['name'].lower():
capabilities.append('calculation')
elif 'python' in tool['name'].lower():
capabilities.append('code_execution')
# Agent-Konfiguration erstellen
config = AgentConfig(
name=f"Migrated {chain_config['chain_type']}",
type='specialist',
capabilities=list(set(capabilities)),
external_config={
'llm_model': chain_config.get('llm_model'),
'prompt_template': chain_config.get('prompt_template'),
'tools': chain_config.get('tools', []),
'memory_config': chain_config.get('memory'),
'migrated_from': 'langchain',
'original_chain_type': chain_config['chain_type']
}
)
return config
# Custom Agent Implementation für LangChain-Migration
class MigratedLangChainAgent(Agent):
"""Agent für migrierte LangChain Chains."""
async def execute_task(self, task: Task) -> TaskResult:
"""Führt Task mit LangChain-Kompatibilität aus."""
# LangChain-spezifische Logik
prompt_template = self.config.external_config.get('prompt_template')
if prompt_template:
# Prompt mit Task-Parametern formatieren
formatted_prompt = prompt_template.format(**task.parameters)
# LLM-Aufruf simulieren
result = await self._call_llm(formatted_prompt)
return TaskResult.success({
'response': result,
'prompt_used': formatted_prompt
})
else:
return await super().execute_task(task)
async def _call_llm(self, prompt: str) -> str:
"""Ruft LLM mit Prompt auf."""
# Hier würde der tatsächliche LLM-Aufruf stehen
# Für Demo-Zwecke simuliert
return f"Response to: {prompt[:50]}..."
🤖 Azure Bot Framework Migration¶
Bot Framework zu Keiko¶
# migration/azure_bot_migrator.py
import json
from pathlib import Path
class AzureBotMigrator(BaseMigrator):
"""Migriert Azure Bot Framework Bots zu Keiko."""
async def extract_bot_config(self, bot_project_path: str) -> Dict[str, Any]:
"""Extrahiert Bot-Konfiguration aus Azure Bot Framework."""
project_path = Path(bot_project_path)
# Bot-Konfiguration laden
config_file = project_path / 'appsettings.json'
with open(config_file, 'r') as f:
app_settings = json.load(f)
# Dialoge extrahieren
dialogs = []
dialogs_path = project_path / 'Dialogs'
if dialogs_path.exists():
for dialog_file in dialogs_path.glob('*.cs'):
dialog_info = await self._extract_dialog_info(dialog_file)
dialogs.append(dialog_info)
# LUIS-Modelle extrahieren
luis_models = []
luis_path = project_path / 'CognitiveModels'
if luis_path.exists():
for luis_file in luis_path.glob('*.json'):
with open(luis_file, 'r') as f:
luis_model = json.load(f)
luis_models.append(luis_model)
return {
'app_settings': app_settings,
'dialogs': dialogs,
'luis_models': luis_models,
'bot_name': app_settings.get('BotName', 'Migrated Bot')
}
async def _extract_dialog_info(self, dialog_file: Path) -> Dict[str, Any]:
"""Extrahiert Dialog-Informationen aus C#-Datei."""
with open(dialog_file, 'r') as f:
content = f.read()
# Vereinfachte Extraktion (in Realität würde man einen C#-Parser verwenden)
dialog_info = {
'name': dialog_file.stem,
'file_path': str(dialog_file),
'has_waterfall': 'WaterfallDialog' in content,
'has_prompts': 'Prompt' in content,
'has_luis': 'LuisRecognizer' in content
}
return dialog_info
async def transform_bot_to_agent(self, bot_config: Dict[str, Any]) -> AgentConfig:
"""Transformiert Azure Bot zu Keiko Agent."""
capabilities = ['conversation', 'dialog_management']
# Capabilities basierend auf Features bestimmen
if bot_config.get('luis_models'):
capabilities.extend(['intent_recognition', 'entity_extraction'])
for dialog in bot_config.get('dialogs', []):
if dialog.get('has_waterfall'):
capabilities.append('workflow_management')
if dialog.get('has_prompts'):
capabilities.append('user_interaction')
config = AgentConfig(
name=bot_config.get('bot_name', 'Migrated Azure Bot'),
type='conversational',
capabilities=list(set(capabilities)),
external_config={
'azure_app_id': bot_config['app_settings'].get('MicrosoftAppId'),
'dialogs': bot_config.get('dialogs', []),
'luis_models': bot_config.get('luis_models', []),
'migrated_from': 'azure_bot_framework',
'original_settings': bot_config['app_settings']
}
)
return config
📊 Custom AI System Migration¶
Generic AI System Migration¶
# migration/custom_migrator.py
class CustomAIMigrator(BaseMigrator):
"""Generischer Migrator für Custom AI Systems."""
def __init__(self, system_config: Dict[str, Any]):
self.system_config = system_config
super().__init__()
async def analyze_system(self, system_path: str) -> Dict[str, Any]:
"""Analysiert Custom AI System."""
analysis = {
'system_type': 'unknown',
'components': [],
'data_sources': [],
'models': [],
'apis': [],
'dependencies': []
}
system_path = Path(system_path)
# Python-Dateien analysieren
for py_file in system_path.rglob('*.py'):
component_info = await self._analyze_python_file(py_file)
analysis['components'].append(component_info)
# Konfigurationsdateien finden
for config_file in system_path.rglob('*.json'):
with open(config_file, 'r') as f:
try:
config_data = json.load(f)
analysis['data_sources'].append({
'file': str(config_file),
'type': 'json_config',
'data': config_data
})
except:
pass
# Requirements analysieren
req_file = system_path / 'requirements.txt'
if req_file.exists():
with open(req_file, 'r') as f:
analysis['dependencies'] = [
line.strip() for line in f.readlines()
if line.strip() and not line.startswith('#')
]
return analysis
async def _analyze_python_file(self, py_file: Path) -> Dict[str, Any]:
"""Analysiert Python-Datei."""
with open(py_file, 'r') as f:
content = f.read()
component_info = {
'file': str(py_file),
'classes': [],
'functions': [],
'imports': [],
'ai_frameworks': []
}
# Einfache Analyse (in Realität würde man AST verwenden)
lines = content.split('\n')
for line in lines:
line = line.strip()
if line.startswith('class '):
class_name = line.split('class ')[1].split('(')[0].split(':')[0]
component_info['classes'].append(class_name)
elif line.startswith('def '):
func_name = line.split('def ')[1].split('(')[0]
component_info['functions'].append(func_name)
elif line.startswith('import ') or line.startswith('from '):
component_info['imports'].append(line)
# AI-Frameworks erkennen
if any(fw in line for fw in ['tensorflow', 'torch', 'sklearn', 'transformers']):
component_info['ai_frameworks'].append(line)
return component_info
async def create_migration_plan(self, analysis: Dict[str, Any]) -> Dict[str, Any]:
"""Erstellt Migration-Plan basierend auf System-Analyse."""
plan = {
'agents_to_create': [],
'data_migration_tasks': [],
'configuration_changes': [],
'manual_steps': []
}
# Agents basierend auf Komponenten erstellen
for component in analysis['components']:
if any('AI' in cls or 'Agent' in cls or 'Bot' in cls for cls in component['classes']):
agent_plan = {
'name': f"Migrated {component['file']}",
'type': 'specialist',
'source_file': component['file'],
'capabilities': self._infer_capabilities(component)
}
plan['agents_to_create'].append(agent_plan)
# Daten-Migration-Tasks
for data_source in analysis['data_sources']:
if data_source['type'] == 'json_config':
plan['data_migration_tasks'].append({
'type': 'config_migration',
'source': data_source['file'],
'target': f"keiko/config/{Path(data_source['file']).name}"
})
# Manuelle Schritte für komplexe Komponenten
if analysis['ai_frameworks']:
plan['manual_steps'].append(
"Review AI framework dependencies and adapt to Keiko's architecture"
)
return plan
def _infer_capabilities(self, component: Dict[str, Any]) -> List[str]:
"""Leitet Capabilities aus Komponenten-Analyse ab."""
capabilities = []
# Basierend auf Imports
for import_line in component['imports']:
if 'requests' in import_line or 'urllib' in import_line:
capabilities.append('web_requests')
elif 'json' in import_line:
capabilities.append('data_processing')
elif 'sqlite' in import_line or 'psycopg' in import_line:
capabilities.append('database_access')
# Basierend auf Funktionen
for func in component['functions']:
if 'process' in func.lower():
capabilities.append('data_processing')
elif 'generate' in func.lower():
capabilities.append('content_generation')
elif 'analyze' in func.lower():
capabilities.append('analysis')
return list(set(capabilities))
🔧 Migration-Utilities¶
Migration-Validator¶
# migration/validator.py
class MigrationValidator:
"""Validiert Migration-Ergebnisse."""
async def validate_migration(self, migration_result: MigrationResult) -> ValidationResult:
"""Validiert vollständige Migration."""
validation = ValidationResult()
# Daten-Integrität prüfen
data_validation = await self._validate_data_integrity(migration_result)
validation.add_check('data_integrity', data_validation)
# Funktionalität prüfen
functionality_validation = await self._validate_functionality(migration_result)
validation.add_check('functionality', functionality_validation)
# Performance prüfen
performance_validation = await self._validate_performance(migration_result)
validation.add_check('performance', performance_validation)
return validation
async def _validate_data_integrity(self, migration_result: MigrationResult) -> bool:
"""Prüft Daten-Integrität nach Migration."""
# Anzahl Datensätze vergleichen
source_counts = await self._get_source_record_counts()
target_counts = await self._get_target_record_counts()
for table, source_count in source_counts.items():
target_count = target_counts.get(table, 0)
if abs(source_count - target_count) > source_count * 0.01: # 1% Toleranz
return False
return True
async def _validate_functionality(self, migration_result: MigrationResult) -> bool:
"""Prüft Funktionalität nach Migration."""
# Test-Tasks ausführen
test_tasks = [
{'type': 'text_processing', 'params': {'text': 'Test'}},
{'type': 'data_analysis', 'params': {'data': [1, 2, 3]}},
{'type': 'conversation', 'params': {'message': 'Hello'}}
]
for test_task in test_tasks:
try:
result = await self._execute_test_task(test_task)
if not result.success:
return False
except Exception:
return False
return True
Legacy-Migration-Hinweise
- Legacy-Migrationen sind komplex und erfordern oft manuelle Anpassungen
- Testen Sie die Migration ausführlich in einer Staging-Umgebung
- Dokumentieren Sie alle manuellen Schritte für zukünftige Referenz
Best Practices
- Analysieren Sie das Legacy-System gründlich vor der Migration
- Erstellen Sie einen detaillierten Migration-Plan
- Implementieren Sie umfassende Validierung und Tests
- Behalten Sie das Legacy-System als Fallback bei