Agent Skills by ALSEL
Anthropic ClaudeLLM・AI開発⭐ リポ 0品質スコア 50/100

autonomous-agent-patterns

自律型コーディングエージェントを構築するための設計パターン集です。ツール統合、パーミッションシステム、ブラウザ自動化、ヒューマン・イン・ザ・ループのワークフローを網羅しています。AIエージェントの構築、ツールAPIの設計、パーミッションシステムの実装、自律型コーディングアシスタントの作成時に活用してください。

description の原文を見る

Design patterns for building autonomous coding agents. Covers tool integration, permission systems, browser automation, and human-in-the-loop workflows. Use when building AI agents, designing tool APIs, implementing permission systems, or creating autonomous coding assistants.

SKILL.md 本文

🕹️ Autonomous Agent Patterns

自律型コーディングエージェント構築のためのデザインパターン。ClineOpenAI Codex にインスピレーションを受けています。

このスキルを使う場面

このスキルは以下の場合に使用します:

  • 自律型AIエージェントの構築
  • ツール/関数呼び出しAPIの設計
  • 権限承認システムの実装
  • エージェント用ブラウザオートメーションの作成
  • 人間参加ワークフロー設計

1. コアエージェントアーキテクチャ

1.1 エージェントループ

┌─────────────────────────────────────────────────────────────┐
│                     AGENT LOOP                               │
│                                                              │
│  ┌──────────┐    ┌──────────┐    ┌──────────┐              │
│  │  Think   │───▶│  Decide  │───▶│   Act    │              │
│  │ (Reason) │    │ (Plan)   │    │ (Execute)│              │
│  └──────────┘    └──────────┘    └──────────┘              │
│       ▲                               │                     │
│       │         ┌──────────┐          │                     │
│       └─────────│ Observe  │◀─────────┘                     │
│                 │ (Result) │                                │
│                 └──────────┘                                │
└─────────────────────────────────────────────────────────────┘
class AgentLoop:
    def __init__(self, llm, tools, max_iterations=50):
        self.llm = llm
        self.tools = {t.name: t for t in tools}
        self.max_iterations = max_iterations
        self.history = []

    def run(self, task: str) -> str:
        self.history.append({"role": "user", "content": task})

        for i in range(self.max_iterations):
            # Think: Get LLM response with tool options
            response = self.llm.chat(
                messages=self.history,
                tools=self._format_tools(),
                tool_choice="auto"
            )

            # Decide: Check if agent wants to use a tool
            if response.tool_calls:
                for tool_call in response.tool_calls:
                    # Act: Execute the tool
                    result = self._execute_tool(tool_call)

                    # Observe: Add result to history
                    self.history.append({
                        "role": "tool",
                        "tool_call_id": tool_call.id,
                        "content": str(result)
                    })
            else:
                # No more tool calls = task complete
                return response.content

        return "Max iterations reached"

    def _execute_tool(self, tool_call) -> Any:
        tool = self.tools[tool_call.name]
        args = json.loads(tool_call.arguments)
        return tool.execute(**args)

1.2 マルチモデルアーキテクチャ

class MultiModelAgent:
    """
    異なる目的に異なるモデルを使用:
    - 高速モデル:計画用
    - 強力なモデル:複雑な推論用
    - 特化したモデル:コード生成用
    """

    def __init__(self):
        self.models = {
            "fast": "gpt-3.5-turbo",      # 迅速な決定
            "smart": "gpt-4-turbo",        # 複雑な推論
            "code": "claude-3-sonnet",     # コード生成
        }

    def select_model(self, task_type: str) -> str:
        if task_type == "planning":
            return self.models["fast"]
        elif task_type == "analysis":
            return self.models["smart"]
        elif task_type == "code":
            return self.models["code"]
        return self.models["smart"]

2. ツール設計パターン

2.1 ツールスキーマ

