冰冰冰-v1 文档
目录

冰冰冰-v1 文档

hyy 开发的中文多模态对话大模型的接入说明。基座 Qwen3-VL-8B-Instruct, LoRA 微调,支持文本、识图与工具调用,提供 OpenAI 与 Anthropic 两种兼容协议。

基址 https://api.bingbingbing.top 131072 token 上下文 模型 ID bingbingbing-v1

快速开始

想聊天,不需要密钥;想接程序,直接跳到 鉴权。

方式一:网页对话

  1. 打开 https://chat.bingbingbing.top,不需要注册,也不需要填任何密钥。
  2. 直接发消息、传图片。长文档可以整篇粘贴,窗口有 131072 token。
  3. 要切思考档位的话,打开右上角 设置 → 思考档位:
    • low:快速作答,适合闲聊、改写、格式转换。
    • medium:均衡,日常问答与写代码的默认选择。
    • high:深入推理,适合数学、复杂逻辑与多步规划。
    • 关闭:不加任何思考指令,模型直接回答。

档位指令由服务端按所选档位注入,前端只负责告诉它档位。所以同一段对话换档位,行为会立刻变化,不需要重开会话。

方式二:调用 API

bash
# 1) 用主密钥换一把 10 分钟有效的临时 key
curl -s https://api.bingbingbing.top/v1/keys \
  -H "Authorization: Bearer $BING_MASTER_KEY"

# 2) 拿返回的 key 直接对话
curl -s https://api.bingbingbing.top/v1/chat/completions \
  -H "Authorization: Bearer $TEMP_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"bingbingbing-v1","messages":[{"role":"user","content":"冰冰冰?"}]}'

模型信息

冰冰冰-v1 模型基本信息
模型 IDbingbingbing-v1
基座Qwen3-VL-8B-Instruct
微调方式LoRA
参数量8.19B
上下文长度131072 token(128K)
单次输出上限8192 token
能力文本 / 识图 / 工具调用
思考档位low / medium / high

8.19B 是权重里的实际参数量,不是「8B 级别」的约数;上下文与输出上限就是服务端 实际接受的值,超出会被截断或直接返回错误,不要按更大的数字做预算。

API 概览

所有接口都挂在同一个基址下:https://api.bingbingbing.top。 同一把 key 既能调 OpenAI 协议,也能调 Anthropic 协议,不需要分别申请。

接口清单
方法路径用途鉴权头
POST/v1/keys用主密钥换临时 keyAuthorization: Bearer <主密钥>
POST/v1/chat/completionsOpenAI 协议对话Authorization: Bearer <key>
POST/v1/messagesAnthropic 协议对话x-api-key: <key>
GET/v1/models列出可用模型Authorization: Bearer <key>

