{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 目录\n", "- [关于 Guidance](../../../../code/01.Introduce)\n", "- [设置](../../../../code/01.Introduce)\n", "- [无约束生成](../../../../code/01.Introduce)\n", "- [Phi 3 的发言](../../../../code/01.Introduce)\n", "- [正则表达式](../../../../code/01.Introduce)\n", "- [选择](../../../../code/01.Introduce)\n", "- [思维链](../../../../code/01.Introduce)\n", "- [JSON 生成](../../../../code/01.Introduce)\n", "- [HTML 生成](../../../../code/01.Introduce)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 关于 Guidance\n", "Guidance 是一个经过验证的开源 Python 库,用于控制任何语言模型(LM)的输出。通过一次 API 调用,您可以在 Python 中表达模型必须遵循的精确程序约束,并生成 JSON、Python、HTML、SQL 或任何用例所需的结构化输出。\n", "\n", "Guidance 不同于传统的提示技术。它通过在推理层逐个引导模型的 token 来强制执行约束,从而生成更高质量的输出,并在处理高度结构化场景时将成本和延迟减少多达 30–50%。\n", "\n", "要了解有关 Guidance 的更多信息,请访问 [GitHub 上的公共仓库](https://github.com/guidance-ai/guidance) 或观看 Microsoft Build 的 [Guidance 分组会议](https://www.youtube.com/watch?v=qXMNPVVlCMs)。\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 设置\n", "1. 使用 `pip install guidance --pre` 安装 Guidance\n", "2. 在 Azure 部署一个 Phi 3.5 mini 端点,访问 https://ai.azure.com/explore/models/Phi-3.5-mini-instruct/version/2/registry/azureml 并点击“部署”按钮\n", "3. 将端点的 API 密钥存储在名为 `AZURE_PHI3_KEY` 的环境变量中,并将 URL 存储在名为 `AZURE_PHI3_URL` 的环境变量中\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from guidance import gen, select, regex, user, assistant, system, json\n", "from guidance.models import AzureGuidance\n", "from json import loads as load_json_str\n", "import os\n", "\n", "phi3_url = os.getenv(\"AZURE_PHI3_URL\")\n", "phi3_api_key = os.getenv(\"AZURE_PHI3_KEY\")\n", "phi3_lm = AzureGuidance(f\"{phi3_url}/guidance#auth={phi3_api_key}\")\n", "\n", "# Or, load from HuggingFace to run locally\n", "# from guidance.models import Transformers\n", "# phi3_lm = Transformers(\"microsoft/Phi-3-mini-4k-instruct\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 无约束生成\n", "可以使用 `gen()` 函数生成没有任何约束的文本。这与使用模型而不使用 Guidance 是相同的。\n", "\n", "## 聊天格式\n", "与许多聊天模型类似,Phi-3 期望用户和助手之间的消息以特定格式呈现。Guidance 支持 Phi-3 的聊天模板,并将为您管理聊天格式。要创建聊天轮次,请将对话的每一部分放在 `with user()` 或 `with assistant()` 块中。可以使用 `with system()` 块来设置系统消息。\n" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
system
You are a helpful assistant. You have a cranky yet entertaining temperament.
user
What is the capital of Australia?
assistant
The capital of Australia is Canberra. It's funny how most people think it's Sydney or Melbourne, isn't it? But hey, don't cry for the spoiled tourists - we all know the real scoop!
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "lm = phi3_lm\n", "with system():\n", " lm += \"You are a helpful assistant. You have a cranky yet entertaining temperament.\"\n", "with user():\n", " lm += \"What is the capital of Australia?\"\n", "with assistant():\n", " lm += gen(temperature=0.8, max_tokens=100)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 节省令牌\n", "在高度结构化的场景中,Guidance可以跳过不必要的令牌,仅生成所需的令牌,从而提升性能、提高效率并节省API成本。生成的令牌在此笔记本中以高亮背景显示。强制生成的令牌则不带高亮显示,其成本与输入令牌相同,估算为输出令牌成本的三分之一。\n", "\n", "*注意:* 第一个没有约束的生成示例无法强制任何令牌,因为我们没有提供任何约束条件。\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 为 Phi 3 发声 \n", "通过 Guidance,你可以轻松地将文本注入模型的响应中。如果你希望引导模型的输出朝某个特定方向发展,这将非常有用。\n" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
user
What is the capital of Australia?
assistant
The capital of Australia is Canberra. It is not Sydney or Melbourne, the cities most commonly associated with Australia, but rather Canberra. The capital was selected as a compromise between rivals Sydney and Melbourne, Australia's two largest cities. Canberra
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "lm = phi3_lm\n", "with user():\n", " lm += \"What is the capital of Australia?\"\n", "with assistant():\n", " lm += \"The capital of Australia is \" + gen(temperature=0.8, max_tokens=50)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 使用正则表达式进行约束\n", "在前面的例子中,Phi 3在回答问题并给出`Canberra`后,提供了后续的解释。为了将模型的输出限制为仅一个单词,可以使用正则表达式。\n" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
user
What is the capital of Australia?
assistant
The capital of Australia is Canberra
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "lm = phi3_lm\n", "with user():\n", " lm += \"What is the capital of Australia?\"\n", "with assistant():\n", " lm += \"The capital of Australia is \" + regex(\"[A-Z][a-z]+\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "使用正则表达式,仅生成单词`Canberra`。\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 从多个选项中进行选择\n", "当已知一些可能的选项时,可以使用 `select()` 函数让模型从选项列表中进行选择。\n" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
user
What is the capital of Australia?
assistant
The capital of Australia is Canberra
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "lm = phi3_lm\n", "with user():\n", " lm += \"What is the capital of Australia?\"\n", "with assistant():\n", " lm += \"The capital of Australia is \" + select([\"Washington\", \"Canberra\", \"Sydney\", \"Melbourne\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "使用 `select()` 时,仅生成了标记 `Can`。由于 `Canberra` 是唯一可能完成响应的选项,其余标记被强制生成。\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 思维链\n", "思维链是一种技术,可以通过鼓励模型逐步处理问题来提高输出质量。通常,为了得到最终答案,需要多次提示。首先,指示模型逐步思考。然后,再次提示模型提供最终答案。使用标准聊天推理API时,这需要进行两次API调用,模型生成的“思维链”会被收费两次——一次是模型生成时作为输出令牌收费,另一次是第二次调用时作为输入令牌收费。而使用Guidance,整个多步骤过程会作为单次API调用的一部分进行处理和收费,从而降低成本和延迟。\n" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
user
Mark has a garden with flowers. He planted plants of three different colors in it. Ten of them are yellow, and there are 80% more of those in purple. There are only 25% as many green flowers as there are yellow and purple flowers. How many flowers does Mark have in his garden?
assistant
Let's think step by step. First, we need to determine the number of purple flowers Mark has. We know there are 80% more purple flowers than yellow flowers. \n", "\n", "To find 80% of the yellow flowers, we calculate:\n", "80% of 10 yellow flowers = 0.80 * 10 = 8\n", "\n", "So there are 8 more purple flowers than yellow flowers. Since there are 10 yellow flowers, the number of purple flowers is:\n", "10 yellow flowers + 8 more purple flowers = 18 purple flowers\n", "\n", "Next, we need to find out how many green flowers there are. The problem states there are only 25% as many green flowers as there are yellow and purple flowers combined.\n", "\n", "First, let's find the total number of yellow and purple flowers:\n", "10 yellow flowers + 18 purple flowers = 28 flowers\n", "\n", "Now, calculate 25% of this total to find the number of green flowers:\n", "25% of 28 flowers = 0.25 * 28 = 7 green flowers\n", "\n", "Finally, to find the total number of flowers in Mark's garden, we add the yellow, purple, and green flowers together:\n", "10 yellow flowers + 18 purple flowers + 7 green flowers = 35 flowers\n", "\n", "Therefore, Mark has a total of 35 flowers in his garden.\n", "\n", "The answer is: 35. \n", "\n", "\n", "Therefore, the final answer is: 35
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Final answer: 35\n" ] } ], "source": [ "gsm8k_question = \"Mark has a garden with flowers. He planted plants of three different colors in it. Ten of them are yellow, and there are 80% more of those in purple. There are only 25% as many green flowers as there are yellow and purple flowers. How many flowers does Mark have in his garden?\"\n", "lm = phi3_lm\n", "with user():\n", " lm += gsm8k_question\n", "with assistant():\n", " lm += \"Let's think step by step. \" + gen(temperature=0.8, max_tokens=500)\n", " # Prompt for the final answer, which should be a number. Store the output in an \"answer\" variable.\n", " lm += \"\\nTherefore, the final answer is: \" + regex(r\"\\d+\", name=\"answer\")\n", "\n", "print(f\"Final answer: {lm['answer']}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# JSON 生成\n", "Guidance 可用于确保生成符合 JSON schema 或 pydantic 模型的 JSON,例如这里展示的用户配置文件 schema。\n" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
user
Generate a JSON object for a user profile. The profile should include a username, age, email, and nothing more.
assistant
{"username": "JohnDoe", "age": 29, "email": "john.doe@example.com"}
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "user_json_schema = load_json_str(\"\"\"{\n", " \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n", " \"title\": \"User Profile\",\n", " \"type\": \"object\",\n", " \"properties\": {\n", " \"username\": {\n", " \"type\": \"string\"\n", " },\n", " \"age\": {\n", " \"type\": \"integer\"\n", " },\n", " \"email\": {\n", " \"type\": \"string\"\n", " }\n", " },\n", " \"additionalProperties\": false\n", "}\n", "\"\"\")\n", "\n", "lm = phi3_lm\n", "with user():\n", " lm += \"Generate a JSON object for a user profile. The profile should include a username, age, email, and nothing more.\"\n", "\n", "with assistant():\n", " lm += json(schema=user_json_schema, temperature=1.0)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
user
Generate a JSON object for a user profile. The profile should include a username, age, email, and nothing more.
assistant
{"username":"tech_guru","age":45,"email":"tech.forlife@example.com"}
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from pydantic import BaseModel\n", "\n", "class UserProfile(BaseModel):\n", " username: str\n", " age: int\n", " email: str\n", "\n", "\n", "lm = phi3_lm\n", "with user():\n", " lm += \"Generate a JSON object for a user profile. The profile should include a username, age, email, and nothing more.\"\n", "\n", "with assistant():\n", " lm += json(schema=UserProfile, temperature=1.0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## HTML生成\n", "\n", "Guidance也可以用于生成代码,并遵循编程语言的语法要求。在本节中,我们将创建一个简单的Guidance程序,用于编写非常基础的HTML网页。\n", "\n", "我们会将网页分解成较小的部分,每个部分都有其独立的Guidance函数。然后在最终的函数中将这些部分组合起来,生成一个HTML网页。\n", "接着,我们会在Azure AI中运行这个函数,使用支持Guidance的模型。\n", "\n", "*注意:* 这不会是一个功能齐全的HTML生成器;目标是展示如何根据个人需求创建结构化输出。\n", "\n", "首先,我们从Guidance中导入所需内容:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from guidance import guidance\n", "from guidance.library import (\n", " zero_or_more,\n", " any_char_but,\n", " select,\n", " capture,\n", " with_temperature,\n", ")\n", "from guidance.models import Model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "HTML网页具有高度结构化,我们将使用Guidance来“强制”页面的这些部分。 \n", "当我们明确要求模型提供文本时,我们需要确保它不包含任何可能是标签的内容——也就是说,我们必须排除“<”和“>”字符。\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@guidance(stateless=True)\n", "def _gen_text(lm: Model):\n", " return lm + zero_or_more(any_char_but([\"<\", \">\"]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "然后我们可以使用此函数在任意HTML标签内生成文本:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@guidance(stateless=True)\n", "def _gen_text_in_tag(lm: Model, tag: str):\n", " lm += f\"<{tag}>\"\n", " lm += _gen_text()\n", " lm += f\"\"\n", " return lm" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "现在,让我们创建页面标题。 \n", "作为其中的一部分,我们需要生成一个页面标题:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@guidance(stateless=True)\n", "def _gen_header(lm: Model):\n", " lm += \"\\n\"\n", " lm += _gen_text_in_tag(\"title\") + \"\\n\"\n", " lm += \"\\n\"\n", " return lm" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "HTML页面的主体将会包含标题和段落。 \n", "我们可以定义一个函数来完成每项任务:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@guidance(stateless=True)\n", "def _gen_heading(lm: Model):\n", " lm += select(\n", " options=[_gen_text_in_tag(\"h1\"), _gen_text_in_tag(\"h2\"), _gen_text_in_tag(\"h3\")]\n", " )\n", " lm += \"\\n\"\n", " return lm\n", "\n", "@guidance(stateless=True)\n", "def _gen_para(lm: Model):\n", " lm += _gen_text_in_tag(\"p\")\n", " lm += \"\\n\"\n", " return lm" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "现在定义 HTML 主体的函数。 \n", "这里使用 `select()` 并设置 `recurse=True` 来生成多个标题和段落:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@guidance(stateless=True)\n", "def _gen_body(lm: Model):\n", " lm += \"\\n\"\n", " lm += select(options=[_gen_heading(), _gen_para()], recurse=True)\n", " lm += \"\\n\"\n", " return lm" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "接下来,我们来看生成完整HTML页面的函数。 \n", "我们先添加HTML起始标签,然后生成头部,再生成主体,最后添加结束HTML标签:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@guidance(stateless=True)\n", "def _gen_html(lm: Model):\n", " lm += \"\\n\"\n", " lm += _gen_header()\n", " lm += _gen_body()\n", " lm += \"\\n\"\n", " return lm" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "我们提供了一个用户友好的封装器,它将允许我们:\n", "- 设置生成的温度\n", "- 从 Model 对象中捕获生成的页面\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@guidance(stateless=True)\n", "def html(\n", " lm,\n", " name: str | None = None,\n", " *,\n", " temperature: float = 0.0,\n", "):\n", " return lm + capture(\n", " with_temperature(_gen_html(), temperature=temperature),\n", " name=name,\n", " )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Create a web page about your life story. Split your uplifting tale into multiple paragraphs with headings:\n",
       "<html>\n",
       "<head>\n",
       "<title>My Life Story</title>\n",
       "</head>\n",
       "<body>\n",
       "<h1>My Life Story</h1>\n",
       "<p></p>\n",
       "<h2>Early Years</h2>\n",
       "<p>I was born and raised in a small town in the Midwest. From a young age, I was fascinated by the world around me and had a natural curiosity that drove me to explore and learn. Despite the challenges of growing up in a tight-knit community, I was fortunate to have a supportive family and a strong sense of community that helped me develop a resilient and optimistic outlook on life.</p>\n",
       "<h2>Education and Career</h2>\n",
       "<p>After graduating from high school, I pursued a degree in engineering at a prestigious university. I was passionate about using my skills to make a positive impact on the world and worked hard to excel in my studies. Upon graduation, I landed a job at a leading tech company, where I quickly rose through the ranks and became a respected leader in my field.</p>\n",
       "<p>Throughout my career, I have been driven by a desire to innovate and create new solutions to complex problems. I have been fortunate to work on a variety of exciting projects, from developing cutting-edge software to designing sustainable energy systems. I have also had the opportunity to travel the world and collaborate with talented individuals from diverse backgrounds.</p>\n",
       "<h2>Personal Growth and Achievements</h2>\n",
       "<p>Outside of work, I have always been committed to personal growth and self-improvement. I have taken courses in meditation, yoga, and mindfulness, and have found that these practices have helped me cultivate a sense of inner peace and balance. I have also been an avid runner and have completed several marathons, which has taught me the importance of perseverance and discipline.</p>\n",
       "<p>In addition to my professional and personal pursuits, I have also been involved in various charitable organizations and have volunteered my time to help those in need. I believe that giving back to the community is an essential part of living a fulfilling life, and I am proud to have made a positive impact in the lives of others.</p>\n",
       "<h2>Conclusion</h2>\n",
       "<p>Looking back on my life, I am grateful for all the experiences and opportunities that have shaped me into the person I am today. I have faced many challenges and setbacks along the way, but I have always remained optimistic and focused on my goals. I am excited to continue growing and learning, and I am committed to using my skills and talents to make a positive impact on the world.</p>\n",
       "</body>\n",
       "</html>\n",
       "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "lm = phi3_lm\n", "\n", "lm += \"Create a web page about your life story. Split your uplifting tale into multiple paragraphs with headings:\\n\"\n", "lm += html(name=\"html_text\", temperature=0.7)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "然后我们可以将输出写入文件:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "with open('./sample_page.html', 'w') as html_file:\n", " html_file.write(lm[\"html_text\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "并[查看结果](../../../../code/01.Introduce/sample_page.html)。\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n---\n\n**免责声明**: \n本文档使用AI翻译服务 [Co-op Translator](https://github.com/Azure/co-op-translator) 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们不对因使用此翻译而产生的任何误解或误读承担责任。\n" ] } ], "metadata": { "kernelspec": { "display_name": "env", "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.6" }, "coopTranslator": { "original_hash": "b1016a6564e31ce413d76659b11effa8", "translation_date": "2025-09-12T16:43:24+00:00", "source_file": "code/01.Introduce/guidance.ipynb", "language_code": "zh" } }, "nbformat": 4, "nbformat_minor": 2 }