コンテンツにスキップ

コンテキスト管理設計書

概要

RefinireAgentのコンテキスト管理機能は、AIエージェントが効率的かつ効果的に会話履歴、文脈情報、長期記憶を管理し、適切なコンテキストをLLMに提供するためのシステムです。

設計原則

極限まで絞った設計思想

  1. 単一責任: 各クラスは一つの役割のみを持つ
  2. 最小限のインターフェース: 必要最小限のメソッドのみ
  3. 直感的な統合: RefinireAgentへの変更を最小限に
  4. 拡張しやすい: 新しい機能の追加が容易
  5. 理解しやすい: 複雑な抽象化を避ける
  6. 文字列指定: YAMLライクな文字列で直感的に設定
  7. コンテキスト連鎖: 前のプロバイダーのコンテキストに依存する動作をサポート

現在の実装状況

既存のコンテキスト管理機能

機能 実装状況 説明
セッション履歴 ✅ 実装済み session_historyで会話履歴を管理
履歴サイズ制限 ✅ 実装済み history_sizeで履歴の最大数を制限
パイプライン履歴 ✅ 実装済み _pipeline_historyで詳細な実行履歴を管理
プロンプト構築 ✅ 実装済み _build_promptで指示文と履歴を組み合わせ

現在の制限事項

  1. 単純な履歴管理: 時系列順の単純な履歴のみ
  2. コンテキスト圧縮なし: 長い会話でコンテキスト長を超過する可能性
  3. 文脈関連性の考慮なし: 現在の質問に関連する履歴の選択機能なし
  4. 外部情報の統合なし: ファイル、ソースコード、長期記憶の統合機能なし

コンテキスト管理ケース

1. 会話履歴の管理

目的: 過去の会話を現在のコンテキストに追加

ユースケース: - 以前の会話で決定した内容を参照 - 継続的なプロジェクトの文脈を維持 - ユーザーの好みや設定の記憶

2. 固定ファイルの統合

目的: 特定のファイル内容を常にコンテキストに含める

ユースケース: - プロジェクトの設定ファイル - システムの仕様書 - ユーザーのプロフィール情報

3. ソースコードの検索

目的: 現在の会話に関連するソースコードを自動検索

ユースケース: - コードレビューの際の関連ファイル参照 - バグ修正時の関連コード特定 - 機能追加時の既存実装確認

4. 長期記憶の統合

目的: 永続的な記憶システムとの統合

ユースケース: - ユーザーの学習履歴 - プロジェクトの重要な決定事項 - システムの設定変更履歴

5. コンテキスト圧縮

目的: モデルのコンテキスト長に合わせてコンテキストを圧縮

ユースケース: - 長い会話履歴の要約 - 重要な情報の抽出 - トークン数の最適化

6. コンテキストフィルタリング

目的: 前のプロバイダーのコンテキストを基にフィルタリング

ユースケース: - 関連性の低いコンテキストの除去 - 重要度に基づくコンテキスト選択 - 重複コンテキストの除去

極限まで絞ったAPI設計

ContextProvider インターフェース(唯一のインターフェース)

from abc import ABC, abstractmethod
from typing import Dict, Any, ClassVar, Optional

