5.6 KiB
Gitee.AI Embedding API 单次请求 input 数组元素数量限制
关联上游 Issue:#IJUQ06
背景
上游 Issue IJUQ06 描述了 LangChain OpenAIEmbeddings 使用 tiktoken 将文本编码为 token ID 列表后发送到 Gitee.AI /v1/embeddings 时返回 400 错误的问题。Gitee.AI 已对此进行了修复。
但我们在实际使用时发现,即使关闭了 tiktoken(tiktoken_enabled=False),某些大文件仍然返回同样的 400 错误。经过排查,发现了一个更深层的 schema 限制。
排查过程
第一阶段(6/19):误判为 tiktoken 格式问题
使用边界测试脚本验证:
import tiktoken
from openai import OpenAI
client = OpenAI(api_key="...", base_url="https://ai.gitee.com/v1")
enc = tiktoken.get_encoding("cl100k_base")
tokens = enc.encode("树状数组是一种支持单点修改和区间查询的数据结构。")
for n in [25, 26]:
payload = [tokens for _ in range(n)]
try:
client.embeddings.create(model="Qwen/Qwen3-Embedding-4B", input=payload)
print(f" {n} 批: ✅")
except Exception as e:
print(f" {n} 批: ❌ {e.response.status_code}")
结果:
--- Gitee.AI ---
25 批: ✅ dim=1024, 返回 25 个向量
26 批: ❌ 400 {"error":{"code":"400","message":"[Bad Request] Validation error for body application/json: No schema matches, </input>","type":"server_error"}}
--- SiliconFlow ---
25 批: ✅ dim=2560, 返回 25 个向量
26 批: ✅ dim=2560, 返回 26 个向量
修复:加 tiktoken_enabled=False 让 LangChain 发送字符串格式。
第二阶段(6/21):发现字符串格式同样受限
加了 tiktoken_enabled=False 后 30 个 chunks 仍然 400。深入排查发现:
即使是 30 个纯字符串 发送给 Gitee.AI,同样返回 400。
这说明限制不是 tiktoken 格式的问题,而是 Gitee.AI 的 /v1/embeddings 对 input 数组的元素数量有硬性上限。
最终验证:8 组对比实验
使用 test/test_provider_comparison.py 进行 2×2×2 对比:
"""
test_provider_comparison.py — 8 组实验对比 Gitee.AI vs SiliconFlow
测试两种 input 格式(字符串 / token ID)× 两种数量(25 / 26)× 两个平台。
用法:uv run python -m test.test_provider_comparison
"""python
import os
from dotenv import load_dotenv
load_dotenv()
import tiktoken
from openai import OpenAI
enc = tiktoken.get_encoding("cl100k_base")
tokens = enc.encode("树状数组是一种支持单点修改和区间查询的数据结构。")
model = "Qwen/Qwen3-Embedding-4B"
providers = [
("Gitee.AI", "https://ai.gitee.com/v1", os.getenv("GITEE_API_KEY", "")),
("SiliconFlow", "https://api.siliconflow.cn/v1", os.getenv("SiliFlow_API_KEY", "")),
]
for name, base_url, api_key in providers:
client = OpenAI(api_key=api_key, base_url=base_url)
for n in [25, 26]:
texts = [f"测试文本_{i}" for i in range(n)]
try:
r = client.embeddings.create(model=model, input=texts)
print(f"{name} str ×{n}: ✅ dim={len(r.data[0].embedding)}")
except Exception as e:
print(f"{name} str ×{n}: ❌ {e.response.status_code}")
batch = [tokens for _ in range(n)]
try:
r = client.embeddings.create(model=model, input=batch)
print(f"{name} tkn ×{n}: ✅ dim={len(r.data[0].embedding)}")
except Exception as e:
print(f"{name} tkn ×{n}: ❌ {e.response.status_code}")
输出结果:
平台 格式 结果 维度
───────────────────────────────────────────────────────
Gitee.AI str ×25 ✅ dim=1024
Gitee.AI str ×26 ❌ 400
Gitee.AI tkn ×25 ✅ dim=1024
Gitee.AI tkn ×26 ❌ 400
SiliconFlow str ×25 ✅ dim=2560
SiliconFlow str ×26 ✅ dim=2560
SiliconFlow tkn ×25 ✅ dim=2560
SiliconFlow tkn ×26 ✅ dim=2560
结论
| 单次请求中 input 元素数 | Gitee.AI | SiliconFlow |
|---|---|---|
| 1–25(字符串或 token IDs) | ✅ | ✅ |
| ≥26(字符串或 token IDs) | ❌ 400 | ✅ |
- Gitee.AI 的限制与 input 元素类型无关,纯数组长度限制(≤25)
- SiliconFlow 无此限制
- 同一模型在两家平台的输出维度不同:Gitee.AI 1024 维,SiliconFlow 2560 维
切换平台后需重建 Chroma 索引,但是不影响复现 API 错误。
当前修复(客户端侧)
核心修复是 chunk_size=25,同时保留 tiktoken_enabled=False 作为兜底:
from langchain.embeddings import init_embeddings
embeddings = init_embeddings(
model="Qwen/Qwen3-Embedding-4B",
provider="openai",
openai_api_key="...",
base_url="https://ai.gitee.com/v1",
tiktoken_enabled=False, # 禁用 tiktoken 编码(兜底)
check_embedding_ctx_length=False, # 跳过上下文长度检查
chunk_size=25, # ★ 关键修复:每批最多 25 条
)
chunk_size=25 让 LangChain 的 embed_documents 将 30 个文本分成 25+5 两批发,每批都在 Gitee.AI 的限制范围内。
上游修复建议
Gitee.AI 需要在 /v1/embeddings 的 schema 定义中放宽对 input 数组元素数量的限制,至少达到与 OpenAI 兼容的水平(单批 2048 条)。