使用ChatGPT应用SDK构建披萨应用:完整指南

本教程详细介绍了如何使用OpenAI ChatGPT应用SDK构建披萨应用,包括设置MCP服务器、创建交互式UI组件、连接本地服务到ChatGPT,以及通过实际代码示例展示工具、资源和部件的实现方式。

如何使用ChatGPT应用SDK:用应用SDK构建披萨应用

OpenAI最近推出了ChatGPT应用,由新的应用SDK和模型上下文协议(MCP)提供支持。将这些应用视为ChatGPT的插件:

  • 您可以在对话中自然地调用它们
  • 它们可以在ChatGPT内部渲染自定义交互式UI(地图、轮播、视频等)
  • 它们运行在您控制的MCP服务器上,该服务器定义了应用提供的工具、资源和部件

在这个分步指南中,您将使用官方的披萨应用示例构建一个ChatGPT应用。该应用展示了ChatGPT如何通过您的本地服务器渲染UI部件,如披萨地图或轮播。

您将学到的内容

通过本教程,您将学习如何:

  • 使用OpenAI应用SDK设置和运行ChatGPT应用
  • 理解核心构建块:工具、资源和部件
  • 使用开发者模式将本地应用服务器连接到ChatGPT
  • 直接在ChatGPT对话中渲染自定义UI

ChatGPT应用如何工作(宏观架构)

以下是简单的架构说明:

1
2
3
4
5
6
7
ChatGPT(前端)
   |
   v
MCP服务器(您的后端)
   |
   v
部件(在ChatGPT内部显示的HTML/JS标记)

ChatGPT发送请求,如:“显示披萨轮播”

MCP服务器响应资源(HTML标记)和工具逻辑

部件在ChatGPT中内联渲染

步骤1. 克隆示例仓库

OpenAI提供了一个官方示例仓库,包含披萨应用。使用以下命令克隆它并安装依赖项:

1
2
3
git clone https://github.com/openai/openai-apps-sdk-examples.git
cd openai-apps-sdk-examples
pnpm install

步骤2. 运行披萨应用服务器

导航到披萨应用服务器并启动它:

1
2
cd pizzaz_server_node
pnpm start

如果工作正常,您应该看到:

1
2
3
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:

1
brew install ngrok

Windows:

  • 下载并解压ngrok
  • 可选地,将文件夹添加到PATH中

3.3 连接您的账户

1
ngrok config add-authtoken <your_authtoken>

3.4 启动隧道

1
ngrok http 8000

这将给您一个公共HTTPS URL(如https://xyz.ngrok.app/mcp)。

步骤4. 浏览披萨应用代码

完整的披萨应用服务器代码很长,让我们将其分解为易于理解的部分。

4.1 导入和设置

1
2
3
4
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来自应用SDK
  • zod验证输入以确保ChatGPT发送正确的参数

4.2 定义披萨部件

部件是应用的核心。每个部件代表ChatGPT可以显示的一块UI。

以下是披萨地图部件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  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标记)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
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调用部件工具时:

1
2
3
4
5
6
7
8
9
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可以流式传输消息。

1
2
3
4
5
6
7
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以确认您确实得到了一个数组。然后尝试类似:

1
2
const toppings = args.pizzaTopping.join(", ");
return { responseText: `披萨订购了 ${toppings}` };

挑战C:从外部API获取真实披萨数据

目标:而不是硬编码内容,获取真实的披萨信息。例如,您可以调用Yelp的API列出某个位置的披萨店,或使用免费的占位符API模拟数据。

更改位置:

  • 在您的部件的CallTool处理程序内部
  • 用fetch(…)调用替换静态HTML,该调用从响应构建动态HTML

提示:从像JSONPlaceholder这样的免费API开始小规模。例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
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应用SDK构建了您的第一个ChatGPT应用。通过一点JavaScript和HTML,您创建了一个ChatGPT可以与之通信的服务器,并在聊天窗口内直接渲染了交互式部件。

这个例子专注于OpenAI提供的披萨应用示例,但您可以构建:

  • 天气仪表板
  • 电影查找器
  • 金融数据查看器
  • 甚至迷你游戏

该SDK使得以强大的新方式融合对话+交互式UI成为可能。

探索OpenAI应用SDK文档以深入了解并开始构建您自己的应用。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计