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 | 說明 |
|---|---|---|
AuthenticationError | 401 | API Key 缺失或無效 |
PaymentRequiredError | 402 | 餘額或配額不足 |
PermissionDeniedError | 403 | API Key 權限不足 |
NotFoundError | 404 | 資源不存在 |
RateLimitError | 429 | 速率限制 |
ServerError | 5xx | 伺服器錯誤 |
TimeoutError | — | 請求逾時 |
NetworkError | — | 連線失敗 |
每個錯誤實例都有:
status— HTTP 狀態碼code— Vecstruct 業務錯誤碼message— 錯誤描述requestId— 請回報問題時附上此 ID