class ContextProvider(ABC):
    """Single interface for all context providers
    すべてのコンテキストプロバイダーの唯一のインターフェース
    """

    # Class variable for provider name
    # プロバイダー名のクラス変数
    provider_name: ClassVar[str] = "base"

    @classmethod
    def get_config_schema(cls) -> Dict[str, Any]:
        """Get configuration schema for this provider
        このプロバイダーの設定スキーマを取得

        Returns:
            Dict[str, Any]: Configuration schema with parameter descriptions
            Dict[str, Any]: パラメータ説明を含む設定スキーマ
        """
        return {
            "description": "Base context provider",
            "parameters": {},
            "example": "base: {}"
        }

    @classmethod
    def from_config(cls, config: Dict[str, Any]) -> 'ContextProvider':
        """Create provider instance from configuration
        設定からプロバイダーインスタンスを作成

        Args:
            config: Configuration dictionary / 設定辞書

        Returns:
            ContextProvider: Provider instance / プロバイダーインスタンス
        """
        return cls(**config)

    @abstractmethod
    def get_context(self, query: str, previous_context: Optional[str] = None, **kwargs) -> str:
        """Get context for the given query
        与えられたクエリ用のコンテキストを取得

        Args:
            query: Current user query / 現在のユーザークエリ
            previous_context: Context provided by previous providers / 前のプロバイダーが提供したコンテキスト
            **kwargs: Additional parameters / 追加パラメータ

        Returns:
            str: Context string (empty string if no context) / コンテキスト文字列(コンテキストがない場合は空文字列)
        """
        pass

    @abstractmethod
    def update(self, interaction: Dict[str, Any]) -> None:
        """Update provider with new interaction
        新しい対話でプロバイダーを更新

        Args:
            interaction: Interaction data / 対話データ
        """
        pass

    @abstractmethod
    def clear(self) -> None:
        """Clear all stored context
        保存されたすべてのコンテキストをクリア
        """
        pass

具体的な実装

ConversationHistoryProvider

from typing import List, Dict, Any, ClassVar, Optional

class ConversationHistoryProvider(ContextProvider):
    """Provides conversation history context
    会話履歴コンテキストを提供
    """

    provider_name: ClassVar[str] = "conversation"

    def __init__(self, history: List[str] = None, max_items: int = 10):
        self.history = history or []
        self.max_items = max_items

    @classmethod
    def get_config_schema(cls) -> Dict[str, Any]:
        """Get configuration schema for conversation history provider
        会話履歴プロバイダーの設定スキーマを取得
        """
        return {
            "description": "Provides conversation history context",
            "parameters": {
                "max_items": {
                    "type": "int",
                    "default": 10,
                    "description": "Maximum number of conversation items to keep"
                }
            },
            "example": """
conversation:
  max_items: 5
            """.strip()
        }

    def get_context(self, query: str, previous_context: Optional[str] = None, **kwargs) -> str:
        """Get relevant conversation history
        関連する会話履歴を取得
        """
        if not self.history:
            return ""

        # Simple implementation: return recent history
        recent_history = self.history[-self.max_items:]
        return "\n".join(recent_history)

    def update(self, interaction: Dict[str, Any]) -> None:
        """Add new interaction to history
        新しい対話を履歴に追加
        """
        user_input = interaction.get("user_input", "")
        result = interaction.get("result", "")

        if user_input and result:
            entry = f"User: {user_input}\nAssistant: {result}"
            self.history.append(entry)

            # Keep only recent items
            if len(self.history) > self.max_items:
                self.history = self.history[-self.max_items:]

    def clear(self) -> None:
        """Clear conversation history
        会話履歴をクリア
        """
        self.history.clear()

FixedFileProvider

class FixedFileProvider(ContextProvider):
    """Provides fixed file content as context
    固定ファイルの内容をコンテキストとして提供
    """

    provider_name: ClassVar[str] = "fixed_file"

    def __init__(self, file_path: str, description: str = ""):
        self.file_path = file_path
        self.description = description
        self._content = ""
        self._load_content()

    @classmethod
    def get_config_schema(cls) -> Dict[str, Any]:
        """Get configuration schema for fixed file provider
        固定ファイルプロバイダーの設定スキーマを取得
        """
        return {
            "description": "Provides fixed file content as context",
            "parameters": {
                "file_path": {
                    "type": "str",
                    "required": True,
                    "description": "Path to the file to include in context"
                },
                "description": {
                    "type": "str",
                    "default": "",
                    "description": "Description of the file content"
                }
            },
            "example": """
fixed_file:
  file_path: "project_config.json"
  description: "Project Configuration"
            """.strip()
        }

    def _load_content(self) -> None:
        """Load file content
        ファイル内容を読み込み
        """
        try:
            with open(self.file_path, 'r', encoding='utf-8') as f:
                self._content = f.read()
        except Exception as e:
            self._content = f"Error loading file: {e}"

    def get_context(self, query: str, previous_context: Optional[str] = None, **kwargs) -> str:
        """Get fixed file content
        固定ファイルの内容を取得
        """
        if not self._content:
            return ""

        context = f"Fixed Context ({self.description}):\n{self._content}"
        return context

    def update(self, interaction: Dict[str, Any]) -> None:
        """Reload file content
        ファイル内容を再読み込み
        """
        self._load_content()

    def clear(self) -> None:
        """Clear file content
        ファイル内容をクリア
        """
        self._content = ""

