获取 API 密钥

Wu Xianzhi API迁移指南

API 中转站迁移指南:从 OpenAI、OpenRouter 切换到无审查 API

如果你的项目现在走的是 OpenAI、OpenRouter 或者某个 API 中转站,想换到一个不会拒答合法需求的无审查 API,其实只需要改三项配置:base_url、密钥和模型名。本文先讲清中转站和专用无审查模型的区别,再给出参数对照表、用环境变量并行运行新旧接口的写法、上线前的切换清单,以及迁移时最容易踩的几个坑。

更新于

要点

  1. 中转站转售的仍是原厂模型,内容策略不变;专用无审查模型才能解决拒答问题
  2. 迁移只改三处:base_url 为 https://api.wuxianzhiapi.com/v1,密钥,模型名 uncensored
  3. 不支持 embeddings、图片、音频和微调,这些能力继续用原来的服务
  4. 用环境变量做灰度切换,出问题改一个变量即可回退

API 中转站和专用无审查模型有什么区别

先把概念说清楚,否则迁移的时候容易选错方向。常见的 API 中转站,本质上是把大厂模型的调用额度转售或聚合起来,对外提供一个 OpenAI 兼容的地址,让你用同一个 SDK 切换不同的模型。它解决的是「访问和付费」的问题,比如统一入口、统一账单,但模型本身还是原来那一个,原厂的内容策略一条不少:该拒绝的话题照样拒绝,换个中转地址并不会改变这一点。

专用的无审查模型是另一回事。它不是转发别人的模型,而是一个单独提供的模型,合法的成人内容、虚构创作和有争议的话题不会被拒答。Wu Xianzhi API 只提供一个模型,模型名是 uncensored,接口兼容 OpenAI 格式,所以迁移成本很低,但它也有清楚的边界:只做文本,不支持图片、音频、向量和微调;涉及未成年人的性内容无论是否虚构都会被拦截,返回 403。

所以迁移前先问自己:我遇到的问题是「接口不稳、价格贵」,还是「模型总是拒绝我的合法需求」?如果是后者,换中转站意义不大,换到专用无审查 API 才对症。很多团队的做法是两者并存:通用任务继续走原来的接口,需要无审查输出的请求单独路由到这里,后文会讲具体怎么做。

从 OpenAI 或 OpenRouter 迁移,要改的三个地方

不管你原来用的是 OpenAI 官方、OpenRouter 这类聚合接口,还是某个中转站,只要代码用的是 OpenAI 兼容的 SDK,需要改的就是三项:base_url 改成 https://api.wuxianzhiapi.com/v1;api_key 换成在 /get-api-key/ 拿到的密钥;model 统一写 uncensored。没有别的模型可选,GET /v1/models 里也只有这一个。

import os
from openai import OpenAI

messages = [{"role": "user", "content": "你好"}]

# 迁移前(示意):
# client = OpenAI(api_key=os.environ["OLD_API_KEY"], base_url="旧地址")
# resp = client.chat.completions.create(model="旧模型名", messages=messages)

# 迁移后:只动 base_url、api_key、model 这三处
client = OpenAI(
    base_url="https://api.wuxianzhiapi.com/v1",
    api_key=os.environ["WUXIANZHI_API_KEY"],
)
resp = client.chat.completions.create(model="uncensored", messages=messages, max_tokens=100)
print(resp.choices[0].message.content)

Node.js 同理,把 new OpenAI({...}) 里的 baseURL 和 apiKey 换掉。如果你的项目是直接用 HTTP 请求的,把请求地址改为 https://api.wuxianzhiapi.com/v1/chat/completions,请求头保持 Authorization: Bearer <密钥> 即可。完整的 Python、Node.js、cURL 写法可以对照 代码示例。

curl https://api.wuxianzhiapi.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $WUXIANZHI_API_KEY" \
  -d '{"model":"uncensored","messages":[{"role":"user","content":"你好"}],"max_tokens":50}'

参数对照:哪些能用,哪些不适用

下面这张表把迁移时最常碰到的字段过了一遍。原则是:对话相关的、OpenAI 格式的核心字段都可以照常使用;和「别的模型、别的模态」相关的功能,这里没有。

原来的用法在这里怎么处理
model(如各种 gpt 型号)必须改成 uncensored
messages(system / user / assistant / tool)格式一致,直接使用
max_tokens默认 2048,最大 16,000;超过会报 400
stream: true支持,最后自动追加一个用量块
tools / tool_choice支持,OpenAI 格式
上下文长度提示词加输出合计 64,000 tokens
请求体大小不超过 8 MB
速率每个密钥每分钟 300 次请求
向量 embeddings不支持
图片生成 / 识图、语音、视频不支持,只处理文本
微调 fine-tuning不支持
切换多个模型只有一个模型,没有可切换的列表

表里没有列出的其他可选字段,不要默认它们都会按原厂的方式生效。稳妥的做法是在测试环境里单独跑一遍,确认行为符合预期再上线,具体支持情况以 接口文档 为准。

没有的能力怎么办:向量、图片、语音的替代思路

如果你原来的项目同时用了对话和向量检索,迁移时不要想着「全部换过来」。这里只提供文本对话,所以 embeddings 相关的代码,比如知识库检索、语义去重,需要继续使用你原来的向量服务,或者换成自己部署的向量方案。对话部分换到这里,检索部分保持不动,两边互不影响,这是最省事的拆法。

图片、语音同理。比如你的产品是「文字加配图」的形态,文字生成可以走这里,配图继续用原来的图片接口;需要语音播报的,文本生成之后再交给你已有的语音服务。把「生成文字」这一步单独抽成一个函数,后面无论怎么拼装其他能力,改动面都会很小。

还有一种情况是你的代码里用了多个模型分工,比如便宜的模型做分类、贵的模型做创作。这里只有一个模型,分类任务也要由它来做。好在输入单价是 $0.25 / 百万 tokens,做分类这种输出很短的任务成本很低,把 max_tokens 设小,成本基本可以忽略。价格细节见 价格页。

并行运行:用环境变量在两套接口间切换

迁移最怕的是「一刀切」。更稳的做法是在代码里做一层很薄的封装,用环境变量决定走哪一个接口,这样可以先让一小部分流量或者一部分功能走新接口,出了问题改一个变量就能退回去。因为两边都是 OpenAI 兼容格式,封装非常简单。

import os
from openai import OpenAI

PROVIDERS = {
    "old": {
        "base_url": os.environ.get("OLD_BASE_URL", ""),
        "api_key": os.environ.get("OLD_API_KEY", ""),
        "model": os.environ.get("OLD_MODEL", ""),
    },
    "wuxianzhi": {
        "base_url": "https://api.wuxianzhiapi.com/v1",
        "api_key": os.environ.get("WUXIANZHI_API_KEY", ""),
        "model": "uncensored",
    },
}

def get_client(name=None):
    name = name or os.environ.get("LLM_PROVIDER", "old")
    cfg = PROVIDERS[name]
    return OpenAI(base_url=cfg["base_url"], api_key=cfg["api_key"]), cfg["model"]

def chat(messages, provider=None, **kwargs):
    client, model = get_client(provider)
    return client.chat.completions.create(model=model, messages=messages, **kwargs)

# 通用任务走旧接口,需要无审查输出的请求显式指定新接口
resp = chat([{"role": "user", "content": "写一个黑色幽默的短故事"}],
            provider="wuxianzhi", max_tokens=800)
print(resp.choices[0].message.content)

切换粒度可以有三层:按环境(测试环境先切)、按功能(只把创作类接口切过来)、按用户(灰度一部分账号)。无论哪一层,都建议把日志里记录的 provider 字段留下,出现差异时才能对照排查。对话历史也建议统一存成标准的 messages 数组,这样同一段会话可以在两边之间无缝接着聊。

切换清单

上线前按下面的顺序过一遍,基本不会漏项:

  1. 在 /get-api-key/ 注册,拿到密钥,用 $0.50 试用额度(7 天内有效)做验证,不需要先充值。
  2. 用 curl /v1/models 确认密钥有效、网络可达。
  3. 把 base_url、api_key、model 三项改成环境变量驱动,密钥不进代码仓库。
  4. 搜一遍代码里写死的模型名、max_tokens 数值和 embeddings 调用。
  5. 检查流式处理代码,兼容最后一个 choices 为空的用量块。
  6. 给 429 和 503 加指数退避重试,给 402 和 403 加明确的提示分支。
  7. 用你真实的提示词跑一批回归样例,重点看原来被拒答的那部分是否正常输出。
  8. 先灰度小比例流量,对比用量和延迟,没问题再扩大。
  9. 确认产品面向的是成年用户,并且用途合法,这是使用本接口的前提。

迁移中最常见的几个坑

模型名忘了改。旧代码里的 gpt 型号或某个聚合平台的模型路径原样发过来,会得到错误响应。全局搜索模型名,确保最终发出去的是 uncensored。

max_tokens 超限。有些项目为了让模型写得长,把 max_tokens 设到 32000 甚至更大,在这里单次最大是 16,000,超过会返回 400。另外,提示词加 max_tokens 不能超过 64,000 tokens,输入很长的请求要相应调小输出上限。

流式用量块。流结束前服务器会自动追加一个带 usage 的块,它的 choices 是空数组。如果你的解析代码写成 chunk.choices[0] 直接取值,就会在最后一步报错。有些旧代码还会手动传 stream_options 去要用量,在这里不需要。

把「无审查」当成「无边界」。合法的成人内容、虚构和争议话题不会被拒绝,但涉及未成年人的性内容始终拦截,包括虚构和角色扮演,返回 403 content_blocked。产品需要自己做好成年用户的准入。

余额与试用到期。试用额度 7 天后失效,余额用完后会收到 402,错误码是 no_credit。在应用里把这个错误翻译成用户能看懂的提示,而不是笼统的「服务出错」。具体场景设计可以参考 应用场景 一文。

常见问题

迁移之后原来的提示词还要重写吗?

格式不用改,messages 结构完全一致。但原来为了绕过拒答而写的那些「越狱式」铺垫可以删掉,直接写清楚角色和任务,既省 token 也更稳定。

迁移期间能不能新旧接口同时保留?

可以,而且推荐这样做。用环境变量决定 base_url、密钥和模型名,先让部分功能或部分用户走新接口,出问题改一个变量就能退回。

旧接口里的 embeddings 调用换过来会怎样?

这里没有 embeddings 接口,请求会返回 404。向量检索部分请继续使用原来的服务,只把对话请求切过来。

怎么判断迁移后效果有没有变好?

拿一批原来被拒答或被改写的真实提示词做回归对比,记录拒答率、回复长度和 usage 里的 token 数。样本要来自你自己的业务,而不是网上的通用测试集。

只需填写表单即可获取密钥

创建账户,复制密钥,修改 Base URL。配置就是这么简单。

获取 API 密钥