Skip to content

网页版 AI 聊天接入 GPT-6 Astra ​

Updated: 2026-09-08

本文说明如何开发自己的网页版 AI 聊天工具,并通过 Cubicspaces 接入 gpt-6-astra。

推荐架构 ​

text
浏览器 -> 你的应用后端 -> Cubicspaces Responses API -> gpt-6-astra

不要从浏览器直接请求 Cubicspaces,也不要把 API Key 写入网页源码、前端环境变量、Local Storage 或公开仓库。浏览器只调用你自己的后端,由后端保存 API Key、调用模型并把流式结果转发给浏览器。

接口配置 ​

项目值
Base URLhttps://cubicspaces.cloud/v1
请求地址POST /responses
模型gpt-6-astra
鉴权Authorization: Bearer YOUR_API_KEY

新开发的 GPT-6 Astra 网页聊天应直接使用 Responses API。Chat Completions 适合兼容已有客户端,不建议作为新应用的首选协议。

后端流式接口 ​

下面使用 Node.js、Express 和 OpenAI SDK 创建一个最小后端。先安装依赖:

bash
npm install express openai

将 Cubicspaces API Key 放入服务端环境变量:

bash
CUBICSPACES_API_KEY=YOUR_API_KEY
js
import express from "express";
import OpenAI from "openai";

const app = express();
app.use(express.json({ limit: "1mb" }));

const client = new OpenAI({
  apiKey: process.env.CUBICSPACES_API_KEY,
  baseURL: "https://cubicspaces.cloud/v1",
});

// 仅用于演示;生产环境应将会话状态保存到数据库或 Redis。
const conversations = new Map();

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

  if (!message || !/^[a-zA-Z0-9_-]{1,128}$/.test(conversationId)) {
    return res.status(400).json({ error: "invalid request" });
  }

  res.setHeader("Content-Type", "text/event-stream; charset=utf-8");
  res.setHeader("Cache-Control", "no-cache, no-transform");
  res.setHeader("Connection", "keep-alive");
  res.flushHeaders();

  try {
    const stream = await client.responses.create({
      model: "gpt-6-astra",
      input: message,
      previous_response_id: conversations.get(conversationId),
      reasoning: { effort: "low" },
      max_output_tokens: 4096,
      stream: true,
    });

    for await (const event of stream) {
      if (event.type === "response.output_text.delta") {
        res.write(`event: delta\ndata: ${JSON.stringify({ text: event.delta })}\n\n`);
      }

      if (event.type === "response.completed") {
        conversations.set(conversationId, event.response.id);
        res.write(
          `event: done\ndata: ${JSON.stringify({ response_id: event.response.id })}\n\n`,
        );
      }

      if (event.type === "response.failed") {
        res.write(
          `event: error\ndata: ${JSON.stringify({
            message: event.response.error?.message || "request failed",
          })}\n\n`,
        );
      }
    }
  } catch (error) {
    const status = Number(error?.status) || 500;
    res.write(
      `event: error\ndata: ${JSON.stringify({ status, message: error?.message || "request failed" })}\n\n`,
    );
  } finally {
    res.end();
  }
});

app.listen(3000);

生产环境还应校验用户身份、限制消息长度、设置单用户限流、串行处理同一会话的请求,并在浏览器断开连接时取消仍在运行的模型请求。

浏览器读取流式响应 ​

由于聊天请求使用 POST,可以通过 fetch 读取响应流:

js
let conversationId = crypto.randomUUID();

async function sendMessage(message, onDelta) {
  const response = await fetch("/api/chat", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      message,
      conversation_id: conversationId,
    }),
  });

  if (!response.ok || !response.body) {
    throw new Error(`Chat request failed: ${response.status}`);
  }

  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buffer = "";

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    buffer += decoder.decode(value, { stream: true });
    const frames = buffer.split(/\r?\n\r?\n/);
    buffer = frames.pop() || "";

    for (const frame of frames) {
      const event = frame.match(/^event: (.+)$/m)?.[1];
      const data = frame.match(/^data: (.+)$/m)?.[1];
      if (!event || !data) continue;

      const payload = JSON.parse(data);
      if (event === "delta") onDelta(payload.text);
      if (event === "error") throw new Error(payload.message || "Chat failed");
    }
  }
}

渲染模型输出时,不要直接赋值给 innerHTML。如果需要 Markdown,请使用支持 HTML 清理的渲染库,避免把模型输出当作可信 HTML 执行。

多轮对话 ​

浏览器只提交应用自己的 conversation_id。后端在首次请求时不传 previous_response_id;请求完成后保存平台返回的 response.id,下一轮再由后端将它作为 previous_response_id 发送。

示例使用内存保存会话,进程重启后会丢失,只适合本地验证。生产环境应由后端按登录用户和会话持久化响应 ID,并校验会话归属;新建对话时创建新的会话 ID,切换对话时读取对应记录。

如果应用不使用响应 ID,则需要在自己的数据库中保存消息历史,并在后续请求中重新构造 input。

GPT-6 Astra 参数 ​

json
{
  "model": "gpt-6-astra",
  "input": "请分析这段代码并给出修改建议。",
  "reasoning": {
    "effort": "low"
  },
  "max_output_tokens": 4096,
  "stream": true
}
  • 输出长度使用 max_output_tokens。
  • 推理强度使用 reasoning.effort,可用值为 low、medium、high、xhigh 和 max。
  • 不支持 none 或 minimal;普通聊天建议从 low 开始。
  • 不要发送 temperature、top_p、top_k、frequency_penalty、presence_penalty、logprobs、stop 或 chat_template_kwargs。

工具调用 ​

需要联网搜索、查询数据库或调用业务接口时,在后端请求中定义 Responses 工具。模型返回函数调用后,由后端执行工具,再提交与原始 call_id 匹配的 function_call_output。

不要让浏览器直接执行需要密钥或后台权限的工具,也不要直接信任模型生成的工具参数。调用前应执行 JSON Schema 校验和权限检查。

请求结构和事件格式参见 OpenAI Responses。

上线检查 ​

  • API Key 只存在于服务端。
  • 每次请求都校验当前登录用户。
  • 会话 ID 与用户绑定,不能跨用户读取。
  • 对消息长度、并发数和请求频率设置限制。
  • 支持浏览器主动停止生成。
  • 区分 400、401、429 和 5xx,不要把所有错误统一显示为“网络错误”。
  • 保存平台返回的请求 ID,便于排查问题。