SourceCodeProvider

import os
from typing import List, ClassVar, Optional

class SourceCodeProvider(ContextProvider):
    """Provides relevant source code as context
    関連するソースコードをコンテキストとして提供
    """

    provider_name: ClassVar[str] = "source_code"

    def __init__(self, codebase_path: str = "./src", max_files: int = 5):
        self.codebase_path = codebase_path
        self.max_files = max_files

    @classmethod
    def get_config_schema(cls) -> Dict[str, Any]:
        """Get configuration schema for source code provider
        ソースコードプロバイダーの設定スキーマを取得
        """
        return {
            "description": "Provides relevant source code as context",
            "parameters": {
                "codebase_path": {
                    "type": "str",
                    "default": "./src",
                    "description": "Path to the codebase to search"
                },
                "max_files": {
                    "type": "int",
                    "default": 5,
                    "description": "Maximum number of files to include"
                }
            },
            "example": """
source_code:
  codebase_path: "./src"
  max_files: 3
            """.strip()
        }

    def get_context(self, query: str, previous_context: Optional[str] = None, **kwargs) -> str:
        """Get relevant source code
        関連するソースコードを取得
        """
        relevant_files = self._find_relevant_files(query)

        if not relevant_files:
            return ""

        context_parts = ["Relevant Source Code:"]
        for file_path in relevant_files[:self.max_files]:
            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    content = f.read()
                    context_parts.append(f"File: {file_path}\n{content}")
            except Exception:
                continue

        return "\n\n".join(context_parts)

    def _find_relevant_files(self, query: str) -> List[str]:
        """Find files relevant to the query
        クエリに関連するファイルを検索
        """
        relevant_files = []
        search_terms = query.lower().split()

        for root, dirs, files in os.walk(self.codebase_path):
            for file in files:
                if file.endswith(('.py', '.js', '.ts', '.java', '.cpp', '.h')):
                    file_path = os.path.join(root, file)
                    file_lower = file.lower()

                    if any(term in file_lower for term in search_terms):
                        relevant_files.append(file_path)

        return relevant_files

    def update(self, interaction: Dict[str, Any]) -> None:
        """No update needed for source code provider
        ソースコードプロバイダーでは更新は不要
        """
        pass

    def clear(self) -> None:
        """No clear needed for source code provider
        ソースコードプロバイダーではクリアは不要
        """
        pass

ContextCompressorProvider

import re
from typing import ClassVar, Optional

class ContextCompressorProvider(ContextProvider):
    """Compresses context to fit within token limits
    トークン制限内に収めるためにコンテキストを圧縮
    """

    provider_name: ClassVar[str] = "compressor"

    def __init__(self, max_tokens: int = 8000, compression_ratio: float = 0.7):
        self.max_tokens = max_tokens
        self.compression_ratio = compression_ratio

    @classmethod
    def get_config_schema(cls) -> Dict[str, Any]:
        """Get configuration schema for context compressor provider
        コンテキスト圧縮プロバイダーの設定スキーマを取得
        """
        return {
            "description": "Compresses context to fit within token limits",
            "parameters": {
                "max_tokens": {
                    "type": "int",
                    "default": 8000,
                    "description": "Maximum number of tokens to allow"
                },
                "compression_ratio": {
                    "type": "float",
                    "default": 0.7,
                    "description": "Compression ratio (0.0 to 1.0)"
                }
            },
            "example": """
compressor:
  max_tokens: 6000
  compression_ratio: 0.8
            """.strip()
        }

    def get_context(self, query: str, previous_context: Optional[str] = None, **kwargs) -> str:
        """Compress previous context to fit within token limits
        前のコンテキストをトークン制限内に収めるように圧縮
        """
        if not previous_context:
            return ""

        # Simple token estimation (rough approximation)
        estimated_tokens = len(previous_context.split()) * 1.3

        if estimated_tokens <= self.max_tokens:
            return previous_context

        # Compress context by keeping important parts
        compressed_context = self._compress_context(previous_context)
        return compressed_context

    def _compress_context(self, context: str) -> str:
        """Compress context by keeping important parts
        重要な部分を保持してコンテキストを圧縮
        """
        lines = context.split('\n')
        compressed_lines = []

        # Keep first and last parts, compress middle
        if len(lines) <= 10:
            return context

        # Keep first 30% and last 30%
        first_count = int(len(lines) * 0.3)
        last_count = int(len(lines) * 0.3)

        compressed_lines.extend(lines[:first_count])
        compressed_lines.append("... (compressed content) ...")
        compressed_lines.extend(lines[-last_count:])

        return '\n'.join(compressed_lines)

    def update(self, interaction: Dict[str, Any]) -> None:
        """No update needed for compressor provider
        圧縮プロバイダーでは更新は不要
        """
        pass

    def clear(self) -> None:
        """No clear needed for compressor provider
        圧縮プロバイダーではクリアは不要
        """
        pass

