创建对话补全 · Create Chat Completion
向指定角色发送一条消息并以流式(SSE)方式获取 AI 回复。这是与角色对话的核心接口。
接口地址
POST https://api.xiangcao.ai/create-chat-completion
该接口为流式(SSE)长连接,单次超时 300s,已开启 CORS。
鉴权
在请求头中携带你的 API Key:
Authorization: Bearer <YOUR_API_KEY>
缺少或无效的 Token 会返回 401。接口对每个用户有调用频率限制(rate limit)。
请求体(JSON)
所有字段均为可选:传 archiveId 续聊、传 characterId 开新对话,二者至少其一。其余字段不传时,网关会用账号的模型设置(model settings)填充默认值,因此最简调用只需 characterId + message。
常用字段
| 字段 | 类型 | 说明 |
|---|---|---|
archiveId | string | 对话存档 ID。续聊已有对话时传入;不传则根据 characterId 自动新建或复用存档。 |
characterId | string | 角色 ID。未提供 archiveId 时必填,用于创建新存档。 |
message | string | 用户消息内容。regenerate 模式下可省略。支持 正文\n{指令} 的内嵌指令格式。 |
regenerate | boolean | 是否重新生成上一条 AI 回复。为 true 时通常无需再传 message。 |
model | string | 覆盖账号默认模型。不传则使用账号模型设置中的模型。 |
maxTokens | number | 本次回复的最大输出 token 数。 |
maxContext | number | 上下文窗口最大 token 数。 |
reasoningEffort | enum | 推理强度,取值见下方类型定义。 |
contentFormat | enum | 内容格式:roleplay / script / novel。 |
inputGuard | enum | 输入审查模式:rules(默认)/ model / off。 |
archiveId与characterId至少提供一个:传archiveId续聊,传characterId开新对话。
完整类型定义(TypeScript)
interface CreateChatCompletionRequest {
/** 对话存档 ID;不传则按 characterId 自动新建/复用 */
archiveId?: string;
/** 角色 ID;未提供 archiveId 时必填 */
characterId?: string;
/** 用户消息;regenerate 模式下可省略。支持 "content\n{instruction}" 内嵌指令 */
message?: string;
/** 重新生成上一条 AI 回复 */
regenerate?: boolean;
/** 覆盖账号默认模型 */
model?: string;
/** 纯标识符,仅写入消息 metadata.modelDisplayName,不参与上游请求构建 */
modelDisplayName?: string;
/** 覆盖存档中的用户名 */
userName?: string;
/** 用户角色描述,用于 {{persona}} 宏 */
userPersona?: string;
/** 上下文窗口最大 token 数 */
maxContext?: number;
/** 本次回复的最大输出 token 数 */
maxTokens?: number;
/** 角色卡内容占用的 token 上限,超出按比例截断 */
maxCharacterTokens?: number;
/** 推理强度(覆盖存档/prompt 模板设置) */
reasoningEffort?: ReasoningEffort;
/** 内容解析模式,写入消息的 content_format 字段 */
contentFormat?: ContentFormat;
/** 输入审查模式,默认 "rules" */
inputGuard?: InputGuardMode;
/** prompt 模板局部变量,可用 {{getvar::变量名}} 引用 */
variables?: ChatVariables;
}
type ReasoningEffort = "none" | "minimal" | "low" | "medium" | "high" | "xhigh";
type ContentFormat = "roleplay" | "script" | "novel";
type InputGuardMode = "rules" | "model" | "off";
interface ChatVariables {
/** 输出语言 */
language?: "English" | "繁體中文" | "简体中文";
/** 字数提示,对应模板里的 {{getvar::word_count}} */
word_count?: string;
model_name?: string;
}
promptId、creditsCost、enableKnowledge、enableStatusBlockContext等字段由网关内部根据账号设置填充,调用方无需传入。
响应:SSE 事件流
响应类型为 text/event-stream。每个事件以 data: {json}\n\n 形式推送,通过 JSON 中的 type 字段区分类型:
| type | 含义 |
|---|---|
archive_created | 新建(或复用)存档时返回,携带 archiveId、reused。 |
user_message | 用户消息已保存到存档,携带 message。 |
message_stream | 生成过程中的中间状态,每次发送当前完整的 contentItems(非增量),前端直接替换即可。 |
assistant_complete | AI 回复生成完成并落库,message 含 tokens、耗时等 metadata。 |
message_deleted | regenerate 模式下,被删除的旧回复消息 ID。 |
knowledge_updated | (可选)开启 Knowledge 时,记忆更新完成。 |
status_bar_generating | (可选)开启状态栏自动生成时,AI 回复完成后开始生成状态栏,前端可进入加载态。 |
status_bar_updated | (可选)状态栏生成完成,携带 messageId 与 statusItems;未产出内容时不发送。 |
chat_complete | 本次对话流程结束,前端可据此释放加载状态。 |
aborted | 请求被中断。 |
error | 生成过程中出错,携带 error 与可选 statusCode。 |
注意:
message_stream每次推送的是「当前完整的contentItems」而非增量,前端直接替换即可。
事件类型定义(TypeScript)
type SSEChunk =
| ArchiveCreatedChunk
| UserMessageChunk
| MessageStreamChunk
| AssistantCompleteChunk
| MessageDeletedChunk
| KnowledgeUpdatedChunk
| StatusBarGeneratingChunk
| StatusBarUpdatedChunk
| ChatCompleteChunk
| AbortedChunk
| ErrorChunk;
interface ArchiveCreatedChunk {
type: "archive_created";
archiveId: string;
/** true=复用了该角色最近一次存档(可能有未加载的历史);false/缺省=新建空存档 */
reused?: boolean;
}
interface UserMessageChunk {
type: "user_message";
message: ArchiveMessage; // 已保存的用户消息
}
interface MessageStreamChunk {
type: "message_stream";
message: ArchiveMessage; // 生成中的当前完整状态(contentItems 全量,非增量)
}
interface AssistantCompleteChunk {
type: "assistant_complete";
message: ArchiveMessage; // 已落库的完整 AI 回复,含 metadata
}
interface MessageDeletedChunk {
type: "message_deleted";
messageId: string; // regenerate 模式下被删除的旧回复 ID
}
interface KnowledgeUpdatedChunk {
type: "knowledge_updated"; // 记忆更新完成(开启 Knowledge 时)
}
interface StatusBarGeneratingChunk {
type: "status_bar_generating"; // 开始生成状态栏(前端进入加载态)
}
interface StatusBarUpdatedChunk {
type: "status_bar_updated";
/** 关联的 AI 回复消息 ID */
messageId: string;
/** 状态栏渲染指令(Server-Driven UI),前端直接渲染 */
statusItems: StatusItem[];
}
interface ChatCompleteChunk {
type: "chat_complete"; // 本次流程结束
}
interface AbortedChunk {
type: "aborted"; // 请求被中断
}
interface ErrorChunk {
type: "error";
error: string;
statusCode?: number;
}
/** status_bar_updated.statusItems 的元素类型(Server-Driven UI,前端按 type 渲染) */
type StatusItem =
| { type: "header"; title: string }
| { type: "range"; key: string; value: string; percent: number; trend?: "up" | "down" }
| { type: "counter"; key: string; value: string; current: number; total: number; trend?: "up" | "down" }
| { type: "tags"; key: string; tags: string[] }
| { type: "text"; key: string; value: string; trend?: "up" | "down" }
| { type: "plain"; text: string };
消息对象 ArchiveMessage
user_message / message_stream / assistant_complete 事件里的 message 字段结构如下:
interface ArchiveMessage {
/** 消息 ID(API 返回时包含) */
id?: string;
/** 角色 */
role: "user" | "assistant" | "system";
/** 原始文本;目前下发为空字符串(兼容保留),请改用 contentItems */
content: string;
/** 内容解析模式 */
contentFormat?: ContentFormat;
/** 服务端解析后的渲染指令(Server-Driven UI),消息正文以此为准 */
contentItems?: ContentItem[];
/** 角色状态栏内容 */
statusBlock?: string[];
/** 状态栏渲染指令 */
statusItems?: StatusItem[];
/** 快捷选项 - 点击后作为 user 消息发送 */
presetOptions?: string[];
/** Tool calls(仅 assistant 消息) */
toolCalls?: ToolCallInfo[];
/** 模型、tokens 等元数据 */
metadata?: MessageMetadata;
/** 关联生成的图片 URL */
imageUrl?: string;
/** 创建时间(毫秒时间戳) */
createdAt?: number;
/** 软删除标记 */
deleted?: boolean;
deletedAt?: number;
}
interface MessageMetadata {
/** 上游实际使用的模型 ID(用于计费) */
model?: string;
/** 调用方传入的展示用标识符 */
modelDisplayName?: string;
promptTokens?: number;
completionTokens?: number;
/** 推理 tokens(部分模型如 DeepSeek-R1、o1 返回) */
reasoningTokens?: number;
/** 缓存命中 tokens(Prompt Caching) */
cachedTokens?: number;
totalTokens?: number;
/** 生成耗时(毫秒) */
latencyMs?: number;
/** 停止原因:stop / length / tool_calls / content_filter */
finishReason?: string;
/** 思维链内容(部分模型返回) */
reasoningContent?: string;
/** 本条消息扣除的积分数 */
creditsCost?: number;
/** 发送失败标记(余额不足等,消息已存但未被 AI 处理) */
sendFailed?: boolean;
[key: string]: unknown;
}
interface ToolCallInfo {
id: string;
type: "function" | "custom";
function?: { name: string; arguments: string };
}
内容格式与解析(contentFormat / contentItems)
消息正文统一通过 contentItems 下发:服务端按 contentFormat 把内容解析成渲染指令数组(Server-Driven UI),前端按 type 直接渲染,无需自己解析标记。
⚠️
content字段目前下发为空字符串(仅作兼容保留),请统一使用contentItems渲染,不要依赖content。
contentFormat 决定解析方式:
| 取值 | 数据格式 |
|---|---|
roleplay | 角色扮演:用符号对标记对话 / 独白 / 音效 / 环境,叙事与对话交织,多用于双人互动。 |
novel | 小说式:标记方式与 roleplay 一致,定位偏连续叙事 / 散文段落,前端可用不同排版样式。 |
script | 剧本式:用 @SCENE / @ROLE 角色名 / @VOICEOVER / @SFX / @INFO 等块标记。 |
解析结果类型(TypeScript)
/** contentItems 的元素:服务端解析后的渲染指令,前端按 type 渲染 */
type ContentItem =
| { type: "paragraph"; segments: ContentSegment[] }
| { type: "scene"; title: string }
| { type: "intext"; intextType: string; lines: string[] }
| { type: "character"; name: string; segments: ContentSegment[] }
| { type: "voiceover"; content: string }
| { type: "sfx"; content: string }
| { type: "info"; infoType: string; source?: string; content: string };
/** 段落 / 角色台词内的细分片段(对话、独白、音效、环境等) */
type ContentSegment =
| { type: "text"; content: string }
| { type: "dialogue"; content: string; open: string; close: string }
| { type: "monologue"; content: string; open: string; close: string }
| { type: "sound"; content: string; open: string; close: string }
| { type: "environment"; content: string; open: string; close: string };
示例
请求:
curl -N -X POST "https://api.xiangcao.ai/create-chat-completion" \
-H "Authorization: Bearer <YOUR_API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"characterId": "abc123",
"message": "你好,今天过得怎么样?"
}'
响应(节选):
data: {"type":"archive_created","archiveId":"arc_001","reused":false}
data: {"type":"user_message","message":{"id":"msg_u1","role":"user","content":"","contentItems":[{"type":"paragraph","segments":[{"type":"text","content":"你好,今天过得怎么样?"}]}]}}
data: {"type":"message_stream","message":{"role":"assistant","content":"","contentItems":[{"type":"paragraph","segments":[{"type":"text","content":"我"}]}]}}
data: {"type":"message_stream","message":{"role":"assistant","content":"","contentItems":[{"type":"paragraph","segments":[{"type":"text","content":"我很好"}]}]}}
data: {"type":"assistant_complete","message":{"id":"msg_a1","role":"assistant","content":"","contentItems":[{"type":"paragraph","segments":[{"type":"text","content":"我很好,谢谢你的关心~"}]}],"metadata":{"model":"...","completionTokens":42,"latencyMs":1830,"finishReason":"stop"}}}
data: {"type":"status_bar_generating"}
data: {"type":"status_bar_updated","messageId":"msg_a1","statusItems":[{"type":"range","key":"好感度","value":"72/100","percent":72,"trend":"up"}]}
data: {"type":"chat_complete"}
错误处理
若在流开始前出错,会返回相应 HTTP 状态码及 JSON:{ "success": false, "error": "..." }。若已进入流式阶段,错误会以 error 事件下发。
| 状态码 | 说明 |
|---|---|
400 | 请求参数无效,例如消息超长或 model 非法。 |
401 | 未携带有效的 Bearer Token,或账号被封禁。 |
402 | 积分不足,无法完成本次生成。 |
403 | 当前模型需要更高的 VIP 等级。 |
500 | 服务端内部错误。 |