Loading...
    • Panduan Pengembang
    • Referensi API
    • MCP
    • Sumber daya
    • Catatan rilis
    Search...
    ⌘K
    Langkah pertama
    Pengenalan ClaudeMulai cepat
    Model & harga
    Ikhtisar modelMemilih modelYang baru di Claude 4.6Panduan migrasiPenghentian modelHarga
    Bangun dengan Claude
    Ikhtisar fiturMenggunakan Messages APIMenangani alasan berhentiPraktik terbaik prompting
    Manajemen konteks
    Jendela konteksKompresiPengeditan konteks
    Kemampuan
    Caching promptPemikiran diperpanjangPemikiran adaptifUpayaStreaming pesanPemrosesan batchKutipanDukungan multibahasaPenghitungan tokenEmbeddingsVisiDukungan PDFFiles APIHasil pencarianOutput terstruktur
    Alat
    IkhtisarCara mengimplementasikan penggunaan alatStreaming alat berbutir halusAlat BashAlat eksekusi kodePemanggilan alat terprogramAlat penggunaan komputerAlat editor teksAlat pengambilan webAlat pencarian webAlat memoriAlat pencarian alat
    Keterampilan Agen
    IkhtisarMulai cepatPraktik terbaikKeterampilan untuk perusahaanMenggunakan Keterampilan dengan API
    Agent SDK
    IkhtisarMulai cepatTypeScript SDKTypeScript V2 (pratinjau)Python SDKPanduan migrasi
    Input streamingStreaming respons secara real-timeMenangani alasan berhentiMenangani izinPersetujuan pengguna dan inputKontrol eksekusi dengan hookManajemen sesiCheckpointing fileOutput terstruktur di SDKHosting Agent SDKPenyebaran agen AI dengan amanMemodifikasi prompt sistemMCP di SDKAlat kustomSubagen di SDKPerintah garis miring di SDKKeterampilan agen di SDKPelacakan biaya dan penggunaanDaftar tugasPlugin di SDK
    MCP di API
    Konektor MCPServer MCP jarak jauh
    Claude di platform pihak ketiga
    Amazon BedrockMicrosoft FoundryVertex AI
    Rekayasa prompt
    IkhtisarGenerator promptGunakan template promptPenyempurna promptJadilah jelas dan langsungGunakan contoh (prompting multishot)Biarkan Claude berpikir (CoT)Gunakan tag XMLBerikan Claude peran (prompt sistem)Rantai prompt kompleksTips konteks panjangTips pemikiran diperpanjang
    Uji & evaluasi
    Tentukan kriteria kesuksesanKembangkan kasus ujiMenggunakan alat evaluasiMengurangi latensi
    Perkuat penjaga
    Kurangi halusinasiTingkatkan konsistensi outputMitigasi jailbreakStreaming penolakanKurangi kebocoran promptJaga Claude tetap dalam karakter
    Administrasi dan pemantauan
    Ikhtisar Admin APIResidensi dataRuang kerjaAPI penggunaan dan biayaClaude Code Analytics APIRetensi data nol
    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
    Panduan

    Menangani persetujuan dan input pengguna

    Tampilkan permintaan persetujuan Claude dan pertanyaan klarifikasi kepada pengguna, kemudian kembalikan keputusan mereka ke SDK.

    Saat mengerjakan tugas, Claude kadang-kadang perlu menghubungi pengguna. Mungkin perlu izin sebelum menghapus file, atau perlu menanyakan database mana yang akan digunakan untuk proyek baru. Aplikasi Anda perlu menampilkan permintaan ini kepada pengguna sehingga Claude dapat melanjutkan dengan input mereka.

    Claude meminta input pengguna dalam dua situasi: ketika membutuhkan izin untuk menggunakan alat (seperti menghapus file atau menjalankan perintah), dan ketika memiliki pertanyaan klarifikasi (melalui alat AskUserQuestion). Keduanya memicu callback canUseTool Anda, yang menghentikan eksekusi sampai Anda mengembalikan respons. Ini berbeda dari putaran percakapan normal di mana Claude selesai dan menunggu pesan berikutnya Anda.

    Untuk pertanyaan klarifikasi, Claude menghasilkan pertanyaan dan opsi. Peran Anda adalah menyajikannya kepada pengguna dan mengembalikan pilihan mereka. Anda tidak dapat menambahkan pertanyaan Anda sendiri ke alur ini; jika Anda perlu menanyakan sesuatu kepada pengguna, lakukan itu secara terpisah dalam logika aplikasi Anda.

    Panduan ini menunjukkan cara mendeteksi setiap jenis permintaan dan merespons dengan tepat.

    Deteksi ketika Claude membutuhkan input

    Berikan callback canUseTool dalam opsi kueri Anda. Callback dipicu setiap kali Claude membutuhkan input pengguna, menerima nama alat dan input sebagai argumen:

    async def handle_tool_request(tool_name, input_data, context):
        # Minta pengguna dan kembalikan izin atau tolak
        ...
    
    options = ClaudeAgentOptions(can_use_tool=handle_tool_request)

    Callback dipicu dalam dua kasus:

    1. Alat membutuhkan persetujuan: Claude ingin menggunakan alat yang tidak disetujui secara otomatis oleh aturan izin atau mode. Periksa tool_name untuk alat (misalnya, "Bash", "Write").
    2. Claude mengajukan pertanyaan: Claude memanggil alat AskUserQuestion. Periksa apakah tool_name == "AskUserQuestion" untuk menanganinya secara berbeda. Jika Anda menentukan array tools, sertakan AskUserQuestion agar ini berfungsi. Lihat Menangani pertanyaan klarifikasi untuk detail.

    Untuk secara otomatis mengizinkan atau menolak alat tanpa meminta pengguna, gunakan hook sebagai gantinya. Hook dijalankan sebelum canUseTool dan dapat mengizinkan, menolak, atau memodifikasi permintaan berdasarkan logika Anda sendiri. Anda juga dapat menggunakan hook PermissionRequest untuk mengirim notifikasi eksternal (Slack, email, push) ketika Claude menunggu persetujuan.

    Menangani permintaan persetujuan alat

    Setelah Anda melewatkan callback canUseTool dalam opsi kueri Anda, callback dipicu ketika Claude ingin menggunakan alat yang tidak disetujui secara otomatis. Callback Anda menerima dua argumen:

    ArgumenDeskripsi
    toolNameNama alat yang ingin digunakan Claude (misalnya, "Bash", "Write", "Edit")
    inputParameter yang Claude teruskan ke alat. Isi bervariasi menurut alat.

    Objek input berisi parameter khusus alat. Contoh umum:

    AlatBidang input
    Bashcommand, description, timeout
    Writefile_path, content
    Editfile_path, old_string, new_string
    Readfile_path, offset, limit

    Lihat referensi SDK untuk skema input lengkap: Python | TypeScript.

    Anda dapat menampilkan informasi ini kepada pengguna sehingga mereka dapat memutuskan apakah akan mengizinkan atau menolak tindakan, kemudian kembalikan respons yang sesuai.

    Contoh berikut meminta Claude untuk membuat dan menghapus file uji. Ketika Claude mencoba setiap operasi, callback mencetak permintaan alat ke terminal dan meminta persetujuan y/n.

    Di Python, can_use_tool memerlukan mode streaming dan hook PreToolUse yang mengembalikan {"continue_": True} untuk menjaga aliran tetap terbuka. Tanpa hook ini, aliran ditutup sebelum callback izin dapat dipanggil.

    Contoh ini menggunakan alur y/n di mana input apa pun selain y diperlakukan sebagai penolakan. Dalam praktik, Anda mungkin membangun UI yang lebih kaya yang memungkinkan pengguna memodifikasi permintaan, memberikan umpan balik, atau mengarahkan Claude sepenuhnya. Lihat Merespons permintaan alat untuk semua cara Anda dapat merespons.

    Merespons permintaan alat

    Callback Anda mengembalikan salah satu dari dua jenis respons:

    ResponsPythonTypeScript
    IzinkanPermissionResultAllow(updated_input=...){ behavior: "allow", updatedInput }
    TolakPermissionResultDeny(message=...){ behavior: "deny", message }

    Saat mengizinkan, berikan input alat (asli atau dimodifikasi). Saat menolak, berikan pesan yang menjelaskan alasannya. Claude melihat pesan ini dan mungkin menyesuaikan pendekatannya.

    from claude_agent_sdk.types import PermissionResultAllow, PermissionResultDeny
    
    # Izinkan alat untuk dijalankan
    return PermissionResultAllow(updated_input=input_data)
    
    # Blokir alat
    return PermissionResultDeny(message="User rejected this action")

    Selain mengizinkan atau menolak, Anda dapat memodifikasi input alat atau memberikan konteks yang membantu Claude menyesuaikan pendekatannya:

    • Setujui: biarkan alat dijalankan seperti yang diminta Claude
    • Setujui dengan perubahan: modifikasi input sebelum eksekusi (misalnya, sanitasi jalur, tambahkan batasan)
    • Tolak: blokir alat dan beri tahu Claude mengapa
    • Sarankan alternatif: blokir tetapi arahkan Claude ke arah yang diinginkan pengguna
    • Alihkan sepenuhnya: gunakan input streaming untuk mengirim Claude instruksi yang sama sekali baru

    Menangani pertanyaan klarifikasi

    Ketika Claude membutuhkan lebih banyak arahan tentang tugas dengan beberapa pendekatan yang valid, Claude memanggil alat AskUserQuestion. Ini memicu callback canUseTool Anda dengan toolName diatur ke AskUserQuestion. Input berisi pertanyaan Claude sebagai opsi pilihan ganda, yang Anda tampilkan kepada pengguna dan kembalikan pilihan mereka.

    Pertanyaan klarifikasi sangat umum dalam mode plan, di mana Claude menjelajahi basis kode dan mengajukan pertanyaan sebelum mengusulkan rencana. Ini membuat mode plan ideal untuk alur kerja interaktif di mana Anda ingin Claude mengumpulkan persyaratan sebelum membuat perubahan.

    Langkah-langkah berikut menunjukkan cara menangani pertanyaan klarifikasi:

    Format pertanyaan

    Input berisi pertanyaan yang dihasilkan Claude dalam array questions. Setiap pertanyaan memiliki bidang-bidang ini:

    BidangDeskripsi
    questionTeks pertanyaan lengkap untuk ditampilkan
    headerLabel pendek untuk pertanyaan (maks 12 karakter)
    optionsArray 2-4 pilihan, masing-masing dengan label dan description
    multiSelectJika true, pengguna dapat memilih beberapa opsi

    Berikut adalah contoh struktur yang akan Anda terima:

    {
      "questions": [
        {
          "question": "How should I format the output?",
          "header": "Format",
          "options": [
            { "label": "Summary", "description": "Brief overview of key points" },
            { "label": "Detailed", "description": "Full explanation with examples" }
          ],
          "multiSelect": false
        }
      ]
    }

    Format respons

    Kembalikan objek answers yang memetakan bidang question setiap pertanyaan ke label opsi yang dipilih:

    BidangDeskripsi
    questionsTeruskan array pertanyaan asli (diperlukan untuk pemrosesan alat)
    answersObjek di mana kunci adalah teks pertanyaan dan nilai adalah label yang dipilih

    Untuk pertanyaan multi-pilih, gabungkan beberapa label dengan ", ". Untuk input teks bebas, gunakan teks kustom pengguna secara langsung.

    {
      "questions": [...],
      "answers": {
        "How should I format the output?": "Summary",
        "Which sections should I include?": "Introduction, Conclusion"
      }
    }

    Dukung input teks bebas

    Opsi yang telah ditentukan Claude tidak akan selalu mencakup apa yang diinginkan pengguna. Untuk memungkinkan pengguna mengetik jawaban mereka sendiri:

    • Tampilkan pilihan "Other" tambahan setelah opsi Claude yang menerima input teks
    • Gunakan teks kustom pengguna sebagai nilai jawaban (bukan kata "Other")

    Lihat contoh lengkap di bawah untuk implementasi lengkap.

    Contoh lengkap

    Claude mengajukan pertanyaan klarifikasi ketika membutuhkan input pengguna untuk melanjutkan. Misalnya, ketika diminta membantu memutuskan tech stack untuk aplikasi seluler, Claude mungkin menanyakan tentang lintas platform vs native, preferensi backend, atau platform target. Pertanyaan-pertanyaan ini membantu Claude membuat keputusan yang sesuai dengan preferensi pengguna daripada menebak.

    Contoh ini menangani pertanyaan-pertanyaan tersebut dalam aplikasi terminal. Berikut yang terjadi di setiap langkah:

    1. Rute permintaan: Callback canUseTool memeriksa apakah nama alat adalah "AskUserQuestion" dan rute ke handler khusus
    2. Tampilkan pertanyaan: Handler melakukan loop melalui array questions dan mencetak setiap pertanyaan dengan opsi bernomor
    3. Kumpulkan input: Pengguna dapat memasukkan angka untuk memilih opsi, atau mengetik teks bebas langsung (misalnya, "jquery", "i don't know")
    4. Peta jawaban: Kode memeriksa apakah input adalah numerik (menggunakan label opsi) atau teks bebas (menggunakan teks langsung)
    5. Kembalikan ke Claude: Respons mencakup array questions asli dan pemetaan answers

    Keterbatasan

    • Subagents: AskUserQuestion saat ini tidak tersedia di subagents yang dihasilkan melalui alat Task
    • Batas pertanyaan: setiap panggilan AskUserQuestion mendukung 1-4 pertanyaan dengan 2-4 opsi masing-masing

    Cara lain untuk mendapatkan input pengguna

    Callback canUseTool dan alat AskUserQuestion mencakup sebagian besar skenario persetujuan dan klarifikasi, tetapi SDK menawarkan cara lain untuk mendapatkan input dari pengguna:

    Input streaming

    Gunakan input streaming ketika Anda perlu:

    • Mengganggu agen di tengah-tugas: kirim sinyal pembatalan atau ubah arah saat Claude sedang bekerja
    • Memberikan konteks tambahan: tambahkan informasi yang Claude butuhkan tanpa menunggu untuk ditanya
    • Membangun antarmuka obrolan: biarkan pengguna mengirim pesan lanjutan selama operasi yang berjalan lama

    Input streaming ideal untuk UI percakapan di mana pengguna berinteraksi dengan agen sepanjang eksekusi, bukan hanya di titik persetujuan.

    Alat kustom

    Gunakan alat kustom ketika Anda perlu:

    • Kumpulkan input terstruktur: bangun formulir, wizard, atau alur kerja multi-langkah yang melampaui format pilihan ganda AskUserQuestion
    • Integrasikan sistem persetujuan eksternal: terhubung ke platform tiket, alur kerja, atau persetujuan yang ada
    • Implementasikan interaksi khusus domain: buat alat yang disesuaikan dengan kebutuhan aplikasi Anda, seperti antarmuka tinjauan kode atau daftar periksa penyebaran

    Alat kustom memberi Anda kontrol penuh atas interaksi, tetapi memerlukan lebih banyak pekerjaan implementasi daripada menggunakan callback canUseTool bawaan.

    Sumber daya terkait

    • Konfigurasi izin: atur mode dan aturan izin
    • Kontrol eksekusi dengan hook: jalankan kode kustom di titik-titik kunci dalam siklus hidup agen
    • Referensi SDK TypeScript: dokumentasi API canUseTool lengkap

    Was this page helpful?

    • Deteksi ketika Claude membutuhkan input
    • Menangani permintaan persetujuan alat
    • Merespons permintaan alat
    • Menangani pertanyaan klarifikasi
    • Format pertanyaan
    • Format respons
    • Contoh lengkap
    • Keterbatasan
    • Cara lain untuk mendapatkan input pengguna
    • Input streaming
    • Alat kustom
    • Sumber daya terkait
    import asyncio
    
    from claude_agent_sdk import ClaudeAgentOptions, query
    from claude_agent_sdk.types import (
        HookMatcher,
        PermissionResultAllow,
        PermissionResultDeny,
        ToolPermissionContext,
    )
    
    
    async def can_use_tool(
        tool_name: str, input_data: dict, context: ToolPermissionContext
    ) -> PermissionResultAllow | PermissionResultDeny:
        # Tampilkan permintaan alat
        print(f"\nTool: {tool_name}")
        if tool_name == "Bash":
            print(f"Command: {input_data.get('command')}")
            if input_data.get("description"):
                print(f"Description: {input_data.get('description')}")
        else:
            print(f"Input: {input_data}")
    
        # Dapatkan persetujuan pengguna
        response = input("Allow this action? (y/n): ")
    
        # Kembalikan izin atau tolak berdasarkan respons pengguna
        if response.lower() == "y":
            # Izinkan: alat dijalankan dengan input asli (atau dimodifikasi)
            return PermissionResultAllow(updated_input=input_data)
        else:
            # Tolak: alat tidak dijalankan, Claude melihat pesan
            return PermissionResultDeny(message="User denied this action")
    
    
    # Solusi kerja yang diperlukan: hook dummy menjaga aliran tetap terbuka untuk can_use_tool
    async def dummy_hook(input_data, tool_use_id, context):
        return {"continue_": True}
    
    
    async def prompt_stream():
        yield {
            "type": "user",
            "message": {
                "role": "user",
                "content": "Create a test file in /tmp and then delete it",
            },
        }
    
    
    async def main():
        async for message in query(
            prompt=prompt_stream(),
            options=ClaudeAgentOptions(
                can_use_tool=can_use_tool,
                hooks={"PreToolUse": [HookMatcher(matcher=None, hooks=[dummy_hook])]},
            ),
        ):
            if hasattr(message, "result"):
                print(message.result)
    
    
    asyncio.run(main())
    1. 1

      Berikan callback canUseTool

      Berikan callback canUseTool dalam opsi kueri Anda. Secara default, AskUserQuestion tersedia. Jika Anda menentukan array tools untuk membatasi kemampuan Claude (misalnya, agen baca-saja dengan hanya Read, Glob, dan Grep), sertakan AskUserQuestion dalam array itu. Jika tidak, Claude tidak akan dapat mengajukan pertanyaan klarifikasi:

      async for message in query(
          prompt="Analyze this codebase",
          options=ClaudeAgentOptions(
              # Sertakan AskUserQuestion dalam daftar alat Anda
              tools=["Read", "Glob", "Grep", "AskUserQuestion"],
              can_use_tool=can_use_tool,
          ),
      ):
          # ...
    2. 2

      Deteksi AskUserQuestion

      Dalam callback Anda, periksa apakah toolName sama dengan AskUserQuestion untuk menanganinya secara berbeda dari alat lain:

      async def can_use_tool(tool_name: str, input_data: dict, context):
          if tool_name == "AskUserQuestion":
              # Implementasi Anda untuk mengumpulkan jawaban dari pengguna
              return await handle_clarifying_questions(input_data)
          # Tangani alat lain secara normal
          return await prompt_for_approval(tool_name, input_data)
    3. 3

      Analisis input pertanyaan

      Input berisi pertanyaan Claude dalam array questions. Setiap pertanyaan memiliki question (teks untuk ditampilkan), options (pilihan), dan multiSelect (apakah beberapa pilihan diizinkan):

      {
        "questions": [
          {
            "question": "How should I format the output?",
            "header": "Format",
            "options": [
              { "label": "Summary", "description": "Brief overview" },
              { "label": "Detailed", "description": "Full explanation" }
            ],
            "multiSelect": false
          },
          {
            "question": "Which sections should I include?",
            "header": "Sections",
            "options": [
              { "label": "Introduction", "description": "Opening context" },
              { "label": "Conclusion", "description": "Final summary" }
            ],
            "multiSelect": true
          }
        ]
      }

      Lihat Format pertanyaan untuk deskripsi bidang lengkap.

    4. 4

      Kumpulkan jawaban dari pengguna

      Presentasikan pertanyaan kepada pengguna dan kumpulkan pilihan mereka. Cara Anda melakukan ini tergantung pada aplikasi Anda: prompt terminal, formulir web, dialog seluler, dll.

    5. 5

      Kembalikan jawaban ke Claude

      Bangun objek answers sebagai catatan di mana setiap kunci adalah teks question dan setiap nilai adalah label opsi yang dipilih:

      Dari objek pertanyaanGunakan sebagai
      Bidang question (misalnya, "How should I format the output?")Kunci
      Bidang label opsi yang dipilih (misalnya, "Summary")Nilai

      Untuk pertanyaan multi-pilih, gabungkan beberapa label dengan ", ". Jika Anda mendukung input teks bebas, gunakan teks kustom pengguna sebagai nilainya.

      return PermissionResultAllow(
          updated_input={
              "questions": input_data.get("questions", []),
              "answers": {
                  "How should I format the output?": "Summary",
                  "Which sections should I include?": "Introduction, Conclusion"
              }
          }
      )
    import asyncio
    
    from claude_agent_sdk import ClaudeAgentOptions, query
    from claude_agent_sdk.types import HookMatcher, PermissionResultAllow
    
    
    def parse_response(response: str, options: list) -> str:
        """Analisis input pengguna sebagai nomor opsi atau teks bebas."""
        try:
            indices = [int(s.strip()) - 1 for s in response.split(",")]
            labels = [options[i]["label"] for i in indices if 0 <= i < len(options)]
            return ", ".join(labels) if labels else response
        except ValueError:
            return response
    
    
    async def handle_ask_user_question(input_data: dict) -> PermissionResultAllow:
        """Tampilkan pertanyaan Claude dan kumpulkan jawaban pengguna."""
        answers = {}
    
        for q in input_data.get("questions", []):
            print(f"\n{q['header']}: {q['question']}")
    
            options = q["options"]
            for i, opt in enumerate(options):
                print(f"  {i + 1}. {opt['label']} - {opt['description']}")
            if q.get("multiSelect"):
                print("  (Enter numbers separated by commas, or type your own answer)")
            else:
                print("  (Enter a number, or type your own answer)")
    
            response = input("Your choice: ").strip()
            answers[q["question"]] = parse_response(response, options)
    
        return PermissionResultAllow(
            updated_input={
                "questions": input_data.get("questions", []),
                "answers": answers,
            }
        )
    
    
    async def can_use_tool(tool_name: str, input_data: dict, context) -> PermissionResultAllow:
        # Rute AskUserQuestion ke handler pertanyaan kami
        if tool_name == "AskUserQuestion":
            return await handle_ask_user_question(input_data)
        # Auto-approve alat lain untuk contoh ini
        return PermissionResultAllow(updated_input=input_data)
    
    
    async def prompt_stream():
        yield {
            "type": "user",
            "message": {"role": "user", "content": "Help me decide on the tech stack for a new mobile app"},
        }
    
    
    # Solusi kerja yang diperlukan: hook dummy menjaga aliran tetap terbuka untuk can_use_tool
    async def dummy_hook(input_data, tool_use_id, context):
        return {"continue_": True}
    
    
    async def main():
        async for message in query(
            prompt=prompt_stream(),
            options=ClaudeAgentOptions(
                can_use_tool=can_use_tool,
                hooks={"PreToolUse": [HookMatcher(matcher=None, hooks=[dummy_hook])]},
            ),
        ):
            if hasattr(message, "result"):
                print(message.result)
    
    
    asyncio.run(main())