ContextFilterProvider

import re
from typing import ClassVar, Optional, List

class ContextFilterProvider(ContextProvider):
    """Filters context based on relevance to query
    クエリとの関連性に基づいてコンテキストをフィルタリング
    """

    provider_name: ClassVar[str] = "filter"

    def __init__(self, relevance_threshold: float = 0.3, max_sections: int = 5):
        self.relevance_threshold = relevance_threshold
        self.max_sections = max_sections

    @classmethod
    def get_config_schema(cls) -> Dict[str, Any]:
        """Get configuration schema for context filter provider
        コンテキストフィルタープロバイダーの設定スキーマを取得
        """
        return {
            "description": "Filters context based on relevance to query",
            "parameters": {
                "relevance_threshold": {
                    "type": "float",
                    "default": 0.3,
                    "description": "Minimum relevance score to keep context"
                },
                "max_sections": {
                    "type": "int",
                    "default": 5,
                    "description": "Maximum number of context sections to keep"
                }
            },
            "example": """
filter:
  relevance_threshold: 0.5
  max_sections: 3
            """.strip()
        }

    def get_context(self, query: str, previous_context: Optional[str] = None, **kwargs) -> str:
        """Filter previous context based on relevance to query
        クエリとの関連性に基づいて前のコンテキストをフィルタリング
        """
        if not previous_context:
            return ""

        # Split context into sections
        sections = self._split_into_sections(previous_context)

        # Calculate relevance for each section
        relevant_sections = []
        for section in sections:
            relevance = self._calculate_relevance(section, query)
            if relevance >= self.relevance_threshold:
                relevant_sections.append((section, relevance))

        # Sort by relevance and keep top sections
        relevant_sections.sort(key=lambda x: x[1], reverse=True)
        filtered_sections = [section for section, _ in relevant_sections[:self.max_sections]]

        return '\n\n'.join(filtered_sections)

    def _split_into_sections(self, context: str) -> List[str]:
        """Split context into logical sections
        コンテキストを論理的なセクションに分割
        """
        # Split by double newlines or section headers
        sections = re.split(r'\n\s*\n', context)
        return [section.strip() for section in sections if section.strip()]

    def _calculate_relevance(self, section: str, query: str) -> float:
        """Calculate relevance score between section and query
        セクションとクエリの間の関連性スコアを計算
        """
        query_words = set(query.lower().split())
        section_words = set(section.lower().split())

        if not query_words:
            return 0.0

        # Simple word overlap calculation
        overlap = len(query_words.intersection(section_words))
        return overlap / len(query_words)

    def update(self, interaction: Dict[str, Any]) -> None:
        """No update needed for filter provider
        フィルタープロバイダーでは更新は不要
        """
        pass

    def clear(self) -> None:
        """No clear needed for filter provider
        フィルタープロバイダーではクリアは不要
        """
        pass

コンテキストプロバイダーファクトリー

ContextProviderFactory

import yaml
from typing import List, Dict, Any, Type
from .context_providers import (
    ConversationHistoryProvider,
    FixedFileProvider,
    SourceCodeProvider,
    ContextCompressorProvider,
    ContextFilterProvider
)

class ContextProviderFactory:
    """Factory for creating context providers from configuration
    設定からコンテキストプロバイダーを作成するファクトリー
    """

    _providers: Dict[str, Type[ContextProvider]] = {
        "conversation": ConversationHistoryProvider,
        "fixed_file": FixedFileProvider,
        "source_code": SourceCodeProvider,
        "compressor": ContextCompressorProvider,
        "filter": ContextFilterProvider,
    }

    @classmethod
    def register_provider(cls, name: str, provider_class: Type[ContextProvider]) -> None:
        """Register a new context provider
        新しいコンテキストプロバイダーを登録
        """
        cls._providers[name] = provider_class

    @classmethod
    def get_available_providers(cls) -> Dict[str, Dict[str, Any]]:
        """Get available providers and their schemas
        利用可能なプロバイダーとそのスキーマを取得
        """
        schemas = {}
        for name, provider_class in cls._providers.items():
            schemas[name] = provider_class.get_config_schema()
        return schemas

    @classmethod
    def create_from_yaml(cls, yaml_config: str) -> List[ContextProvider]:
        """Create context providers from YAML configuration string
        YAML設定文字列からコンテキストプロバイダーを作成
        """
        try:
            config = yaml.safe_load(yaml_config)
            return cls.create_from_config(config)
        except yaml.YAMLError as e:
            raise ValueError(f"Invalid YAML configuration: {e}")

    @classmethod
    def create_from_config(cls, config: List[Dict[str, Any]]) -> List[ContextProvider]:
        """Create context providers from configuration list
        設定リストからコンテキストプロバイダーを作成
        """
        providers = []

        for item in config:
            if not isinstance(item, dict):
                raise ValueError(f"Invalid configuration item: {item}")

            for provider_name, provider_config in item.items():
                if provider_name not in cls._providers:
                    raise ValueError(f"Unknown provider: {provider_name}")

                provider_class = cls._providers[provider_name]
                provider = provider_class.from_config(provider_config or {})
                providers.append(provider)

        return providers

RefinireAgentへの統合

RefinireAgentの拡張

RefinireAgentのコンストラクタにcontext_providers_configパラメータを追加し、YAMLライクな文字列でコンテキストプロバイダーを指定できるようにします。

from typing import List, Optional, Union
from .pipeline.llm_pipeline import RefinireAgent, LLMResult
from .context_provider_factory import ContextProviderFactory

class RefinireAgent:
    """
    Refinire Agent - AI agent with automatic evaluation and tool integration
    Refinireエージェント - 自動評価とツール統合を備えたAIエージェント
    """

    def __init__(
        self,
        name: str,
        generation_instructions: str,
        evaluation_instructions: Optional[str] = None,
        *,
        model: str = "gpt-4o-mini",
        evaluation_model: Optional[str] = None,
        output_model: Optional[Type[BaseModel]] = None,
        temperature: float = 0.7,
        max_tokens: Optional[int] = None,
        timeout: float = 30.0,
        threshold: float = 85.0,
        max_retries: int = 3,
        input_guardrails: Optional[List[Callable[[str], bool]]] = None,
        output_guardrails: Optional[List[Callable[[Any], bool]]] = None,
        session_history: Optional[List[str]] = None,
        history_size: int = 10,
        improvement_callback: Optional[Callable[[LLMResult, EvaluationResult], str]] = None,
        locale: str = "en",
        tools: Optional[List[Callable]] = None,
        mcp_servers: Optional[List[str]] = None,
        context_providers: Optional[List[ContextProvider]] = None,
        context_providers_config: Optional[str] = None  # 新規追加
    ) -> None:
        """
        Initialize Refinire Agent
        Refinireエージェントを初期化する

        Args:
            name: Agent name / エージェント名
            generation_instructions: Instructions for generation / 生成用指示
            evaluation_instructions: Instructions for evaluation / 評価用指示
            model: OpenAI model name / OpenAIモデル名
            evaluation_model: Model for evaluation / 評価用モデル
            output_model: Pydantic model for structured output / 構造化出力用Pydanticモデル
            temperature: Sampling temperature / サンプリング温度
            max_tokens: Maximum tokens / 最大トークン数
            timeout: Request timeout / リクエストタイムアウト
            threshold: Evaluation threshold / 評価閾値
            max_retries: Maximum retry attempts / 最大リトライ回数
            input_guardrails: Input validation functions / 入力検証関数
            output_guardrails: Output validation functions / 出力検証関数
            session_history: Session history / セッション履歴
            history_size: History size limit / 履歴サイズ制限
            improvement_callback: Callback for improvement suggestions / 改善提案コールバック
            locale: Locale for messages / メッセージ用ロケール
            tools: OpenAI function tools / OpenAI関数ツール
            mcp_servers: MCP server identifiers / MCPサーバー識別子
            context_providers: List of context providers / コンテキストプロバイダーリスト
            context_providers_config: YAML-like string configuration for context providers / コンテキストプロバイダー用のYAMLライクな文字列設定
        """
        # 既存の初期化処理...

        # Context providers initialization
        # コンテキストプロバイダーの初期化
        if context_providers_config:
            self.context_providers = ContextProviderFactory.create_from_yaml(context_providers_config)
        else:
            self.context_providers = context_providers or []

        # OpenAI Agents SDK Agentを初期化
        self._sdk_agent = Agent(
            name=f"{name}_sdk_agent",
            instructions=self.generation_instructions,
            tools=self.tools
        )

    @classmethod
    def get_context_provider_schemas(cls) -> Dict[str, Dict[str, Any]]:
        """Get available context provider schemas
        利用可能なコンテキストプロバイダーのスキーマを取得
        """
        return ContextProviderFactory.get_available_providers()

    def _build_prompt(self, user_input: str, include_instructions: bool = True) -> str:
        """
        Build complete prompt with instructions, history, and context providers
        指示、履歴、コンテキストプロバイダーを含む完全なプロンプトを構築

        Args:
            user_input: User input / ユーザー入力
            include_instructions: Whether to include instructions (for OpenAI Agents SDK, set to False)
            include_instructions: 指示文を含めるかどうか(OpenAI Agents SDKの場合はFalse)
        """
        prompt_parts = []

        # Add instructions only if requested (not for OpenAI Agents SDK)
        # 要求された場合のみ指示文を追加(OpenAI Agents SDKの場合は除く)
        if include_instructions:
            prompt_parts.append(self.generation_instructions)

        # Add context from context providers with chaining
        # コンテキストプロバイダーからコンテキストを連鎖的に追加
        current_context = ""
        for provider in self.context_providers:
            try:
                context = provider.get_context(user_input, previous_context=current_context, agent_name=self.name)
                if context:
                    current_context = context
            except Exception as e:
                logger.warning(f"Context provider {provider.__class__.__name__} failed: {e}")

        if current_context:
            prompt_parts.append("Context:\n" + current_context)

        # Add history if available (existing functionality)
        # 履歴が利用可能な場合は追加(既存機能)
        if self.session_history:
            history_text = "\n".join(self.session_history[-self.history_size:])
            prompt_parts.append(f"Previous context:\n{history_text}")

        prompt_parts.append(f"User input: {user_input}")

        return "\n\n".join(prompt_parts)

    def _store_in_history(self, user_input: str, result: LLMResult) -> None:
        """Store interaction in history and update context providers
        対話を履歴に保存し、コンテキストプロバイダーを更新
        """
        # Existing history storage logic
        # 既存の履歴保存ロジック
        interaction = {
            "user_input": user_input,
            "result": result.content,
            "success": result.success,
            "metadata": result.metadata,
            "timestamp": json.dumps({"pipeline": self.name}, ensure_ascii=False)
        }

        self._pipeline_history.append(interaction)

        # Add to session history for context
        session_entry = f"User: {user_input}\nAssistant: {result.content}"
        self.session_history.append(session_entry)

        # Trim history if needed
        if len(self.session_history) > self.history_size:
            self.session_history = self.session_history[-self.history_size:]

        # Update context providers
        # コンテキストプロバイダーを更新
        for provider in self.context_providers:
            try:
                provider.update(interaction)
            except Exception as e:
                logger.warning(f"Failed to update context provider {provider.__class__.__name__}: {e}")

    def clear_context(self) -> None:
        """Clear all context providers
        すべてのコンテキストプロバイダーをクリア
        """
        for provider in self.context_providers:
            try:
                provider.clear()
            except Exception as e:
                logger.warning(f"Failed to clear context provider {provider.__class__.__name__}: {e}")

使用例

YAMLライクな文字列指定(コンテキスト連鎖)

# YAMLライクな文字列でコンテキストプロバイダーを指定(連鎖的な処理)
context_config = """
- conversation:
    max_items: 10
- source_code:
    codebase_path: "./src"
    max_files: 5
- filter:
    relevance_threshold: 0.4
    max_sections: 3
- compressor:
    max_tokens: 6000
    compression_ratio: 0.8
"""

agent = RefinireAgent(
    name="AdvancedContextAgent",
    generation_instructions="You are a coding assistant with intelligent context management.",
    context_providers_config=context_config
)

result = agent.run("How should I implement the new feature?")

基本的な使用例

# 会話履歴プロバイダー付きエージェント
context_config = """
- conversation:
    max_items: 5
"""

agent = RefinireAgent(
    name="HistoryAwareAgent",
    generation_instructions="You are a helpful assistant with conversation history.",
    context_providers_config=context_config
)

result = agent.run("What did we discuss about the project?")

既存のRefinireAgentとの互換性

# 既存の使用方法(コンテキストプロバイダーなし)
agent = RefinireAgent(
    name="SimpleAgent",
    generation_instructions="You are a helpful assistant."
)

# 新しい使用方法(YAMLライクな文字列指定)
context_config = """
- conversation:
    max_items: 5
"""

agent = RefinireAgent(
    name="EnhancedAgent",
    generation_instructions="You are a helpful assistant.",
    context_providers_config=context_config
)

利用可能なプロバイダーの確認

# 利用可能なコンテキストプロバイダーとその設定スキーマを確認
schemas = RefinireAgent.get_context_provider_schemas()
for provider_name, schema in schemas.items():
    print(f"Provider: {provider_name}")
    print(f"Description: {schema['description']}")
    print(f"Parameters: {schema['parameters']}")
    print(f"Example:\n{schema['example']}")
    print()

実装計画

Phase 1: 基本コンテキストプロバイダー

  • [ ] ContextProvider インターフェースの実装
  • [ ] ConversationHistoryProviderの実装
  • [ ] FixedFileProviderの実装
  • [ ] ContextProviderFactoryの実装
  • [ ] RefinireAgentのコンストラクタ拡張

Phase 2: 高度なコンテキストプロバイダー

  • [ ] SourceCodeProviderの実装
  • [ ] ContextCompressorProviderの実装
  • [ ] ContextFilterProviderの実装
  • [ ] LongTermMemoryProviderの実装

Phase 3: 最適化と拡張

  • [ ] パフォーマンス最適化
  • [ ] テストケースの作成
  • [ ] ドキュメントの更新

まとめ

この設計により、RefinireAgentは以下の機能を獲得します:

  1. 直感的な設定: YAMLライクな文字列でコンテキストプロバイダーを指定
  2. 後方互換性: 既存のRefinireAgentとの互換性を維持
  3. 柔軟なコンテキスト管理: 複数のコンテキストソースを統合
  4. 自動更新: 対話時にコンテキストプロバイダーも自動更新
  5. 拡張しやすい: 新しいコンテキストプロバイダーの簡単な追加
  6. 設定スキーマ: 各プロバイダーの設定方法を明確に定義
  7. コンテキスト連鎖: 前のプロバイダーのコンテキストに依存する動作をサポート

この設計により、RefinireAgentは必要最小限の変更で高度なコンテキスト管理機能を獲得でき、直感的な文字列指定の利点も維持できます。