ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

generative-ai-for-beginners 实战:使用 Azure OpenAI Function Calling(函数调用)构建结构化、可扩展的 AI 应用

generative-ai-for-beginners 实战:使用 Azure OpenAI Function Calling(函数调用)构建结构化、可扩展的 AI 应用 generative-ai-for-beginners 实战使用 Azure OpenAI Function Calling函数调用构建结构化、可扩展的 AI 应用【免费下载链接】generative-ai-for-beginners21 Lessons, Get Started Building with Generative AI项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai-for-beginners本文是开源课程 generative-ai-for-beginners 第 11 课的技术实战指南围绕函数调用Function Calling这一 Azure OpenAI Service 核心能力展开。你将学会函数调用如何解决 LLM 响应格式不一致、无法访问外部数据这两大痛点如何从零定义一个search_courses函数并完成用户消息 → 模型返回调用意图 → 应用执行真实 API → 二次请求生成自然语言回复的完整闭环最终把它集成进真实的教育课程推荐聊天机器人场景。为什么需要函数调用LLM 的两个根本局限在函数调用出现之前从大语言模型LLM拿到的响应是非结构化且不一致的。开发者必须编写大量复杂的校验代码才能处理每一种响应变体同时模型受限于训练数据的截止时间无法回答斯德哥尔摩现在的天气如何这类需要实时数据的问题。函数调用Function Calling正是 Azure OpenAI Service 为克服这两大局限而提供的能力一致的响应格式Consistent response format更好地控制响应格式就能更轻松地把响应集成到下游系统外部数据接入External data能够在聊天上下文中使用应用其他来源的数据。想亲手运行下面的演示推荐直接使用仓库自带的 Notebookaoai-assignment.ipynbAzure OpenAI 版或 oai-assignment.ipynbOpenAI 版也可以先跟着文字理解函数能解决的问题。用场景演示问题同样的提示词返回的 JSON 却不一样假设我们要为教育创业项目建立一个学生数据库以便向学生推荐合适的课程。下面有两份数据结构非常相似的学生描述student_1_descriptionEmily Johnson is a sophomore majoring in computer science at Duke University. She has a 3.7 GPA. Emily is an active member of the universitys Chess Club and Debate Team. She hopes to pursue a career in software engineering after graduating. student_2_description Michael Lee is a sophomore majoring in computer science at Stanford University. He has a 3.8 GPA. Michael is known for his programming skills and is an active member of the universitys Robotics Club. He hopes to pursue a career in artificial intelligence after finishing his studies.首先建立与 Azure OpenAI 资源的连接文档中的经典AzureOpenAI客户端写法import os import json from openai import AzureOpenAI from dotenv import load_dotenv load_dotenv() client AzureOpenAI( api_keyos.environ[AZURE_OPENAI_API_KEY], # 默认读取该环境变量可省略 api_version 2023-07-01-preview ) deployment os.environ[AZURE_OPENAI_DEPLOYMENT]说明仓库中的新版 Notebook 已迁移到基于/openai/v1/端点的 Responses API 写法详见下文仓库中的多框架实现对照但函数调用的核心逻辑一致。旧版api_version、api_key、deployment环境变量配置方式仍可参考本文。接着构造两个完全相同的提示词要求 LLM 从文本中抽取指定字段并以 JSON 对象返回prompt1 f Please extract the following information from the given text and return it as a JSON object: name major school grades club This is the body of text to extract the information from: {student_1_description} prompt2 f Please extract the following information from the given text and return it as a JSON object: name major school grades club This is the body of text to extract the information from: {student_2_description} 然后通过client.chat.completions.create发送请求messages中角色设为user以模拟用户在聊天框中输入# response from prompt one openai_response1 client.chat.completions.create( modeldeployment, messages [{role: user, content: prompt1}] ) openai_response1.choices[0].message.content # response from prompt two openai_response2 client.chat.completions.create( modeldeployment, messages [{role: user, content: prompt2}] ) openai_response2.choices[0].message.content最后用json.loads把响应解析为 JSON 对象# Loading the response as a JSON object json_response1 json.loads(openai_response1.choices[0].message.content) json_response1两次返回的结果分别是{ name: Emily Johnson, major: computer science, school: Duke University, grades: 3.7, club: Chess Club }{ name: Michael Lee, major: computer science, school: Stanford University, grades: 3.8 GPA, club: Robotics Club }尽管提示词完全相同、描述也高度相似Grades属性的值却出现了3.7和3.7 GPA两种格式多次运行甚至可能互换。根本原因在于LLM 接收的是书面提示词这种非结构化数据返回的也必然是非结构化数据。当我们要存储或消费这些数据时必须依赖确定性的格式。函数调用的核心原理模型不执行函数只返回调用意图解决格式问题的方法就是函数调用。需要特别强调的是使用函数调用时LLM 并不会真正调用或运行任何函数。相反我们为 LLM 创建一个必须遵循的响应结构函数定义模型按这个结构返回想调用哪个函数、传入什么参数然后由我们自己的应用代码根据这个结构化响应去执行真实的函数或 API 请求。流程如下对应上方的 Function-Flow 图用户发送消息 → LLM 根据函数元数据判断并产出结构化调用意图 → 应用执行函数如find_course(skill, product)→ 把函数返回值再送回 LLM → LLM 用自然语言回答用户的原始问题。函数调用的典型使用场景函数调用能显著提升应用能力常见场景包括调用外部工具Calling External Tools聊天机器人擅长回答用户问题借助函数调用机器人可以用用户消息去完成具体任务。例如学生请求给我的老师发一封邮件说我需要这门课的更多帮助可映射为一次send_email(to: string, body: string)函数调用。创建 API 或数据库查询Create API or Database Queries用户用自然语言查找信息被转换为格式化查询或 API 请求。例如老师问哪些学生完成了最后一次作业可调用get_completed(student_name: string, assignment: int, current_status: string)。生成结构化数据Creating Structured Data用户粘贴一段文本或 CSV让 LLM 抽取关键信息。例如学生把一篇关于和平协议的维基百科文章转成 AI 闪卡可调用get_important_facts(agreement_name: string, date_signed: string, parties_involved: list)。创建你的第一个函数调用Azure OpenAI 版创建一次函数调用包含 3 个主要步骤调用Chat Completions API同时传入你的函数列表和用户消息读取模型响应以执行动作执行函数或发起 API 调用再次调用Chat Completions API把函数响应一并传入让模型基于这些信息生成面向用户的回复。步骤 1创建用户消息消息可以动态取自文本输入框的值也可以在此直接赋值。role可以是system设定规则、assistant模型或user最终用户对函数调用我们将其设为usermessages [ {role: user, content: Find me a good course for a beginner student to learn Azure.} ]通过区分不同的角色LLM 能清楚判断是系统在说话还是用户在说话这有助于构建可供 LLM 持续扩展的对话历史。步骤 2创建函数定义接下来定义函数及其参数。这里只用到一个名为search_courses的函数你也可以一次定义多个函数。重要提示函数会随系统消息一起发送给 LLM并计入你可用的 token 数量因此函数定义应保持精简。函数以数组形式创建每个元素就是一个函数包含name、description、parameters三个属性functions [ { name:search_courses, description:Retrieves courses from the search index based on the parameters provided, parameters:{ type:object, properties:{ role:{ type:string, description:The role of the learner (i.e. developer, data scientist, student, etc.) }, product:{ type:string, description:The product that the lesson is covering (i.e. Azure, Power BI, etc.) }, level:{ type:string, description:The level of experience the learner has prior to taking the course (i.e. beginner, intermediate, advanced) } }, required:[ role ] } } ]逐层拆解这个定义结构层级字段含义顶层name希望被调用的函数名称顶层description函数如何工作的说明务必具体、清晰顶层parameters希望模型在响应中产出的值列表与格式参数对象type参数对象的数据类型通常是object参数对象properties模型响应将使用的具体取值列表单个参数键名模型在格式化响应中使用的属性名例如product单个参数type该属性的数据类型例如string单个参数description该属性的具体说明可选required完成函数调用所必需的属性数组步骤 3发起函数调用定义完函数后把它加入 Chat Completion API 请求——通过functionsfunctions传入。同时可把function_call设为auto这意味着由 LLM 根据用户消息自行决定该调用哪个函数而不是由我们硬编码response client.chat.completions.create(modeldeployment, messagesmessages, functionsfunctions, function_callauto) print(response.choices[0].message)返回的响应如下{ role: assistant, function_call: { name: search_courses, arguments: {\n \role\: \student\,\n \product\: \Azure\,\n \level\: \beginner\\n} } }可以看到search_courses被选中并携带了参数参数值来自arguments属性。LLM 之所以能匹配出这些参数是因为它从messages中提取了关键信息——回顾我们传入的消息messages [ {role: user, content: Find me a good course for a beginner student to learn Azure.} ]student、Azure、beginner正是从这条消息中被抽取出来、填入函数参数的。这种用法既能从提示词中提取信息又能给 LLM 提供结构、沉淀可复用的功能。将函数调用集成进应用程序在验证了 LLM 的格式化响应后就可以把它集成进应用了。管理完整调用流第一步调用 OpenAI 服务并把消息存入response_message变量response_message response.choices[0].message第二步定义真正会调用 Microsoft Learn API 的 Python 函数注意函数名必须与functions变量中声明的名称一致import requests def search_courses(role, product, level): url https://learn.microsoft.com/api/catalog/ params { role: role, product: product, level: level } response requests.get(url, paramsparams) modules response.json()[modules] results [] for module in modules[:5]: title module[title] url module[url] results.append({title: title, url: url}) return str(results)这里我们建立了与functions变量中声明的函数名一一对应的真实 Python 函数并发起了真实的外部 API 请求Microsoft Learn API 搜索训练模块。第三步检查 LLM 响应中是否包含function_call若包含则调用指定函数并把助手调用意图与函数返回结果都追加进messages# Check if the model wants to call a function if response_message.function_call.name: print(Recommended Function call:) print(response_message.function_call.name) print() # Call the function. function_name response_message.function_call.name available_functions { search_courses: search_courses, } function_to_call available_functions[function_name] function_args json.loads(response_message.function_call.arguments) function_response function_to_call(**function_args) print(Output of function call:) print(function_response) print(type(function_response)) # Add the assistant response and function response to the messages messages.append( # adding assistant response to messages { role: response_message.role, function_call: { name: function_name, arguments: response_message.function_call.arguments, }, content: None } ) messages.append( # adding function response to messages { role: function, name: function_name, content:function_response, } )核心的三行逻辑是提取函数名 → 解析参数 → 实际调用function_to_call available_functions[function_name] function_args json.loads(response_message.function_call.arguments) function_response function_to_call(**function_args)运行上述代码后得到的输出Recommended Function call: { name: search_courses, arguments: {\n \role\: \student\,\n \product\: \Azure\,\n \level\: \beginner\\n} } Output of function call: [{title: Describe concepts of cryptography, url: https://learn.microsoft.com/training/modules/describe-concepts-of-cryptography/?WT.mc_idapi_CatalogApi}, {title: Introduction to audio classification with TensorFlow, url: https://learn.microsoft.com/en-us/training/modules/intro-audio-classification-tensorflow/?WT.mc_idapi_CatalogApi}, {title: Design a Performant Data Model in Azure SQL Database with Azure Data Studio, url: https://learn.microsoft.com/training/modules/design-a-data-model-with-ads/?WT.mc_idapi_CatalogApi}, {title: Getting started with the Microsoft Cloud Adoption Framework for Azure, url: https://learn.microsoft.com/training/modules/cloud-adoption-framework-getting-started/?WT.mc_idapi_CatalogApi}, {title: Set up the Rust development environment, url: https://learn.microsoft.com/training/modules/rust-set-up-environment/?WT.mc_idapi_CatalogApi}] class str第四步把更新后的messages再次发送给 LLM让它把API JSON 格式的结果转化为自然语言回答print(Messages in next request:) print(messages) print() second_response client.chat.completions.create( messagesmessages, modeldeployment, function_callauto, functionsfunctions, temperature0 ) # get a new response from GPT where it can see the function response print(second_response.choices[0].message)输出结果{ role: assistant, content: I found some good courses for beginner students to learn Azure:\n\n1. [Describe concepts of cryptography](https://learn.microsoft.com/training/modules/describe-concepts-of-cryptography/?WT.mc_idapi_CatalogApi)\n2. [Introduction to audio classification with TensorFlow](https://learn.microsoft.com/training/modules/intro-audio-classification-tensorflow/?WT.mc_idapi_CatalogApi)\n3. [Design a Performant Data Model in Azure SQL Database with Azure Data Studio](https://learn.microsoft.com/training/modules/design-a-data-model-with-ads/?WT.mc_idapi_CatalogApi)\n4. [Getting started with the Microsoft Cloud Adoption Framework for Azure](https://learn.microsoft.com/training/modules/cloud-adoption-framework-getting-started/?WT.mc_idapi_CatalogApi)\n5. [Set up the Rust development environment](https://learn.microsoft.com/training/modules/rust-set-up-environment/?WT.mc_idapi_CatalogApi)\n\nYou can click on the links to access the courses. }至此用户获得了带可点击课程链接的自然语言回复——这正是LLM 不执行函数、由应用执行并回填结果的完整闭环。仓库中的多框架实现对照课程仓库为这一课提供了多语言、多接口的实现可以作为本文代码的对照与进阶参考新版 Responses API推荐仓库中的 oai-assignment.ipynb 与 aoai-assignment.ipynb 已改用client.responses.create函数以扁平化的tools数组传入顶层包含type: function、name、description、parameters并用tool_choiceauto代替function_callauto模型响应中通过response.output里的function_call条目携带call_id与arguments函数结果则追加为function_call_output条目call_id必须与模型的调用条目一一对应最后用output_text读取自然语言回复。连接方式也简化为base_urlf{endpoint}/openai/v1/无需再传api_version。TypeScript 版本function-app/src/main.ts 演示了 Responses API 真实 Bing Maps 天气查询值得关注的点包括用enum约束参数取值如温度单位C/F、对 JSON 解析做 try/catch 安全处理、JSON.parse(item.arguments || {})兜底、以及缺失必填参数时的防御性continue。JavaScript 版本js-githubmodels/app.js 基于azure-rest/ai-inferenceSDK 演示机票/酒店查询场景包含两个关键安全实践调用前用Object.prototype.hasOwnProperty.call(namesToFunctions, functionName)校验函数名是否在白名单内防止未知函数注入对tool_calls数量与类型做显式断言并依靠finish_reason tool_calls判断是否需要执行工具。从源码结构看仓库把这节课定位为函数调用的模式模板无论底层是 Chat Completions 还是 Responses API、无论语言是 Python / TypeScript / JavaScript定义函数 Schema → 模型返回调用意图 → 应用执行并回填 → 模型生成最终回复的四段式骨架完全一致。练习与进阶方向为了继续深入 Azure OpenAI Function Calling文档建议你动手构建更丰富的函数参数为search_courses增加更多参数帮助学习者找到更多课程可参考 Microsoft Learn Catalog API 的开发者参考文档查看可用参数及位置新的函数调用创建另一个函数接收学习者的更多信息例如母语错误处理为函数调用/API 调用未返回合适课程的情况增加兜底错误处理逻辑。小结与下一步本课围绕响应格式一致 外部数据接入两个目标完整演示了函数调用从问题复现、Schema 定义、发起调用到应用集成的全过程。核心要点可以总结为函数定义是给 LLM 看的协议真实函数是给应用自己执行的实现两者通过函数名建立映射而messages上下文调用意图 函数结果则是让 LLM 用自然语言完成最终回复的桥梁。完成本课后可以继续阅读第 12 课学习如何为 AI 应用设计 UX用户体验更多配套练习与 Notebook 位于仓库的 11-integrating-with-function-calling 目录下。【免费下载链接】generative-ai-for-beginners21 Lessons, Get Started Building with Generative AI项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai-for-beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表