class Tool:
    """エージェントツールの基底クラス"""

    @property
    def schema(self) -> dict:
        """ツール用JSON Schema"""
        return {
            "name": self.name,
            "description": self.description,
            "parameters": {
                "type": "object",
                "properties": self._get_parameters(),
                "required": self._get_required()
            }
        }

    def execute(self, **kwargs) -> ToolResult:
        """ツールを実行して結果を返す"""
        raise NotImplementedError

class ReadFileTool(Tool):
    name = "read_file"
    description = "ファイルシステムからファイルの内容を読み込む"

    def _get_parameters(self):
        return {
            "path": {
                "type": "string",
                "description": "ファイルへの絶対パス"
            },
            "start_line": {
                "type": "integer",
                "description": "読み込みを開始する行番号(1から始まる)"
            },
            "end_line": {
                "type": "integer",
                "description": "読み込みを終了する行番号(含む)"
            }
        }

    def _get_required(self):
        return ["path"]

    def execute(self, path: str, start_line: int = None, end_line: int = None) -> ToolResult:
        try:
            with open(path, 'r') as f:
                lines = f.readlines()

            if start_line and end_line:
                lines = lines[start_line-1:end_line]

            return ToolResult(
                success=True,
                output="".join(lines)
            )
        except FileNotFoundError:
            return ToolResult(
                success=False,
                error=f"File not found: {path}"
            )

2.2 必須エージェントツール

CODING_AGENT_TOOLS = {
    # ファイル操作
    "read_file": "ファイルの内容を読み込む",
    "write_file": "ファイルを作成または上書きする",
    "edit_file": "ファイルに対してターゲット編集を行う",
    "list_directory": "ファイルとフォルダをリストアップする",
    "search_files": "パターンでファイルを検索する",

    # コード理解
    "search_code": "コードパターンを検索(grep)",
    "get_definition": "関数/クラスの定義を見つける",
    "get_references": "シンボルへの全参照を見つける",

    # ターミナル
    "run_command": "シェルコマンドを実行する",
    "read_output": "コマンド出力を読み込む",
    "send_input": "実行中のコマンドに入力を送信する",

    # ブラウザ(オプション)
    "open_browser": "ブラウザでURLを開く",
    "click_element": "ページ要素をクリックする",
    "type_text": "入力フィールドにテキストを入力する",
    "screenshot": "スクリーンショットをキャプチャする",

    # コンテキスト
    "ask_user": "ユーザーに質問する",
    "search_web": "ウェブで情報を検索する"
}

2.3 編集ツール設計

class EditFileTool(Tool):
    """
    競合検出を伴う正確なファイル編集。
    信頼性の高い編集のために検索/置換パターンを使用。
    """

    name = "edit_file"
    description = "特定のコンテンツを置換することでファイルを編集する"

    def execute(
        self,
        path: str,
        search: str,
        replace: str,
        expected_occurrences: int = 1
    ) -> ToolResult:
        """
        Args:
            path: 編集するファイル
            search: 検索する正確なテキスト(空白を含めて完全に一致する必要があります)
            replace: 置換するテキスト
            expected_occurrences: 検索テキストが出現すると予想される回数(検証用)
        """
        with open(path, 'r') as f:
            content = f.read()

        # 検証
        actual_occurrences = content.count(search)
        if actual_occurrences != expected_occurrences:
            return ToolResult(
                success=False,
                error=f"Expected {expected_occurrences} occurrences, found {actual_occurrences}"
            )

        if actual_occurrences == 0:
            return ToolResult(
                success=False,
                error="Search text not found in file"
            )

        # 編集を適用
        new_content = content.replace(search, replace)

        with open(path, 'w') as f:
            f.write(new_content)

        return ToolResult(
            success=True,
            output=f"Replaced {actual_occurrences} occurrence(s)"
        )

3. 権限とセーフティパターン

3.1 権限レベル

class PermissionLevel(Enum):
    # 完全自動 - ユーザー承認不要
    AUTO = "auto"

    # セッション内で1回だけ問い合わせ
    ASK_ONCE = "ask_once"

    # 毎回問い合わせ
    ASK_EACH = "ask_each"

    # 許可しない
    NEVER = "never"

