DEV Community

Jia
Jia

Posted on

Add an Embeddings Route Smoke Test for Vector Engine Before Dify Knowledge Workflows

Add an Embeddings Route Smoke Test for Vector Engine Before Dify Knowledge Workflows

When a team connects Dify knowledge workflows, Cursor assistants, and a Node.js service to the same Vector Engine account, chat completion checks are not enough. A chat request can succeed while an embedding route is still using the wrong model name, the wrong Base URL, or a stale API Key. The failure often appears later inside retrieval logic, where the error is harder to separate from document parsing or chunking.

This tutorial adds a small embeddings smoke test before production traffic depends on Vector Engine as an OpenAI-compatible API gateway and LLM API provider layer. The goal is simple: prove that the route used by Dify knowledge retrieval is valid, then prove that a normal chat route still works from Node.js.

Use one shared configuration file:

VECTOR_ENGINE_BASE_URL=https://api.vectorengine.cn/v1
VECTOR_ENGINE_API_KEY=replace_with_your_key
VECTOR_ENGINE_EMBEDDING_MODEL=text-embedding-3-small
VECTOR_ENGINE_CHAT_MODEL=gpt-4o-mini
Enter fullscreen mode Exit fullscreen mode

Keep the Dify provider screen, Cursor custom model settings, and Node.js environment variables aligned with the same Base URL and model names. Do not copy an embedding model name into a chat field, and do not use a chat model name for a retrieval index.

Here is a minimal Node.js smoke test:

const baseUrl = process.env.VECTOR_ENGINE_BASE_URL;
const apiKey = process.env.VECTOR_ENGINE_API_KEY;
const embeddingModel = process.env.VECTOR_ENGINE_EMBEDDING_MODEL;
const chatModel = process.env.VECTOR_ENGINE_CHAT_MODEL;

function required(name, value) {
  if (!value) throw new Error(`Missing ${name}`);
  return value;
}

async function vectorEngineRequest(path, body) {
  const response = await fetch(`${required("VECTOR_ENGINE_BASE_URL", baseUrl)}${path}`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${required("VECTOR_ENGINE_API_KEY", apiKey)}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify(body)
  });

  const text = await response.text();
  let json;
  try {
    json = JSON.parse(text);
  } catch {
    throw new Error(`Non-JSON response from Vector Engine: ${text.slice(0, 160)}`);
  }

  if (!response.ok) {
    const code = json?.error?.code || json?.code || response.status;
    throw new Error(`Vector Engine request failed: ${code} ${JSON.stringify(json)}`);
  }

  return json;
}

async function main() {
  const embedding = await vectorEngineRequest("/embeddings", {
    model: required("VECTOR_ENGINE_EMBEDDING_MODEL", embeddingModel),
    input: "Vector Engine route smoke test for Dify retrieval"
  });

  if (!Array.isArray(embedding.data) || !embedding.data[0]?.embedding?.length) {
    throw new Error("Embedding response did not include a usable vector");
  }

  const chat = await vectorEngineRequest("/chat/completions", {
    model: required("VECTOR_ENGINE_CHAT_MODEL", chatModel),
    messages: [
      { role: "system", content: "Reply with one short diagnostic sentence." },
      { role: "user", content: "Confirm that the provider route is reachable." }
    ]
  });

  if (!chat.choices?.[0]?.message?.content) {
    throw new Error("Chat response did not include message content");
  }

  console.log({
    embeddingDimensions: embedding.data[0].embedding.length,
    chatSample: chat.choices[0].message.content
  });
}

main().catch((error) => {
  if (String(error.message).includes("model_not_found")) {
    console.error("model_not_found usually means the model name is not available on this route or was copied into the wrong field.");
  }
  console.error(error);
  process.exit(1);
});
Enter fullscreen mode Exit fullscreen mode

Use the result as a deployment gate:

Check What to compare
Base URL Dify, Cursor, and Node.js should all point to the same OpenAI-compatible endpoint style.
API Key The key should belong to the intended environment, not a personal test setup.
Embedding model Dify retrieval should use an embedding-capable model.
Chat model Cursor and application chat should use a chat-capable model.
model_not_found Treat it as a route or model-name signal before changing application code.

This smoke test is intentionally small. It does not replace observability, rate-limit handling, or cost tracking. It only protects one critical handoff: before documents, prompts, and users depend on retrieval, confirm that the provider route works for both embeddings and chat.

Registration URL: https://api.vectorengine.cn/register?aff=Igym


