ARTICLE DETAIL

资讯详情

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

generative-ai-for-beginners 第 11 课:用函数调用(Function Calling)让生成式 AI 应用接入外部数据与结构化输出

generative-ai-for-beginners 第 11 课:用函数调用(Function Calling)让生成式 AI 应用接入外部数据与结构化输出 generative-ai-for-beginners 第 11 课用函数调用Function Calling让生成式 AI 应用接入外部数据与结构化输出【免费下载链接】generative-ai-for-beginners21 Lessons, Get Started Building with Generative AI项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai-for-beginners本文围绕本仓库第 11 课文档展开完整讲解「函数调用」这一 Azure OpenAI 核心能力它如何解决 LLM 响应格式不一致、无法访问外部实时数据这两大痛点并通过「教育创业公司课程推荐聊天机器人」的完整案例带你从零创建第一个函数调用并把函数调用真正集成进应用程序。读完本文你将掌握函数调用的原理、三步式调用流程、函数 schema 的每个字段含义以及消息往返编排的完整代码模式。为什么需要函数调用在前面的课程中我们已经见识了 LLM 的强大但它也存在两个明显局限响应非结构化、不一致。函数调用出现之前LLM 的响应既无结构也不稳定开发者不得不编写复杂的校验代码去处理每一种可能的响应变体。无法访问训练时间之后的外部数据。模型的知识被限制在训练数据的时间点上因此用户问斯德哥尔摩现在的天气如何这类实时问题模型无法回答。函数调用Function Calling是 Azure OpenAI 服务提供的一项能力正是用来克服上述限制一致的响应格式能更好地控制响应格式就能更轻松地把响应集成到下游的其他系统外部数据可以把应用中其他来源的数据引入到聊天上下文中使用。场景演示先看看格式不一致到底有多痛本文的完整场景是为一家教育创业公司构建课程推荐聊天机器人用户通过聊天找到符合自己技能水平、当前角色和兴趣技术的课程。解决方案组合三样东西用Azure OpenAI提供聊天体验、用Microsoft Learn Catalog API按用户请求检索课程、用Function Calling把用户查询送入函数以发起 API 请求。动手前先看一个最能说明问题的例子。假设我们要建立学生数据库以便推荐合适课程下面是两条包含非常相似数据的学生描述。我们想让 LLM 解析这些数据之后用于应用、发送给 API 或存入数据库。第一步创建到 Azure OpenAI 资源的连接import os import json from openai import AzureOpenAI from dotenv import load_dotenv load_dotenv() client AzureOpenAI( api_keyos.environ[AZURE_OPENAI_API_KEY], # this is also the default, it can be omitted api_version 2023-07-01-preview ) deploymentos.environ[AZURE_OPENAI_DEPLOYMENT]上面这段 Python 代码通过api_type、api_base、api_version、api_key等参数配置与 Azure OpenAI 的连接。需要注意的是仓库内更新的教学文件例如 英文版 README 与配套 notebook已迁移到 Responses API 的 v1 端点写法改用OpenAI(api_key..., base_urlf{endpoint.rstrip(/)}/openai/v1/)无需再传api_version对应实现可参考 shared/python/api_utils.py 中的create_azure_openai_client。第二步创建两条学生描述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.第三步构造两条完全相同的提取指令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} 这两条提示词要求 LLM 提取信息并以 JSON 格式返回。第四步把提示词发送给 LLM# 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提示词保存在messages变量中role设为user用以模拟用户向聊天机器人发消息。第五步用json.loads把响应转成 JSON# Loading the response as a JSON object json_response1 json.loads(openai_response1.choices[0].message.content) json_response1响应 1{ name: Emily Johnson, major: computer science, school: Duke University, grades: 3.7, club: Chess Club }响应 2{ name: Michael Lee, major: computer science, school: Stanford University, grades: 3.8 GPA, club: Robotics Club }注意提示词完全相同、学生描述也高度相似但grades字段的值格式却不一致——一个是3.7另一个是3.8 GPA。原因在于 LLM 接收的是以提示词形式存在的非结构化数据返回的也是非结构化数据。当我们需要存储或使用这些数据时必须有一个可预期的结构化格式。函数调用解决格式问题LLM 不执行函数只负责产生结构那么如何解决格式问题答案是函数调用。使用函数调用时LLM 实际上并不会真的去调用或运行任何函数而是由我们为 LLM 创建一套它必须遵循的响应结构然后应用根据这些结构化响应决定在程序里执行哪个真实函数。之后我们把函数返回的数据拿回来再发回给 LLMLLM 用自然语言回答用户的提问。这也是后续集成章节中两次调用循环的由来。函数调用的典型使用场景函数调用能在很多场景下显著改进应用调用外部工具聊天机器人擅长回答问题借助函数调用它还能利用用户消息完成特定任务。例如学生说给我的老师发一封邮件说我需要这门课的更多帮助即可触发send_email(to: string, body: string)这个函数调用。生成 API 或数据库查询用户用自然语言查找信息被转换为格式化查询或 API 请求。例如老师问哪些学生完成了最后一次作业可调用get_completed(student_name: string, assignment: int, current_status: string)函数。生成结构化数据用户可以把一段文本或 CSV 交给 LLM 提取关键信息。例如学生把关于和平协议的维基百科文章转成 AI 记忆卡片可通过get_important_facts(agreement_name: string, date_signed: string, parties_involved: list)完成。创建你的第一个函数调用函数调用创建过程包含 3 个主要步骤调用Chat Completions API传入函数列表和用户消息读取模型响应并执行动作即运行函数或 API 调用再次调用Chat Completions API把函数返回的响应一并传入让模型据此生成对用户的回复。第 1 步创建消息第一步是创建用户消息。可以从文本输入动态赋值也可以在这里直接赋值。初次使用 Chat Completions API 时需要定义消息的role和content。role可以是system制定规则、assistant模型或user最终用户。在函数调用场景中我们将其设为user并附上一个示例问题messages [ {role: user, content: Find me a good course for a beginner student to learn Azure.} ]通过区分不同角色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对函数工作方式的说明这里要写具体、清晰它直接决定 LLM 在何时选择该函数parameters模型生成响应时将要使用的取值列表与格式parameters内部由若干条目组成每个条目包含type—— 属性存储的数据类型如objectproperties—— 模型在响应中会使用的具体取值列表其中每一项又包含name模型在格式化响应中使用的属性名例如producttype该属性的数据类型例如stringdescription对该属性的说明。此外还有一个可选属性required列出函数调用完成所必需的属性。在仓库配套实现中可以看到同样 schema 的其他形态JavaScript 版 js-githubmodels/app.js 定义了getFlightInfo、getHotelInfo两个工具TypeScript 版 typescript/function-app/src/main.ts 定义了findWeather工具并给unit参数增加了enum: [C, F]取值约束——枚举是约束参数取值范围的实用技巧。第 3 步发起函数调用定义好函数后把它加入 Chat Completions 请求通过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函数被调用其参数列在 JSON 响应的arguments属性中。LLM 之所以能提炼出匹配函数参数的数据是因为它从messages参数提供的值中完成了提取。回顾一下消息内容messages [ {role: user, content: Find me a good course for a beginner student to learn Azure.} ]显然student、Azure、beginner这三个词从messages中被提取出来作为函数输入。以这种方式使用函数是从提示词中抽取信息、为 LLM 提供结构、并沉淀可复用功能的好方法。版本说明上述代码采用 Chat Completions API 的functions/function_call参数。仓库当前英文版文档与配套 notebookpython/aoai-assignment.ipynb已升级为 Responses API 写法请求参数变为toolsfunctions与tool_choiceauto返回结构变为response.output中type为function_call的条目含call_id与arguments。两种写法核心思想一致本文后续集成代码仍以关联文档的 Chat Completions 写法为主线。把函数调用集成进应用程序验证了 LLM 的格式化响应之后就可以把它集成到应用中。核心是管理好两次请求的消息流第一次拿到结构化函数调用执行真实函数把结果拼回消息列表第二次再让 LLM 用自然语言总结。管理调用流程第 1 步保存模型返回的消息response_message response.choices[0].message第 2 步定义调用 Microsoft Learn API 的真实函数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 Catalog API用来检索培训模块取前 5 条结果。从工程角度看这类带超时、带重试、带错误处理的 HTTP 请求在仓库中已有封装可复用例如 shared/python/api_utils.py 的make_safe_request提供了默认 30 秒超时与 3 次重试TypeScript 示例 typescript/function-app/src/main.ts 则为 Bing Maps 请求设置了 10 秒超时并对失败返回结构化错误。第 3 步检查模型是否要求调用函数并完成名称 → 函数映射有了functions变量和对应的 Python 函数如何把它们映射起来答案是检查 LLM 响应中是否包含function_call若包含则调用指定函数# 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)运行上述代码的输出输出{ 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/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注意available_functions字典充当白名单只有注册过的函数才允许被调用。仓库的 JavaScript 示例对此有更严格的安全处理——调用前用Object.prototype.hasOwnProperty.call(namesToFunctions, functionName)校验函数名是否在白名单中并对JSON.parse包裹 try/catch 防止畸形参数导致崩溃见 js-githubmodels/app.jsTypeScript 版同样在 typescript/function-app/src/main.ts 对参数解析做了保护。这些都是在生产环境集成函数调用时必须补齐的防线。第 4 步把更新后的messages再次发给 LLM获得自然语言回复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. }至此模型已经看到了真实 API 返回的课程列表并用自然语言组织成带链接的推荐回复。这里把temperature设为0让第二次总结的输出更确定、更贴近事实减少编造。仓库配套实现一览除了文档代码本课目录下还提供了可直接运行的多语言实现供对照学习Python notebookpython/aoai-assignment.ipynbAzure OpenAI 版、python/oai-assignment.ipynbOpenAI 版均采用 Responses API 的tools/tool_choice写法并用function_call_output回填函数结果。JavaScriptGitHub Models / Azure AI Inferencejs-githubmodels/app.js通过azure-rest/ai-inference客户端调用/chat/completions演示航班 酒店查询双工具场景。TypeScriptAzure OpenAItypescript/function-app/src/main.ts使用官方openaiSDK 的client.responses.create演示天气查询并在其中演示了 URL 校验、超时、参数白名单校验等安全最佳实践运行脚本见 typescript/function-app/package.json。公共工具shared/python/api_utils.py 提供create_azure_openai_clientv1 端点客户端工厂与make_safe_request带超时重试的 HTTP 封装。课后练习要深入掌握 Azure OpenAI 函数调用可以动手完成以下挑战为search_courses函数增加更多参数例如课程时长、认证类型帮助学习者找到更匹配的课程新建另一个函数调用采集学习者更多信息例如母语native_language为函数调用和/或 API 调用增加错误处理——当没有返回合适课程时给出兜底提示。提示可查阅 Microsoft Learn Catalog API 的开发者参考文档确认上述数据在 API 中的字段与位置。学完本课还可以继续阅读本仓库的第 12 课 为 AI 应用设计 UX了解如何把这些能力包装成更好的用户界面与交互体验。【免费下载链接】generative-ai-for-beginners21 Lessons, Get Started Building with Generative AI项目地址: https://gitcode.com/GitHub_Trending/ge/generative-ai-for-beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表