中文 ▾

Chinese LLM API快速入门

获取 API 密钥

更新于

构建中文应用:提示词、脚本控制与 UTF-8

上线中文功能主要是本地化问题,而非模型问题。你可以决定用户看到的脚本,保持从文件到网络传输的编码干净,并为不分词的文本规划 token。本指南涵盖这三个层面,并提供可直接针对聊天补全接口运行的代码。

你正在连接的内容

服务暴露了 POST /v1/chat/completions 和 GET /v1/models 端点,位于 https://api.chinesellmapi.com/v1。认证方式为 bearer key,唯一的模型 id 为 uncensored。这是一个仅文本的 API,只有一个模型,因此无需选择:你的本地化工作完全在提示词及其周围的代码中完成。

设计前值得了解的限制:提示词和补全共享 100,000 token 的上下文窗口,max_tokens 默认为 2,048,上限为 32,000,请求体最大 8 MB,每个密钥每分钟 300 次请求。流式输出(stream: true)通过服务器发送事件工作,并接受 OpenAI 函数调用格式的 tools。

新账户获得 $0.50 试用额度,有效期七天,无需支付详情;使用电子邮件和密码注册,密钥将立即出现。试用常见问题 详细介绍了规则。

用中文编写提示词,并指明是哪种中文

混合语言提示词是本地化功能中漂移的最常见来源。如果指令是英文但内容是中文,回复有时会返回英文或混合语言。可靠的模式是使用目标语言编写系统提示词,说明三点:角色、脚本和区域词汇。将用户提供的文本放在单独的消息中,以免被误认为指令。

以下是简体中文设置。注意系统提示词指示模型仅使用简体字符回答,并避免杂乱的英文,专有名词除外:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.chinesellmapi.com/v1",
    api_key=os.environ["API_KEY"],
)

SYSTEM_SC = (
    "你是一名产品文案助手。始终使用简体中文回答,使用中国大陆常见的用词和标点,"
    "不要夹杂繁体字或英文句子,专有名词除外。"
)

resp = client.chat.completions.create(
    model="uncensored",
    messages=[
        {"role": "system", "content": SYSTEM_SC},
        {"role": "user", "content": "为一款记账应用写三条应用商店的一句话简介。"},
    ],
    max_tokens=300,
    temperature=0.7,
)
print(resp.choices[0].message.content)
print(resp.usage)

两个习惯能迅速见效。首先,保持提示词简短具体:一个角色、一个输出格式、一到两个约束。其次,将语言要求放在系统消息中,而不是在每次用户交互中重复,以免对话历史稀释它。

控制简体与繁体输出

脚本选择是与用户地区相关的产品决策,而非模型设置。面向中国大陆的产品期望使用简体字符;台湾和香港受众期望使用繁体字,且词汇也不同(常见的例子是软件、网络和数据库术语)。实用的做法是将你的地区标签映射到系统提示词中,并在代码中明确做出选择。

  • zh-CN, zh-SG: 简体,大陆词汇,半角数字,全角中文标点。
  • zh-TW:繁体字,台湾词汇,引号常用直角引号。
  • zh-HK: 繁体,带有香港措辞;如果你的产品有固定术语,请提供简短词汇表。

相同调用的繁体变体如下;仅系统提示词发生变化:

import os
from openai import OpenAI

client = OpenAI(base_url="https://api.chinesellmapi.com/v1", api_key=os.environ["API_KEY"])

SYSTEM_TC = (
    "你是一名產品文案助手。請一律使用繁體中文回答,採用臺灣常用的詞彙與全形標點,"
    "例如「軟體」「網路」「資料庫」,不要混入簡體字。"
)

resp = client.chat.completions.create(
    model="uncensored",
    messages=[
        {"role": "system", "content": SYSTEM_TC},
        {"role": "user", "content": "請用兩句話說明什麼是雙重驗證。"},
    ],
    max_tokens=200,
)
print(resp.choices[0].message.content)

