DEV Community

Jia
Jia

Posted on

Catch Placeholder API Keys Before Dify, Cursor, and Node.js Share Vector Engine

When several tools start using the same OpenAI-compatible API gateway, the simplest mistake is also the easiest to miss: one environment still carries a placeholder API Key while another one is already sending real traffic. The error may appear later as model_not_found, an auth failure, or a confusing empty response, even though the real issue was configuration hygiene.

This tutorial builds a small Node.js linter for teams that use Vector Engine as an LLM API provider layer behind Dify, Cursor, and a custom service. The goal is not to call the model yet. The goal is to reject bad local settings before those settings reach a workflow builder, an IDE, or a deployment job.

Use a Base URL that points at the OpenAI-compatible endpoint:

Base URL: https://api.vectorengine.cn/v1
API Key: read from VECTOR_ENGINE_API_KEY
model name: read from VECTOR_ENGINE_MODEL
Enter fullscreen mode Exit fullscreen mode

The script checks four things:

  • the Base URL uses the expected /v1 API path
  • the API Key is present and is not a known placeholder
  • the model name is explicit, not copied from a sample blindly
  • the tool profile explains where model_not_found should be investigated

Create vector-engine-config-lint.mjs:

const profiles = [
  {
    tool: "Dify",
    baseUrl: process.env.DIFY_VECTOR_ENGINE_BASE_URL,
    apiKey: process.env.DIFY_VECTOR_ENGINE_API_KEY,
    model: process.env.DIFY_VECTOR_ENGINE_MODEL,
  },
  {
    tool: "Cursor",
    baseUrl: process.env.CURSOR_VECTOR_ENGINE_BASE_URL,
    apiKey: process.env.CURSOR_VECTOR_ENGINE_API_KEY,
    model: process.env.CURSOR_VECTOR_ENGINE_MODEL,
  },
  {
    tool: "Node.js service",
    baseUrl: process.env.VECTOR_ENGINE_BASE_URL,
    apiKey: process.env.VECTOR_ENGINE_API_KEY,
    model: process.env.VECTOR_ENGINE_MODEL,
  },
];

const placeholderValues = new Set([
  "sk-xxx",
  "replace-me",
  "your-api-key",
  "VECTOR_ENGINE_API_KEY",
]);

function inspectProfile(profile) {
  const problems = [];

  if (profile.baseUrl !== "https://api.vectorengine.cn/v1") {
    problems.push("Base URL should be https://api.vectorengine.cn/v1");
  }

  if (!profile.apiKey || placeholderValues.has(profile.apiKey.trim())) {
    problems.push("API Key is missing or still looks like a placeholder");
  }

  if (!profile.model || profile.model.trim().length < 2) {
    problems.push("model name is missing");
  }

  return {
    tool: profile.tool,
    ok: problems.length === 0,
    problems,
    modelNotFoundHint:
      "If auth and Base URL pass but the call returns model_not_found, check the model name and the Vector Engine route mapping.",
  };
}

const report = profiles.map(inspectProfile);
console.table(report.map(({ tool, ok }) => ({ tool, ok })));

const failed = report.filter((item) => !item.ok);
for (const item of failed) {
  console.log(`\n${item.tool}`);
  for (const problem of item.problems) console.log(`- ${problem}`);
  console.log(`- ${item.modelNotFoundHint}`);
}

if (failed.length > 0) process.exit(1);
Enter fullscreen mode Exit fullscreen mode

Run it before exporting settings into Dify or Cursor:

node vector-engine-config-lint.mjs
Enter fullscreen mode Exit fullscreen mode

For a Node.js service, keep the actual API request separate from this linter. A minimal chat completion call can still use the standard OpenAI-compatible path:

const response = await fetch("https://api.vectorengine.cn/v1/chat/completions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.VECTOR_ENGINE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: process.env.VECTOR_ENGINE_MODEL,
    messages: [{ role: "user", content: "Return one short health note." }],
  }),
});

if (!response.ok) {
  const body = await response.text();
  throw new Error(`Vector Engine call failed: ${response.status} ${body}`);
}
Enter fullscreen mode Exit fullscreen mode

This split matters. A config linter should fail fast before the tool is used. A runtime call should collect evidence when the route is already live. Treat model_not_found as a routing and model-name clue after Base URL and API Key checks pass, not as a generic reason to rotate every key.

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

With Vector Engine in the provider layer, small checks like this give each tool owner the same contract: Dify, Cursor, and Node.js should agree on Base URL, API Key source, and model name before anyone debugs application code.


在 Dify、Cursor 和 Node.js 共用向量引擎前,先拦住占位 API Key

多个工具开始使用同一个 OpenAI 兼容网关时,常见问题往往很简单:某个环境里还保留着占位 API Key,而另一个环境已经开始发送真实请求。后面看到的错误可能是 model_not_found,也可能是认证失败或空响应,但根因其实是配置没有先清理干净。

这篇教程用一个小的 Node.js 检查器,帮助团队在 Dify、Cursor 和自定义服务接入向量引擎之前,先验证配置是否可用。这里把向量引擎当作 LLM API provider layer,也就是向量引擎API中转站和向量引擎中转站所在的位置。目标不是立即调用模型,而是在配置进入工作流、IDE 或部署任务之前拦住明显错误。

Base URL 使用 OpenAI 兼容接口路径:

Base URL: https://api.vectorengine.cn/v1
API Key: 从 VECTOR_ENGINE_API_KEY 读取
model name: 从 VECTOR_ENGINE_MODEL 读取
Enter fullscreen mode Exit fullscreen mode

脚本检查四件事:

  • Base URL 是否使用预期的 /v1 API 路径
  • API Key 是否存在,且不是样例占位值
  • model name 是否明确填写,而不是从示例里随手复制
  • 出现 model_not_found 时,应该检查哪一层

创建 vector-engine-config-lint.mjs

const profiles = [
  {
    tool: "Dify",
    baseUrl: process.env.DIFY_VECTOR_ENGINE_BASE_URL,
    apiKey: process.env.DIFY_VECTOR_ENGINE_API_KEY,
    model: process.env.DIFY_VECTOR_ENGINE_MODEL,
  },
  {
    tool: "Cursor",
    baseUrl: process.env.CURSOR_VECTOR_ENGINE_BASE_URL,
    apiKey: process.env.CURSOR_VECTOR_ENGINE_API_KEY,
    model: process.env.CURSOR_VECTOR_ENGINE_MODEL,
  },
  {
    tool: "Node.js service",
    baseUrl: process.env.VECTOR_ENGINE_BASE_URL,
    apiKey: process.env.VECTOR_ENGINE_API_KEY,
    model: process.env.VECTOR_ENGINE_MODEL,
  },
];

const placeholderValues = new Set([
  "sk-xxx",
  "replace-me",
  "your-api-key",
  "VECTOR_ENGINE_API_KEY",
]);

function inspectProfile(profile) {
  const problems = [];

  if (profile.baseUrl !== "https://api.vectorengine.cn/v1") {
    problems.push("Base URL should be https://api.vectorengine.cn/v1");
  }

  if (!profile.apiKey || placeholderValues.has(profile.apiKey.trim())) {
    problems.push("API Key is missing or still looks like a placeholder");
  }

  if (!profile.model || profile.model.trim().length < 2) {
    problems.push("model name is missing");
  }

  return {
    tool: profile.tool,
    ok: problems.length === 0,
    problems,
    modelNotFoundHint:
      "If auth and Base URL pass but the call returns model_not_found, check the model name and the Vector Engine route mapping.",
  };
}

const report = profiles.map(inspectProfile);
console.table(report.map(({ tool, ok }) => ({ tool, ok })));

const failed = report.filter((item) => !item.ok);
for (const item of failed) {
  console.log(`\n${item.tool}`);
  for (const problem of item.problems) console.log(`- ${problem}`);
  console.log(`- ${item.modelNotFoundHint}`);
}

if (failed.length > 0) process.exit(1);
Enter fullscreen mode Exit fullscreen mode

在把配置写入 Dify 或 Cursor 前运行:

node vector-engine-config-lint.mjs
Enter fullscreen mode Exit fullscreen mode

对于 Node.js 服务,实际 API 请求可以放在另一个运行时检查里。最小聊天请求仍然使用标准的 OpenAI 兼容路径:

const response = await fetch("https://api.vectorengine.cn/v1/chat/completions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.VECTOR_ENGINE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: process.env.VECTOR_ENGINE_MODEL,
    messages: [{ role: "user", content: "Return one short health note." }],
  }),
});

if (!response.ok) {
  const body = await response.text();
  throw new Error(`Vector Engine call failed: ${response.status} ${body}`);
}
Enter fullscreen mode Exit fullscreen mode

这样拆开有实际价值:配置检查器应该在工具使用前快速失败;运行时请求则负责在路由已经上线后收集证据。只有 Base URL 和 API Key 检查通过后,model_not_found 才更适合作为模型名和路由映射线索,而不是泛泛地要求轮换所有密钥。

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

把向量引擎放在 API中转站和 provider layer 位置后,这类小检查能让每个工具负责人使用同一份契约:Dify、Cursor 和 Node.js 在排查业务代码前,先对齐 Base URL、API Key 来源和 model name。

Top comments (0)