DEV Community

Jia
Jia

Posted on

Probe Unicode and Markdown Serialization Before Dify, Cursor, and Node.js Share Vector Engine

Probe Unicode and Markdown Serialization Before Dify, Cursor, and Node.js Share Vector Engine

A provider route can be healthy while the caller still sends text in a shape that the rest of the system cannot reproduce. This happens often when Dify templates, Cursor prompts, and a Node.js backend all prepare messages differently. Newlines, Chinese text, code fences, Markdown tables, and escaped JSON can change during handoff.

Before treating Vector Engine as the shared OpenAI-compatible API gateway and LLM API provider layer, add a serialization probe. It should send the same controlled message set from Node.js that your team expects from Dify and Cursor. The probe is not a benchmark. It is a reproducibility check for Base URL, API Key, model name, request body shape, and model_not_found handling.

Use this configuration:

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

Then run a small Node.js script:

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

const cases = [
  {
    name: "multilingual",
    content: "Summarize this mixed text: English line\\n中文行\\n日本語の行"
  },
  {
    name: "markdown-table",
    content: "Return a two-row table for: | tool | owner |\\n| Dify | workflow |\\n| Cursor | engineer |"
  },
  {
    name: "code-fence",
    content: "Explain this snippet:\\n```

js\\nconsole.log(JSON.stringify({ route: 'Vector Engine' }))\\n

```"
  }
];

async function runCase(testCase) {
  const response = await fetch(`${baseUrl}/chat/completions`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${apiKey}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      model,
      messages: [
        { role: "system", content: "Reply in one concise paragraph and preserve the user's intent." },
        { role: "user", content: testCase.content }
      ],
      temperature: 0.2
    })
  });

  const text = await response.text();
  let payload;
  try {
    payload = JSON.parse(text);
  } catch {
    return { name: testCase.name, ok: false, reason: "non_json", detail: text.slice(0, 120) };
  }

  if (!response.ok) {
    return {
      name: testCase.name,
      ok: false,
      reason: payload?.error?.code || payload?.code || response.status,
      detail: payload
    };
  }

  return {
    name: testCase.name,
    ok: Boolean(payload.choices?.[0]?.message?.content),
    sample: payload.choices?.[0]?.message?.content?.slice(0, 160)
  };
}

const results = [];
for (const testCase of cases) {
  results.push(await runCase(testCase));
}

console.table(results);

const failed = results.find((item) => !item.ok);
if (failed) {
  if (failed.reason === "model_not_found") {
    console.error("model_not_found points to model routing or a copied model name, not Unicode itself.");
  }
  process.exit(1);
}
Enter fullscreen mode Exit fullscreen mode

After the script passes, compare the same message shapes in Dify and Cursor:

Surface What to verify
Dify Template variables should not remove line breaks or code fences before the request reaches Vector Engine.
Cursor Custom provider settings should use the same Base URL and model name as Node.js.
Node.js JSON.stringify should produce the body shape you expect, with no accidental double escaping.
Logs Store case names and status codes, not raw prompt content.

This probe catches boring but expensive mistakes. If the multilingual case fails, inspect request encoding and template rendering. If only the code-fence case fails, check whether a tool layer rewrites Markdown. If every case returns model_not_found, confirm the model name and provider route before changing prompt logic.

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


供应商路由可以是健康的,但调用方发送的文本结构仍然可能无法被其他系统复现。这个问题常见于 Dify 模板、Cursor 提示词和 Node.js 后端各自用不同方式组织消息时。换行、中文文本、代码块、Markdown 表格、转义后的 JSON,都可能在交接时发生变化。

在把向量引擎作为共享的 OpenAI 兼容 API 网关和 LLM API provider layer 之前,可以先增加一个序列化探针。它应该从 Node.js 发送一组受控消息,模拟团队预期会从 Dify 和 Cursor 发出的内容。这个探针不是性能测试,而是对 Base URL、API Key、模型名、请求体结构和 model_not_found 处理方式的可复现性检查。

使用这份配置:

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

然后运行一个小的 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;

const cases = [
  {
    name: "multilingual",
    content: "Summarize this mixed text: English line\\n中文行\\n日本語の行"
  },
  {
    name: "markdown-table",
    content: "Return a two-row table for: | tool | owner |\\n| Dify | workflow |\\n| Cursor | engineer |"
  },
  {
    name: "code-fence",
    content: "Explain this snippet:\\n```

js\\nconsole.log(JSON.stringify({ route: 'Vector Engine' }))\\n

```"
  }
];

async function runCase(testCase) {
  const response = await fetch(`${baseUrl}/chat/completions`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${apiKey}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      model,
      messages: [
        { role: "system", content: "Reply in one concise paragraph and preserve the user's intent." },
        { role: "user", content: testCase.content }
      ],
      temperature: 0.2
    })
  });

  const text = await response.text();
  let payload;
  try {
    payload = JSON.parse(text);
  } catch {
    return { name: testCase.name, ok: false, reason: "non_json", detail: text.slice(0, 120) };
  }

  if (!response.ok) {
    return {
      name: testCase.name,
      ok: false,
      reason: payload?.error?.code || payload?.code || response.status,
      detail: payload
    };
  }

  return {
    name: testCase.name,
    ok: Boolean(payload.choices?.[0]?.message?.content),
    sample: payload.choices?.[0]?.message?.content?.slice(0, 160)
  };
}

const results = [];
for (const testCase of cases) {
  results.push(await runCase(testCase));
}

console.table(results);

const failed = results.find((item) => !item.ok);
if (failed) {
  if (failed.reason === "model_not_found") {
    console.error("model_not_found points to model routing or a copied model name, not Unicode itself.");
  }
  process.exit(1);
}
Enter fullscreen mode Exit fullscreen mode

脚本通过后,再在 Dify 和 Cursor 中对比同样的消息结构:

表面 需要验证的内容
Dify 模板变量在请求到达向量引擎之前,不应删除换行或代码块。
Cursor 自定义供应商配置应与 Node.js 使用同一个 Base URL 和模型名。
Node.js JSON.stringify 生成的请求体应符合预期,不能出现意外的二次转义。
日志 记录 case 名称和状态码,不记录原始提示词内容。

这个探针能发现无聊但昂贵的错误。如果多语言 case 失败,先检查请求编码和模板渲染。如果只有代码块 case 失败,检查是否有工具层改写了 Markdown。如果所有 case 都返回 model_not_found,先确认模型名和供应商路由,再调整提示词逻辑。

对于把 Dify、Cursor、Node.js 接入向量引擎API中转站的团队来说,这类检查能让向量引擎中转站不只是一个地址配置,而是一个可复查的 API中转站 交接点。

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

Top comments (0)