跳至主要内容

Node.js / TypeScript SDK

套件: @vecstruct/sdk
最低版本: Node.js v22+
GitHub: vecstruct/vecstruct-sdk-node

安裝

npm install @vecstruct/sdk dotenv

初始化

import 'dotenv/config';
import { Vecstruct } from '@vecstruct/sdk';

const client = new Vecstruct({
apiKey: process.env.VECSTRUCT_API_KEY, // 預設讀取 VECSTRUCT_API_KEY 環境變數
});

進階設定:

const client = new Vecstruct({
apiKey: 'sk-...',
timeoutMs: 60_000, // 預設 60 秒
defaultHeaders: { 'x-team': 'backend' }, // 附加在每個請求上的 header
});

Chat Completions

一般請求

const completion = await client.chat.completions.create({
model: 'openai/gpt-4o',
messages: [
{ role: 'system', content: '你是資深工程師' },
{ role: 'user', content: '幫我 review 這段 TypeScript' },
],
temperature: 0.7,
max_tokens: 1024,
});

console.log(completion.choices[0].message.content);

串流回應

for await (const event of client.chat.completions.stream({
model: 'openai/gpt-4o',
messages: [{ role: 'user', content: '用繁體中文介紹 RAG 技術' }],
})) {
if (event.type === 'chunk') {
process.stdout.write(event.chunk.choices[0]?.delta.content ?? '');
} else if (event.type === 'vecstruct') {
// RAG 引用來源、Credits 用量、Audit ID 等
console.log('\nvecstruct metadata:', event.vecstruct);
}
}

啟用 RAG 與 Memory

const reply = await client.chat.completions.create({
model: 'openai/gpt-4o',
messages: [{ role: 'user', content: '我們的退款政策是什麼?' }],
vecstruct: {
rag: true,
rag_top_k: 5,
use_memory: true,
metadata: { user_id: 'user-123' }, // 寫入 Audit Log 的自訂標記
},
});

Embeddings

const res = await client.embeddings.create({
model: 'openai/text-embedding-3-small',
input: ['向量搜尋的原理', '如何評估 Embedding 品質'],
});

console.log(res.data[0].embedding); // number[]

Rerank

const res = await client.rerank.create({
model: 'baai/bge-reranker-v2-m3',
query: 'OAuth 認證流程',
documents: [
'OAuth 2.0 認證流程包含...',
'今天天氣很好',
'Authorization Code Flow 是...',
],
top_n: 2,
});

for (const r of res.results) {
console.log(r.relevance_score, r.document.slice(0, 50));
}

Models

// 列出所有可用模型
const all = await client.models.list();

// 只看 OpenAI 的模型
const openaiModels = await client.models.list({ owned_by: 'openai' });

// 取得特定模型的詳情(含定價)
const model = await client.models.retrieve('openai/gpt-4o');
console.log(`${model.model_id}: $${model.input_price_per_1m} / 1M tokens`);

RAG 查詢(知識庫)

不透過 Chat 模型,直接搜尋知識庫的段落:

const result = await client.rag.query({
query: '什麼是向量資料庫?',
config: {
top_k: 5,
min_similarity: 0.7,
retrieval_strategy: 'hybrid', // dense | sparse | hybrid
rerank_strategy: 'cross_encoder',
},
});

for (const r of result.results) {
console.log(`${r.score.toFixed(3)} | ${r.content.slice(0, 80)}`);
}

Memory(長期記憶)

// 新增記憶
const mem = await client.memories.create({
content: '使用者偏好繁體中文回覆,技術術語保留英文',
memory_type: 'rule',
importance: 0.9,
});

// 語義搜尋
const hits = await client.memories.search({
query: '使用者語言偏好',
top_k: 5,
});

// 從對話自動萃取
await client.memories.extract({
messages: [
{ role: 'user', content: '我用 React 19 + TypeScript' },
{ role: 'assistant', content: '了解,之後預設用這個 stack 給範例' },
],
});

// 分頁列表
const list = await client.memories.list({ page: 1, page_size: 20 });

// 更新 / 刪除
await client.memories.update(mem.id, { importance: 0.7 });
await client.memories.delete(mem.id);

// 批次刪除
await client.memories.batchDelete({ memory_type: 'context' });

Documents(文件管理)

import { readFile } from 'node:fs/promises';

// 上傳
const buffer = await readFile('./manual.pdf');
const doc = await client.documents.upload({
file: buffer,
filename: 'manual.pdf',
contentType: 'application/pdf',
chunk_strategy: 'recursive',
chunk_size: 800,
chunk_overlap: 80,
metadata: { team: 'support' },
});

// 列表 / 取得 / 刪除
await client.documents.list({ page: 1, page_size: 20 });
await client.documents.retrieve(doc.id);
await client.documents.delete(doc.id);

// 啟用 / 停用 / 重新索引
await client.documents.deactivate(doc.id);
await client.documents.activate(doc.id);
await client.documents.reindex(doc.id);

// 更新切分設定
await client.documents.updateChunking(doc.id, {
chunk_strategy: 'semantic',
chunk_semantic_threshold: 0.65,
});

// 下載原檔與 Markdown 版本
const original = await client.documents.downloadFile(doc.id);
const markdown = await client.documents.downloadMarkdown(doc.id);

// 查看段落
const { chunks, total } = await client.documents.chunks(doc.id);

稽核日誌(Audit Logs)

// 列表
const logs = await client.audit.list({
start_time: '2026-01-01T00:00:00Z',
end_time: '2026-02-01T00:00:00Z',
page: 1,
page_size: 20,
});

// 單條詳情
const detail = await client.audit.retrieve('audit-uuid');

// 匯出
const job = await client.audit.export({
format: 'csv',
start_time: '2026-01-01T00:00:00Z',
end_time: '2026-02-01T00:00:00Z',
});

取消請求

const controller = new AbortController();
setTimeout(() => controller.abort(), 5_000);

await client.chat.completions.create(
{ model: 'openai/gpt-4o', messages: [{ role: 'user', content: 'hi' }] },
{ signal: controller.signal },
);

錯誤處理

import {
AuthenticationError,
PaymentRequiredError,
PermissionDeniedError,
NotFoundError,
RateLimitError,
} from '@vecstruct/sdk';

try {
await client.chat.completions.create({
model: 'openai/gpt-4o',
messages: [{ role: 'user', content: 'hi' }],
});
} catch (err) {
if (err instanceof RateLimitError) {
console.error('已觸發速率限制,請稍後再試');
} else if (err instanceof PaymentRequiredError) {
console.error('餘額或配額不足');
} else if (err instanceof AuthenticationError) {
console.error('API Key 無效,請確認是否正確');
} else {
throw err;
}
}

常見錯誤類型:

錯誤類別HTTP說明
AuthenticationError401API Key 缺失或無效
PaymentRequiredError402餘額或配額不足
PermissionDeniedError403API Key 權限不足
NotFoundError404資源不存在
RateLimitError429速率限制
ServerError5xx伺服器錯誤
TimeoutError請求逾時
NetworkError連線失敗

每個錯誤實例都有:

  • status — HTTP 狀態碼
  • code — Vecstruct 業務錯誤碼
  • message — 錯誤描述
  • requestId — 請回報問題時附上此 ID