ChatGPT开发指南

ChatGPT 开发指南:用 OpenAI Responses API 构建对话应用

作者:AI 使用指南编辑部 · 发布于 2026/7/13 · 更新于 2026/7/13

很多人说“开发一个 ChatGPT”,实际要做的通常不是复制 ChatGPT 产品,而是通过 OpenAI API,在自己的网页、企业工具或应用中加入对话式 AI。本指南以 Node.js 为例,从一次最小调用开始,逐步搭出一个可继续扩展的服务端应用。

完成后,你会知道请求应该放在哪里、如何保留多轮上下文、何时使用流式输出、如何让模型调用自己的业务函数,以及上线前必须补齐哪些安全和成本控制。本文依据 2026 年 7 月 13 日核验的 OpenAI 官方开发文档撰写;模型名称、功能支持和限制可能变化,正式上线前应再次查看文末官方来源。

1、先分清 ChatGPT 产品与 OpenAI API

ChatGPT 是面向用户的产品,OpenAI API 是开发者把模型能力接入自己软件的接口。二者的界面、账号使用方式和计费管理不能简单等同。本指南讨论的是 API 应用开发,不是修改 ChatGPT 网页,也不需要抓取或模拟 ChatGPT 的前端请求。

一个最小应用通常分为三层:

  1. 浏览器或客户端负责收集用户输入和展示结果。
  2. 你自己的服务端负责保存密钥、校验用户、组织提示词并调用 OpenAI。
  3. OpenAI Responses API 负责生成响应,必要时请求服务端执行工具。

OpenAI API 对话应用架构:浏览器请求自己的服务端,服务端调用 Responses API,并按需执行受控业务工具

这张图最重要的信息是安全边界:OpenAI API Key 只能保存在服务端。如果把密钥写进浏览器 JavaScript、移动端安装包或公开仓库,其他人可能提取并滥用它。

2、准备 Node.js 项目与 API Key

本文示例需要较新的 Node.js 版本,并使用 OpenAI 官方 JavaScript SDK。新建一个空目录后执行:

npm init -y
npm install openai
npm pkg set type=module

在 OpenAI 平台创建 API Key,然后把它设置为环境变量。PowerShell 当前会话可以这样设置:

$env:OPENAI_API_KEY="你的_API_Key"

不要把真实密钥写入教程代码、提交到 Git,或发送给聊天机器人协助排错。生产环境应使用部署平台的 Secret 管理功能,并为开发、测试、生产分别配置项目和权限。

3、完成第一次 Responses API 调用

新建 app.js

import OpenAI from "openai";

const client = new OpenAI();

const response = await client.responses.create({
  model: "gpt-5.6",
  instructions: "你是中文产品助手。回答要准确、简洁;不确定时明确说明。",
  input: "用三点说明,为什么 API Key 不能放在浏览器前端。",
});

console.log(response.output_text);

运行:

node app.js

官方最新模型指南在本文核验时建议新项目从 gpt-5.6 开始。它是会变化的配置,不应散落在业务代码中。实际项目可通过环境变量设置模型默认值:

const model = process.env.OPENAI_MODEL || "gpt-5.6";

官方 SDK 提供的 response.output_text 会聚合响应中的文本。不要长期假设文本固定存在于 output[0].content[0].text,因为 output 还可能包含工具调用等其他项目。

3.1、instructionsinput 怎么分工

  • instructions 放应用级规则,例如角色、语言、边界和输出原则。
  • input 放当前用户任务与材料。
  • 来自用户的文本不要直接拼进开发者规则,否则容易让权限边界变得模糊。

如果结果不稳定,先明确任务、材料、限制和验收标准,再考虑更换模型。可继续阅读站内的提示词基础教程,把产品需求转换为可测试的指令。

4、把脚本改成真正的服务端接口

浏览器不应该直接调用 OpenAI。下面用 Express 建立一个最小后端:

npm install express
import express from "express";
import OpenAI from "openai";

const app = express();
const client = new OpenAI();

app.use(express.json({ limit: "32kb" }));

app.post("/api/chat", async (req, res) => {
  const message = String(req.body?.message || "").trim();

  if (!message || message.length > 4000) {
    return res.status(400).json({ error: "请输入 1 到 4000 个字符。" });
  }

  try {
    const response = await client.responses.create({
      model: process.env.OPENAI_MODEL || "gpt-5.6",
      instructions: "你是中文产品助手。不要编造事实;信息不足时先提问。",
      input: message,
    });

    res.json({ text: response.output_text, responseId: response.id });
  } catch (error) {
    console.error("OpenAI request failed", error);
    res.status(502).json({ error: "AI 服务暂时不可用,请稍后重试。" });
  }
});