模型偶尔会泄露少量另一种脚本的字符,特别是当用户消息本身是另一种脚本时。添加一个低成本的后置校验,如果触发则用更明确的指令重试一次。对于超出样本检查的情况,将输出通过专门的转换库(如 OpenCC)进行处理:

# A cheap guard: flag replies that contain characters that exist only in Simplified.
# The set below is a small sample, not a full list; use a converter such as OpenCC
# for production-grade checks.
SIMPLIFIED_ONLY = set("这个们说话时间书买卖东车门开关见觉")

def looks_simplified(text: str) -> bool:
    return any(ch in SIMPLIFIED_ONLY for ch in text)

reply = "請用繁體中文回覆的範例文字"
print(looks_simplified(reply))   # False

从磁盘到网络传输再返回的 UTF-8

大多数乱码中文问题不是模型问题。它们来自管道中某处的默认编码:Windows 控制台使用遗留代码页、未指定编码打开的 CSV、重写内容类型的代理。使每个边界显式化。

In Python, pass encoding="utf-8" to open, and if you hand-build JSON, use ensure_ascii=False followed by .encode("utf-8"). The example below does it with plain requests, which also shows the raw HTTP shape of the call:

import json
import os
import requests

# 1) Always open files as UTF-8, never rely on the platform default encoding.
with open("notes_zh.txt", "r", encoding="utf-8") as f:
    note = f.read()

payload = {
    "model": "uncensored",
    "messages": [{"role": "user", "content": "请把下面的笔记整理成三个要点:\n" + note}],
    "max_tokens": 400,
}

# 2) requests encodes json= as UTF-8 for you. If you build the body by hand,
#    keep Chinese readable and make the encoding explicit.
body = json.dumps(payload, ensure_ascii=False).encode("utf-8")

r = requests.post(
    "https://api.chinesellmapi.com/v1/chat/completions",
    headers={
        "Authorization": "Bearer " + os.environ["API_KEY"],
        "Content-Type": "application/json; charset=utf-8",
    },
    data=body,
    timeout=60,
)
r.raise_for_status()
r.encoding = "utf-8"
print(r.json()["choices"][0]["message"]["content"])

在 Node.js 中,除非提供编码,否则 readFile 返回 Buffer,包含中文的模板字符串只要源文件本身保存为 UTF-8 就没问题。官方 SDK 会自动序列化请求体:

import { readFile } from "node:fs/promises";
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.chinesellmapi.com/v1",
  apiKey: process.env.API_KEY,
});

// Pass "utf8" explicitly; without it readFile returns a Buffer, not a string.
const note = await readFile("notes_zh.txt", "utf8");

const res = await client.chat.completions.create({
  model: "uncensored",
  messages: [{ role: "user", content: `请把下面的笔记整理成三个要点:\n${note}` }],
  max_tokens: 400,
});

console.log(res.choices[0].message.content);
console.log(res.usage);

另外两个陷阱。按字节长度截断字符串可能会切断一个字符,因此始终应按字符切片。当你进行流式输出时,以 UTF-8 格式增量解码流,因为多字节字符可能会跨网络块分割;SDK 会处理这种情况,但手写解析器通常不会。

为中文文本规划 token

中文没有空格,所以词数对于分配 token 预算毫无用处。作为规划假设而非测量常量,将一个中文字符视为大约 1 到 2 个 token,当你需要一个单一数字时使用 1.5。文本中嵌入的拉丁单词和数字每个词更接近 1.3 个 token。比例因词汇而异,因此唯一的权威数据是每个响应返回的 usage 对象。

一个小助手可以轻松估算发送提示词前的 token 数,并根据随时间推移的真实使用情况调整比率:

import re

CJK = re.compile(r"[㐀-鿿＀-￯ -〿]")

def rough_tokens(text: str, per_cjk: float = 1.5, per_other_word: float = 1.3) -> int:
    """Planning estimate only. The 1.5 and 1.3 ratios are assumptions, not
    measured values; compare against resp.usage and adjust them."""
    cjk = len(CJK.findall(text))
    others = len(re.findall(r"[A-Za-z0-9_]+", CJK.sub(" ", text)))
    return round(cjk * per_cjk + others * per_other_word)

