news 2026/9/12 12:47:42

Semantic Kernel Python OpenAPI 插件实战:从 OpenAPI 规范到可调用 Kernel Function 的完整示例解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Semantic Kernel Python OpenAPI 插件实战:从 OpenAPI 规范到可调用 Kernel Function 的完整示例解析

Semantic Kernel Python OpenAPI 插件实战:从 OpenAPI 规范到可调用 Kernel Function 的完整示例解析

【免费下载链接】semantic-kernelIntegrate cutting-edge LLM technology quickly and easily into your apps项目地址: https://gitcode.com/GitHub_Trending/se/semantic-kernel

本指南围绕python/samples/concepts/plugins/openapi目录下的 OpenAPI 语法示例展开,讲解如何基于一份 OpenAPI 3.1 规范文档(openapi.yaml),借助 Semantic Kernel Python 的add_plugin_from_openapi能力,将 REST API 操作自动转换为可被 Kernel 调用的插件函数(Kernel Function),并通过本地 aiohttp 服务器完成端到端请求验证。读完本文,你将掌握 OpenAPI 插件的完整运行流程、参数映射规则、底层调用链,以及动态 payload、SSRF 防护、认证回调等执行参数的配置方法。

示例全景:三个文件构成的最小可运行闭环

该示例由三个文件组成,构成一个"规范定义 → 服务端实现 → 客户端调用"的完整闭环:

文件角色说明
openapi.yamlAPI 规范OpenAPI 3.1.0 文档,定义一个POST /{name}接口,operationIdhelloWorld
openapi_server.py服务端基于 aiohttp 的本地 HTTP 服务器,监听POST /{name}并回显路径、查询、请求体与请求头
openapi_client.py客户端使用kernel.add_plugin_from_openapiopenapi.yaml注册为插件,并调用helloWorld函数

从源码结构看,示例刻意选用本地服务器而非真实第三方 API,目的是在无外部依赖的环境下完整演示"OpenAPI 规范 → Kernel 插件 → HTTP 请求"的语法链路,因此非常适合作为学习和二次开发的起点。

环境准备:使用 uv 建立可复现的开发环境

示例的运行依赖 Semantic Kernel Python 源码环境,其通用安装说明位于 python/DEV_SETUP.md。核心工具是uv,它允许直接从本地源码使用 SK,无需关心包路径解析,效果等同于安装了 pip 包。

对于 Windows(非 WSL)环境,可按官方 uv 安装文档安装后执行:

# 安装 Python 3.10、3.11、3.12 uv python install 3.10 3.11 3.12 # 创建虚拟环境(可切换 3.10/3.11/3.12) uv venv --python 3.10 # 安装 SK 及全部依赖 uv sync --all-extras --dev

对于 Mac 和 Linux(含 WSL),可直接使用仓库自带的 Makefile 目标:

make install

如需指定 Python 版本,可通过PYTHON_VERSION环境变量控制:

make install PYTHON_VERSION=3.12

分步运行:两终端、四步骤完成端到端调用

原文档给出了清晰的运行步骤,这里补充每一步的目的与细节:

第 1 步:进入示例目录

cd semantic_kernel/python/samples/concepts/plugins/openapi

第 2 步:同步依赖并激活虚拟环境

uv sync source .venv/bin/activate

uv sync会根据仓库的uv.lock(位于 python/uv.lock)锁定并安装全部依赖;source .venv/bin/activate用于激活虚拟环境。文档特别提醒:取决于操作系统,activate 脚本可能位于不同位置——例如 Windows 下通常是.venv\Scripts\activate

第 3 步:启动本地 API 服务器

python openapi_server.py

该命令启动 aiohttp 应用,默认监听localhost:8080(端口来源于openapi.yamlservers节点的声明,见下文)。启动后终端会持续输出访问日志,保持运行。

第 4 步:另开终端,重复第 1、2 步后运行客户端

python openapi_client.py

客户端将注册一个代表openapi.yaml所定义 API 的插件,执行helloWorld函数,并向第 3 步启动的服务器发起真实的 HTTP 请求。在客户端终端应能看到类似Hello, John: q=0.7, body={'input': 'hello world'}, headers=...的输出(具体内容由服务器端回显逻辑决定)。

规范即契约:逐字段解析 openapi.yaml

openapi.yaml 是一份精简但完整的 OpenAPI 3.1.0 文档,其结构如下:

openapi: 3.1.0 info: title: Test API version: 1.0.0 servers: - url: http://localhost:8080 paths: /{name}: post: summary: Hello World operationId: helloWorld requestBody: required: true content: application/json: schema: type: object properties: input: type: string description: The input of the request example: Howdy responses: '200': description: OK parameters: - name: name in: path required: true schema: type: string description: Your name - name: Header in: header required: true schema: type: string description: The header - name: q in: query required: false schema: type: string description: The query parameter

各关键节点的作用如下:

  • servers[0].url:声明服务器基地址为http://localhost:8080。OpenAPI 插件解析后会用该地址拼接操作路径,构造最终请求 URL。
  • operationId: helloWorld:这是语义内核映射函数名的关键。插件中每个 OpenAPI 操作会被包装为一个以operationId命名的 Kernel Function,因此客户端可以用openapi_plugin["helloWorld"]获取对应函数。
  • parameters:声明三个参数,覆盖了 REST 参数的三类常见位置:
    • namein: path,必填):路径参数,会被替换进/{name}中的占位符;
    • Headerin: header,必填):请求头参数,大小写敏感,与客户端传入的Header="example-header"一一对应;
    • qin: query,可选):查询字符串参数。
  • requestBody:声明application/json请求体,含一个input字符串属性。这是"动态 payload"机制的数据来源——客户端无需手动构造完整 JSON,只需按属性名传入参数,由运行时自动组装请求体(详见下文)。

服务端实现:aiohttp 如何回显各类参数

openapi_server.py 使用 aiohttp 实现,核心代码如下:

from aiohttp import web routes = web.RouteTableDef() @routes.post("/{name}") async def hello(request): # 路径参数 name = request.match_info.get("name", "") # 查询参数 q = request.rel_url.query.get("q", "") # 请求体 body = await request.json() # 请求头 headers = request.headers return web.Response(text=f"Hello, {name}: q={q}, body={body}, headers={headers}") app = web.Application() app.add_routes(routes) if __name__ == "__main__": web.run_app(app)

该服务器的作用是"照单全收":分别从match_info(路径)、rel_url.query(查询串)、request.json()(请求体)和request.headers(请求头)提取客户端发送的全部数据并原样回显。这使开发者可以直观地核对客户端插件是否按照openapi.yaml的声明,将nameqinputHeader正确放到了对应的 HTTP 位置——这正是该示例作为"语法验证器"的价值所在。

客户端调用:三行核心代码背后的调用链

openapi_client.py 的核心逻辑非常紧凑:

from semantic_kernel import Kernel from semantic_kernel.functions.kernel_arguments import KernelArguments async def main(): kernel = Kernel() spec_path = os.path.join( os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))), "plugins", "openapi", "openapi.yaml", ) openapi_plugin = kernel.add_plugin_from_openapi( plugin_name="openApiPlugin", openapi_document_path=spec_path, ) arguments = KernelArguments( input="hello world", name="John", q=0.7, Header="example-header", ) result = await kernel.invoke(openapi_plugin["helloWorld"], arguments=arguments) print(result)

这里有几个值得注意的细节:

  1. spec_path的动态定位:客户端通过os.path.realpath(__file__)向上回溯三层目录,拼出plugins/openapi/openapi.yaml的绝对路径,而不是写死路径。这样无论从哪个工作目录启动脚本都能正确定位规范文件。
  2. 插件注册kernel.add_plugin_from_openapi是入口方法,plugin_name="openApiPlugin"定义了插件的命名空间,openapi_document_path指向规范文件。KernelArgumentsinputnameqHeader分别对应规范中的请求体属性、路径参数、查询参数与请求头参数。
  3. 函数调用openapi_plugin["helloWorld"]operationId索引到包装后的 Kernel Function,kernel.invoke执行后返回KernelResult并打印。

从源码实现看,add_plugin_from_openapi最终落在 kernel_plugin.py 的KernelPlugin.from_openapi类方法上。该方法要求openapi_document_pathopenapi_parsed_spec至少提供一个,否则抛出PluginInitializationError;随后调用 openapi_manager.py 中的create_functions_from_openapi(该函数被@experimental装饰器标记,属于实验性 API)完成"规范 → 函数"的转换。

底层调用链:规范如何变成可执行函数

