OpenAI 兼容 API
NovelAI 提供了 OpenAI 兼容的 API 端点,允许你使用标准的 OpenAI API 格式与 NovelAI 的文本生成服务进行交互。这降低了从 OpenAI 迁移的成本,并提高了与现有工具的互操作性。
注意
OpenAI 兼容 API 使用的模型与原生文本生成 API 不同:
- OpenAI 兼容 API:使用 GLM 系列模型(
glm-4-5、glm-4-6) - 原生文本生成 API:使用 NovelAI 专有模型(
llama-3-erato-v1、kayra-v1、clio-v1)
GLM 模型是通用对话模型,而 Erato/Kayra/Clio 是专门为故事写作优化的模型。
可用模型
通过 listModels() 获取当前可用的模型:
| 模型 | 描述 |
|---|---|
glm-4-6 | GLM-4 第 6 版(推荐) |
glm-4-5 | GLM-4 第 5 版 |
typescript
const models = await client.openai.listModels();
// 返回: [{ id: 'glm-4-5', owned_by: 'novelai' }, { id: 'glm-4-6', owned_by: 'novelai' }]端点概览
| 端点 | 方法 | 完整 URL | 描述 |
|---|---|---|---|
/oa/v1/completions | POST | https://text.novelai.net/oa/v1/completions | 文本补全 |
/oa/v1/chat/completions | POST | https://text.novelai.net/oa/v1/chat/completions | 聊天补全 |
/oa/v1/models | GET | https://text.novelai.net/oa/v1/models | 列出可用模型 |
/oa/v1/internal/token-count | POST | https://text.novelai.net/oa/v1/internal/token-count | Token 计数 |
基本用法
文本补全
typescript
import { NovelAI } from 'novelai-sdk-unofficial';
const client = new NovelAI({ apiKey: 'your-api-key' });
// 首先获取可用模型
const models = await client.openai.listModels();
const model = models[0].id; // 例如 'glm-4-6'
const response = await client.openai.completion({
prompt: 'Once upon a time, in a kingdom far away,',
model,
maxTokens: 100,
temperature: 0.7,
});
console.log(response.choices[0].text);聊天补全
typescript
const response = await client.openai.chatCompletion({
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: 'Hello! How are you?' },
],
model: 'glm-4-6',
maxTokens: 100,
});
console.log(response.choices[0].message.content);流式响应
文本补全流式
typescript
const stream = client.openai.completionStream({
prompt: 'The quick brown fox',
model: 'glm-4-6',
maxTokens: 100,
});
for await (const chunk of stream) {
const text = chunk.choices[0]?.text;
if (text) process.stdout.write(text);
}聊天补全流式
typescript
const stream = client.openai.chatCompletionStream({
messages: [{ role: 'user', content: 'Tell me a story' }],
model: 'glm-4-6',
maxTokens: 200,
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content;
if (content) process.stdout.write(content);
}取消流式请求
typescript
const controller = new AbortController();
// 5 秒后取消
setTimeout(() => controller.abort(), 5000);
try {
for await (const chunk of client.openai.chatCompletionStream({
messages: [{ role: 'user', content: 'Write a long story' }],
}, controller.signal)) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
}
} catch (error) {
if (error.name === 'AbortError') {
console.log('\nGeneration cancelled');
}
}列出模型
typescript
const models = await client.openai.listModels();
for (const model of models) {
console.log(`${model.id} (owned by ${model.owned_by})`);
}Token 计数
typescript
const count = await client.openai.tokenCount({
prompt: 'Hello, world! This is a test.',
model: 'llama-3-erato-v1',
});
console.log(`Token count: ${count}`);参数说明
补全参数
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
prompt | string | 必填 | 输入提示文本 |
model | string | 必填 | 使用的模型(如 glm-4-6) |
maxTokens | number | - | 最大生成 token 数 (1-2048) |
temperature | number | - | 采样温度 (0-2) |
topP | number | - | 核采样阈值 (0-1) |
topK | number | - | Top-K 采样 |
minP | number | - | Min-P 采样阈值 (0-1) |
stop | string | string[] | - | 停止序列 |
stream | boolean | false | 启用流式响应 |
n | number | - | 生成的补全数量 |
frequencyPenalty | number | - | 频率惩罚 (-2.0 到 2.0) |
presencePenalty | number | - | 存在惩罚 (-2.0 到 2.0) |
seed | number | - | 随机种子 |
聊天补全参数
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
messages | OAIChatMessage[] | 必填 | 聊天消息数组 |
model | string | 必填 | 使用的模型(如 glm-4-6) |
maxTokens | number | - | 最大生成 token 数 (1-2048) |
temperature | number | - | 采样温度 (0-2) |
topP | number | - | 核采样阈值 (0-1) |
topK | number | - | Top-K 采样 |
minP | number | - | Min-P 采样阈值 (0-1) |
stop | string | string[] | - | 停止序列 |
stream | boolean | false | 启用流式响应 |
enableThinking | boolean | - | 启用思考/推理模式 |
消息格式
typescript
interface OAIChatMessage {
role: 'system' | 'user' | 'assistant';
content: string;
name?: string; // 可选的作者名称
}统一采样参数
NovelAI 支持额外的统一采样参数:
| 参数 | 类型 | 描述 |
|---|---|---|
unifiedLinear | number | 统一线性采样参数 |
unifiedQuadratic | number | 统一二次采样参数 |
unifiedCubic | number | 统一三次采样参数 |
unifiedIncreaseLinearWithEntropy | number | 统一熵增线性参数 |
与原生 API 的对比
| 特性 | OpenAI 兼容 API | 原生 API |
|---|---|---|
| 接口风格 | OpenAI 标准格式 | NovelAI 原生格式 |
| 可用模型 | GLM 系列(glm-4-5、glm-4-6) | Erato/Kayra/Clio |
| 模型特点 | 通用对话模型 | 故事写作专用模型 |
| 聊天支持 | ✅ 内置 | ❌ 需手动构建 |
| 迁移成本 | 低 | 高 |
| 参数命名 | camelCase | snake_case |
| 流式格式 | SSE (data: JSON) | 原生流 |
何时使用 OpenAI 兼容 API
- 从 OpenAI 迁移现有代码
- 需要与 OpenAI 兼容的工具集成
- 构建通用聊天应用
- 需要标准化的 API 格式
何时使用原生 API
- 需要 NovelAI 专有的故事写作模型(Erato/Kayra/Clio)
- 需要更精细的参数控制
- 已有 NovelAI 原生代码
- 需要最佳的故事生成质量
响应格式
补全响应
typescript
interface OAICompletionResponse {
id: string;
object: 'text_completion';
created: number;
model: string;
choices: Array<{
text: string;
index: number;
finish_reason: 'stop' | 'length' | null;
}>;
usage: {
prompt_tokens: number;
completion_tokens: number;
total_tokens: number;
};
}聊天补全响应
typescript
interface OAIChatCompletionResponse {
id: string;
object: 'chat.completion';
created: number;
model: string;
choices: Array<{
index: number;
message: {
role: 'assistant';
content: string;
};
finish_reason: 'stop' | 'length' | null;
}>;
usage: {
prompt_tokens: number;
completion_tokens: number;
total_tokens: number;
};
}错误处理
typescript
import {
NovelAI,
AuthenticationError,
InvalidRequestError,
RateLimitError
} from 'novelai-sdk-unofficial';
try {
const response = await client.openai.chatCompletion({
messages: [{ role: 'user', content: 'Hello' }],
});
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('API Key 无效');
} else if (error instanceof InvalidRequestError) {
console.error('请求参数错误:', error.message);
} else if (error instanceof RateLimitError) {
console.error('请求频率限制');
}
}