Qwen Embedding 说明
概述¶
createEmbedder()
函数实现了 Qwen 的 text-embedding-v4 模型的批量嵌入调用,可高效地将文本块转换为 1024 维向量,支持批量处理。
createEmbedder()
的批量调用实现¶
1. Qwen 请求结构¶
// 来自 src/providers/embeddings.ts
export function createEmbedder(env: Env): Embedder {
if (env.PROVIDER === 'qwen') {
return {
async embed(texts, dim) {
const baseUrl = env.QWEN_BASE || 'https://dashscope.aliyuncs.com/compatible-mode/v1';
const url = baseUrl.endsWith('/embeddings') ? baseUrl : `${baseUrl}/embeddings`;
const model = env.QWEN_EMBED_MODEL || 'text-embedding-v4'; // 默认使用 v4
const requestBody = {
model: model,
input: texts // 批量文本
};
const resp = await fetch(url, {
method: 'POST',
headers: {
'Authorization': `Bearer ${env.QWEN_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
});
const data = await resp.json();
return data.data.map((d: any) => d.embedding.slice(0, dim));
}
};
}
}
2. 批量请求/响应 JSON 示例¶
请求 JSON¶
{
"model": "text-embedding-v4",
"input": [
"Kubernetes 是一个开源容器编排平台,可自动化部署、扩展和管理容器化应用。",
"Service mesh 为微服务通信提供基础设施层,具备流量管理、安全和可观测性等功能。",
"云原生技术让组织能够在公有云、私有云和混合云等动态环境中构建和运行可扩展应用。"
]
}
响应 JSON¶
{
"object": "list",
"data": [
{
"object": "embedding",
"index": 0,
"embedding": [
-0.0123456789, 0.0987654321, -0.0456789123, 0.0234567891,
-0.0345678912, 0.0567891234, -0.0678912345, 0.0789123456,
// ... 共 1024 维
]
},
{
"object": "embedding",
"index": 1,
"embedding": [
-0.0234567891, 0.0876543210, -0.0567891234, 0.0345678912,
-0.0456789123, 0.0678912345, -0.0789123456, 0.0891234567,
// ... 共 1024 维
]
},
{
"object": "embedding",
"index": 2,
"embedding": [
-0.0345678912, 0.0765432109, -0.0678912345, 0.0456789123,
-0.0567891234, 0.0789123456, -0.0891234567, 0.0912345678,
// ... 共 1024 维
]
}
],
"model": "text-embedding-v4",
"usage": {
"prompt_tokens": 45,
"total_tokens": 45
}
}
text-embedding-v4 如何将文本转换为 1024 维向量¶
流程概述¶
- 分词:使用模型的分词器将文本拆分为 token
- 上下文建模:Transformer 层通过自注意力机制处理 token
- 池化:将 token 表示聚合(通常为均值池化)
- 归一化:最终向量归一化为单位长度
- 维度:输出为 1024 个浮点数
批量处理实现¶
在 scripts/fast-ingest.ts
中,批量处理每次最多支持 10 条文本:
const EMBEDDING_BATCH_SIZE = PROVIDER === 'gemini' ? 1 : 10; // Qwen v4 最大批量为 10
async function getBatchEmbeddings(texts: string[]): Promise<number[][]> {
if (PROVIDER === 'qwen') {
// Qwen 支持批量处理,效率更高!
const url = QWEN_BASE || 'https://dashscope.aliyuncs.com/compatible-mode/v1/embeddings';
const r = await fetch(url, {
method: 'POST',
headers: {
'Authorization': `Bearer ${QWEN_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: QWEN_EMBED_MODEL,
input: texts
}),
agent: proxyAgent
});
const j = await r.json();
return j.data.map((d: any) => d.embedding.slice(0, EMBED_DIM));
}
}
Node.js 最简脚本示例¶
完整示例:
// qwen-embedding-example.js
import fetch from 'node-fetch';
const QWEN_API_KEY = 'your-api-key-here';
const QWEN_BASE_URL = 'https://dashscope.aliyuncs.com/compatible-mode/v1/embeddings';
async function getQwenEmbeddings(texts) {
const requestBody = {
model: 'text-embedding-v4',
input: texts
};
console.log('=== REQUEST ===');
console.log('URL:', QWEN_BASE_URL);
console.log('Body:', JSON.stringify(requestBody, null, 2));
const response = await fetch(QWEN_BASE_URL, {
method: 'POST',
headers: {
'Authorization': `Bearer ${QWEN_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
});
if (!response.ok) {
throw new Error(`API Error: ${response.status} - ${await response.text()}`);
}
const data = await response.json();
console.log('=== RESPONSE ===');
console.log('Status:', response.status);
console.log('Model:', data.model);
console.log('Embeddings count:', data.data.length);
console.log('Each embedding dimension:', data.data[0].embedding.length);
return data.data.map(item => item.embedding);
}
// 使用示例
async function main() {
const sampleTexts = [
"Kubernetes 管理集群中的容器化应用。",
"微服务架构实现可扩展的分布式系统。",
"云计算提供按需的计算资源。"
];
try {
const embeddings = await getQwenEmbeddings(sampleTexts);
// 前后对比展示
console.log('\n=== BEFORE/AFTER COMPARISON ===');
sampleTexts.forEach((text, index) => {
console.log(`\n文本 ${index + 1}:`);
console.log(`输入:"${text}"`);
console.log(`输出:1024 维向量`);
console.log(`前 5 维:[${embeddings[index].slice(0, 5).map(n => n.toFixed(6)).join(', ')}...]`);
console.log(`后 5 维:[...${embeddings[index].slice(-5).map(n => n.toFixed(6)).join(', ')}]`);
console.log(`向量模长:${Math.sqrt(embeddings[index].reduce((sum, val) => sum + val * val, 0)).toFixed(6)}`);
});
} catch (error) {
console.error('Error:', error.message);
}
}
main();
前后向量片段示例¶
输入文本¶
"Kubernetes 是一个开源容器编排平台,可自动化部署、扩展和管理容器化应用。"
输出向量(前 10 和后 10 维,共 1024 维)¶
// 前 10 维
[
-0.012543, 0.098432, -0.045123, 0.067891, -0.034567,
0.023456, -0.078912, 0.056789, -0.089123, 0.034567
]
// ...(中间 1004 维)...
// 后 10 维
[
-0.023456, 0.067891, -0.012345, 0.045678, -0.089012,
0.034567, -0.078901, 0.056789, -0.023456, 0.067891
]
向量属性¶
- 维度:固定为 1024 个浮点数
- 数值范围:通常在 -1.0 到 1.0 之间
- 模长:一般归一化为单位长度(约 1.0)
- 语义特性:语义相近的文本生成的向量相似(余弦相似度高)
批量处理的主要优势¶
- 效率高:每次 API 调用最多处理 10 条文本,远优于单条请求
- 成本低:减少 API 调用次数,降低费用和限流风险
- 速度快:批量内部并行处理
- 一致性好:同批文本由同一模型状态处理,结果更一致
该实现让 RAG 系统能高效地将文本块转换为高维向量,便于存储到向量数据库并用于语义相似度检索。