如何使用ChatGPT Apps SDK:用Apps SDK构建披萨应用
OpenAI最近推出了ChatGPT Apps,由新的Apps SDK和模型上下文协议(MCP)提供支持。将这些应用视为ChatGPT的插件:
- 您可以在对话中自然地调用它们
- 它们可以在ChatGPT内部渲染自定义交互式UI(地图、轮播图、视频等)
- 它们在您控制的MCP服务器上运行,该服务器定义了应用提供的工具、资源和部件
在这个分步指南中,您将使用官方的披萨应用示例构建一个ChatGPT应用。该应用展示了ChatGPT如何通过您的本地服务器渲染UI部件,如披萨地图或轮播图。
您将学到的内容
通过本教程,您将学习如何:
- 使用OpenAI Apps SDK设置和运行ChatGPT应用
- 理解核心构建块:工具、资源和部件
- 使用开发者模式将本地应用服务器连接到ChatGPT
- 直接在ChatGPT对话中渲染自定义UI
ChatGPT应用工作原理(宏观视角)
以下是简化的架构:
ChatGPT(前端)
|
v
MCP服务器(您的后端)
|
v
部件(在ChatGPT内部显示的HTML/JS标记)
ChatGPT发送请求,如:"显示披萨轮播图" MCP服务器响应资源(HTML标记)和工具逻辑 部件在ChatGPT中内联渲染
步骤1:克隆示例仓库
OpenAI提供了一个包含披萨应用的官方示例仓库。使用以下命令克隆并安装依赖:
git clone https://github.com/openai/openai-apps-sdk-examples.git
cd openai-apps-sdk-examples
pnpm install
步骤2:运行披萨应用服务器
导航到披萨应用服务器并启动它:
cd pizzaz_server_node
pnpm start
如果工作正常,您应该看到:
Pizzaz MCP server listening on http://localhost:8000
SSE stream: GET http://localhost:8000/mcp
Message post endpoint: POST http://localhost:8000/mcp/messages
这意味着您的服务器正在本地运行。
步骤3:暴露您的本地服务器
为了让ChatGPT与您的应用通信,您的本地服务器需要一个公共URL。ngrok提供了一种在开发期间快速暴露它的方法。
3.1 获取ngrok
在ngrok.com注册并复制您的authtoken。
3.2 安装ngrok
macOS:
brew install ngrok
Windows:
- 下载并解压ngrok
- 可选:将文件夹添加到PATH
3.3 连接您的账户
ngrok config add-authtoken <your_authtoken>
3.4 启动隧道
ngrok http 8000
这将给您一个公共HTTPS URL(如xyz.ngrok.app/mcp)。
步骤4:浏览披萨应用代码
完整的披萨应用服务器代码很长,让我们将其分解为可理解的部分。
4.1 导入和设置
import { createServer } from "node:http";
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import { z } from "zod";
- Server和SSEServerTransport来自Apps SDK
- zod验证输入以确保ChatGPT发送正确的参数
4.2 定义披萨部件
部件是应用的核心。每个部件代表ChatGPT可以显示的一块UI。
以下是披萨地图部件:
{
id: "pizza-map",
title: "Show Pizza Map",
templateUri: "ui://widget/pizza-map.html",
html: `
<div id="pizzaz-root"></div>
<link rel="stylesheet" href=".../pizzaz-0038.css">
<script type="module" src=".../pizzaz-0038.js"></script>
`,
responseText: "Rendered a pizza map!"
}
- id → 部件的唯一名称
- templateUri → ChatGPT如何获取UI
- html → 实际标记和资源
- responseText → 在聊天中显示的消息
该应用定义了五个部件:
- 披萨地图
- 披萨轮播图
- 披萨相册
- 披萨列表
- 披萨视频
4.3 将部件映射到工具和资源
接下来,部件被转换为工具(ChatGPT可以调用的东西)和资源(ChatGPT可以渲染的UI标记)。
const tools = widgets.map((widget) => ({
name: widget.id,
description: widget.title,
inputSchema: toolInputSchema,
title: widget.title,
_meta: widgetMeta(widget)
}));
const resources = widgets.map((widget) => ({
uri: widget.templateUri,
name: widget.title,
description: `${widget.title} widget markup`,
mimeType: "text/html+skybridge",
_meta: widgetMeta(widget)
}));
这使得每个部件都可调用和可显示。
4.4 处理请求
MCP服务器响应ChatGPT的请求。例如,当ChatGPT调用部件工具时:
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const widget = widgetsById.get(request.params.name);
const args = toolInputParser.parse(request.params.arguments ?? {});
return {
content: [{ type: "text", text: widget.responseText }],
structuredContent: { pizzaTopping: args.pizzaTopping },
_meta: widgetMeta(widget)
};
});
这:
- 找到请求的部件
- 验证输入(pizzaTopping)
- 响应文本+元数据,以便ChatGPT可以渲染部件
4.5 创建服务器
最后,服务器绑定到HTTP端点(/mcp和/mcp/messages),以便ChatGPT可以与其流式传输消息。
const httpServer = createServer(async (req, res) => {
// 处理对/mcp和/mcp/messages的请求
});
httpServer.listen(8000, () => {
console.log("Pizzaz MCP server running on port 8000");
});
步骤5:在ChatGPT中启用开发者模式
5.1 启用开发者模式
- 打开ChatGPT
- 转到设置 → 应用和连接器 → 高级设置
- 切换开发者模式
当开发者模式启用时,ChatGPT应该看起来像这样。
5.2 创建应用
- 返回设置 → 应用和连接器
- 点击创建
- 下一步:
- 名称:输入您的应用名称(例如,披萨应用)
- 描述:输入应用的任何描述(或留空)
- MCP服务器URL:粘贴您的MCP端点的公共HTTPS URL。确保它直接指向/mcp,而不仅仅是服务器根目录
- 认证:选择无认证
- 选中"我信任此应用"
- 点击创建完成
一旦您的应用连接到ChatGPT,它应该看起来像这样。
当您点击返回图标时,您应该看到您的应用以及其他可以连接并与ChatGPT一起使用的应用。
5.3 使用您的应用
要使用您的应用:
- 在ChatGPT中打开新聊天
- 点击+图标
- 向下滚动到更多
- 您会看到您的应用
- 选择披萨应用开始使用您的应用
以下是一些您可以在ChatGPT中尝试的命令:
- 显示带有意大利辣香肠配料的披萨地图
- 显示带有蘑菇配料的披萨轮播图
- 显示带有蔬菜配料的披萨相册
- 显示带有奶酪配料的披萨列表
- 显示带有鸡肉配料的披萨视频
每个命令告诉ChatGPT要渲染哪个部件,您可以替换任何您喜欢的配料。
挑战(自己尝试这些)
以下是三种扩展披萨应用的实用方法。每种方法都与您已有的代码直接相关。
挑战A:添加"披萨特价"部件(仅文本)
目标: 创建一个仅显示短消息的部件,如"今日特价:玛格丽塔配罗勒"。
更改位置:
- resources.widgets → 复制一个条目并给它一个新的id/标题
- tools → 将其注册为新工具
- CallTool处理程序 → 检测何时被调用(if (request.params.name === "pizza-special"))并返回您的特价
提示: 此部件不需要额外的CSS/JS文件。只需将其html保持为类似<div>🍕 今日特价:玛格丽塔</div>。这个想法是展示部件可以像纯HTML一样简单。
挑战B:支持多种配料
目标: 让用户订购带有多种配料的披萨,如["意大利辣香肠", "蘑菇"]。
更改位置:
- toolInputSchema → 从z.string()切换到z.array(z.string())
- CallTool处理程序 → 解析后,args.pizzaTopping将是一个数组。在插入HTML/响应之前将其连接成字符串
- 部件HTML → 更新显示以列出所有选择的配料
提示: 首先console.log解析的args以确认您实际上得到了一个数组。然后尝试类似:
const toppings = args.pizzaTopping.join(", ");
return { responseText: `披萨订购了 ${toppings}` };
挑战C:从外部API获取真实披萨数据
目标: 而不是硬编码内容,获取真实的披萨信息。例如,您可以调用Yelp的API列出某个位置的披萨店,或使用免费的占位符API模拟数据。
更改位置:
- 在您的部件的CallTool处理程序内部
- 用fetch(...)调用替换静态HTML,该调用从响应构建动态HTML
提示: 从像JSONPlaceholder这样的免费API开始小规模。例如:
const res = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=3");
const data = await res.json();
const html = `
<ul>
${data.map((p: any) => `<li>${p.title}</li>`).join("")}
</ul>
`;
return { responseText: "获取了披萨店!", content: [{ type: "text/html", text: html }] };
一旦工作正常,换入真实的API,如Yelp或Google Maps Places,以渲染实际的披萨店。
结论
您刚刚使用OpenAI Apps SDK构建了您的第一个ChatGPT应用。通过一点JavaScript和HTML,您创建了一个ChatGPT可以与之通信的服务器,并在聊天窗口内部渲染了交互式部件。
这个例子专注于OpenAI提供的披萨应用示例,但您可以构建:
- 天气仪表板
- 电影查找器
- 金融数据查看器
- 甚至迷你游戏
SDK使得以强大的新方式融合对话+交互式UI成为可能。
探索OpenAI Apps SDK文档以深入并开始构建您自己的应用。