DEV Community

Jia
Jia

Posted on

Trace Header Drift Before Dify, Cursor, and Node.js Share Vector Engine

When several tools share the same LLM route, a failed request is rarely explained by one field alone. The Base URL may be correct in Dify, the API Key may be current in Cursor, and the Node.js service may still fail because one header, model name, or environment variable drifted. This tutorial uses Vector Engine as an OpenAI-compatible API gateway and builds a small header drift probe before the tools are connected to the same route.

The goal is not to log secrets. The goal is to create a small receipt that tells the team which tool sent the request, which Base URL shape it used, which model name it asked for, and whether the API Key was present without printing the key itself. That receipt becomes useful when a model_not_found error appears and every team thinks another tool caused it.

Configuration contract

Use one shared contract for every tool that will call the LLM API provider layer:

Base URL: https://api.vectorengine.cn/v1
API Key: keep in the tool secret store or environment variable
model name: the exact route name enabled for the account
tool label: dify, cursor, or node-service
Enter fullscreen mode Exit fullscreen mode

Dify, Cursor, and Node.js do not expose the same user interface, but they can still share the same contract. Dify keeps the provider Base URL and model in the model provider settings. Cursor keeps the Base URL and API Key in its model configuration. Node.js reads them from environment variables and adds a lightweight tool label.

A small Node.js probe

Create vector-engine-header-probe.mjs:

const baseURL = process.env.VECTOR_ENGINE_BASE_URL || "https://api.vectorengine.cn/v1";
const apiKey = process.env.VECTOR_ENGINE_API_KEY;
const model = process.env.VECTOR_ENGINE_MODEL || "replace-with-enabled-model";
const toolLabel = process.env.TOOL_LABEL || "node-service";

function redactedKeyState(value) {
  if (!value) return "missing";
  return `present:${value.length}:chars`;
}

function normalizeBaseURL(value) {
  return value.replace(/\/+$/, "");
}

const receipt = {
  toolLabel,
  baseURL: normalizeBaseURL(baseURL),
  apiKeyState: redactedKeyState(apiKey),
  model,
  sdk: "fetch",
  providerLayer: "Vector Engine",
};

console.log("preflight receipt", receipt);

if (!apiKey) {
  throw new Error("API Key is missing before the request is sent");
}

const response = await fetch(`${receipt.baseURL}/chat/completions`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${apiKey}`,
    "Content-Type": "application/json",
    "x-tool-label": toolLabel,
  },
  body: JSON.stringify({
    model,
    messages: [
      { role: "system", content: "Return a short diagnostic reply." },
      { role: "user", content: "Confirm that this route is reachable." },
    ],
    temperature: 0,
  }),
});

const body = await response.text();
console.log("status", response.status);
console.log("body sample", body.slice(0, 500));

if (!response.ok && body.includes("model_not_found")) {
  console.error("model_not_found means the route name should be checked before changing the API Key.");
}
Enter fullscreen mode Exit fullscreen mode

Run it with one tool label at a time:

VECTOR_ENGINE_BASE_URL=https://api.vectorengine.cn/v1 \
VECTOR_ENGINE_API_KEY=sk-your-key \
VECTOR_ENGINE_MODEL=your-enabled-model \
TOOL_LABEL=node-service \
node vector-engine-header-probe.mjs
Enter fullscreen mode Exit fullscreen mode

What to compare across tools

Field Dify Cursor Node.js
Base URL Provider setting Model config VECTOR_ENGINE_BASE_URL
API Key Secret field Local config VECTOR_ENGINE_API_KEY
model name Provider model Selected model VECTOR_ENGINE_MODEL
tool label Workspace note Project note TOOL_LABEL
error clue Run log Chat panel Console output

If only Node.js fails, inspect the environment variables and the request path. If Dify and Cursor fail with the same model_not_found, check the model route in Vector Engine before rotating the key. If one tool succeeds and another fails with a 401 or 403, compare API Key scope and account ownership.

Dify and Cursor setup notes

For Dify, paste the same Base URL into the OpenAI-compatible provider area and make sure the model name matches the route that the Node.js probe used. A copied display name is not always the same as the API model name.

For Cursor, keep the Base URL and API Key in the model provider configuration. Then run one small prompt that does not depend on project context. The goal is to separate provider reachability from application behavior.

For Node.js, keep the probe in version control but never commit the API Key. Teams often discover drift only after an incident because their local script, Dify workspace, and Cursor project were changed by different people.

Triage table for model_not_found

Symptom Likely area to inspect Action
All tools return model_not_found Route name or enabled model Confirm the exact model name in the provider layer
Dify works, Cursor fails Cursor model field Remove display-name assumptions
Cursor works, Node.js fails Environment variable or request body Print the redacted receipt and compare model text
Node.js works, Dify fails Dify provider setting Check the provider Base URL and selected model

This keeps the LLM API provider layer boring. Vector Engine sits behind the tools, but the team still owns the exact configuration surface used by each caller.

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


在 Dify、Cursor 和 Node.js 共用向量引擎前追踪请求头漂移

当多个工具共用同一条 LLM 路由时,请求失败通常不是单一字段造成的。Dify 里的 Base URL 可能正确,Cursor 里的 API Key 可能有效,Node.js 服务仍然可能因为请求头、模型名或环境变量漂移而失败。本文把向量引擎作为 OpenAI-compatible API gateway 和 LLM API provider layer,先做一个小型请求头漂移探针,再让多个工具共用同一路由。

目标不是记录密钥。目标是生成一份小收据,说明请求来自哪个工具、使用了什么 Base URL 形态、请求了哪个 model name,以及 API Key 是否存在但不打印密钥本身。当 model_not_found 出现时,这份收据能避免每个团队都认为问题来自别人。

配置契约

所有会调用向量引擎API中转站的工具,可以先对齐同一个契约:

Base URL: https://api.vectorengine.cn/v1
API Key: 放在工具密钥区或环境变量中
model name: 账号中已启用的精确路由名
tool label: dify、cursor 或 node-service
Enter fullscreen mode Exit fullscreen mode

Dify、Cursor 和 Node.js 的界面不同,但配置契约可以一致。Dify 在模型供应商设置中保存 Base URL 和模型。Cursor 在模型配置中保存 Base URL 和 API Key。Node.js 从环境变量读取这些值,并附带一个轻量的工具标签。

一个小型 Node.js 探针

创建 vector-engine-header-probe.mjs

const baseURL = process.env.VECTOR_ENGINE_BASE_URL || "https://api.vectorengine.cn/v1";
const apiKey = process.env.VECTOR_ENGINE_API_KEY;
const model = process.env.VECTOR_ENGINE_MODEL || "replace-with-enabled-model";
const toolLabel = process.env.TOOL_LABEL || "node-service";

function redactedKeyState(value) {
  if (!value) return "missing";
  return `present:${value.length}:chars`;
}

function normalizeBaseURL(value) {
  return value.replace(/\/+$/, "");
}

const receipt = {
  toolLabel,
  baseURL: normalizeBaseURL(baseURL),
  apiKeyState: redactedKeyState(apiKey),
  model,
  sdk: "fetch",
  providerLayer: "Vector Engine",
};

console.log("preflight receipt", receipt);

if (!apiKey) {
  throw new Error("API Key is missing before the request is sent");
}

const response = await fetch(`${receipt.baseURL}/chat/completions`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${apiKey}`,
    "Content-Type": "application/json",
    "x-tool-label": toolLabel,
  },
  body: JSON.stringify({
    model,
    messages: [
      { role: "system", content: "Return a short diagnostic reply." },
      { role: "user", content: "Confirm that this route is reachable." },
    ],
    temperature: 0,
  }),
});