create_functions_from_openapi的执行流程可以概括为四个阶段:

  1. 解析(Parse):使用OpenApiParser(位于 openapi_parser.py)读取 YAML 文档,生成解析后的规范字典。
  2. 建模(Model):将规范转换为RestApiOperation等 REST 操作模型(位于 models 目录,含RestApiParameterRestApiPayloadRestApiSecurityRequirementRestApiUri等类型)。
  3. 包装(Wrap):对每个操作创建一个@kernel_function装饰的异步闭包run_openapi_operation,函数名取operation.id(即operationId),描述取自operation.summaryoperation.description
  4. 注册(Register):将闭包包装为KernelFunctionFromMethod,并把 HTTP 方法、服务器 URL、安全要求等写入additional_metadata,最终返回函数列表。

参数映射与必填校验

包装函数执行时,会遍历该操作的全部RestApiParameter,按以下规则从kwargs中取值(见 openapi_manager.py):

  • 优先使用参数的alternative_name(即规范参数名),其次使用name
  • 找到且值非None时写入KernelArguments
  • 若参数标记为is_required但调用时缺失,则抛出FunctionExecutionException,提示"没有找到可用于 REST 函数{plugin_name}.{operation.id}参数{parameter.name}的变量"。

同时,每个参数都会转换为KernelParameterMetadata(名称、描述、默认值、是否必填、类型及 schema),这使得 OpenAPI 插件函数可以被 Kernel 的自动函数调用(function calling)机制识别,向 LLM 暴露正确的参数 schema。

请求构建:URL、查询串与动态 payload

请求的最终构造在 openapi_runner.py 的OpenApiRunner中完成:

  • URL 构建build_operation_url将路径参数替换进模板路径,build_query_string从参数中收集in: query的参数生成查询串,再通过build_full_url拼接出完整 URL。
  • 动态 payload(默认开启):当enable_dynamic_payload=True时,build_json_payload依据规范中requestBody的 schema 逐属性从参数中取值,自动组装 JSON 请求体;必需属性缺失时抛出FunctionExecutionException。这正是客户端只需传input="hello world"而不必手工构造 JSON 的原因。
  • 静态 payload(关闭动态模式时):若enable_dynamic_payload=False,则要求通过名为payload的字符串参数直接提供完整请求体。
  • enable_payload_namespacing:开启后,嵌套对象属性会以属性路径的命名空间形式映射为扁平参数,便于大模型直接传参。

执行参数详解:OpenAPIFunctionExecutionParameters 全字段

若需要定制插件行为,可通过 openapi_function_execution_parameters.py 中的OpenAPIFunctionExecutionParameters(基于 pydantic 的KernelBaseModel)向from_openapi传入execution_settings。全部字段如下:

