agent-governance
外部ツール(API・データベース・ファイルシステム等)を呼び出すAIエージェントに、ガバナンス・安全性・信頼制御を組み込むためのパターンと技術を提供するスキルです。ポリシーベースのアクセス制御、危険なプロンプトを検出するセマンティック意図分類、マルチエージェントワークフローの信頼スコアリング、エージェントの行動監査ログ、レート制限やコンテンツフィルターの適用など、安全なエージェント設計が必要な場面で活用できます。PydanticAI・CrewAI・OpenAI Agents・LangChain・AutoGenなど、あらゆるエージェントフレームワークに対応しています。
description の原文を見る
| Patterns and techniques for adding governance, safety, and trust controls to AI agent systems. Use this skill when: - Building AI agents that call external tools (APIs, databases, file systems) - Implementing policy-based access controls for agent tool usage - Adding semantic intent classification to detect dangerous prompts - Creating trust scoring systems for multi-agent workflows - Building audit trails for agent actions and decisions - Enforcing rate limits, content filters, or tool restrictions on agents - Working with any agent framework (PydanticAI, CrewAI, OpenAI Agents, LangChain, AutoGen)
SKILL.md 本文
Agent Governance Patterns
AI エージェントシステムにセーフティ、信頼、ポリシー適用を追加するためのパターン。
概要
ガバナンスパターンにより、AI エージェントが定義された境界内で動作することを保証します。呼び出し可能なツール、処理できるコンテンツ、実行可能な範囲をコントロールし、監査証跡を通じて説明責任を維持します。
User Request → Intent Classification → Policy Check → Tool Execution → Audit Log
↓ ↓ ↓
Threat Detection Allow/Deny Trust Update
使用する場合
- ツールアクセスを持つエージェント: 外部ツール(API、データベース、シェルコマンド)を呼び出す任意のエージェント
- マルチエージェントシステム: 他のエージェントに委譲するエージェントは信頼の境界を必要とします
- 本番環境へのデプロイ: コンプライアンス、監査、セーフティ要件
- 機密オペレーション: 財務取引、データアクセス、インフラストラクチャ管理
パターン 1: ガバナンスポリシー
エージェントが何をしてもよいかを、構成可能かつシリアル化可能なポリシーオブジェクトとして定義します。
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional
import re
class PolicyAction(Enum):
ALLOW = "allow"
DENY = "deny"
REVIEW = "review" # flag for human review
@dataclass
class GovernancePolicy:
"""Declarative policy controlling agent behavior."""
name: str
allowed_tools: list[str] = field(default_factory=list) # allowlist
blocked_tools: list[str] = field(default_factory=list) # blocklist
blocked_patterns: list[str] = field(default_factory=list) # content filters
max_calls_per_request: int = 100 # rate limit
require_human_approval: list[str] = field(default_factory=list) # tools needing approval
def check_tool(self, tool_name: str) -> PolicyAction:
"""Check if a tool is allowed by this policy."""
if tool_name in self.blocked_tools:
return PolicyAction.DENY
if tool_name in self.require_human_approval:
return PolicyAction.REVIEW
if self.allowed_tools and tool_name not in self.allowed_tools:
return PolicyAction.DENY
return PolicyAction.ALLOW
def check_content(self, content: str) -> Optional[str]:
"""Check content against blocked patterns. Returns matched pattern or None."""
for pattern in self.blocked_patterns:
if re.search(pattern, content, re.IGNORECASE):
return pattern
return None
ポリシー構成
複数のポリシー(例:組織全体 + チーム + エージェント固有)を組み合わせます:
def compose_policies(*policies: GovernancePolicy) -> GovernancePolicy:
"""Merge policies with most-restrictive-wins semantics."""
combined = GovernancePolicy(name="composed")
for policy in policies:
combined.blocked_tools.extend(policy.blocked_tools)
combined.blocked_patterns.extend(policy.blocked_patterns)
combined.require_human_approval.extend(policy.require_human_approval)
combined.max_calls_per_request = min(
combined.max_calls_per_request,
policy.max_calls_per_request
)
if policy.allowed_tools:
if combined.allowed_tools:
combined.allowed_tools = [
t for t in combined.allowed_tools if t in policy.allowed_tools
]
else:
combined.allowed_tools = list(policy.allowed_tools)
return combined
# Usage: layer policies from broad to specific
org_policy = GovernancePolicy(
name="org-wide",
blocked_tools=["shell_exec", "delete_database"],
blocked_patterns=[r"(?i)(api[_-]?key|secret|password)\s*[:=]"],
max_calls_per_request=50
)
team_policy = GovernancePolicy(
name="data-team",
allowed_tools=["query_db", "read_file", "write_report"],
require_human_approval=["write_report"]
)
agent_policy = compose_policies(org_policy, team_policy)
YAML としてのポリシー
ポリシーを設定として保存し、コードとしてではなく:
# governance-policy.yaml
name: production-agent
allowed_tools:
- search_documents
- query_database
- send_email
blocked_tools:
- shell_exec
- delete_record
blocked_patterns:
- "(?i)(api[_-]?key|secret|password)\\s*[:=]"
- "(?i)(drop|truncate|delete from)\\s+\\w+"
max_calls_per_request: 25
require_human_approval:
- send_email
import yaml
def load_policy(path: str) -> GovernancePolicy:
with open(path) as f:
data = yaml.safe_load(f)
return GovernancePolicy(**data)
パターン 2: セマンティック意図分類
プロンプトがエージェントに到達する前に、パターンベースの信号を使用して危険な意図を検出します。
from dataclasses import dataclass
@dataclass
class IntentSignal:
category: str # e.g., "data_exfiltration", "privilege_escalation"
confidence: float # 0.0 to 1.0
evidence: str # what triggered the detection
# Weighted signal patterns for threat detection
THREAT_SIGNALS = [
# Data exfiltration
(r"(?i)send\s+(all|every|entire)\s+\w+\s+to\s+", "data_exfiltration", 0.8),
(r"(?i)export\s+.*\s+to\s+(external|outside|third.?party)", "data_exfiltration", 0.9),
(r"(?i)curl\s+.*\s+-d\s+", "data_exfiltration", 0.7),
# Privilege escalation
(r"(?i)(sudo|as\s+root|admin\s+access)", "privilege_escalation", 0.8),
(r"(?i)chmod\s+777", "privilege_escalation", 0.9),
# System modification
(r"(?i)(rm\s+-rf|del\s+/[sq]|format\s+c:)", "system_destruction", 0.95),
(r"(?i)(drop\s+database|truncate\s+table)", "system_destruction", 0.9),
# Prompt injection
(r"(?i)ignore\s+(previous|above|all)\s+(instructions?|rules?)", "prompt_injection", 0.9),
(r"(?i)you\s+are\s+now\s+(a|an)\s+", "prompt_injection", 0.7),
]
def classify_intent(content: str) -> list[IntentSignal]:
"""Classify content for threat signals."""
signals = []
for pattern, category, weight in THREAT_SIGNALS:
match = re.search(pattern, content)
if match:
signals.append(IntentSignal(
category=category,
confidence=weight,
evidence=match.group()
))
return signals
def is_safe(content: str, threshold: float = 0.7) -> bool:
"""Quick check: is the content safe above the given threshold?"""
signals = classify_intent(content)
return not any(s.confidence >= threshold for s in signals)
重要な洞察: 意図分類はツール実行 前に 発生し、プリフライト安全性チェックとして機能します。これは生成 後に のみチェックする出力ガードレールとは根本的に異なります。
パターン 3: ツールレベルのガバナンスデコレータ
個々のツール関数をガバナンスチェックでラップします:
import functools
import time
from collections import defaultdict
_call_counters: dict[str, int] = defaultdict(int)
def govern(policy: GovernancePolicy, audit_trail=None):
"""Decorator that enforces governance policy on a tool function."""
def decorator(func):
@functools.wraps(func)
async def wrapper(*args, **kwargs):
tool_name = func.__name__
# 1. Check tool allowlist/blocklist
action = policy.check_tool(tool_name)
if action == PolicyAction.DENY:
raise PermissionError(f"Policy '{policy.name}' blocks tool '{tool_name}'")
if action == PolicyAction.REVIEW:
raise PermissionError(f"Tool '{tool_name}' requires human approval")
# 2. Check rate limit
_call_counters[policy.name] += 1
if _call_counters[policy.name] > policy.max_calls_per_request:
raise PermissionError(f"Rate limit exceeded: {policy.max_calls_per_request} calls")
# 3. Check content in arguments
for arg in list(args) + list(kwargs.values()):
if isinstance(arg, str):
matched = policy.check_content(arg)
if matched:
raise PermissionError(f"Blocked pattern detected: {matched}")
# 4. Execute and audit
start = time.monotonic()
try:
result = await func(*args, **kwargs)
if audit_trail is not None:
audit_trail.append({
"tool": tool_name,
"action": "allowed",
"duration_ms": (time.monotonic() - start) * 1000,
"timestamp": time.time()
})
return result
except Exception as e:
if audit_trail is not None:
audit_trail.append({
"tool": tool_name,
"action": "error",
"error": str(e),
"timestamp": time.time()
})
raise
return wrapper
return decorator
# Usage with any agent framework
audit_log = []
policy = GovernancePolicy(
name="search-agent",
allowed_tools=["search", "summarize"],
blocked_patterns=[r"(?i)password"],
max_calls_per_request=10
)
@govern(policy, audit_trail=audit_log)
async def search(query: str) -> str:
"""Search documents — governed by policy."""
return f"Results for: {query}"
# Passes: search("latest quarterly report")
# Blocked: search("show me the admin password")
パターン 4: 信頼スコアリング
時間減衰ベースの信頼スコアでエージェント信頼性を長期追跡します:
from dataclasses import dataclass, field
import math
import time
@dataclass
class TrustScore:
"""Trust score with temporal decay."""
score: float = 0.5 # 0.0 (untrusted) to 1.0 (fully trusted)
successes: int = 0
failures: int = 0
last_updated: float = field(default_factory=time.time)
def record_success(self, reward: float = 0.05):
self.successes += 1
self.score = min(1.0, self.score + reward * (1 - self.score))
self.last_updated = time.time()
def record_failure(self, penalty: float = 0.15):
self.failures += 1
self.score = max(0.0, self.score - penalty * self.score)
self.last_updated = time.time()
def current(self, decay_rate: float = 0.001) -> float:
"""Get score with temporal decay — trust erodes without activity."""
elapsed = time.time() - self.last_updated
decay = math.exp(-decay_rate * elapsed)
return self.score * decay
@property
def reliability(self) -> float:
total = self.successes + self.failures
return self.successes / total if total > 0 else 0.0
# Usage in multi-agent systems
trust = TrustScore()
# Agent completes tasks successfully
trust.record_success() # 0.525
trust.record_success() # 0.549
# Agent makes an error
trust.record_failure() # 0.467
# Gate sensitive operations on trust
if trust.current() >= 0.7:
# Allow autonomous operation
pass
elif trust.current() >= 0.4:
# Allow with human oversight
pass
else:
# Deny or require explicit approval
pass
マルチエージェント信頼: エージェントが他のエージェントに委譲するシステムでは、各エージェントが委譲先の信頼スコアを維持します:
class AgentTrustRegistry:
def __init__(self):
self.scores: dict[str, TrustScore] = {}
def get_trust(self, agent_id: str) -> TrustScore:
if agent_id not in self.scores:
self.scores[agent_id] = TrustScore()
return self.scores[agent_id]
def most_trusted(self, agents: list[str]) -> str:
return max(agents, key=lambda a: self.get_trust(a).current())
def meets_threshold(self, agent_id: str, threshold: float) -> bool:
return self.get_trust(agent_id).current() >= threshold
パターン 5: 監査証跡
すべてのエージェントアクション向けの追記専用監査ログ — コンプライアンスとデバッグに不可欠:
from dataclasses import dataclass, field
import json
import time
@dataclass
class AuditEntry:
timestamp: float
agent_id: str
tool_name: str
action: str # "allowed", "denied", "error"
policy_name: str
details: dict = field(default_factory=dict)
class AuditTrail:
"""Append-only audit trail for agent governance events."""
def __init__(self):
self._entries: list[AuditEntry] = []
def log(self, agent_id: str, tool_name: str, action: str,
policy_name: str, **details):
self._entries.append(AuditEntry(
timestamp=time.time(),
agent_id=agent_id,
tool_name=tool_name,
action=action,
policy_name=policy_name,
details=details
))
def denied(self) -> list[AuditEntry]:
"""Get all denied actions — useful for security review."""
return [e for e in self._entries if e.action == "denied"]
def by_agent(self, agent_id: str) -> list[AuditEntry]:
return [e for e in self._entries if e.agent_id == agent_id]
def export_jsonl(self, path: str):
"""Export as JSON Lines for log aggregation systems."""
with open(path, "w") as f:
for entry in self._entries:
f.write(json.dumps({
"timestamp": entry.timestamp,
"agent_id": entry.agent_id,
"tool": entry.tool_name,
"action": entry.action,
"policy": entry.policy_name,
**entry.details
}) + "\n")
パターン 6: フレームワーク統合
PydanticAI
from pydantic_ai import Agent
policy = GovernancePolicy(
name="support-bot",
allowed_tools=["search_docs", "create_ticket"],
blocked_patterns=[r"(?i)(ssn|social\s+security|credit\s+card)"],
max_calls_per_request=20
)
agent = Agent("openai:gpt-4o", system_prompt="You are a support assistant.")
@agent.tool
@govern(policy)
async def search_docs(ctx, query: str) -> str:
"""Search knowledge base — governed."""
return await kb.search(query)
@agent.tool
@govern(policy)
async def create_ticket(ctx, title: str, body: str) -> str:
"""Create support ticket — governed."""
return await tickets.create(title=title, body=body)
CrewAI
from crewai import Agent, Task, Crew
policy = GovernancePolicy(
name="research-crew",
allowed_tools=["search", "analyze"],
max_calls_per_request=30
)
# Apply governance at the crew level
def governed_crew_run(crew: Crew, policy: GovernancePolicy):
"""Wrap crew execution with governance checks."""
audit = AuditTrail()
for agent in crew.agents:
for tool in agent.tools:
original = tool.func
tool.func = govern(policy, audit_trail=audit)(original)
result = crew.kickoff()
return result, audit
OpenAI Agents SDK
from agents import Agent, function_tool
policy = GovernancePolicy(
name="coding-agent",
allowed_tools=["read_file", "write_file", "run_tests"],
blocked_tools=["shell_exec"],
max_calls_per_request=50
)
@function_tool
@govern(policy)
async def read_file(path: str) -> str:
"""Read file contents — governed."""
import os
safe_path = os.path.realpath(path)
if not safe_path.startswith(os.path.realpath(".")):
raise ValueError("Path traversal blocked by governance")
with open(safe_path) as f:
return f.read()
ガバナンスレベル
ガバナンスの厳しさをリスクレベルに合わせます:
| レベル | コントロール | ユースケース |
|---|---|---|
| オープン | 監査のみ、制限なし | 内部開発/テスト |
| 標準 | ツール許可リスト + コンテンツフィルター | 一般的な本番エージェント |
| 厳密 | すべてのコントロール + 機密オペレーション向け人間承認 | 金融、医療、法務 |
| ロック | 許可リストのみ、動的ツールなし、完全監査 | コンプライアンス重視システム |
ベストプラクティス
| プラクティス | 理由 |
|---|---|
| 設定としてのポリシー | ポリシーを YAML/JSON に保存し、ハードコードしない — デプロイなしで変更可能 |
| 最も制限的なもの優先 | ポリシーを構成する場合、deny は常に allow を上書き |
| プリフライト意図チェック | ツール実行 後 ではなく 前 に意図を分類 |
| 信頼の減衰 | 信頼スコアは時間とともに減衰 — 継続的な良好な行動が必要 |
| 追記専用監査 | 監査エントリを決して修正または削除しない — 不変性がコンプライアンスを有効化 |
| 閉じた状態で失敗 | ガバナンスチェックがエラーの場合、許可するのではなく、アクションを deny |
| ポリシーとロジックの分離 | ガバナンス適用はエージェントのビジネスロジックから独立 |
クイックスタートチェックリスト
## Agent ガバナンス実装チェックリスト
### セットアップ
- [ ] ガバナンスポリシーを定義 (許可ツール、ブロックパターン、レート制限)
- [ ] ガバナンスレベルを選択 (open/standard/strict/locked)
- [ ] 監査証跡ストレージをセットアップ
### 実装
- [ ] すべてのツール関数に @govern デコレータを追加
- [ ] ユーザー入力処理に意図分類を追加
- [ ] マルチエージェント相互作用向け信頼スコアリングを実装
- [ ] 監査証跡エクスポートを接続
### 検証
- [ ] ブロックされたツールが正しく否定されることをテスト
- [ ] コンテンツフィルターが機密パターンをキャッチすることをテスト
- [ ] レート制限動作をテスト
- [ ] 監査証跡がすべてのイベントをキャプチャすることを確認
- [ ] ポリシー構成をテスト (最も制限的なもの優先)
関連リソース
- Agent Governance Toolkit — 完全ガバナンスフレームワーク
- AgentMesh Integrations — フレームワーク固有のパッケージ
- OWASP Top 10 for LLM Applications
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- github
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/github/awesome-copilot / ライセンス: MIT
関連スキル
agent-browser
AI エージェント向けのブラウザ自動化 CLI です。ウェブサイトとの対話が必要な場合に使用します。ページ遷移、フォーム入力、ボタンクリック、スクリーンショット取得、データ抽出、ウェブアプリのテスト、ブラウザ操作の自動化など、あらゆるブラウザタスクに対応できます。「ウェブサイトを開く」「フォームに記入する」「ボタンをクリックする」「スクリーンショットを取得する」「ページからデータを抽出する」「このウェブアプリをテストする」「サイトにログインする」「ブラウザ操作を自動化する」といった要求や、プログラマティックなウェブ操作が必要なタスクで起動します。
anyskill
AnySkill — あなたのプライベート・スキルクラウド。GitHubを基盤としたリポジトリからエージェントスキルを管理、同期、動的にロードできます。自然言語でクラウドスキルを検索し、オンデマンドでプロンプトを自動ロード、カスタムスキルのアップロードと共有、スキルバンドルの一括インストールが可能です。OpenClaw、Antigravity、Claude Code、Cursorに対応しています。
engram
AIエージェント向けの永続的なメモリシステムです。バグ修正、意思決定、発見、設定変更の後はmem_saveを使用してください。ユーザーが「覚えている」「記憶している」と言及した場合、または以前のセッションと重複する作業を開始する際はmem_searchを使用します。セッション終了前にmem_session_summaryを使用して、コンテキストを保持してください。
skyvern
AI駆動のブラウザ自動化により、任意のウェブサイトを自動化できます。フォーム入力、データ抽出、ファイルダウンロード、ログイン、複数ステップのワークフロー実行など、ユーザーがウェブサイトと連携する必要があるときに使用します。Skyvernは、LLMとコンピュータビジョンを活用して、未知のサイトも自動操作可能です。Python SDK、TypeScript SDK、REST API、MCPサーバー、またはCLIを通じて統合できます。
pinchbench
PinchBenchベンチマークを実行して、OpenClawエージェントの実世界タスクにおけるパフォーマンスを評価できます。モデルの機能テスト、モデル間の比較、ベンチマーク結果のリーダーボード提出、またはOpenClawのセットアップがカレンダー、メール、リサーチ、コーディング、複数ステップのワークフローにどの程度対応しているかを確認する際に使用します。
openui
OpenUIとOpenUI Langを使用してジェネレーティブUIアプリを構築できます。これらはLLM生成インターフェースのためのトークン効率的なオープン標準です。OpenUI、@openuidev、ジェネレーティブUI、LLMからのストリーミングUI、AI向けコンポーネントライブラリ、またはjson-render/A2UIの置き換えについて述べる際に使用します。スキャフォルディング、defineComponent、システムプロンプト、Renderer、およびOpenUI Lang出力のデバッグに対応しています。