sample = "订单 A-1042 已发货,预计周三送达。"
print(rough_tokens(sample))

计算示例,已说明假设:一篇 2,000 字符的文章,每字符 1.5 个 token,大约需要 3,000 个输入 token。400 字符的摘要大约需要 600 个输出 token。输入 token 每百万 $0.25,输出 token 每百万 $1.00,一次调用的输入成本约为 $0.00075,输出成本约为 $0.0006,总计约 $0.00135。由于上下文窗口限制为 100,000 个 token,同样的假设意味着约 40,000 字符的提示词会留出回复的空间。

当你需要喂送长文档时,按段落或标题分块,绝不在句子中间分块,并保持 max_tokens 明确。价格和限制列在 定价页面上。

将多轮中文聊天保持在窗口内

聊天功能会在每次请求时重新发送整个历史记录,因此成本和上下文会随每次对话增加。因为上下文窗口在提示词和补全之间共享 100,000 个 token,如果什么都不做,长对话最终会触发 400 错误。尽早决定修剪策略,而不是对错误做出反应。

一个简单的策略是保留系统提示词,丢弃最旧的交互直到估计的提示词符合预算,并将剩余部分保留给答案。下面的草图重用上一节中的估算器:

MAX_PROMPT_TOKENS = 48_000   # leave headroom under the 100,000 window for the reply

def trim_history(messages, estimate):
    # messages[0] is the system prompt and is always kept
    system, rest = messages[0], messages[1:]
    while rest and sum(estimate(m["content"]) for m in [system] + rest) > MAX_PROMPT_TOKENS:
        rest.pop(0)   # drop the oldest turn first
    return [system] + rest

对于早期上下文很重要的产品,如辅导机器人或支持助手,用简短的摘要消息替换丢弃的交互,而不是直接丢弃。要求模型将旧交互压缩为几句话,使用与对话相同的脚本,然后将该摘要插入系统提示词之后。这每隔一段时间需要一次额外的调用,并保持角色和事实稳定。

还要记得为聊天合理限制 max_tokens。消息界面中的回复通常不需要超过几百个 token,更严格的限制使延迟和成本更可预测。逐 token 流式输出回复有助于提升感知速度,特别是对于中文文本,用户阅读时通常是分段进行的。

上线前检查清单和后续步骤

  1. 将每个区域设置映射到系统提示词,并对映射进行单元测试。
  2. 在文件读取、请求体和日志中显式设置编码。
  3. 按功能记录 usage,并与你的估算器每周进行比较。
  4. 以不同方式处理 402(no_credit)、429 和 503(upstream_busy):充值、降低速率、几秒后重试。
  5. 将 403(content_blocked)视为该请求的最终处理结果,而不是重试情况。

如果你的应用涉及翻译管道,请继续查看 翻译和本地化指南;对于连载小说和角色聊天,请参阅 网络小说指南。完整的参数参考在 文档中。

问答

如何使回复仅包含简体中文?

在中文系统提示词中声明,例如“始终使用中国大陆词汇用简体中文回答”。将该指令保留在系统消息中,如果输出必须严格,则添加后置校验。

我可以为台湾用户请求繁体中文吗?

可以。使用用繁体字符编写的系统提示词,指定你想要的地区词汇,并从代码中的 zh-TW 地区进行映射。

为什么我的输出中会出现乱码中文?

几乎总是客户端编码问题。以 UTF-8 格式读取文件,设置内容类型字符集,并确保您的终端或日志查看器也使用 UTF-8。

中文文本消耗多少 token?

按每个字符约 1.5 个 token 进行估算,然后检查每个响应中的 usage 字段,并调整您的估算值。

只差一张表单,即可获得密钥

创建账户,复制密钥,更改基础 URL。这就是全部设置。

获取 API 密钥