跳转到主要内容
嵌入(embedding)就是把一段文本表示成一个向量(一串数字)。语义相近的文本,即使没有任何相同的词,得到的向量也相近。语义检索正是建立在这之上的:你匹配的是含义,而不是关键词。它也是 RAG(检索增强生成)的核心——让模型根据你自己的文档来回答。 RuAPI 的嵌入和聊天走同一个 OpenAI 兼容端点:https://www.ruapi.ai/v1,用的也是同一把 sk-... 密钥。代码里需要改的只有 base_url
还没有密钥?先看快速开始。下文默认你已经拿到了 sk-... 密钥。

第一个向量

Python (OpenAI SDK)
from openai import OpenAI

client = OpenAI(
    api_key="sk-你的密钥",
    base_url="https://www.ruapi.ai/v1",
)

resp = client.embeddings.create(
    model="text-embedding-3-small",
    input="莫斯科是俄罗斯的首都",
)

vector = resp.data[0].embedding
print(len(vector))   # 向量维度
print(vector[:5])    # 前五个数字
resp.data 是一个列表:一段输入文本对应一个元素,元素里有 .embedding 字段。text-embedding-3-small 返回的向量含 1536 个数字。 想要更高质量,就用 text-embedding-3-large(每个向量 3072 个数字)。它在复杂文本上更准确,但更贵、更慢。大多数场景用 -small 就够了。

一次处理多段文本

把列表传给 input,一次请求就能为每段文本返回一个向量——比逐条发送更快也更省请求。
resp = client.embeddings.create(
    model="text-embedding-3-small",
    input=[
        "怎么给余额充值?",
        "最低充值金额是 10 USDT。",
        "猫睡在窗台上。",
    ],
)

vectors = [item.embedding for item in resp.data]
返回结果的顺序与输入文本的顺序一致。

五步搭一套完整 RAG

思路很简单:提前把文档切成小块,为每块算好向量;用户提问时,找出最相近的几块,作为上下文交给聊天模型。 1. 把文本切成块(chunk)。 块太长会稀释语义,太短又会丢失上下文。一般按段落,或者 200-500 词的窗口来切。
docs = [
    "RuAPI 支持用 USDT 付款。最低 10 USDT。",
    "嵌入和聊天共用一把密钥、一个 base_url。",
    "OpenAI 兼容客户端的基础地址是 https://www.ruapi.ai/v1",
]
2. 计算向量并存起来。 数据量小时,内存里放个普通列表就够。上生产环境就用向量数据库——FAISS、pgvector 或 Chroma,它们能在上百万向量里快速检索。
import numpy as np

emb = client.embeddings.create(model="text-embedding-3-small", input=docs)
index = np.array([item.embedding for item in emb.data])
3. 计算问题的向量——要用和文档相同的嵌入模型(这点很关键,见下文)。
question = "充值最低要多少?"
q = np.array(
    client.embeddings.create(
        model="text-embedding-3-small", input=question
    ).data[0].embedding
)
4. 用余弦相似度找最近的块。 余弦衡量两个向量之间的夹角:1 表示几乎相同,0 表示毫不相关。
def cosine(a, b):
    return a @ b / (np.linalg.norm(a) * np.linalg.norm(b))

scores = [cosine(q, v) for v in index]
top = sorted(range(len(scores)), key=lambda i: scores[i], reverse=True)[:2]
context = "\n".join(docs[i] for i in top)
5. 把检索到的块交给聊天模型。 把最相关的几块放进系统提示词作为上下文,模型就会依据你的数据回答,而不是凭空猜测。
answer = client.chat.completions.create(
    model="claude-opus-4-8",
    messages=[
        {"role": "system", "content": f"只根据以下上下文回答:\n{context}"},
        {"role": "user", "content": question},
    ],
)

print(answer.choices[0].message.content)
第 2 步建好的索引只需算一次、反复使用——不必每次提问都重新计算嵌入。

注意事项

text-embedding-3-smalltext-embedding-3-large 产出的向量无法互相比较——维度不同,语义空间也不同。用哪个模型建的索引,就用哪个模型算查询向量。换了模型,整个索引都得重建。
逐条发送既慢又多耗请求。把列表传给 input(通常一次几百条以内),返回结果会保持同样的顺序。
text-embedding-3-small 每个向量 1536 个数字,更便宜、更快,适合大多数场景。text-embedding-3-large 是 3072 个数字,在复杂长文本上更准,但更贵,占用的存储也翻倍。先用 -small,只有当检索质量不够时再换 -large

下一步

  • 快速开始 — 注册、拿密钥、发出第一个请求
  • GPT 模型 — 给 RAG 收尾作答的聊天模型怎么选
  • API 参考 — 端点、协议与 base_url 的完整说明
  • LangChain — 在 RuAPI 之上现成的链和 RAG,无需手写代码