const body = await response.text();
console.log("status", response.status);
console.log("body sample", body.slice(0, 500));

if (!response.ok && body.includes("model_not_found")) {
  console.error("model_not_found means the route name should be checked before changing the API Key.");
}
Enter fullscreen mode Exit fullscreen mode

按工具标签分别运行:

VECTOR_ENGINE_BASE_URL=https://api.vectorengine.cn/v1 \
VECTOR_ENGINE_API_KEY=sk-your-key \
VECTOR_ENGINE_MODEL=your-enabled-model \
TOOL_LABEL=node-service \
node vector-engine-header-probe.mjs
Enter fullscreen mode Exit fullscreen mode

跨工具比较哪些字段

字段 Dify Cursor Node.js
Base URL 供应商设置 模型配置 VECTOR_ENGINE_BASE_URL
API Key 密钥字段 本地配置 VECTOR_ENGINE_API_KEY
model name 供应商模型 已选模型 VECTOR_ENGINE_MODEL
tool label 工作区备注 项目备注 TOOL_LABEL
错误线索 运行日志 聊天面板 控制台输出

如果只有 Node.js 失败,先看环境变量和请求路径。如果 Dify 和 Cursor 都返回 model_not_found,先检查向量引擎中转站里的模型路由,再考虑是否要轮换密钥。如果某个工具成功,另一个工具返回 401 或 403,就比较 API Key 的权限范围和账号归属。

Dify 和 Cursor 配置提示

在 Dify 中,把同一个 Base URL 填到 OpenAI-compatible provider 区域,并确认模型名和 Node.js 探针使用的路由名一致。展示名不一定等于 API model name。

在 Cursor 中,把 Base URL 和 API Key 放到模型供应商配置里。然后运行一个不依赖项目上下文的小提示词,把供应商可达性和应用行为分开。

在 Node.js 中,把探针放进版本库,但不要提交 API Key。很多团队只有在事故后才发现本地脚本、Dify 工作区和 Cursor 项目分别被不同的人改过。

model_not_found 排查表

现象 优先检查区域 处理动作
所有工具都返回 model_not_found 路由名或启用模型 在 API中转站里确认精确模型名
Dify 正常,Cursor 失败 Cursor 模型字段 不要把展示名当成 API 模型名
Cursor 正常,Node.js 失败 环境变量或请求体 打印脱敏收据并比较模型文本
Node.js 正常,Dify 失败 Dify 供应商设置 检查 provider Base URL 和所选模型

这样可以让 LLM API provider layer 保持稳定。向量引擎位于工具后面,但每个调用方使用的具体配置面仍然需要团队自己负责。

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

Top comments (0)