{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Microsoft Agent Framework — Azure OpenAI（Responses API）\n",
    "\n",
    "在此代码示例中，您将使用 **Microsoft Agent Framework (MAF)** 来创建一个由 **Azure OpenAI** 支持的简单代理，使用的是 **Responses API**。\n",
    "\n",
    "> **迁移说明：** 该示例之前使用了 Semantic Kernel 和 GitHub Models。现在已迁移到 Microsoft Agent Framework，GitHub Models（已弃用，将于 2026 年 7 月退役）被 Azure OpenAI 所取代，Azure OpenAI 支持 Responses API。MAF 中的 `OpenAIChatClient` 目标是 Azure OpenAI 的稳定 `/openai/v1/` 端点，默认使用 Responses API。\n",
    "\n",
    "本示例的目的是演示后续其他代码示例中实现各种智能代理模式时将应用的步骤。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip install agent-framework agent-framework-openai azure-identity -q\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 导入所需的 Python 包\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import random\n",
    "\n",
    "from dotenv import load_dotenv\n",
    "from IPython.display import display, HTML\n",
    "\n",
    "from agent_framework import tool\n",
    "from agent_framework.openai import OpenAIChatClient\n",
    "from azure.identity import AzureCliCredential\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 定义工具\n",
    "\n",
    "在 Microsoft Agent Framework 中，<strong>工具</strong> 是一个使用 `@tool` 装饰的普通 Python 函数，代理可以调用它。下面我们定义了一个工具，该工具返回一个随机的度假目的地，并避免重复上一次的选择。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# A list of vacation destinations the tool can choose from.\n",
    "_DESTINATIONS = [\n",
    "    \"Barcelona, Spain\",\n",
    "    \"Paris, France\",\n",
    "    \"Berlin, Germany\",\n",
    "    \"Tokyo, Japan\",\n",
    "    \"Sydney, Australia\",\n",
    "    \"New York, USA\",\n",
    "    \"Cairo, Egypt\",\n",
    "    \"Cape Town, South Africa\",\n",
    "    \"Rio de Janeiro, Brazil\",\n",
    "    \"Bali, Indonesia\",\n",
    "]\n",
    "\n",
    "# Track the last destination so repeated calls avoid immediate repeats.\n",
    "_last_destination: str | None = None\n",
    "\n",
    "\n",
    "@tool(approval_mode=\"never_require\")\n",
    "def get_random_destination() -> str:\n",
    "    \"\"\"Provides a random vacation destination.\"\"\"\n",
    "    global _last_destination\n",
    "    available = _DESTINATIONS.copy()\n",
    "    if _last_destination and len(available) > 1:\n",
    "        available.remove(_last_destination)\n",
    "    destination = random.choice(available)\n",
    "    _last_destination = destination\n",
    "    return destination\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "load_dotenv()\n",
    "\n",
    "endpoint = os.environ[\"AZURE_OPENAI_ENDPOINT\"]\n",
    "deployment = os.environ[\"AZURE_OPENAI_DEPLOYMENT\"]\n",
    "\n",
    "# OpenAIChatClient targets Azure OpenAI's v1 endpoint and uses the Responses API.\n",
    "# Sign in with `az login` first so AzureCliCredential can authenticate.\n",
    "chat_client = OpenAIChatClient(\n",
    "    model=deployment,\n",
    "    azure_endpoint=endpoint,\n",
    "    credential=AzureCliCredential(),\n",
    ")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 创建代理\n",
    "\n",
    "在这里，我们创建名为 `TravelAgent` 的代理。\n",
    "\n",
    "在此示例中，我们使用非常基本的指令。您可以自由修改这些指令，以观察代理行为的变化。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "agent = chat_client.as_agent(\n",
    "    name=\"TravelAgent\",\n",
    "    instructions=\"You are a helpful AI Agent that can help plan vacations for customers at random destinations\",\n",
    "    tools=[get_random_destination],\n",
    ")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 运行代理\n",
    "\n",
    "现在我们可以运行代理了。我们创建一个 `AgentSession`，这样代理就能记住跨轮的对话，然后发送两个 `user_inputs`。第一个请求一个旅行计划；第二个表示用户不喜欢建议，并请求另一个——代理使用会话历史加上 `get_random_destination` 工具进行回应。\n",
    "\n",
    "你可以修改这些消息，观察代理的不同反应。响应是按<strong>令牌逐个</strong>流式传输的。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "user_inputs = [\n",
    "    \"Plan me a day trip.\",\n",
    "    \"I don't like that destination. Plan me another vacation.\",\n",
    "]\n",
    "\n",
    "\n",
    "async def main():\n",
    "    # A session keeps conversation history across turns.\n",
    "    session = agent.create_session()\n",
    "\n",
    "    for user_input in user_inputs:\n",
    "        html_output = (\n",
    "            f\"<div style='margin-bottom:10px'>\"\n",
    "            f\"<div style='font-weight:bold'>User:</div>\"\n",
    "            f\"<div style='margin-left:20px'>{user_input}</div></div>\"\n",
    "        )\n",
    "\n",
    "        full_response: list[str] = []\n",
    "        # Stream the agent's response token-by-token. The agent will call the\n",
    "        # get_random_destination tool automatically when it needs a destination.\n",
    "        async for chunk in agent.run(user_input, session=session, stream=True):\n",
    "            full_response.append(str(chunk))\n",
    "\n",
    "        html_output += (\n",
    "            \"<div style='margin-bottom:20px'>\"\n",
    "            f\"<div style='font-weight:bold'>TravelAgent:</div>\"\n",
    "            f\"<div style='margin-left:20px; white-space:pre-wrap'>{''.join(full_response)}</div></div><hr>\"\n",
    "        )\n",
    "\n",
    "        display(HTML(html_output))\n",
    "\n",
    "\n",
    "await main()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**免责声明**：\n本文件由 AI 翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 翻译完成。尽管我们力求准确，但请注意，自动翻译可能包含错误或不准确之处。原始语言版文件应视为权威来源。对于重要信息，建议使用专业人工翻译。我们对因使用本翻译而产生的任何误解或误释不承担责任。\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.12.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}