当团队把 Dify 知识库流程、Cursor 助手和 Node.js 服务接到同一个向量引擎账号时,只测试聊天补全是不够的。聊天请求可能已经成功,但 embedding 路由仍然使用了错误的模型名、错误的 Base URL,或者旧的 API Key。这个问题经常到检索链路里才暴露,那时它会和文档解析、分块、索引更新混在一起,排查成本更高。

这篇教程会在生产流量依赖之前,增加一个很小的 embedding 冒烟测试,用向量引擎作为 OpenAI 兼容 API 网关和 LLM API provider layer。目标很明确:先证明 Dify 知识检索使用的路由可用,再证明 Node.js 中的普通聊天路由仍然可用。

使用同一份配置:

VECTOR_ENGINE_BASE_URL=https://api.vectorengine.cn/v1
VECTOR_ENGINE_API_KEY=replace_with_your_key
VECTOR_ENGINE_EMBEDDING_MODEL=text-embedding-3-small
VECTOR_ENGINE_CHAT_MODEL=gpt-4o-mini
Enter fullscreen mode Exit fullscreen mode

把 Dify 的供应商配置、Cursor 的自定义模型配置、Node.js 的环境变量保持一致。不要把 embedding 模型名复制到聊天字段,也不要把聊天模型名用于检索索引。

下面是一个最小 Node.js 冒烟测试:

const baseUrl = process.env.VECTOR_ENGINE_BASE_URL;
const apiKey = process.env.VECTOR_ENGINE_API_KEY;
const embeddingModel = process.env.VECTOR_ENGINE_EMBEDDING_MODEL;
const chatModel = process.env.VECTOR_ENGINE_CHAT_MODEL;

function required(name, value) {
  if (!value) throw new Error(`Missing ${name}`);
  return value;
}

async function vectorEngineRequest(path, body) {
  const response = await fetch(`${required("VECTOR_ENGINE_BASE_URL", baseUrl)}${path}`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${required("VECTOR_ENGINE_API_KEY", apiKey)}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify(body)
  });

  const text = await response.text();
  let json;
  try {
    json = JSON.parse(text);
  } catch {
    throw new Error(`Non-JSON response from Vector Engine: ${text.slice(0, 160)}`);
  }

  if (!response.ok) {
    const code = json?.error?.code || json?.code || response.status;
    throw new Error(`Vector Engine request failed: ${code} ${JSON.stringify(json)}`);
  }

  return json;
}

async function main() {
  const embedding = await vectorEngineRequest("/embeddings", {
    model: required("VECTOR_ENGINE_EMBEDDING_MODEL", embeddingModel),
    input: "Vector Engine route smoke test for Dify retrieval"
  });

  if (!Array.isArray(embedding.data) || !embedding.data[0]?.embedding?.length) {
    throw new Error("Embedding response did not include a usable vector");
  }

  const chat = await vectorEngineRequest("/chat/completions", {
    model: required("VECTOR_ENGINE_CHAT_MODEL", chatModel),
    messages: [
      { role: "system", content: "Reply with one short diagnostic sentence." },
      { role: "user", content: "Confirm that the provider route is reachable." }
    ]
  });

  if (!chat.choices?.[0]?.message?.content) {
    throw new Error("Chat response did not include message content");
  }

  console.log({
    embeddingDimensions: embedding.data[0].embedding.length,
    chatSample: chat.choices[0].message.content
  });
}

main().catch((error) => {
  if (String(error.message).includes("model_not_found")) {
    console.error("model_not_found usually means the model name is not available on this route or was copied into the wrong field.");
  }
  console.error(error);
  process.exit(1);
});
Enter fullscreen mode Exit fullscreen mode

可以把结果作为上线前的门槛:

检查项 对比内容
Base URL Dify、Cursor、Node.js 是否使用同一种 OpenAI 兼容端点形式。
API Key Key 是否属于目标环境,而不是个人测试环境。
Embedding 模型 Dify 检索是否使用支持 embedding 的模型。
Chat 模型 Cursor 和应用聊天是否使用支持聊天的模型。
model_not_found 先把它当作路由或模型名信号,而不是直接修改业务代码。

这个测试刻意保持很小。它不会替代可观测性、限流处理或成本追踪。它只保护一个关键交接点:在文档、提示词和用户依赖检索之前,先确认向量引擎API中转站同时支持 embedding 和聊天路由。对于多工具团队来说,向量引擎中转站的价值不是把配置藏起来,而是让 API中转站 的路由证据更容易被复查。

注册地址:https://api.vectorengine.cn/register?aff=Igym

Top comments (0)