← 返回资讯

Embedding API 调用成本:主流厂商定价与省钱策略

2026-07-13

你大概率是在算完对话 API 的账单之后,才第一次正眼看 Embedding 的账单——毕竟一次问答几毛钱,肉眼可见;但把十万篇文档喂进向量库、每次用户提问都要再向量化一遍查询语句,这笔钱是悄悄堆起来的,月底一看总额度才发现 Embedding 调用次数比对话调用高一个数量级。这篇就是把这笔”隐形账”摊开来算清楚,顺便把踩过的坑标出来。

声明:以下价格描述均为截至 2026-06 的定性比较,仅供参考,以各厂商官方定价页面为准。

Embedding API 的计费逻辑

Embedding 调用的计费与对话 API 有一个重要区别:只有输入 token,没有输出 token(输出是一个固定维度的向量,不按 token 计费)。

计费项说明
输入 token待向量化的文本内容
输出(向量)固定维度,不额外计费
请求次数少数厂商按请求数收费,多数不单独计

因此,Embedding 的成本计算相对简单:文本总 token 数 × 单价

但这句话里藏着一个很多人第一次接手 RAG 项目都会踩的坑:中文文本的 token 数不能拍脑袋估。英文按空格分词,一个单词大致对应 1 个 token,估算误差不大;中文分词器(不管是 OpenAI 的 tiktoken 还是国产厂商自己的分词器)对汉字的切分粒度不统一,同一段 500 字的中文,不同厂商算出来的 token 数可能相差 20%~30%。如果你是按”字数 × 经验系数”去预估预算,建议先用目标厂商的官方 tokenizer(大多数厂商控制台或 SDK 里都带)跑一遍真实语料,再定系数,不要直接照抄别人文章里的中文系数——那个系数是针对他的语料分布算出来的,未必适配你的文档结构(比如你的知识库里代码块、表格、标点符号占比高,token 密度会明显不同)。

主流厂商 Embedding 定价对比

以下为定性分层,具体数字以各官方文档为准。

厂商代表模型价格定性向量维度
OpenAItext-embedding-3-small低(海外中最低)1536(可压缩)
OpenAItext-embedding-3-large3072
Cohereembed-v31024
阿里云text-embedding-v3低(国内主流)1024/1536
百度Embedding-V1低到中384
智谱Embedding-32048
DeepSeek(暂无独立 Embedding)

关键结论:Embedding 在所有 AI API 调用中单价最低,但体量大时总成本不可忽视。

这张对比表背后还有个值得说清楚的原因:为什么 Embedding 单价能压得这么低?对话模型每次推理要生成不定长的输出,中间要维护完整的注意力上下文,算力开销随生成长度线性增长;而 Embedding 是一次前向传播就出结果,模型规模通常也比对话大模型小得多(几百 M 到几 B 参数级别,远小于旗舰对话模型),单次推理的算力成本天然就低。国产厂商价格更低,一部分是模型本身更精简,另一部分是把 Embedding 当作获客钩子——先用低价甚至免费额度把你的向量库和索引沉淀在自己的生态里,后续检索、重排、Agent 编排的调用才是真正的利润点。理解这一层逻辑,你在选型时就不会只盯着单价,还要看这家厂商的 Embedding 生态是否配套(比如向量库、重排模型是否在同一个体系里,联调成本能不能省下来)。

OpenAI text-embedding-3 系列能做维度压缩,底层用的是 Matryoshka Representation Learning(套娃式表征学习):训练时就让向量的前 N 维尽量保留主要语义信息,截断后半部分维度也能用,只是精度略降。这也是为什么”降维”不是简单的 PCA 降维或者随手截断——如果你用的是不支持这种训练方式的旧模型(比如 text-embedding-ada-002)或者国产某些模型,直接截断维度会导致语义信息被破坏,检索效果断崖式下跌。降维前一定确认模型文档里明确写了支持 dimensions 参数,而不是自己去截。

Embedding 成本的量级感知

以一个典型的 RAG 知识库构建场景为例:

参数假设值
知识库文档10,000 篇
平均每篇 token500
总输入 token5,000,000(500 万)

按海外最低档(text-embedding-3-small)的定价量级,500 万 token 的成本大约在几美元到十几美元之间。国内厂商则通常更低。

结论:初次构建知识库成本可控,但实时更新场景(频繁增删文档)或高并发查询时实时重算才是成本黑洞。

自己动手估一遍比看任何文章里的数字都靠谱,花不了五分钟:

import tiktoken

enc = tiktoken.get_encoding("cl100k_base")  # 部分厂商可替换为对应分词器
docs = load_your_documents()  # 你自己的文档加载逻辑

total_tokens = sum(len(enc.encode(doc)) for doc in docs)
price_per_1k = 0.00002  # 换成目标厂商官网当前单价,别抄文章里的旧数字
print(f"总 token 数: {total_tokens}")
print(f"预估成本: ${total_tokens / 1000 * price_per_1k:.4f}")

跑完你应该能看到一个具体的美元或人民币数字——如果这个数字比你想象中高一个数量级,大概率是文档里混了大段代码、日志或重复模板内容,先做去重和清洗再入库,能省下的钱往往比你后续做任何”选便宜模型”的优化都多。