PERMISSION_CONFIG = {
    # 低リスク - 自動承認可能
    "read_file": PermissionLevel.AUTO,
    "list_directory": PermissionLevel.AUTO,
    "search_code": PermissionLevel.AUTO,

    # 中程度リスク - 1回だけ問い合わせ
    "write_file": PermissionLevel.ASK_ONCE,
    "edit_file": PermissionLevel.ASK_ONCE,

    # 高リスク - 毎回問い合わせ
    "run_command": PermissionLevel.ASK_EACH,
    "delete_file": PermissionLevel.ASK_EACH,

    # 危険 - 自動承認しない
    "sudo_command": PermissionLevel.NEVER,
    "format_disk": PermissionLevel.NEVER
}

3.2 承認UI パターン

class ApprovalManager:
    def __init__(self, ui, config):
        self.ui = ui
        self.config = config
        self.session_approvals = {}

    def request_approval(self, tool_name: str, args: dict) -> bool:
        level = self.config.get(tool_name, PermissionLevel.ASK_EACH)

        if level == PermissionLevel.AUTO:
            return True

        if level == PermissionLevel.NEVER:
            self.ui.show_error(f"Tool '{tool_name}' is not allowed")
            return False

        if level == PermissionLevel.ASK_ONCE:
            if tool_name in self.session_approvals:
                return self.session_approvals[tool_name]

        # 承認ダイアログを表示
        approved = self.ui.show_approval_dialog(
            tool=tool_name,
            args=args,
            risk_level=self._assess_risk(tool_name, args)
        )

        if level == PermissionLevel.ASK_ONCE:
            self.session_approvals[tool_name] = approved

        return approved

    def _assess_risk(self, tool_name: str, args: dict) -> str:
        """特定の呼び出しのリスクレベルを分析"""
        if tool_name == "run_command":
            cmd = args.get("command", "")
            if any(danger in cmd for danger in ["rm -rf", "sudo", "chmod"]):
                return "HIGH"
        return "MEDIUM"

3.3 サンドボックス化

class SandboxedExecution:
    """
    隔離環境でコード/コマンドを実行
    """

    def __init__(self, workspace_dir: str):
        self.workspace = workspace_dir
        self.allowed_commands = ["npm", "python", "node", "git", "ls", "cat"]
        self.blocked_paths = ["/etc", "/usr", "/bin", os.path.expanduser("~")]

    def validate_path(self, path: str) -> bool:
        """パスがワークスペース内にあることを確認"""
        real_path = os.path.realpath(path)
        workspace_real = os.path.realpath(self.workspace)
        return real_path.startswith(workspace_real)

    def validate_command(self, command: str) -> bool:
        """コマンドが許可されているかを確認"""
        cmd_parts = shlex.split(command)
        if not cmd_parts:
            return False

        base_cmd = cmd_parts[0]
        return base_cmd in self.allowed_commands

    def execute_sandboxed(self, command: str) -> ToolResult:
        if not self.validate_command(command):
            return ToolResult(
                success=False,
                error=f"Command not allowed: {command}"
            )

        # 隔離環境で実行
        result = subprocess.run(
            command,
            shell=True,
            cwd=self.workspace,
            capture_output=True,
            timeout=30,
            env={
                **os.environ,
                "HOME": self.workspace,  # ホームディレクトリを隔離
            }
        )

        return ToolResult(
            success=result.returncode == 0,
            output=result.stdout.decode(),
            error=result.stderr.decode() if result.returncode != 0 else None
        )

4. ブラウザオートメーション

4.1 ブラウザツールパターン

class BrowserTool:
    """
    Playwright/Puppeteerを使用したエージェント向けブラウザオートメーション。
    ビジュアルデバッグとウェブテストを有効にします。
    """

    def __init__(self, headless: bool = True):
        self.browser = None
        self.page = None
        self.headless = headless

    async def open_url(self, url: str) -> ToolResult:
        """URLにナビゲートしてページ情報を返す"""
        if not self.browser:
            self.browser = await playwright.chromium.launch(headless=self.headless)
            self.page = await self.browser.new_page()

        await self.page.goto(url)

        # 状態をキャプチャ
        screenshot = await self.page.screenshot(type='png')
        title = await self.page.title()

        return ToolResult(
            success=True,
            output=f"Loaded: {title}",
            metadata={
                "screenshot": base64.b64encode(screenshot).decode(),
                "url": self.page.url
            }
        )

    async def click(self, selector: str) -> ToolResult:
        """要素をクリック"""
        try:
            await self.page.click(selector, timeout=5000)
            await self.page.wait_for_load_state("networkidle")

            screenshot = await self.page.screenshot()
            return ToolResult(
                success=True,
                output=f"Clicked: {selector}",
                metadata={"screenshot": base64.b64encode(screenshot).decode()}
            )
        except TimeoutError:
            return ToolResult(
                success=False,
                error=f"Element not found: {selector}"
            )

    async def type_text(self, selector: str, text: str) -> ToolResult:
        """入力フィールドにテキストを入力"""
        await self.page.fill(selector, text)
        return ToolResult(success=True, output=f"Typed into {selector}")

    async def get_page_content(self) -> ToolResult:
        """ページのアクセス可能なテキストコンテンツを取得"""
        content = await self.page.evaluate("""
            () => {
                // 表示可能なテキストを取得
                const walker = document.createTreeWalker(
                    document.body,
                    NodeFilter.SHOW_TEXT,
                    null,
                    false
                );

                let text = '';
                while (walker.nextNode()) {
                    const node = walker.currentNode;
                    if (node.textContent.trim()) {
                        text += node.textContent.trim() + '\\n';
                    }
                }
                return text;
            }
        """)
        return ToolResult(success=True, output=content)

4.2 ビジュアルエージェントパターン

class VisualAgent:
    """
    スクリーンショットを使用してウェブページを理解するエージェント。
    セレクタなしで視覚的に要素を識別できます。
    """

    def __init__(self, llm, browser):
        self.llm = llm
        self.browser = browser

    async def describe_page(self) -> str:
        """ビジョンモデルを使用して現在のページを説明"""
        screenshot = await self.browser.screenshot()

        response = self.llm.chat([
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": "このウェブページについて説明してください。見えるすべてのインタラクティブ要素をリストアップしてください。"},
                    {"type": "image", "data": screenshot}
                ]
            }
        ])

        return response.content

    async def find_and_click(self, description: str) -> ToolResult:
        """視覚的説明で要素を見つけてクリック"""
        screenshot = await self.browser.screenshot()

        # ビジョンモデルに要素を見つけるよう依頼
        response = self.llm.chat([
            {
                "role": "user",
                "content": [
                    {
                        "type": "text",
                        "text": f"""
                        一致する要素を見つけてください: "{description}"
                        JSONとして概算座標を返してください: {{"x": number, "y": number}}
                        """
                    },
                    {"type": "image", "data": screenshot}
                ]
            }
        ])

        coords = json.loads(response.content)
        await self.browser.page.mouse.click(coords["x"], coords["y"])

        return ToolResult(success=True, output=f"Clicked at ({coords['x']}, {coords['y']})")

5. コンテキスト管理

5.1 コンテキスト注入パターン

