DEV Community

Jia
Jia

Posted on

Add a Tool-Call Capability Probe Before Dify, Cursor, and Node.js Share Vector Engine

When a team moves Dify workflows, Cursor assistants, and a Node.js service behind the same Vector Engine provider route, the first smoke test is usually a simple chat completion. That is useful, but it does not prove that tool-call style responses survive the OpenAI-compatible API gateway. A route can answer a normal prompt while still dropping the tools field, returning an unexpected response shape, or mapping the wrong model name.

This tutorial adds a small capability probe before tool calling becomes part of a production workflow. It checks the Base URL, API Key, model name, and response shape from Node.js, then gives the team a compact failure table for Dify and Cursor handoff. The point is not to test every agent behavior. The point is to make the LLM API provider layer explicit before several tools depend on it.

Use one configuration block for the probe:

VECTOR_ENGINE_BASE_URL=https://api.vectorengine.cn/v1
VECTOR_ENGINE_API_KEY=replace_with_your_key
VECTOR_ENGINE_MODEL=gpt-4o-mini
Enter fullscreen mode Exit fullscreen mode

Keep the same Base URL in Dify provider settings, Cursor custom model settings, and the Node.js environment. If Dify uses one model name and Node.js uses another, a model_not_found report becomes harder to interpret because the route and the caller changed at the same time.

Here is a minimal Node.js probe:

const baseUrl = process.env.VECTOR_ENGINE_BASE_URL;
const apiKey = process.env.VECTOR_ENGINE_API_KEY;
const model = process.env.VECTOR_ENGINE_MODEL;

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

async function probeToolCalls() {
  const response = await fetch(`${requireEnv("VECTOR_ENGINE_BASE_URL", baseUrl)}/chat/completions`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${requireEnv("VECTOR_ENGINE_API_KEY", apiKey)}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      model: requireEnv("VECTOR_ENGINE_MODEL", model),
      messages: [
        { role: "system", content: "Return a tool call when a lookup is needed." },
        { role: "user", content: "Find the status for route ve-chat-prod." }
      ],
      tools: [
        {
          type: "function",
          function: {
            name: "lookup_route_status",
            description: "Look up a provider route status by route id.",
            parameters: {
              type: "object",
              properties: {
                routeId: { type: "string" }
              },
              required: ["routeId"]
            }
          }
        }
      ],
      tool_choice: "auto"
    })
  });

  const text = await response.text();
  let data;
  try {
    data = JSON.parse(text);
  } catch {
    throw new Error(`Non-JSON response: ${text.slice(0, 300)}`);
  }

  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${JSON.stringify(data).slice(0, 500)}`);
  }

  const message = data.choices?.[0]?.message;
  const toolCalls = message?.tool_calls || [];

  return {
    id: data.id,
    model: data.model,
    finishReason: data.choices?.[0]?.finish_reason,
    toolCallCount: toolCalls.length,
    toolNames: toolCalls.map(call => call.function?.name).filter(Boolean)
  };
}

probeToolCalls()
  .then(result => {
    console.log("Vector Engine tool-call probe passed");
    console.log(JSON.stringify(result, null, 2));
  })
  .catch(error => {
    console.error("Vector Engine tool-call probe failed");
    console.error(error.message);
    process.exitCode = 1;
  });
Enter fullscreen mode Exit fullscreen mode

Run the probe before enabling the same route in a Dify agent workflow or a Cursor rule that expects structured tool calls. If the probe returns no tool calls, first check whether the selected model supports that response style. Then check whether the request body was sent through the correct OpenAI-compatible API gateway path. Only after that should you treat it as an application-level agent bug.

Use this small table during triage:

Symptom Likely area Check
model_not_found Route or model name Compare the model name in Vector Engine, Dify, Cursor, and Node.js
HTTP 401 or 403 API Key Confirm the key belongs to the expected tool and environment
Tool call missing Capability or request body Confirm model support and the tools payload
Non-JSON response Base URL or proxy path Confirm the Base URL ends at the OpenAI-compatible API root
Dify works but Node.js fails Local env drift Compare environment variables and provider screen values

The same evidence helps when Cursor is involved. Record the Cursor model name, Base URL, and the prompt that expected a tool-like result. For Dify, record the workflow name, provider configuration, and whether the failing node expected structured output or a plain chat response.

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

The practical benefit is boring but important: a shared provider route gets a repeatable capability check. Vector Engine can act as the central LLM API provider layer, but each team still needs to prove that the route supports the response style their tools rely on.


在 Dify、Cursor 和 Node.js 共用向量引擎前增加工具调用能力探针

当团队把 Dify 工作流、Cursor 助手和 Node.js 服务迁移到同一个向量引擎供应商路由后,最常见的初始检查通常是一次普通聊天补全。这个检查有用,但它不能证明工具调用类响应能够稳定穿过 OpenAI 兼容 API 网关。某个路由可以回答普通提示词,却仍然丢失 tools 字段,返回不符合预期的响应结构,或者映射了错误的模型名。

这篇教程增加一个小型能力探针,在工具调用进入生产工作流之前使用。它会从 Node.js 检查 Base URL、API Key、模型名和响应结构,然后给 Dify 与 Cursor 的排障交接提供一个简洁表格。重点不是测试所有 Agent 行为,而是在多个工具依赖同一路由前,把 LLM API provider layer 的能力边界说清楚。

先使用一份统一配置:

VECTOR_ENGINE_BASE_URL=https://api.vectorengine.cn/v1
VECTOR_ENGINE_API_KEY=replace_with_your_key
VECTOR_ENGINE_MODEL=gpt-4o-mini
Enter fullscreen mode Exit fullscreen mode

在 Dify 供应商设置、Cursor 自定义模型设置和 Node.js 环境变量里保持同一个 Base URL。 如果 Dify 使用一个模型名,而 Node.js 使用另一个模型名,那么 model_not_found 就很难判断,因为路由和调用方同时发生了变化。

下面是一个最小 Node.js 探针:

const baseUrl = process.env.VECTOR_ENGINE_BASE_URL;
const apiKey = process.env.VECTOR_ENGINE_API_KEY;
const model = process.env.VECTOR_ENGINE_MODEL;

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

async function probeToolCalls() {
  const response = await fetch(`${requireEnv("VECTOR_ENGINE_BASE_URL", baseUrl)}/chat/completions`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${requireEnv("VECTOR_ENGINE_API_KEY", apiKey)}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      model: requireEnv("VECTOR_ENGINE_MODEL", model),
      messages: [
        { role: "system", content: "Return a tool call when a lookup is needed." },
        { role: "user", content: "Find the status for route ve-chat-prod." }
      ],
      tools: [
        {
          type: "function",
          function: {
            name: "lookup_route_status",
            description: "Look up a provider route status by route id.",
            parameters: {
              type: "object",
              properties: {
                routeId: { type: "string" }
              },
              required: ["routeId"]
            }
          }
        }
      ],
      tool_choice: "auto"
    })
  });

  const text = await response.text();
  let data;
  try {
    data = JSON.parse(text);
  } catch {
    throw new Error(`Non-JSON response: ${text.slice(0, 300)}`);
  }

  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${JSON.stringify(data).slice(0, 500)}`);
  }

  const message = data.choices?.[0]?.message;
  const toolCalls = message?.tool_calls || [];

  return {
    id: data.id,
    model: data.model,
    finishReason: data.choices?.[0]?.finish_reason,
    toolCallCount: toolCalls.length,
    toolNames: toolCalls.map(call => call.function?.name).filter(Boolean)
  };
}

probeToolCalls()
  .then(result => {
    console.log("Vector Engine tool-call probe passed");
    console.log(JSON.stringify(result, null, 2));
  })
  .catch(error => {
    console.error("Vector Engine tool-call probe failed");
    console.error(error.message);
    process.exitCode = 1;
  });
Enter fullscreen mode Exit fullscreen mode

在 Dify Agent 工作流或依赖结构化工具调用的 Cursor 规则启用同一路由前,先运行这个探针。如果探针没有返回工具调用,先检查所选模型是否支持这种响应方式,再检查请求体是否发送到了正确的 OpenAI 兼容 API 网关路径。只有这些都排除后,才应该把问题当成应用层 Agent 逻辑错误。

排障时可以使用这个小表格:

现象 可能范围 检查项
model_not_found 路由或模型名 对比向量引擎、Dify、Cursor 和 Node.js 里的模型名
HTTP 401 或 403 API Key 确认密钥属于预期工具和环境
工具调用缺失 能力或请求体 确认模型支持能力以及 tools 载荷
非 JSON 响应 Base URL 或代理路径 确认 Base URL 指向 OpenAI 兼容 API 根路径
Dify 正常但 Node.js 失败 本地环境漂移 对比环境变量和供应商配置页面

当 Cursor 参与时,同样需要记录 Cursor 的模型名、Base URL,以及触发工具类结果预期的提示词。对 Dify 来说,要记录工作流名称、供应商配置,以及失败节点期望的是结构化输出还是普通聊天响应。

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

实际收益很朴素但重要:共享供应商路由有了一个可重复的能力检查。向量引擎可以作为集中的 LLM API provider layer,但团队仍然需要证明路由支持各工具依赖的响应方式。这样使用向量引擎API中转站、向量引擎中转站或其他 API中转站 接入方案时,排障口径会更一致。

Top comments (0)