字段类型默认值说明
http_clienthttpx.AsyncClient \| NoneNone自定义 HTTP 客户端(可注入代理、TLS 配置等)
auth_callback异步回调None认证回调,执行请求前调用,返回请求头字典,用于注入令牌等凭据
server_url_overridestr \| NoneNone覆盖规范中声明的服务器 URL(若格式非法会在初始化时抛出ValueError
ignore_non_compliant_errorsboolFalse是否忽略不符合规范的错误
user_agentstr \| None默认 SK UA请求 User-Agent,未设置时自动使用 Semantic Kernel 的HTTP_USER_AGENT
enable_dynamic_payloadboolTrue是否根据 schema 动态组装请求体
enable_payload_namespacingboolFalse是否将嵌套 payload 属性扁平化为命名空间参数
operations_to_excludelist[str][]需要排除的operationId列表,用于过滤不希望暴露给 Kernel 的操作
operation_selection_predicate回调None操作选择谓词,接收OperationSelectionPredicateContext,返回bool决定是否注册该操作
timeoutfloat \| NoneNoneHTTP 请求超时(秒),为None时使用 httpx 默认值 5 秒
enable_file_ref_resolutionboolFalse是否解析 OpenAPI 文档中的本地文件$ref引用(适用于规范拆分为多个本地文件的场景,仅信任来源时开启)
enable_http_ref_resolutionboolFalse是否解析外部 HTTP$ref引用(默认关闭,仅在信任文档来源时开启)
server_url_validation_allowed_base_urlslist[str][]显式信任的基地址白名单,匹配的 URL 可绕过默认的 HTTPS-only 与私有网络校验
allow_private_network_accessboolFalse是否允许请求目标为私网、回环(loopback)、链路本地等非公网地址

注意:示例中的http://localhost:8080属于回环地址。根据默认的 URL 校验策略,这类请求默认会被拦截,因此在客户端脚本中不会显式配置allow_private_network_access,其实际处理依赖运行时的默认行为——在自行搭建类似本地示例时,若请求被安全校验拦截,需要通过server_url_validation_allowed_base_urls显式放行http://localhost:8080或设置allow_private_network_access=True

安全机制:默认开启的 SSRF 防护

OpenAPIFunctionExecutionParameters的类文档明确说明:OpenAPI 操作请求 URL默认经过校验以降低 SSRF 风险——请求必须使用 HTTPS,且不得解析到私网、回环、链路本地等非公网 IP 地址,除非目标通过server_url_validation_allowed_base_urls显式信任,或通过allow_private_network_access放开私有网络访问。相关校验逻辑位于 server_url_validator.py(ServerUrlValidationOptions/validate_server_url)。

这一设计意味着:当你的openapi.yaml来自不可信的第三方来源时,即便其中声明了内网地址,插件默认也不会向内网发起请求,从而避免恶意规范被用作 SSRF 攻击跳板。在配置自己的 OpenAPI 插件时,应遵循最小信任原则,只在明确需要时修改这两个字段。

进阶指引:如何把示例改造成真实 API 插件

在理解示例后,替换为真实 API 只需三步:

  1. 替换规范文件:将openapi.yaml换成目标 API 的 OpenAPI 3.x 文档(语义内核使用openapi_core进行规范解析与请求校验,支持 JSON Pointer 内部引用,跨文件/HTTP 引用需按上文说明显式开启)。
  2. 调整服务器 URL:确认规范中servers声明的是可访问的 HTTPS 公网地址;若使用内网或本地服务,需同步配置 URL 白名单。
  3. 按需注入认证:若 API 需要鉴权,通过execution_settings传入auth_callback,在回调中返回携带访问令牌(如 Bearer Token)的请求头字典;需要精细化控制时,还可使用operation_selection_predicateoperations_to_exclude只暴露必要的操作。

完成上述替换后,即可让 LLM 通过函数调用机制自动发现并调用这些由 OpenAPI 规范生成的 Kernel Functions,实现"自然语言 → 结构化 API 调用"的完整链路。

【免费下载链接】semantic-kernelIntegrate cutting-edge LLM technology quickly and easily into your apps项目地址: https://gitcode.com/GitHub_Trending/se/semantic-kernel

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 12:45:27

dcode 如何在会话中切换模型并持久化模型配置?

dcode 如何在会话中切换模型并持久化模型配置? 【免费下载链接】deepagents The batteries-included agent harness. 项目地址: https://gitcode.com/GitHub_Trending/de/deepagents 在 deepagents 仓库的终端编码产品 deepagents-code(命令名为 …

作者头像 李华
网站建设 2026/9/12 12:44:17

专业图像管理与命名规范全指南

1. 项目概述:从"照片0001"看数字图像管理的重要性"照片0001"这个看似简单的文件名,实际上揭示了数字时代我们面临的普遍问题——如何有效管理海量图像文件。作为一名经历过从胶片相机到智能手机摄影变革的摄影师,我深刻理…

作者头像 李华
网站建设 2026/9/12 12:44:15

RAG技术解析:大模型知识检索与生成的工程实践

1. RAG技术:让AI学会"查资料"的进化革命第一次看到GPT模型对着2023年以后的问题信誓旦旦地编造答案时,我就意识到大模型需要一种"查资料"的能力。去年为一个金融客户部署问答系统时,传统微调方式需要每周更新数GB的行业报…

作者头像 李华
网站建设 2026/9/12 12:44:06

大模型智能体的自我进化机制与实现

1. 项目概述:大模型智能体的自我进化机制这个项目探讨了一种基于大语言模型(LLM)的智能体架构设计,核心是通过生成器(Generator)和反思器(Reflector)的对抗性交互实现持续自我优化。想象两个顶尖棋手不断对弈切磋的场景——生成器负责产出解决方案&#…

作者头像 李华
网站建设 2026/9/12 12:44:04

2026学术论文AI检测工具评测与降AI率方案

1. 项目背景与需求分析2026年学术圈将面临一个关键转折点——全球超过60%的学术期刊将强制要求论文提交时附带AI生成内容检测报告。这个硬性指标催生了一个新兴市场:论文降AI率服务。我们的实测团队历时三个月,对市面上20款主流工具进行了全方位评测&…

作者头像 李华