404 lines
17 KiB
Plaintext
404 lines
17 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b8c57858",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Ejen AI Azure dengan Sokongan Protokol Konteks Model (MCP) - Python\n",
|
|
"\n",
|
|
"Notebook ini menunjukkan cara menggunakan Ejen AI Azure dengan alat Protokol Konteks Model (MCP) dalam Python. Ia menunjukkan cara untuk mencipta ejen pintar yang boleh memanfaatkan pelayan MCP luaran (seperti Microsoft Learn) untuk keupayaan yang dipertingkatkan menggunakan pengesahan tanpa kunci.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "2e6e4234",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Pasang Pakej Python yang Diperlukan\n",
|
|
"\n",
|
|
"Pertama, kita perlu memasang pakej Python yang diperlukan:\n",
|
|
"- **azure-ai-projects**: SDK Projek Azure AI Teras\n",
|
|
"- **azure-ai-agents**: SDK Ejen Azure AI untuk mencipta dan mengurus ejen\n",
|
|
"- **azure-identity**: Menyediakan pengesahan tanpa kunci menggunakan DefaultAzureCredential\n",
|
|
"- **mcp**: Pelaksanaan Protokol Konteks Model untuk Python\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "6a2e9a05",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Kelebihan Pengesahan Tanpa Kunci\n",
|
|
"\n",
|
|
"Notebook ini menunjukkan **pengesahan tanpa kunci** yang memberikan beberapa kelebihan:\n",
|
|
"- ✅ **Tiada kunci API untuk diuruskan** - Menggunakan pengesahan berasaskan identiti Azure\n",
|
|
"- ✅ **Keselamatan yang dipertingkatkan** - Tiada rahsia disimpan dalam kod atau fail konfigurasi\n",
|
|
"- ✅ **Putaran kelayakan automatik** - Azure menguruskan kitaran hayat kelayakan\n",
|
|
"- ✅ **Kawalan akses berasaskan peranan** - Menggunakan Azure RBAC untuk kebenaran yang lebih terperinci\n",
|
|
"- ✅ **Sokongan pelbagai persekitaran** - Berfungsi dengan lancar di persekitaran pembangunan dan pengeluaran\n",
|
|
"\n",
|
|
"`DefaultAzureCredential` secara automatik memilih sumber kelayakan terbaik yang tersedia:\n",
|
|
"1. **Identiti Terurus** (apabila dijalankan di Azure)\n",
|
|
"2. Kelayakan **Azure CLI** (semasa pembangunan tempatan)\n",
|
|
"3. Kelayakan **Visual Studio**\n",
|
|
"4. **Pembolehubah persekitaran** (jika dikonfigurasi)\n",
|
|
"5. Pengesahan **penyemak imbas interaktif** (sebagai pilihan terakhir)\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "43efa94d",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Tetapan Pengesahan Tanpa Kunci\n",
|
|
"\n",
|
|
"**Prasyarat untuk pengesahan tanpa kunci:**\n",
|
|
"\n",
|
|
"### Untuk Pembangunan Tempatan:\n",
|
|
"```bash\n",
|
|
"# Install Azure CLI and login\n",
|
|
"az login\n",
|
|
"# Verify your identity\n",
|
|
"az account show\n",
|
|
"```\n",
|
|
"\n",
|
|
"### Untuk Persekitaran Azure:\n",
|
|
"- Aktifkan **Identiti Terurus yang Ditetapkan oleh Sistem** pada sumber Azure anda\n",
|
|
"- Tetapkan **peranan RBAC** yang sesuai kepada identiti terurus:\n",
|
|
" - `Cognitive Services OpenAI User` untuk akses Azure OpenAI\n",
|
|
" - `AI Developer` untuk akses Projek AI Azure\n",
|
|
"\n",
|
|
"### Pembolehubah Persekitaran (Pilihan):\n",
|
|
"```python\n",
|
|
"# These are automatically detected by DefaultAzureCredential\n",
|
|
"# AZURE_CLIENT_ID=<your-client-id>\n",
|
|
"# AZURE_CLIENT_SECRET=<your-client-secret>\n",
|
|
"# AZURE_TENANT_ID=<your-tenant-id>\n",
|
|
"```\n",
|
|
"\n",
|
|
"**Tiada kunci API atau rentetan sambungan diperlukan!** 🔐\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "2e21387d",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"! pip install azure-ai-projects -U\n",
|
|
"! pip install azure-ai-agents==1.1.0b4 -U\n",
|
|
"! pip install azure-identity -U\n",
|
|
"! pip install mcp==1.11.0 -U"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b31c8873",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Import Perpustakaan Diperlukan\n",
|
|
"\n",
|
|
"Import modul Python yang diperlukan:\n",
|
|
"- **os, time**: Perpustakaan standard Python untuk pembolehubah persekitaran dan kelewatan\n",
|
|
"- **AIProjectClient**: Klien utama untuk Projek AI Azure\n",
|
|
"- **DefaultAzureCredential**: Pengesahan tanpa kunci untuk perkhidmatan Azure\n",
|
|
"- **Kelas berkaitan MCP**: Untuk mencipta dan mengurus alat MCP serta mengendalikan kelulusan\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "43667b32",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import os, time\n",
|
|
"from azure.ai.projects import AIProjectClient\n",
|
|
"from azure.identity import DefaultAzureCredential\n",
|
|
"from azure.ai.agents.models import McpTool, RequiredMcpToolCall, SubmitToolApprovalAction, ToolApproval\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "721355e5",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Konfigurasi Tetapan Pelayan MCP\n",
|
|
"\n",
|
|
"Tetapkan konfigurasi pelayan MCP menggunakan pembolehubah persekitaran dengan nilai lalai sebagai sandaran:\n",
|
|
"- **MCP_SERVER_URL**: URL pelayan MCP (lalai kepada API Microsoft Learn)\n",
|
|
"- **MCP_SERVER_LABEL**: Label untuk mengenal pasti pelayan MCP (lalai kepada \"mslearn\")\n",
|
|
"\n",
|
|
"Pendekatan ini membolehkan konfigurasi yang fleksibel merentasi pelbagai persekitaran.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "189f3d55",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"mcp_server_url = os.environ.get(\"MCP_SERVER_URL\", \"https://learn.microsoft.com/api/mcp\")\n",
|
|
"mcp_server_label = os.environ.get(\"MCP_SERVER_LABEL\", \"mslearn\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "20612d9a",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Cipta Klien Projek Azure AI (Pengesahan Tanpa Kunci)\n",
|
|
"\n",
|
|
"Inisialisasi klien Projek Azure AI menggunakan **pengesahan tanpa kunci**:\n",
|
|
"- **endpoint**: URL endpoint projek Azure AI Foundry\n",
|
|
"- **credential**: Menggunakan `DefaultAzureCredential()` untuk pengesahan yang selamat dan tanpa kunci\n",
|
|
"- **Tiada kunci API diperlukan**: Secara automatik mengesan dan menggunakan kelayakan terbaik yang tersedia\n",
|
|
"\n",
|
|
"**Aliran Pengesahan:**\n",
|
|
"1. Memeriksa Managed Identity (dalam persekitaran Azure)\n",
|
|
"2. Beralih kepada kelayakan Azure CLI (untuk pembangunan tempatan)\n",
|
|
"3. Menggunakan sumber kelayakan lain yang tersedia jika diperlukan\n",
|
|
"\n",
|
|
"Pendekatan ini menghapuskan keperluan untuk mengurus kunci API atau rentetan sambungan dalam kod anda.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "36b1dbd8",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"project_client = AIProjectClient(\n",
|
|
" endpoint=\"Your Azure AI Foundry Endpoint\",\n",
|
|
" credential=DefaultAzureCredential(),\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cdb6ab8c",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Cipta Definisi Alat MCP\n",
|
|
"\n",
|
|
"Cipta alat MCP yang berhubung dengan pelayan MCP Microsoft Learn:\n",
|
|
"- **server_label**: Pengenal untuk pelayan MCP\n",
|
|
"- **server_url**: URL endpoint pelayan MCP\n",
|
|
"- **allowed_tools**: Senarai pilihan untuk mengehadkan alat yang boleh digunakan (senarai kosong membenarkan semua alat)\n",
|
|
"\n",
|
|
"Alat ini akan membolehkan ejen mengakses dokumentasi dan sumber Microsoft Learn.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "51e7e136",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"mcp_tool = McpTool(\n",
|
|
" server_label=mcp_server_label,\n",
|
|
" server_url=mcp_server_url,\n",
|
|
" allowed_tools=[], # Optional: specify allowed tools\n",
|
|
")\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "6e894b0b",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Cipta Ejen dan Laksanakan Perbualan (Aliran Kerja Tanpa Kunci)\n",
|
|
"\n",
|
|
"Bahagian komprehensif ini menunjukkan keseluruhan **aliran kerja ejen tanpa kunci**:\n",
|
|
"\n",
|
|
"1. **Cipta Ejen AI**: Sediakan ejen dengan model GPT-4.1 nano dan alat MCP\n",
|
|
"2. **Cipta Thread**: Wujudkan thread perbualan untuk komunikasi\n",
|
|
"3. **Hantar Mesej**: Tanyakan ejen tentang perbezaan antara Azure OpenAI dan OpenAI\n",
|
|
"4. **Kendalikan Kelulusan Alat**: Luluskan panggilan alat MCP secara automatik apabila diperlukan\n",
|
|
"5. **Pantau Pelaksanaan**: Jejaki kemajuan ejen dan kendalikan sebarang tindakan yang diperlukan\n",
|
|
"6. **Paparkan Hasil**: Tunjukkan perbualan dan butiran penggunaan alat\n",
|
|
"\n",
|
|
"**Ciri-ciri Tanpa Kunci:**\n",
|
|
"- ✅ **Tiada rahsia yang dikodkan secara keras** - Semua pengesahan dikendalikan oleh identiti Azure\n",
|
|
"- ✅ **Selamat secara lalai** - Menggunakan kawalan akses berasaskan peranan\n",
|
|
"- ✅ **Penyebaran dipermudahkan** - Tiada pengurusan kelayakan diperlukan\n",
|
|
"- ✅ **Mesra audit** - Semua akses dijejaki melalui identiti Azure\n",
|
|
"\n",
|
|
"Ejen akan menggunakan alat MCP untuk mengakses sumber Microsoft Learn dengan keselamatan penuh dan tanpa pengurusan kunci API.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "68c49af5",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"with project_client:\n",
|
|
" agents_client = project_client.agents\n",
|
|
"\n",
|
|
" # Create a new agent with keyless authentication\n",
|
|
" # NOTE: To reuse existing agent, fetch it with get_agent(agent_id)\n",
|
|
" agent = agents_client.create_agent(\n",
|
|
" model=\"Your Azure OpenAI Model Deployment Name\",\n",
|
|
" name=\"my-mcp-agent\",\n",
|
|
" instructions=\"You are a helpful agent that can use MCP tools to assist users. Use the available MCP tools to answer questions and perform tasks.\",\n",
|
|
" tools=mcp_tool.definitions,\n",
|
|
" )\n",
|
|
" print(f\"Created agent, ID: {agent.id}\")\n",
|
|
" print(f\"MCP Server: {mcp_tool.server_label} at {mcp_tool.server_url}\")\n",
|
|
"\n",
|
|
" # Create thread for communication\n",
|
|
" thread = agents_client.threads.create()\n",
|
|
" print(f\"Created thread, ID: {thread.id}\")\n",
|
|
"\n",
|
|
" # Create message to thread\n",
|
|
" message = agents_client.messages.create(\n",
|
|
" thread_id=thread.id,\n",
|
|
" role=\"user\",\n",
|
|
" content=\"What's difference between Azure OpenAI and OpenAI?\",\n",
|
|
" )\n",
|
|
" print(f\"Created message, ID: {message.id}\")\n",
|
|
"\n",
|
|
" # KEYLESS APPROACH: Handle tool approvals without hardcoded secrets\n",
|
|
" \n",
|
|
" # Option 1: Completely keyless (recommended for Azure identity-enabled MCP servers)\n",
|
|
" # run = agents_client.runs.create(thread_id=thread.id, agent_id=agent.id, tool_resources=mcp_tool.resources)\n",
|
|
" \n",
|
|
" # Option 2: With minimal headers (if MCP server requires specific headers)\n",
|
|
" # For demonstration purposes, using a placeholder header\n",
|
|
" mcp_tool.update_headers(\"SuperSecret\", \"123456\") # Replace with actual auth if needed\n",
|
|
" \n",
|
|
" # Set approval mode - uncomment next line to disable approval requirement completely\n",
|
|
" # mcp_tool.set_approval_mode(\"never\") # Fully automated, no approval needed\n",
|
|
" \n",
|
|
" run = agents_client.runs.create(thread_id=thread.id, agent_id=agent.id, tool_resources=mcp_tool.resources)\n",
|
|
" print(f\"Created run, ID: {run.id}\")\n",
|
|
"\n",
|
|
" while run.status in [\"queued\", \"in_progress\", \"requires_action\"]:\n",
|
|
" time.sleep(1)\n",
|
|
" run = agents_client.runs.get(thread_id=thread.id, run_id=run.id)\n",
|
|
"\n",
|
|
" if run.status == \"requires_action\" and isinstance(run.required_action, SubmitToolApprovalAction):\n",
|
|
" tool_calls = run.required_action.submit_tool_approval.tool_calls\n",
|
|
" if not tool_calls:\n",
|
|
" print(\"No tool calls provided - cancelling run\")\n",
|
|
" agents_client.runs.cancel(thread_id=thread.id, run_id=run.id)\n",
|
|
" break\n",
|
|
"\n",
|
|
" tool_approvals = []\n",
|
|
" for tool_call in tool_calls:\n",
|
|
" if isinstance(tool_call, RequiredMcpToolCall):\n",
|
|
" try:\n",
|
|
" print(f\"Approving tool call: {tool_call}\")\n",
|
|
" \n",
|
|
" # KEYLESS APPROVAL OPTIONS:\n",
|
|
" \n",
|
|
" # Option 1: No headers (fully keyless)\n",
|
|
" # tool_approvals.append(\n",
|
|
" # ToolApproval(\n",
|
|
" # tool_call_id=tool_call.id,\n",
|
|
" # approve=True,\n",
|
|
" # headers={} # No headers needed for keyless\n",
|
|
" # )\n",
|
|
" # )\n",
|
|
" \n",
|
|
" # Option 2: With headers (if MCP server requires them)\n",
|
|
" tool_approvals.append(\n",
|
|
" ToolApproval(\n",
|
|
" tool_call_id=tool_call.id,\n",
|
|
" approve=True,\n",
|
|
" headers=mcp_tool.headers, # Uses configured headers if needed\n",
|
|
" )\n",
|
|
" )\n",
|
|
" except Exception as e:\n",
|
|
" print(f\"Error approving tool_call {tool_call.id}: {e}\")\n",
|
|
"\n",
|
|
" print(f\"tool_approvals: {tool_approvals}\")\n",
|
|
" if tool_approvals:\n",
|
|
" agents_client.runs.submit_tool_outputs(\n",
|
|
" thread_id=thread.id, run_id=run.id, tool_approvals=tool_approvals\n",
|
|
" )\n",
|
|
"\n",
|
|
" print(f\"Current run status: {run.status}\")\n",
|
|
"\n",
|
|
" print(f\"Run completed with status: {run.status}\")\n",
|
|
" if run.status == \"failed\":\n",
|
|
" print(f\"Run failed: {run.last_error}\")\n",
|
|
"\n",
|
|
" # Display run steps and tool calls\n",
|
|
" run_steps = agents_client.run_steps.list(thread_id=thread.id, run_id=run.id)\n",
|
|
"\n",
|
|
" # Loop through each step\n",
|
|
" for step in run_steps:\n",
|
|
" print(f\"Step {step['id']} status: {step['status']}\")\n",
|
|
"\n",
|
|
" # Check if there are tool calls in the step details\n",
|
|
" step_details = step.get(\"step_details\", {})\n",
|
|
" tool_calls = step_details.get(\"tool_calls\", [])\n",
|
|
"\n",
|
|
" if tool_calls:\n",
|
|
" print(\" MCP Tool calls:\")\n",
|
|
" for call in tool_calls:\n",
|
|
" print(f\" Tool Call ID: {call.get('id')}\")\n",
|
|
" print(f\" Type: {call.get('type')}\")\n",
|
|
"\n",
|
|
" print() # add an extra newline between steps\n",
|
|
"\n",
|
|
" # Fetch and log all messages\n",
|
|
" messages = agents_client.messages.list(thread_id=thread.id)\n",
|
|
" print(\"\\nConversation:\")\n",
|
|
" print(\"-\" * 50)\n",
|
|
" for msg in messages:\n",
|
|
" if msg.text_messages:\n",
|
|
" last_text = msg.text_messages[-1]\n",
|
|
" print(f\"{msg.role.upper()}: {last_text.text.value}\")\n",
|
|
" print(\"-\" * 50)\n",
|
|
"\n",
|
|
" # Example of dynamic tool management (keyless)\n",
|
|
" print(f\"\\nDemonstrating keyless dynamic tool management:\")\n",
|
|
" print(f\"Current allowed tools: {mcp_tool.allowed_tools}\")\n",
|
|
" print(\"✅ All operations completed using keyless authentication!\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"\n---\n\n**Penafian**: \nDokumen ini telah diterjemahkan menggunakan perkhidmatan terjemahan AI [Co-op Translator](https://github.com/Azure/co-op-translator). Walaupun kami berusaha untuk memastikan ketepatan, sila ambil perhatian bahawa terjemahan automatik mungkin mengandungi kesilapan atau ketidaktepatan. Dokumen asal dalam bahasa asalnya harus dianggap sebagai sumber yang berwibawa. Untuk maklumat yang kritikal, terjemahan manusia profesional adalah disyorkan. Kami tidak bertanggungjawab atas sebarang salah faham atau salah tafsir yang timbul daripada penggunaan terjemahan ini.\n"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "demo",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.10.15"
|
|
},
|
|
"coopTranslator": {
|
|
"original_hash": "39a035fea0d10767dfcb0662bd3528fa",
|
|
"translation_date": "2025-08-26T21:37:45+00:00",
|
|
"source_file": "05-AdvancedTopics/mcp-foundry-agent-integration/mcp_support_python.ipynb",
|
|
"language_code": "ms"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
} |