Skip to content

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 维向量

流程概述

  1. 分词:使用模型的分词器将文本拆分为 token
  2. 上下文建模:Transformer 层通过自注意力机制处理 token
  3. 池化:将 token 表示聚合(通常为均值池化)
  4. 归一化:最终向量归一化为单位长度
  5. 维度:输出为 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)
  • 语义特性:语义相近的文本生成的向量相似(余弦相似度高)

批量处理的主要优势

  1. 效率高:每次 API 调用最多处理 10 条文本,远优于单条请求
  2. 成本低:减少 API 调用次数,降低费用和限流风险
  3. 速度快:批量内部并行处理
  4. 一致性好:同批文本由同一模型状态处理,结果更一致

该实现让 RAG 系统能高效地将文本块转换为高维向量,便于存储到向量数据库并用于语义相似度检索。