app.listen(3000, () => {
  console.log("Server running at http://localhost:3000");
});

这只是教学起点。上线前还必须加入用户鉴权、请求频率限制、超时、日志脱敏、内容安全策略和费用上限。不要把底层错误对象原样返回给浏览器,因为其中可能含有不适合公开的调试信息。

5、实现多轮对话状态

模型请求本身不会自动知道某个浏览器用户之前说过什么。Responses API 支持多种上下文管理方式,其中一种简洁做法是把上一轮 response.id 作为下一轮的 previous_response_id

const first = await client.responses.create({
  model: "gpt-5.6",
  input: "给我的读书应用取三个中文名字。",
  store: true,
});

const second = await client.responses.create({
  model: "gpt-5.6",
  previous_response_id: first.id,
  input: "保留第二个,再给它写一句介绍。",
  store: true,
});

console.log(second.output_text);

在真实服务中,必须把响应 ID 与当前登录用户、会话 ID 绑定,不能接受浏览器随意提交一个响应 ID 就继续对话。还要设置会话过期和删除机制,并说明数据如何保留。

另一个选择是由应用自己保存并重新发送必要的消息。这样更容易控制数据存储,但你需要负责裁剪历史、控制上下文长度,并保留 API 后续处理所需的完整响应项目。无论选择哪种方案,都不要把“无限历史记录”当成默认设计;更稳妥的做法是保留近期对话,把较早内容压缩成经过核验的摘要。

6、用流式输出改善等待体验

普通请求会等模型生成完成后一次返回。长回答可能让页面像“卡住”一样。开启流式输出后,服务端可以通过 Server-Sent Events(SSE)逐步接收有明确类型的事件,并把文本增量转发给前端。

const stream = await client.responses.create({
  model: "gpt-5.6",
  input: "为一个记账应用写一段 300 字的新手说明。",
  stream: true,
});

for await (const event of stream) {
  if (event.type === "response.output_text.delta") {
    process.stdout.write(event.delta);
  }
}

流式输出改善的是“开始看到结果的时间”,不等于总生成时间一定更短。前端还要处理断线、取消、重复事件、最终完成状态和错误状态。涉及内容审核时也要谨慎:部分内容在完整输出前已经显示给用户,审核链路需要与产品风险相匹配。

7、用工具调用连接真实业务数据

模型只负责判断是否需要工具并生成参数,真正的数据库查询、日历写入或订单操作仍由你的服务端执行。基本循环是:

  1. 请求中提供工具名称、用途和 JSON Schema 参数。
  2. 模型返回函数调用请求。
  3. 服务端验证参数、检查用户权限并执行函数。
  4. 服务端用 function_call_output 把结果交回模型。
  5. 模型根据工具结果生成面向用户的答案。

一个只读天气工具可以这样声明:

const tools = [
  {
    type: "function",
    name: "get_weather",
    description: "查询指定城市的当前天气。仅用于用户明确询问天气时。",
    parameters: {
      type: "object",
      properties: {
        city: { type: "string", description: "城市名称,例如杭州" },
      },
      required: ["city"],
      additionalProperties: false,
    },
    strict: true,
  },
];

const response = await client.responses.create({
  model: "gpt-5.6",
  input: "杭州今天适合骑车吗?",
  tools,
});

接下来应遍历 response.output,识别 function_call 项,按工具名路由到你允许的函数,并校验参数。不要把模型生成的函数名、SQL、URL 或金额当成可信指令直接执行。

7.1、高影响操作必须二次确认

退款、发邮件、删除数据、创建订单等写操作,应满足至少三道条件:

  • 当前用户本来就有执行权限;
  • 服务端对参数做独立校验,并限制可操作范围;
  • 执行前向用户展示动作、对象和关键参数,获得明确确认。

工具描述不是安全策略。即使提示词写着“不要误操作”,真正的权限控制仍必须在服务端代码、数据库规则和审计日志中实现。

8、用结构化输出替代脆弱的文本解析

如果下游代码需要固定字段,不要要求模型“返回一段看起来像 JSON 的文本”后就直接解析。Structured Outputs 可以让响应遵循提供的 JSON Schema,适合信息抽取、分类和表单生成。