真实踩过的一个坑:批量调用时如果单次传入的文本条数超过厂商限制(比如 OpenAI 的 2048 条上限),接口会直接返回 400 错误,报错信息类似 Invalid input: array too long。第一次遇到很容易误以为是 token 超限,去折腾单条文本长度,结果排查半天发现是数组条数超了。解决办法很简单:批量提交前先按厂商的条数上限做分片(chunk),每片单独发请求,用 for i in range(0, len(texts), 2048) 这种滑窗分片即可,不要指望 SDK 会自动帮你切。

节省 Embedding 成本的核心策略

1. 向量缓存(最重要)

相同文本不要重复调用 Embedding API,本地缓存结果:

  • 使用 SQLite / Redis / 向量数据库存储 <文本哈希, 向量> 映射
  • 命中缓存直接返回,不调用 API
  • 对于固定知识库,构建一次后只在更新时重新调用

缓存的关键是用文本内容的哈希做 key,而不是文档 ID。很多人第一版实现图省事,直接拿文档 ID 当缓存 key,结果文档内容改了一个标点,缓存没失效,检索出来的还是旧向量——这个 bug 排查起来很折磨人,因为向量本身看不出”新旧”,只有检索结果隐约不对劲。正确做法是对文本内容做 hashlib.sha256(text.encode()).hexdigest(),内容变了哈希自然变,缓存自动失效,不用你手动管理版本号:

import hashlib

def get_cache_key(text: str) -> str:
    return hashlib.sha256(text.encode("utf-8")).hexdigest()

def get_or_embed(text: str, cache, embed_fn):
    key = get_cache_key(text)
    if key in cache:
        return cache[key]
    vector = embed_fn(text)
    cache[key] = vector
    return vector

命中率是这套机制的核心指标,值得单独打点记录:如果你的知识库是”高频重复问答”场景(比如客服 FAQ),缓存命中率做到 60% 以上很常见,等于直接省掉六成 Embedding 调用;如果是”每次内容都不一样”的场景(比如实时抓取的新闻摘要),命中率天然就低,这时候优化重点应该转向下面的批量提交和本地部署,而不是死磕缓存策略。

2. 批量提交

大多数 Embedding API 支持一次请求传入多段文本(batch input):

  • 减少请求次数,降低网络延迟
  • 部分厂商对批量请求有额外优化
  • OpenAI text-embedding 支持一次最多 2048 个文本段

批量提交还有一个绕不开的问题:请求量上来之后大概率会撞到限速(rate limit),报错通常是 HTTP 429,Rate limit reached for requests。裸调用遇到 429 直接抛异常会让整个入库脚本中途崩掉,正确做法是加指数退避重试:

import time

def embed_with_retry(text, embed_fn, max_retries=5):
    for attempt in range(max_retries):
        try:
            return embed_fn(text)
        except RateLimitError:
            wait = 2 ** attempt  # 1s, 2s, 4s, 8s, 16s
            time.sleep(wait)
    raise RuntimeError("重试次数耗尽,检查是否需要申请更高并发额度")

如果你的知识库构建是一次性批量任务(比如夜间跑批),比起同步一条条发请求,用 asyncio + 信号量控制并发数会快很多,同时又不会因为并发过高触发限速:

import asyncio

sem = asyncio.Semaphore(10)  # 按厂商实际并发上限调整

async def embed_one(text, embed_fn):
    async with sem:
        return await embed_fn(text)

async def embed_all(texts, embed_fn):
    return await asyncio.gather(*[embed_one(t, embed_fn) for t in texts])

并发数不是越大越好——超过厂商单账号的并发上限,一样会被限速甚至触发风控,具体数值以你账号控制台里显示的配额为准,不同套餐、不同实名等级的并发上限差异很大。

3. 选对维度(OpenAI 特有)

OpenAI text-embedding-3 系列支持维度压缩dimensions 参数),可以在牺牲少量精度的前提下降低存储成本和计算成本。对于对精度要求不极致的场景,1024 维往往足够。

4. 选本地 Embedding 模型

对于对延迟、成本敏感的场景,开源 Embedding 模型(如 bge-m3nomic-embed-text)可本地部署,API 调用费用为零,只需算力成本:

方案优点缺点
API Embedding零维护、开箱即用有调用成本、延迟依赖网络
本地 Embedding零 API 成本、低延迟需要 GPU/CPU 资源,维护成本

小规模项目 API 更省心;大规模生产环境值得评估本地部署。

RAG 场景的 Embedding 成本规划

RAG 系统的 Embedding 成本分两部分:

阶段触发时机优化方向
索引构建文档入库时批量处理,缓存已有向量
查询向量化每次用户查询时低维模型,本地小模型

查询向量化是高频操作,建议选小维度、低价格的 Embedding 模型,或者本地部署轻量 Embedding 模型处理查询,只用 API 处理文档入库。

更多成本优化技巧见:大模型 API 成本优化 10 招

常见问题

Embedding API 和对话 API 共用同一个 token 配额吗?
通常分开计费,使用不同的价格区间和配额池。具体以各厂商控制台显示为准。

Embedding 的质量怎么评估?
通常用检索召回率(Recall@K)衡量。对于中文场景,建议实测对比 OpenAI 和国产 Embedding 模型,不要只看参数维度。中文 Embedding 模型(如 bge-m3)在中文检索任务上往往优于 OpenAI 模型。

换 Embedding 模型需要重建向量库吗?
是的。不同模型的向量空间不兼容,切换模型必须对所有文档重新 Embedding 并重建索引。这是一次性成本,提前选好模型可以避免重建。


延伸阅读: