Ai

聊天机器人

使用 Nebutra 的聊天补全 API 构建聊天机器人——系统提示、对话历史和限流配置。

概述

聊天补全接口接收一组消息并返回模型响应。支持流式(SSE)和非流式响应、自定义系统提示,以及存储在 @nebutra/db 中的持久对话历史。

配置步骤

.env 中添加模型供应商密钥:

OPENAI_API_KEY=""
AI_DEFAULT_MODEL="gpt-5.4-mini"

# 可选:启用多模型路由
OPENROUTER_API_KEY=""

AI 聊天默认关闭,需为租户启用:

import { setFeatureFlag } from "@nebutra/preset";

await setFeatureFlag("org_123", "ai.chat", true);

也可在控制台 → 组织 → 功能 → AI 聊天中切换。

Authorization 请求头中携带 API Key,向 /api/v1/ai/chat 发送 POST 请求:

curl -X POST https://api.yourdomain.com/api/v1/ai/chat \
  -H "Authorization: Bearer nbk_live_org123_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      { "role": "user", "content": "你好,你能帮我做什么?" }
    ]
  }'

请求格式

POST /api/v1/ai/chat

interface ChatRequest {
  messages: Array<{
    role: "system" | "user" | "assistant";
    content: string;
  }>;
  model?: string;           // 默认为 AI_DEFAULT_MODEL
  stream?: boolean;         // 默认为 true
  conversationId?: string;  // 在 @nebutra/db 中持久化对话历史
  systemPrompt?: string;    // 覆盖默认系统提示
  maxTokens?: number;       // 默认:2048
  temperature?: number;     // 0–2,默认:0.7
}

响应格式

{
  "id": "chatcmpl-abc123",
  "object": "chat.completion",
  "model": "gpt-5.4-mini",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "我可以帮您……"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 42,
    "completion_tokens": 87,
    "total_tokens": 129
  }
}

响应为 Server-Sent Events(SSE)流。完整的客户端处理方式请参阅流式传输页面。

data: {"choices":[{"delta":{"role":"assistant"},"index":0}]}

data: {"choices":[{"delta":{"content":"我可以"},"index":0}]}

data: {"choices":[{"delta":{"content":"帮您"},"index":0}]}

data: [DONE]

自定义系统提示

可以在每次请求中覆盖系统提示,也可以为租户全局设置默认值。

单次请求覆盖:

const response = await fetch("/api/v1/ai/chat", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${apiKey}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    messages: [{ role: "user", content: userMessage }],
    systemPrompt: "你是 Acme Corp 的客户支持专员。请简洁、专业地回答问题。",
  }),
});

租户全局默认值(存储在租户设置中):

import { updateTenantAiSettings } from "@nebutra/tenant";

await updateTenantAiSettings("org_123", {
  systemPrompt: "你是 Acme Corp 的智能助手。",
  defaultModel: "gpt-5.5",
});

对话历史

传入 conversationId 可自动持久化和读取消息历史。对话按租户隔离,存储在 Nebutra 数据库中。

// 第一条消息——创建新对话
const res1 = await fetch("/api/v1/ai/chat", {
  method: "POST",
  headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    messages: [{ role: "user", content: "法国的首都是哪里?" }],
    conversationId: "conv_abc123",
  }),
});

// 后续消息——自动读取历史上下文
const res2 = await fetch("/api/v1/ai/chat", {
  method: "POST",
  headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    messages: [{ role: "user", content: "那里的人说什么语言?" }],
    conversationId: "conv_abc123",  // 相同 ID——自动加载之前的上下文
  }),
});

对话历史会占用模型的上下文窗口。对于非常长的对话,旧消息会被自动摘要以保持在上下文限制内。

上下文窗口管理

API 网关在对话历史接近模型上下文限制时自动进行裁剪:

  1. 摘要 — 最早的消息被压缩为一条摘要消息
  2. 滑动窗口 — 最近的 N 条消息始终保留原文
  3. 系统提示保护 — 系统提示永远不会被裁剪

可以通过响应头查看实际发送给模型的上下文信息:

X-Nebutra-Prompt-Tokens: 1842
X-Nebutra-Context-Window: 128000
X-Nebutra-Messages-Trimmed: 4

在服务端代码中调用

在服务端代码(API 路由、后台任务)中直接使用 @nebutra/agents

import { generateText, streamText } from "@nebutra/agents";
import { getCurrentTenant } from "@nebutra/tenant";

const { tenantId } = getCurrentTenant();

// 非流式——适合后台处理
const { text } = await generateText({
  model: "gpt-5.4-mini",
  prompt: "总结以下文档:" + document.content,
  tenantId,
});

// 流式——适合实时 UI
const stream = await streamText({
  model: "gpt-5.5",
  messages: conversation.messages,
  tenantId,
});

限流

AI 接口按租户进行限流,防止 Token 消耗失控:

套餐请求数/分钟Token 数/分钟
FREE1040,000
PRO60300,000
ENTERPRISE自定义自定义

触发限流时,API 返回 429 Too Many Requests,并在响应头中携带 Retry-After

{
  "error": "rate_limit_exceeded",
  "message": "AI 请求频率超限,请在 12 秒后重试。",
  "retryAfter": 12
}

错误码

错误码HTTP 状态含义
feature_disabled403该租户的 ai.chat 标志已关闭
quota_exceeded402月度 AI Token 配额已耗尽
rate_limit_exceeded429触发每分钟限流
invalid_model400模型标识符无法识别
upstream_error502OpenAI / OpenRouter 返回错误

相关文档

How is this guide?

目录