class ContextManager:
    """
    エージェントに提供するコンテキストを管理。
    Clineの@-mentionパターンにインスピレーションを受けています。
    """

    def __init__(self, workspace: str):
        self.workspace = workspace
        self.context = []

    def add_file(self, path: str) -> None:
        """@file - ファイル内容をコンテキストに追加"""
        with open(path, 'r') as f:
            content = f.read()

        self.context.append({
            "type": "file",
            "path": path,
            "content": content
        })

    def add_folder(self, path: str, max_files: int = 20) -> None:
        """@folder - フォルダ内のすべてのファイルを追加"""
        for root, dirs, files in os.walk(path):
            for file in files[:max_files]:
                file_path = os.path.join(root, file)
                self.add_file(file_path)

    def add_url(self, url: str) -> None:
        """@url - URLをフェッチして内容を追加"""
        response = requests.get(url)
        content = html_to_markdown(response.text)

        self.context.append({
            "type": "url",
            "url": url,
            "content": content
        })

    def add_problems(self, diagnostics: list) -> None:
        """@problems - IDE診断情報を追加"""
        self.context.append({
            "type": "diagnostics",
            "problems": diagnostics
        })

    def format_for_prompt(self) -> str:
        """LLMプロンプト用にすべてのコンテキストをフォーマット"""
        parts = []
        for item in self.context:
            if item["type"] == "file":
                parts.append(f"## File: {item['path']}\n```\n{item['content']}\n```")
            elif item["type"] == "url":
                parts.append(f"## URL: {item['url']}\n{item['content']}")
            elif item["type"] == "diagnostics":
                parts.append(f"## Problems:\n{json.dumps(item['problems'], indent=2)}")

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

5.2 チェックポイント/再開

class CheckpointManager:
    """
    長時間実行タスク用にエージェント状態を保存・復元。
    """

    def __init__(self, storage_dir: str):
        self.storage_dir = storage_dir
        os.makedirs(storage_dir, exist_ok=True)

    def save_checkpoint(self, session_id: str, state: dict) -> str:
        """現在のエージェント状態を保存"""
        checkpoint = {
            "timestamp": datetime.now().isoformat(),
            "session_id": session_id,
            "history": state["history"],
            "context": state["context"],
            "workspace_state": self._capture_workspace(state["workspace"]),
            "metadata": state.get("metadata", {})
        }

        path = os.path.join(self.storage_dir, f"{session_id}.json")
        with open(path, 'w') as f:
            json.dump(checkpoint, f, indent=2)

        return path

    def restore_checkpoint(self, checkpoint_path: str) -> dict:
        """チェックポイントからエージェント状態を復元"""
        with open(checkpoint_path, 'r') as f:
            checkpoint = json.load(f)

        return {
            "history": checkpoint["history"],
            "context": checkpoint["context"],
            "workspace": self._restore_workspace(checkpoint["workspace_state"]),
            "metadata": checkpoint["metadata"]
        }

    def _capture_workspace(self, workspace: str) -> dict:
        """関連するワークスペース状態をキャプチャ"""
        # Gitステータス、ファイルハッシュなど
        return {
            "git_ref": subprocess.getoutput(f"cd {workspace} && git rev-parse HEAD"),
            "git_dirty": subprocess.getoutput(f"cd {workspace} && git status --porcelain")
        }

6. MCP (Model Context Protocol) 統合

6.1 MCPサーバーパターン

from mcp import Server, Tool

class MCPAgent:
    """
    MCPツールを動的に発見して使用できるエージェント。
    Clineからの「Add a tool that...」パターン。
    """

    def __init__(self, llm):
        self.llm = llm
        self.mcp_servers = {}
        self.available_tools = {}

    def connect_server(self, name: str, config: dict) -> None:
        """MCPサーバーに接続"""
        server = Server(config)
        self.mcp_servers[name] = server

        # ツールを発見
        tools = server.list_tools()
        for tool in tools:
            self.available_tools[tool.name] = {
                "server": name,
                "schema": tool.schema
            }

    async def create_tool(self, description: str) -> str:
        """
        ユーザーの説明に基づいて新しいMCPサーバーを作成。
        「Jiraチケットを取得するツールを追加」
        """
        # MCPサーバーコードを生成
        code = self.llm.generate(f"""
        以下を行うツールを持つPython MCPサーバーを作成してください:
        {description}

        FastMCPフレームワークを使用してください。適切なエラー処理を含めてください。
        Pythonコードのみを返してください。
        """)

        # 保存してインストール
        server_name = self._extract_name(description)
        path = f"./mcp_servers/{server_name}/server.py"

        with open(path, 'w') as f:
            f.write(code)

        # ホットリロード
        self.connect_server(server_name, {"path": path})

        return f"Created tool: {server_name}"

ベストプラクティスチェックリスト