网页端还有一条自己的通道。 chat.bingbingbing.top 走的是 /api/chat,不在这份文档的 /v1/* 范围内,也不需要你提供 key。 第三方客户端一律接 /v1/*。

鉴权:两段式

不要把主密钥塞进浏览器、前端项目或公开的 CI 变量里。正确做法是先换一把 临时 key,再用它调接口。

第一步:换临时 key

POST /v1/keys 用主密钥换
bash
curl -s -X POST https://api.bingbingbing.top/v1/keys \
  -H "Authorization: Bearer $BING_MASTER_KEY"

返回:

json
{
  "key": "bbk_9f3c...d21",
  "expires_at": "2026-01-01T00:10:00Z",
  "ttl_seconds": 600,
  "concurrency": 1,
  "reused": false
}
/v1/keys 返回字段说明
字段类型说明
keystring临时 key,直接当 Bearer token 用。
expires_atstring过期时间(UTC,ISO 8601)。
ttl_secondsnumber剩余有效秒数,正常是 600。
concurrencynumber这把 key 的并发上限,临时 key 固定为 1。
reusedboolean为 true 表示这把是复用已有的,没有新签发。

三条必须记住的规则

  • 有效期 10 分钟。 ttl_seconds 到点即失效,继续用会拿到 401。客户端应当在缓存里存住 key,在快过期时重新申请,而不是每个请求都申请一次。
  • 同一个 IP 只会拿到同一把。 重复申请返回 reused: true,服务端不重复签发。所以同一台机器上多进程共享一把 key 是正常现象,不是 bug。
  • 临时 key 并发上限是 1。 同一把 key 同时发起第二个请求,会直接得到 429,而不是排队。需要并发就换长期 key。

长期 key

服务端通过环境变量 BING_API_KEYS 配置长期 key(多个用分隔符隔开), 它不过期、并发上限更高,适合放在自建后端的服务端环境里。用法与临时 key 完全一样, 直接放在 Authorization: Bearer 或 x-api-key 里即可。

长期 key 一旦泄露,等于把模型对外的额度永久交出去。前端(浏览器 / 小程序 / 桌面客户端) 只应该用临时 key,并且由你自己的后端去换,主密钥永远不出服务端。

OpenAI 协议

POST /v1/chat/completions Authorization: Bearer <key>
bash
curl -s https://api.bingbingbing.top/v1/chat/completions \
  -H "Authorization: Bearer $TEMP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "bingbingbing-v1",
    "messages": [
      {"role": "user", "content": "你敢冰我?"}
    ],
    "reasoning_effort": "medium",
    "max_tokens": 512,
    "stream": false
  }'
python
from openai import OpenAI

client = OpenAI(
    base_url="https://api.bingbingbing.top/v1",
    api_key=temp_key,          # 临时 key 或长期 key
)

resp = client.chat.completions.create(
    model="bingbingbing-v1",
    messages=[{"role": "user", "content": "你敢冰我?"}],
    max_tokens=512,
    extra_body={"reasoning_effort": "medium"},  # SDK 尚未认识的参数放这里
)

msg = resp.choices[0].message
print(getattr(msg, "reasoning_content", None))  # 思考内容,与正文分开
print(msg.content)                                    # 正文

返回结构与 OpenAI 官方一致:choices[0].message.content 是正文, 思考内容在 choices[0].message.reasoning_content。流式(stream: true) 时两者都走 SSE 的 delta,字段名相同。

Anthropic 协议

POST /v1/messages x-api-key + anthropic-version

这个协议必须带 anthropic-version: 2023-06-01, 且 key 放在 x-api-key 而不是 Authorization —— 少任何一个都会被判成鉴权失败。

bash
curl -s https://api.bingbingbing.top/v1/messages \
  -H "x-api-key: $TEMP_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "bingbingbing-v1",
    "max_tokens": 512,
    "thinking": {"type": "enabled", "budget_tokens": 1024},
    "messages": [
      {"role": "user", "content": "你敢冰我?"}
    ]
  }'
python
import anthropic

client = anthropic.Anthropic(
    base_url="https://api.bingbingbing.top",  # 注意:SDK 自己会补 /v1
    api_key=temp_key,
)

msg = client.messages.create(
    model="bingbingbing-v1",
    max_tokens=512,
    thinking={"type": "enabled", "budget_tokens": 1024},
    messages=[{"role": "user", "content": "你敢冰我?"}],
)

for block in msg.content:
    if block.type == "thinking":
        print(block.thinking)
    elif block.type == "text":
        print(block.text)

Anthropic 协议把内容拆成块:思考在 type: "thinking" 的块里(字段是 thinking), 正文在 type: "text" 的块里。两者永远不会混在同一个块里。

列出模型

GET /v1/models Authorization: Bearer <key>
bash
curl -s https://api.bingbingbing.top/v1/models \
  -H "Authorization: Bearer $TEMP_KEY"

返回只有一个模型 bingbingbing-v1。这个接口常被用来做连通性探活: 它不触发模型推理,因此不会因为实例缩容到零而等冷启动。

思考档位

三档的区别只有一件事:给模型多少思考预算。预算越大,复杂任务越稳,简单任务越浪费。

三档思考预算与适用场景
档位思考预算适合
low192 token闲聊、改写、翻译、格式转换
medium256 token日常问答、写代码、读图(默认)
high1024 token数学、复杂逻辑、多步规划

三种传参写法

同一个档位,三条路都能到;用你手上 SDK 顺手的那条。

1. OpenAI 协议的 reasoning_effort

json
{
  "model": "bingbingbing-v1",
  "reasoning_effort": "high",
  "messages": [{ "role": "user", "content": "证明 √2 是无理数" }]
}

2. reasoning_level(同一套档位名的别名)

json
{
  "model": "bingbingbing-v1",
  "reasoning_level": "low",
  "messages": [{ "role": "user", "content": "把这段改得更口语" }]
}

3. Anthropic 协议的 thinking.budget_tokens

json
{
  "model": "bingbingbing-v1",
  "max_tokens": 2048,
  "thinking": { "type": "enabled", "budget_tokens": 1024 },
  "messages": [{ "role": "user", "content": "这道题错在哪" }]
}

思考内容怎么取

  • OpenAI 协议:choices[0].message.reasoning_content(流式在 delta.reasoning_content)。
  • Anthropic 协议:content 数组里 type: "thinking" 的块,字段名 thinking。
  • 两者都不会混进正文:content / text 里只有答案。所以可以放心把正文直接渲染给用户,把思考过程丢进折叠块或干脆丢掉。

预算不是「至少会想这么多」,而是上限。模型判断问题简单时会提前结束思考, 实际消耗往往小于预算值。

图片输入

基座是 VL 模型,图片和文字可以放在同一条消息里。OpenAI 协议用 image_url 块,Anthropic 协议用 image 块(base64)。

python
import base64, pathlib
from openai import OpenAI

client = OpenAI(base_url="https://api.bingbingbing.top/v1", api_key=temp_key)

b64 = base64.b64encode(pathlib.Path("shot.png").read_bytes()).decode()

resp = client.chat.completions.create(
    model="bingbingbing-v1",
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": "这张图里的报错是什么原因?"},
            {"type": "image_url",
             "image_url": {"url": f"data:image/png;base64,{b64}"}},
        ],
    }],
)

print(resp.choices[0].message.content)

ToolCall

/v1/* 不会替你执行任何工具。 服务端只回传模型决定的 tool_calls;真正去查数据库、调天气、读文件的是调用方。 执行完把结果作为一条 role: "tool" 的消息发回去,模型才会继续。

一次完整往返

  1. 请求里带上 tools 定义。
  2. 模型这次不回答,返回 finish_reason: "tool_calls" 与 message.tool_calls。
  3. 你自己执行这些调用。
  4. 把助手消息原样、再加 role: "tool" 的结果,一起发第二次请求。
  5. 模型基于工具结果给出最终回答。
完整示例:请求 → tool_calls → 执行 → role: tool 发回

第 1 步:带上工具定义请求

json
POST /v1/chat/completions
{
  "model": "bingbingbing-v1",
  "messages": [
    { "role": "user", "content": "杭州现在多少度?" }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "查询某个城市的当前气温",
        "parameters": {
          "type": "object",
          "properties": {
            "city": { "type": "string", "description": "城市名" }
          },
          "required": ["city"]
        }
      }
    }
  ]
}

第 2 步:拿到 tool_calls(模型还没有回答)

json
{
  "choices": [{
    "finish_reason": "tool_calls",
    "message": {
      "role": "assistant",
      "content": null,
      "tool_calls": [{
        "id": "call_01H...",
        "type": "function",
        "function": { "name": "get_weather", "arguments": "{\"city\":\"杭州\"}" }
      }]
    }
  }]
}

第 3 步:自己执行,再把结果发回第二次请求

json
POST /v1/chat/completions
{
  "model": "bingbingbing-v1",
  "messages": [
    { "role": "user", "content": "杭州现在多少度?" },

    // 助手那条必须原样带回,tool_calls 里的 id 是关联凭据
    { "role": "assistant", "content": null,
      "tool_calls": [{
        "id": "call_01H...", "type": "function",
        "function": { "name": "get_weather", "arguments": "{\"city\":\"杭州\"}" }
      }]},

    // 这一步就是你执行工具后的产物
    { "role": "tool", "tool_call_id": "call_01H...", "content": "{\"temp_c\": 21, \"sky\": \"多云\"}" }
  ]
}

Python:把往返写成循环

python
import json
from openai import OpenAI

client = OpenAI(base_url="https://api.bingbingbing.top/v1", api_key=temp_key)

# 工具表:名字 → 真正干活的函数。模型只会报名字,执行权在你手里。
HANDLERS = {"get_weather": lambda city: {"temp_c": 21, "sky": "多云"}}

messages = [{"role": "user", "content": "杭州现在多少度?"}]
tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "查询某个城市的当前气温",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    },
}]

for _ in range(5):  # 设个上限,避免模型来回调工具停不下来
    resp = client.chat.completions.create(
        model="bingbingbing-v1", messages=messages, tools=tools,
    )
    msg = resp.choices[0].message

    if not msg.tool_calls:
        print(msg.content)
        break

    messages.append(msg)  # 助手消息原样入列,保留 tool_call_id

    for call in msg.tool_calls:
        args = json.loads(call.function.arguments or "{}")
        result = HANDLERS[call.function.name](**args)      # ← 你在执行
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,                # 必须对上,否则模型认不出这是哪次调用的结果
            "content": json.dumps(result, ensure_ascii=False),
        })

Anthropic 协议的写法差别

  • 工具定义是 tools: [{ name, description, input_schema }],没有 function 这层包装。
  • 模型返回 stop_reason: "tool_use",内容块 type: "tool_use",字段是 id / name / input(已经是对象,不用再 json.loads)。
  • 结果回填成一条 user 消息,内容块为 { type: "tool_result", tool_use_id, content }。

错误码

错误码与处理方式
状态码含义你该怎么做
401 key 无效或已过期(临时 key 超过 10 分钟就会走到这里) 重新调 POST /v1/keys 换一把;长期 key 则检查是否配到 BING_API_KEYS 里。
429 并发超出上限(临时 key 为 1),或触发限流 串行化请求,或退避后重试;确实需要并发就改用长期 key。
503 服务端未配置密钥 这是部署方的问题,不是你的请求有问题。联系服务提供者。
502 上游不可达 指数退避重试。若持续出现,多半是上游实例正在拉起或已经挂掉。
504 上游超时(冷启动时最容易遇到) 把客户端超时放宽到 180 秒以上再重试,见下一节。

401 和 429 是客户端可以自己处理的;502 / 503 / 504 是服务端与上游的状态,重试策略比改请求参数更有用。

冷启动

实例在空闲时会缩容到零。这意味着一段时间没人用之后的第一个请求会明显变慢, 通常需要 1–3 分钟把模型加载起来。

  • 网页端会显示「服务器正在启动 bingbingbing-v1 模型…」,这段时间不用刷新页面。
  • API 调用请把客户端超时设到 180 秒以上。默认的 30 秒或 60 秒几乎必然在冷启动时超时,然后你会看到一个 504。
  • 冷启动期间不要并发重试:同一把临时 key 并发上限是 1,第二个请求会拿到 429,反而更难判断真实状态。
  • 想探活又不想触发加载,用 GET /v1/models,它不进入推理。
python
from openai import OpenAI

client = OpenAI(
    base_url="https://api.bingbingbing.top/v1",
    api_key=temp_key,
    timeout=240.0,   # 冷启动留够 1–3 分钟 + 推理时间
    max_retries=1,     # 别在冷启动时打出一串并发请求
)

限额

网页端(chat.bingbingbing.top)有两道每分钟的限流,用于保护公共实例:

网页端限流
范围限制命中后
网页端对话 /api/chat每分钟 12 次被拒绝,稍后重试
网页端工具调用每分钟 60 次被拒绝,稍后重试

这两条限流只作用于网页端那条通道。/v1/* 不受它们约束, 而是受 key 自身的并发上限约束(临时 key 为 1,超出返回 429)。

限额是每分钟重置的滑动窗口,不是整数分钟边界。被拒后等一小会儿再试,比立刻重试更容易成功。