Loading...
    • 開發者指南
    • API 參考
    • MCP
    • 資源
    • 發行說明
    Search...
    ⌘K
    入門
    Claude 簡介快速開始
    模型與定價
    模型概覽選擇模型Claude 4.6 新功能遷移指南模型棄用定價
    使用 Claude 構建
    功能概覽使用 Messages API處理停止原因提示詞最佳實踐
    上下文管理
    上下文視窗壓縮上下文編輯
    功能
    提示詞快取延伸思考自適應思考思考力度串流訊息批次處理引用多語言支援Token 計數嵌入視覺PDF 支援Files API搜尋結果結構化輸出
    工具
    概覽如何實作工具使用細粒度工具串流Bash 工具程式碼執行工具程式化工具呼叫電腦使用工具文字編輯器工具網頁擷取工具網頁搜尋工具記憶工具工具搜尋工具
    Agent Skills
    概覽快速開始最佳實踐企業級 Skills透過 API 使用 Skills
    Agent SDK
    概覽快速開始TypeScript SDKTypeScript V2(預覽版)Python SDK遷移指南
    串流輸入即時串流回應處理停止原因處理權限使用者核准與輸入使用 hooks 控制執行工作階段管理檔案檢查點SDK 中的結構化輸出託管 Agent SDK安全部署 AI 代理修改系統提示詞SDK 中的 MCP自訂工具SDK 中的子代理SDK 中的斜線命令SDK 中的 Agent Skills追蹤成本與用量待辦清單SDK 中的外掛
    API 中的 MCP
    MCP 連接器遠端 MCP 伺服器
    第三方平台上的 Claude
    Amazon BedrockMicrosoft FoundryVertex AI
    提示詞工程
    概覽提示詞產生器使用提示詞範本提示詞改進器清晰直接使用範例(多範例提示)讓 Claude 思考(CoT)使用 XML 標籤賦予 Claude 角色(系統提示詞)串聯複雜提示詞長上下文技巧延伸思考技巧
    測試與評估
    定義成功標準開發測試案例使用評估工具降低延遲
    強化防護機制
    減少幻覺提高輸出一致性防範越獄攻擊串流拒絕減少提示詞洩漏讓 Claude 保持角色
    管理與監控
    Admin API 概覽資料駐留工作區用量與成本 APIClaude Code Analytics API零資料保留
    Console
    Log in
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...

    Solutions

    • AI agents
    • Code modernization
    • Coding
    • Customer support
    • Education
    • Financial services
    • Government
    • Life sciences

    Partners

    • Amazon Bedrock
    • Google Cloud's Vertex AI

    Learn

    • Blog
    • Catalog
    • Courses
    • Use cases
    • Connectors
    • Customer stories
    • Engineering at Anthropic
    • Events
    • Powered by Claude
    • Service partners
    • Startups program

    Company

    • Anthropic
    • Careers
    • Economic Futures
    • Research
    • News
    • Responsible Scaling Policy
    • Security and compliance
    • Transparency

    Learn

    • Blog
    • Catalog
    • Courses
    • Use cases
    • Connectors
    • Customer stories
    • Engineering at Anthropic
    • Events
    • Powered by Claude
    • Service partners
    • Startups program

    Help and security

    • Availability
    • Status
    • Support
    • Discord

    Terms and policies

    • Privacy policy
    • Responsible disclosure policy
    • Terms of service: Commercial
    • Terms of service: Consumer
    • Usage policy
    指南

    使用 hooks 攔截和控制代理行為

    透過 hooks 在關鍵執行點攔截和自訂代理行為

    Hooks 讓您在關鍵點攔截代理執行,以新增驗證、日誌記錄、安全控制或自訂邏輯。透過 hooks,您可以:

    • 在危險操作執行前阻止它們,例如破壞性的 shell 命令或未經授權的檔案存取
    • 記錄和稽核每個工具呼叫,用於合規性、除錯或分析
    • 轉換輸入和輸出以清理資料、注入憑證或重新導向檔案路徑
    • 要求人工核准敏感操作,例如資料庫寫入或 API 呼叫
    • 追蹤工作階段生命週期以管理狀態、清理資源或傳送通知

    一個 hook 有兩個部分:

    1. 回呼函式:hook 觸發時執行的邏輯
    2. Hook 設定:告訴 SDK 要掛接到哪個事件(例如 PreToolUse)以及要匹配哪些工具

    以下範例阻止代理修改 .env 檔案。首先,定義一個檢查檔案路徑的回呼,然後將其傳遞給 query() 以在任何 Write 或 Edit 工具呼叫之前執行:

    import asyncio
    from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher
    
    # Define a hook callback that receives tool call details
    async def protect_env_files(input_data, tool_use_id, context):
        # Extract the file path from the tool's input arguments
        file_path = input_data['tool_input'].get('file_path', '')
        file_name = file_path.split('/')[-1]
    
        # Block the operation if targeting a .env file
        if file_name == '.env':
            return {
                'hookSpecificOutput': {
                    'hookEventName': input_data['hook_event_name'],
                    'permissionDecision': 'deny',
                    'permissionDecisionReason': 'Cannot modify .env files'
                }
            }
    
        # Return empty object to allow the operation
        return {}
    
    async def main():
        async for message in query(
            prompt="Update the database configuration",
            options=ClaudeAgentOptions(
                hooks={
                    # Register the hook for PreToolUse events
                    # The matcher filters to only Write and Edit tool calls
                    'PreToolUse': [HookMatcher(matcher='Write|Edit', hooks=[protect_env_files])]
                }
            )
        ):
            print(message)
    
    asyncio.run(main())

    這是一個 PreToolUse hook。它在工具執行之前執行,可以根據您的邏輯阻止或允許操作。本指南的其餘部分涵蓋所有可用的 hooks、它們的設定選項,以及常見使用案例的模式。

    可用的 hooks

    SDK 為代理執行的不同階段提供 hooks。某些 hooks 在兩個 SDK 中都可用,而其他的僅限 TypeScript,因為 Python SDK 不支援它們。

    Hook 事件Python SDKTypeScript SDK觸發條件範例使用案例
    PreToolUse是是工具呼叫請求(可阻止或修改)阻止危險的 shell 命令
    PostToolUse是是工具執行結果將所有檔案變更記錄到稽核軌跡
    PostToolUseFailure否是工具執行失敗處理或記錄工具錯誤
    UserPromptSubmit是是使用者提示提交將額外上下文注入提示
    Stop是是代理執行停止在退出前儲存工作階段狀態
    SubagentStart否是子代理初始化追蹤平行任務產生
    SubagentStop是是子代理完成彙總平行任務的結果
    PreCompact是是對話壓縮請求在摘要之前封存完整記錄
    PermissionRequest否是將顯示權限對話框自訂權限處理
    SessionStart否是工作階段初始化初始化日誌記錄和遙測
    SessionEnd否是工作階段終止清理臨時資源
    Notification否是代理狀態訊息將代理狀態更新傳送到 Slack 或 PagerDuty

    常見使用案例

    Hooks 足夠靈活,可以處理許多不同的場景。以下是按類別組織的一些最常見模式。

    設定 hooks

    要為您的代理設定 hook,請在呼叫 query() 時透過 options.hooks 參數傳遞 hook:

    async for message in query(
        prompt="Your prompt",
        options=ClaudeAgentOptions(
            hooks={
                'PreToolUse': [HookMatcher(matcher='Bash', hooks=[my_callback])]
            }
        )
    ):
        print(message)

    hooks 選項是一個字典(Python)或物件(TypeScript),其中:

    • 鍵是 hook 事件名稱(例如 'PreToolUse'、'PostToolUse'、'Stop')
    • 值是匹配器陣列,每個匹配器包含一個可選的篩選模式和您的回呼函式

    您的 hook 回呼函式接收關於事件的輸入資料,並回傳一個回應,讓代理知道要允許、阻止或修改操作。

    匹配器

    使用匹配器來篩選哪些工具觸發您的回呼:

    選項類型預設值描述
    matcherstringundefined用於匹配工具名稱的正規表達式模式。內建工具包括 Bash、Read、Write、Edit、Glob、Grep、WebFetch、Task 等。MCP 工具使用 mcp__<server>__<action> 模式。
    hooksHookCallback[]-必填。當模式匹配時要執行的回呼函式陣列
    timeoutnumber60逾時秒數;對於進行外部 API 呼叫的 hooks 請增加此值

    盡可能使用 matcher 模式來鎖定特定工具。使用 'Bash' 的匹配器只會對 Bash 命令執行,而省略模式則會對每個工具呼叫執行您的回呼。請注意,匹配器只按工具名稱篩選,不按檔案路徑或其他引數篩選——要按檔案路徑篩選,請在回呼內部檢查 tool_input.file_path。

    匹配器僅適用於基於工具的 hooks(PreToolUse、PostToolUse、PostToolUseFailure、PermissionRequest)。對於生命週期 hooks 如 Stop、SessionStart 和 Notification,匹配器會被忽略,hook 會對該類型的所有事件觸發。

    探索工具名稱: 在工作階段啟動時檢查初始系統訊息中的 tools 陣列,或新增一個沒有匹配器的 hook 來記錄所有工具呼叫。

    MCP 工具命名: MCP 工具始終以 mcp__ 開頭,後接伺服器名稱和操作:mcp__<server>__<action>。例如,如果您設定了一個名為 playwright 的伺服器,其工具將命名為 mcp__playwright__browser_screenshot、mcp__playwright__browser_click 等。伺服器名稱來自您在 mcpServers 設定中使用的鍵。

    此範例使用匹配器,僅在 PreToolUse 事件觸發時對檔案修改工具執行 hook:

    options = ClaudeAgentOptions(
        hooks={
            'PreToolUse': [
                HookMatcher(matcher='Write|Edit', hooks=[validate_file_path])
            ]
        }
    )

    回呼函式輸入

    每個 hook 回呼接收三個引數:

    1. 輸入資料(dict / HookInput):事件詳細資訊。請參閱輸入資料了解欄位
    2. 工具使用 ID(str | None / string | null):關聯 PreToolUse 和 PostToolUse 事件
    3. 上下文(HookContext):在 TypeScript 中,包含一個 signal 屬性(AbortSignal)用於取消。將此傳遞給 fetch() 等非同步操作,以便在 hook 逾時時自動取消。在 Python 中,此引數保留供未來使用。

    輸入資料

    hook 回呼的第一個引數包含關於事件的資訊。欄位名稱在兩個 SDK 中相同(都使用 snake_case)。

    通用欄位存在於所有 hook 類型中:

    欄位類型描述
    hook_event_namestringHook 類型(PreToolUse、PostToolUse 等)
    session_idstring目前工作階段識別碼
    transcript_pathstring對話記錄的路徑
    cwdstring目前工作目錄

    Hook 特定欄位因 hook 類型而異。標記 TS 的項目僅在 TypeScript SDK 中可用:

    欄位類型描述Hooks
    tool_namestring被呼叫的工具名稱PreToolUse、PostToolUse、PostToolUseFailureTS、PermissionRequestTS
    tool_inputobject傳遞給工具的引數PreToolUse、PostToolUse、PostToolUseFailureTS、PermissionRequestTS
    tool_responseany工具執行回傳的結果PostToolUse
    errorstring工具執行失敗的錯誤訊息PostToolUseFailureTS
    is_interruptboolean失敗是否由中斷引起PostToolUseFailureTS
    promptstring使用者的提示文字UserPromptSubmit
    stop_hook_activeboolean停止 hook 是否正在處理中Stop、SubagentStop
    agent_idstring子代理的唯一識別碼SubagentStartTS、SubagentStopTS
    agent_typestring子代理的類型/角色SubagentStartTS
    agent_transcript_pathstring子代理對話記錄的路徑SubagentStopTS
    triggerstring觸發壓縮的原因:manual 或 autoPreCompact
    custom_instructionsstring為壓縮提供的自訂指示PreCompact
    permission_suggestionsarray工具的建議權限更新PermissionRequestTS
    sourcestring工作階段如何啟動:startup、resume、clear 或 compactSessionStartTS
    reasonstring工作階段結束的原因:clear、logout、prompt_input_exit、bypass_permissions_disabled 或 otherSessionEndTS
    messagestring來自代理的狀態訊息NotificationTS
    notification_typestring通知類型:permission_prompt、idle_prompt、auth_success 或 elicitation_dialogNotificationTS
    titlestring代理設定的可選標題NotificationTS

    以下程式碼定義了一個 hook 回呼,使用 tool_name 和 tool_input 來記錄每個工具呼叫的詳細資訊:

    async def log_tool_calls(input_data, tool_use_id, context):
        if input_data['hook_event_name'] == 'PreToolUse':
            print(f"Tool: {input_data['tool_name']}")
            print(f"Input: {input_data['tool_input']}")
        return {}

    回呼輸出

    您的回呼函式回傳一個物件,告訴 SDK 如何繼續。回傳一個空物件 {} 以允許操作不做任何變更。要阻止、修改或為操作新增上下文,請回傳一個包含 hookSpecificOutput 欄位的物件,其中包含您的決定。

    頂層欄位(hookSpecificOutput 之外):

    欄位類型描述
    continueboolean代理是否應在此 hook 之後繼續(預設:true)
    stopReasonstring當 continue 為 false 時顯示的訊息
    suppressOutputboolean從記錄中隱藏 stdout(預設:false)
    systemMessagestring注入對話中供 Claude 查看的訊息

    hookSpecificOutput 內的欄位:

    欄位類型Hooks描述
    hookEventNamestring全部必填。使用 input.hook_event_name 來匹配目前事件
    permissionDecision'allow' | 'deny' | 'ask'PreToolUse控制工具是否執行
    permissionDecisionReasonstringPreToolUse向 Claude 顯示的決定說明
    updatedInputobjectPreToolUse修改後的工具輸入(需要 permissionDecision: 'allow')
    additionalContextstringPreToolUse、PostToolUse、UserPromptSubmit、SessionStartTS、SubagentStartTS新增到對話中的上下文

    此範例阻止對 /etc 目錄的寫入操作,同時注入系統訊息提醒 Claude 關於安全檔案操作的做法:

    async def block_etc_writes(input_data, tool_use_id, context):
        file_path = input_data['tool_input'].get('file_path', '')
    
        if file_path.startswith('/etc'):
            return {
                # Top-level field: inject guidance into the conversation
                'systemMessage': 'Remember: system directories like /etc are protected.',
                # hookSpecificOutput: block the operation
                'hookSpecificOutput': {
                    'hookEventName': input_data['hook_event_name'],
                    'permissionDecision': 'deny',
                    'permissionDecisionReason': 'Writing to /etc is not allowed'
                }
            }
        return {}

    權限決定流程

    當多個 hooks 或權限規則適用時,SDK 按以下順序評估它們:

    1. 首先檢查 Deny 規則(任何匹配 = 立即拒絕)。
    2. 其次檢查 Ask 規則。
    3. 第三檢查 Allow 規則。
    4. 如果沒有匹配,預設為 Ask。

    如果任何 hook 回傳 deny,操作將被阻止——其他 hook 回傳 allow 不會覆蓋它。

    阻止工具

    回傳拒絕決定以防止工具執行:

    async def block_dangerous_commands(input_data, tool_use_id, context):
        if input_data['hook_event_name'] != 'PreToolUse':
            return {}
    
        command = input_data['tool_input'].get('command', '')
    
        if 'rm -rf /' in command:
            return {
                'hookSpecificOutput': {
                    'hookEventName': input_data['hook_event_name'],
                    'permissionDecision': 'deny',
                    'permissionDecisionReason': 'Dangerous command blocked: rm -rf /'
                }
            }
        return {}

    修改工具輸入

    回傳更新後的輸入以變更工具接收的內容:

    async def redirect_to_sandbox(input_data, tool_use_id, context):
        if input_data['hook_event_name'] != 'PreToolUse':
            return {}
    
        if input_data['tool_name'] == 'Write':
            original_path = input_data['tool_input'].get('file_path', '')
            return {
                'hookSpecificOutput': {
                    'hookEventName': input_data['hook_event_name'],
                    'permissionDecision': 'allow',
                    'updatedInput': {
                        **input_data['tool_input'],
                        'file_path': f'/sandbox{original_path}'
                    }
                }
            }
        return {}

    使用 updatedInput 時,您還必須包含 permissionDecision。始終回傳一個新物件,而不是修改原始的 tool_input。

    新增系統訊息

    將上下文注入對話中:

    async def add_security_reminder(input_data, tool_use_id, context):
        return {
            'systemMessage': 'Remember to follow security best practices.'
        }

    自動核准特定工具

    繞過受信任工具的權限提示。當您希望某些操作無需使用者確認即可執行時,這很有用:

    async def auto_approve_read_only(input_data, tool_use_id, context):
        if input_data['hook_event_name'] != 'PreToolUse':
            return {}
    
        read_only_tools = ['Read', 'Glob', 'Grep', 'LS']
        if input_data['tool_name'] in read_only_tools:
            return {
                'hookSpecificOutput': {
                    'hookEventName': input_data['hook_event_name'],
                    'permissionDecision': 'allow',
                    'permissionDecisionReason': 'Read-only tool auto-approved'
                }
            }
        return {}

    permissionDecision 欄位接受三個值:'allow'(自動核准)、'deny'(阻止)或 'ask'(提示確認)。

    處理進階場景

    這些模式幫助您為複雜的使用案例建構更精密的 hook 系統。

    串連多個 hooks

    Hooks 按照它們在陣列中出現的順序執行。讓每個 hook 專注於單一職責,並串連多個 hooks 以實現複雜邏輯。此範例對每個工具呼叫執行所有四個 hooks(未指定匹配器):

    options = ClaudeAgentOptions(
        hooks={
            'PreToolUse': [
                HookMatcher(hooks=[rate_limiter]),        # First: check rate limits
                HookMatcher(hooks=[authorization_check]), # Second: verify permissions
                HookMatcher(hooks=[input_sanitizer]),     # Third: sanitize inputs
                HookMatcher(hooks=[audit_logger])         # Last: log the action
            ]
        }
    )

    使用正規表達式的工具特定匹配器

    使用正規表達式模式來匹配多個工具:

    options = ClaudeAgentOptions(
        hooks={
            'PreToolUse': [
                # Match file modification tools
                HookMatcher(matcher='Write|Edit|Delete', hooks=[file_security_hook]),
    
                # Match all MCP tools
                HookMatcher(matcher='^mcp__', hooks=[mcp_audit_hook]),
    
                # Match everything (no matcher)
                HookMatcher(hooks=[global_logger])
            ]
        }
    )

    匹配器只匹配工具名稱,不匹配檔案路徑或其他引數。要按檔案路徑篩選,請在 hook 回呼內部檢查 tool_input.file_path。

    追蹤子代理活動

    使用 SubagentStop hooks 來監控子代理完成。tool_use_id 有助於將父代理呼叫與其子代理關聯起來:

    async def subagent_tracker(input_data, tool_use_id, context):
        if input_data['hook_event_name'] == 'SubagentStop':
            print(f"[SUBAGENT] Completed")
            print(f"  Tool use ID: {tool_use_id}")
            print(f"  Stop hook active: {input_data.get('stop_hook_active')}")
        return {}
    
    options = ClaudeAgentOptions(
        hooks={
            'SubagentStop': [HookMatcher(hooks=[subagent_tracker])]
        }
    )

    hooks 中的非同步操作

    Hooks 可以執行非同步操作,例如 HTTP 請求。透過捕獲例外而非拋出例外來優雅地處理錯誤。在 TypeScript 中,將 signal 傳遞給 fetch() 以便在 hook 逾時時取消請求:

    import aiohttp
    from datetime import datetime
    
    async def webhook_notifier(input_data, tool_use_id, context):
        if input_data['hook_event_name'] != 'PostToolUse':
            return {}
    
        try:
            async with aiohttp.ClientSession() as session:
                await session.post(
                    'https://api.example.com/webhook',
                    json={
                        'tool': input_data['tool_name'],
                        'timestamp': datetime.now().isoformat()
                    }
                )
        except Exception as e:
            print(f'Webhook request failed: {e}')
    
        return {}

    傳送通知(僅限 TypeScript)

    使用 Notification hooks 接收來自代理的狀態更新,並將其轉發到外部服務,如 Slack 或監控儀表板:

    TypeScript
    import { query, HookCallback, NotificationHookInput } from "@anthropic-ai/claude-agent-sdk";
    
    const notificationHandler: HookCallback = async (input, toolUseID, { signal }) => {
      const notification = input as NotificationHookInput;
    
      await fetch('https://hooks.slack.com/services/YOUR/WEBHOOK/URL', {
        method: 'POST',
        body: JSON.stringify({
          text: `Agent status: ${notification.message}`
        }),
        signal
      });
    
      return {};
    };
    
    for await (const message of query({
      prompt: "Analyze this codebase",
      options: {
        hooks: {
          Notification: [{ hooks: [notificationHandler] }]
        }
      }
    })) {
      console.log(message);
    }

    修復常見問題

    本節涵蓋常見問題及其解決方法。

    Hook 未觸發

    • 驗證 hook 事件名稱正確且區分大小寫(PreToolUse,而非 preToolUse)
    • 檢查您的匹配器模式是否完全匹配工具名稱
    • 確保 hook 位於 options.hooks 中正確的事件類型下
    • 對於 SubagentStop、Stop、SessionStart、SessionEnd 和 Notification hooks,匹配器會被忽略。這些 hooks 會對該類型的所有事件觸發。
    • 當代理達到 max_turns 限制時,hooks 可能不會觸發,因為工作階段在 hooks 可以執行之前就結束了

    匹配器未按預期篩選

    匹配器只匹配工具名稱,不匹配檔案路徑或其他引數。要按檔案路徑篩選,請在 hook 內部檢查 tool_input.file_path:

    const myHook: HookCallback = async (input, toolUseID, { signal }) => {
      const preInput = input as PreToolUseHookInput;
      const filePath = preInput.tool_input?.file_path as string;
      if (!filePath?.endsWith('.md')) return {};  // Skip non-markdown files
      // Process markdown files...
    };

    Hook 逾時

    • 增加 HookMatcher 設定中的 timeout 值
    • 在 TypeScript 中使用第三個回呼引數中的 AbortSignal 來優雅地處理取消

    工具意外被阻止

    • 檢查所有 PreToolUse hooks 是否有 permissionDecision: 'deny' 的回傳
    • 在 hooks 中新增日誌記錄,以查看它們回傳的 permissionDecisionReason
    • 驗證匹配器模式是否過於寬泛(空匹配器匹配所有工具)

    修改後的輸入未套用

    • 確保 updatedInput 在 hookSpecificOutput 內部,而非頂層:

      return {
        hookSpecificOutput: {
          hookEventName: input.hook_event_name,
          permissionDecision: 'allow',
          updatedInput: { command: 'new command' }
        }
      };
    • 您還必須回傳 permissionDecision: 'allow' 才能使輸入修改生效

    • 在 hookSpecificOutput 中包含 hookEventName 以識別輸出對應的 hook 類型

    工作階段 hooks 不可用

    SessionStart、SessionEnd 和 Notification hooks 僅在 TypeScript SDK 中可用。由於設定限制,Python SDK 不支援這些事件。

    子代理權限提示倍增

    當產生多個子代理時,每個子代理可能會分別請求權限。子代理不會自動繼承父代理的權限。為避免重複提示,請使用 PreToolUse hooks 自動核准特定工具,或設定適用於子代理工作階段的權限規則。

    子代理的遞迴 hook 迴圈

    產生子代理的 UserPromptSubmit hook 如果這些子代理觸發相同的 hook,可能會建立無限迴圈。為防止這種情況:

    • 在產生之前檢查 hook 輸入中的子代理指示器
    • 使用 parent_tool_use_id 欄位來偵測您是否已在子代理上下文中
    • 將 hooks 的範圍限定為僅對頂層代理工作階段執行

    systemMessage 未出現在輸出中

    systemMessage 欄位將上下文新增到模型可見的對話中,但它可能不會出現在所有 SDK 輸出模式中。如果您需要將 hook 決定呈現給您的應用程式,請單獨記錄它們或使用專用的輸出通道。

    了解更多

    • 權限:控制您的代理可以做什麼
    • 自訂工具:建構工具以擴展代理功能
    • TypeScript SDK 參考
    • Python SDK 參考

    Was this page helpful?

    • 可用的 hooks
    • 設定 hooks
    • 串連多個 hooks
    • hooks 中的非同步操作
    • 傳送通知(僅限 TypeScript)
    • Hook 未觸發
    • Hook 逾時
    • 工作階段 hooks 不可用
    • 子代理的遞迴 hook 迴圈
    • systemMessage 未出現在輸出中