エージェント設計

  • タスク分解が明確である
  • ツール粒度が適切である
  • 各ステップでエラー処理されている
  • ユーザーに進捗が見える化されている

セーフティ

  • 権限システムが実装されている
  • 危険な操作がブロックされている
  • 信頼できないコード用のサンドボックスがある
  • 監査ログが有効である

UX

  • 承認UIが明確である
  • 進捗更新が提供されている
  • アンドゥ/ロールバックが利用可能である
  • アクション説明が提供されている

リソース

ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
davila7
リポジトリ
davila7/claude-code-templates
ライセンス
MIT
最終更新
不明

Source: https://github.com/davila7/claude-code-templates / ライセンス: MIT

関連スキル

OpenAILLM・AI開発⭐ リポ 6,054

agent-browser

AI エージェント向けのブラウザ自動化 CLI です。ウェブサイトとの対話が必要な場合に使用します。ページ遷移、フォーム入力、ボタンクリック、スクリーンショット取得、データ抽出、ウェブアプリのテスト、ブラウザ操作の自動化など、あらゆるブラウザタスクに対応できます。「ウェブサイトを開く」「フォームに記入する」「ボタンをクリックする」「スクリーンショットを取得する」「ページからデータを抽出する」「このウェブアプリをテストする」「サイトにログインする」「ブラウザ操作を自動化する」といった要求や、プログラマティックなウェブ操作が必要なタスクで起動します。

by JimmyLv
汎用LLM・AI開発⭐ リポ 1,982

anyskill

AnySkill — あなたのプライベート・スキルクラウド。GitHubを基盤としたリポジトリからエージェントスキルを管理、同期、動的にロードできます。自然言語でクラウドスキルを検索し、オンデマンドでプロンプトを自動ロード、カスタムスキルのアップロードと共有、スキルバンドルの一括インストールが可能です。OpenClaw、Antigravity、Claude Code、Cursorに対応しています。

by LeoYeAI
汎用LLM・AI開発⭐ リポ 1,982

engram

AIエージェント向けの永続的なメモリシステムです。バグ修正、意思決定、発見、設定変更の後はmem_saveを使用してください。ユーザーが「覚えている」「記憶している」と言及した場合、または以前のセッションと重複する作業を開始する際はmem_searchを使用します。セッション終了前にmem_session_summaryを使用して、コンテキストを保持してください。

by LeoYeAI
汎用LLM・AI開発⭐ リポ 21,584

skyvern

AI駆動のブラウザ自動化により、任意のウェブサイトを自動化できます。フォーム入力、データ抽出、ファイルダウンロード、ログイン、複数ステップのワークフロー実行など、ユーザーがウェブサイトと連携する必要があるときに使用します。Skyvernは、LLMとコンピュータビジョンを活用して、未知のサイトも自動操作可能です。Python SDK、TypeScript SDK、REST API、MCPサーバー、またはCLIを通じて統合できます。

by Skyvern-AI
汎用LLM・AI開発⭐ リポ 1,149

pinchbench

PinchBenchベンチマークを実行して、OpenClawエージェントの実世界タスクにおけるパフォーマンスを評価できます。モデルの機能テスト、モデル間の比較、ベンチマーク結果のリーダーボード提出、またはOpenClawのセットアップがカレンダー、メール、リサーチ、コーディング、複数ステップのワークフローにどの程度対応しているかを確認する際に使用します。

by pinchbench
汎用LLM・AI開発⭐ リポ 4,693

openui

OpenUIとOpenUI Langを使用してジェネレーティブUIアプリを構築できます。これらはLLM生成インターフェースのためのトークン効率的なオープン標準です。OpenUI、@openuidev、ジェネレーティブUI、LLMからのストリーミングUI、AI向けコンポーネントライブラリ、またはjson-render/A2UIの置き換えについて述べる際に使用します。スキャフォルディング、defineComponent、システムプロンプト、Renderer、およびOpenUI Lang出力のデバッグに対応しています。

by thesysdev
本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: davila7 · davila7/claude-code-templates · ライセンス: MIT