const response = await client.responses.create({
  model: "gpt-5.6",
  input: "把这条反馈分类:登录后页面一直转圈,希望尽快修复。",
  text: {
    format: {
      type: "json_schema",
      name: "feedback_result",
      strict: true,
      schema: {
        type: "object",
        properties: {
          category: {
            type: "string",
            enum: ["bug", "feature", "billing", "other"],
          },
          urgency: {
            type: "string",
            enum: ["low", "medium", "high"],
          },
          summary: { type: "string" },
        },
        required: ["category", "urgency", "summary"],
        additionalProperties: false,
      },
    },
  },
});

const result = JSON.parse(response.output_text);

结构符合 Schema 不代表事实一定正确。比如模型可以合法输出 urgency: "high",但是否真的紧急仍取决于你的业务规则。因此要分别验证“格式正确”和“业务判断正确”。

9、建立错误、限流与成本控制

一个能演示的脚本与一个能上线的服务,差别往往在异常路径。至少处理以下情况:

情况 应用应该怎么做
输入为空或过长 在调用 API 前拒绝并给出可执行提示
身份无效 返回 401 或 403,不调用模型
触发速率限制 使用带随机抖动的指数退避,限制最大重试次数
上游超时 允许用户取消,记录请求 ID,返回可重试状态
模型拒绝请求 识别拒绝状态,不把它伪装成系统故障
工具执行失败 返回结构化错误给模型,禁止无限循环调用
输出不满足业务规则 服务端校验,必要时进入人工复核

失败请求也可能占用速率配额,所以不能无间隔地不断重发。应用还应为单个用户设置日、周或月用量上限,监控异常增长,并在平台项目中配置预算提醒和支出限制。

成本评估不要只看单次 API 价格。还应记录每类任务的输入规模、输出长度、重试次数、工具调用次数和人工修正时间。模型选择可参考站内的模型任务评测方法,用自己的代表性任务做固定测试,而不是只比较一次演示结果。

10、补齐安全与隐私设计

OpenAI 官方安全最佳实践建议使用内容审核、对抗测试和人工复核等措施。具体组合取决于应用风险,但下面几项不应省略:

  1. 输入边界:限制长度、文件类型、URL 和允许的业务范围。
  2. 提示注入防护:把外部网页和文档当作不可信数据,不让其中的文字改变系统权限。
  3. 最小工具权限:能只读就不给写入权限,能按用户限定就不开放全库访问。
  4. 敏感信息处理:提交前删除不必要的密码、密钥、身份信息和公司机密。
  5. 人工复核:医疗、法律、财务、高影响决策和代码执行等场景保留人工检查。
  6. 审计与删除:记录必要的操作证据,同时设置保留期限和删除流程。

测试时既要覆盖正常问题,也要主动尝试“忽略之前规则”“输出隐藏指令”“读取其他用户数据”等对抗输入。测试目标不是证明模型永不出错,而是确认错误不会越过服务端权限边界。

11、用评测决定是否可以上线

不要用“感觉回答不错”作为发布标准。建立一组来自真实业务、但已经去除敏感信息的测试样本,并为每条样本记录:

  • 任务是否完成;
  • 事实是否正确;
  • 输出格式是否合规;
  • 工具是否选择正确;
  • 是否出现越权或泄露;
  • 响应时间、用量和人工修改时间。

每次修改模型、指令、Schema 或工具描述后重新运行同一组样本。先在测试项目和小流量环境验证,再逐步扩大范围。模型更新时,至少同时测试当前推理设置和相邻设置,不要只替换模型字符串就直接推到生产环境。

12、上线前检查清单

  • API Key 只存在于服务端 Secret 或环境变量中。
  • 开发、测试、生产使用独立项目和权限。
  • 用户身份、请求长度、频率与总用量都有限制。
  • 错误响应不会泄露密钥、内部提示或堆栈信息。
  • 多轮会话数据与正确用户绑定,并有过期和删除机制。
  • 工具参数经过服务端校验,高影响操作需要再次确认。
  • 结构化输出同时经过 Schema 与业务规则验证。
  • 流式输出支持取消、断线和最终状态处理。
  • 代表性任务已经完成回归测试和对抗测试。
  • 平台预算提醒、应用日志和异常告警已经启用。

13、下一步怎么扩展

先让最小文本接口稳定运行,再按真实需求增加能力。需要连续对话时加入会话状态;等待体验不好时加入流式输出;必须访问实时数据时再加入只读工具;下游程序需要可靠字段时使用结构化输出。不要一开始就把搜索、写操作、长记忆和多个工具全部开放。

如果你还没有形成稳定的指令模板,下一步先完成ChatGPT 提示词实战,为每个 API 任务写清输入、限制与验收标准,再把它们纳入自动评测。

参考来源