跳至主要内容

Go SDK

模組: github.com/vecstruct/vecstruct-sdk-go
最低版本: Go 1.25+
GitHub: vecstruct/vecstruct-sdk-go

安裝

go get github.com/vecstruct/vecstruct-sdk-go
go get github.com/joho/godotenv

初始化

package main

import (
"context"
"fmt"
"log"
"os"

vecstruct "github.com/vecstruct/vecstruct-sdk-go"
"github.com/joho/godotenv"
)

func main() {
godotenv.Load()

client, err := vecstruct.NewClient(os.Getenv("VECSTRUCT_API_KEY"))
if err != nil {
log.Fatal(err)
}

resp, err := client.CreateChatCompletion(context.Background(), vecstruct.ChatCompletionRequest{
Model: "openai/gpt-4o",
Messages: []vecstruct.ChatMessage{
{Role: "user", Content: "你好,Vecstruct!"},
},
})
if err != nil {
log.Fatal(err)
}

fmt.Println(resp.Choices[0].Message.Content)
}

進階設定:

import "time"

client, err := vecstruct.NewClient(
"sk-...",
vecstruct.WithBaseURL("https://api.vecstruct.com/v1"),
vecstruct.WithTimeout(60 * time.Second),
vecstruct.WithUserAgent("my-app/1.0"),
)
選項說明
WithBaseURL(url)覆蓋 API 的 Base URL
WithTimeout(d)HTTP 請求逾時設定
WithHTTPClient(c)注入自訂 *http.Client(proxy、mTLS 等)
WithUserAgent(ua)覆蓋 User-Agent header

Chat Completions

一般請求

resp, err := client.CreateChatCompletion(ctx, vecstruct.ChatCompletionRequest{
Model: "openai/gpt-4o",
Messages: []vecstruct.ChatMessage{
{Role: "system", Content: "你是資深工程師"},
{Role: "user", Content: "幫我 review 這段 Go 程式碼"},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Choices[0].Message.Content)
fmt.Println("Token 用量:", resp.Usage.TotalTokens)

串流回應

import (
"errors"
"io"
)

stream, err := client.StreamChatCompletion(ctx, vecstruct.ChatCompletionRequest{
Model: "openai/gpt-4o",
Messages: []vecstruct.ChatMessage{
{Role: "user", Content: "介紹向量資料庫"},
},
})
if err != nil {
log.Fatal(err)
}
defer stream.Close()

for {
chunk, err := stream.Next()
if errors.Is(err, io.EOF) {
break
}
if err != nil {
log.Fatal(err)
}
if len(chunk.Choices) > 0 {
fmt.Print(chunk.Choices[0].Delta.Content)
}
}

// 取得串流結束後的 Vecstruct metadata
if vc := stream.Vecstruct(); vc != nil {
fmt.Printf("\nAudit ID: %s, Credits: %.4f\n", vc.AuditID, vc.CreditsConsumed)
}

啟用 RAG 與 Memory

ragOn := true
resp, err := client.CreateChatCompletion(ctx, vecstruct.ChatCompletionRequest{
Model: "openai/gpt-4o",
Messages: []vecstruct.ChatMessage{
{Role: "user", Content: "我們的退款政策是什麼?"},
},
Vecstruct: &vecstruct.VecstructParams{
RAG: &ragOn,
RAGTopK: 5,
},
})

// 取得 RAG 引用來源
for _, src := range resp.Vecstruct.RAGSources {
fmt.Printf("- %s (相似度: %.3f)\n", src.Title, src.Similarity)
}

Embeddings

emb, err := client.CreateEmbedding(ctx, vecstruct.EmbeddingRequest{
Model: "openai/text-embedding-3-small",
Input: []string{"向量搜尋的原理", "如何評估 Embedding 品質"},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("向量數量: %d, 維度: %d\n", len(emb.Data), len(emb.Data[0].Embedding))

Rerank

rr, err := client.Rerank(ctx, vecstruct.RerankRequest{
Model: "cohere/rerank-v3.5",
Query: "什麼是向量搜尋?",
Documents: []string{"A: 向量搜尋用向量距離...", "B: 今天天氣很好", "C: 向量資料庫索引..."},
TopN: 2,
})
for _, hit := range rr.Results {
fmt.Printf("Index %d -> %.3f\n", hit.Index, hit.RelevanceScore)
}

Models

// 列出所有模型
models, err := client.ListModels(ctx, nil)

// 按 provider 篩選
models, err = client.ListModels(ctx, &vecstruct.ListModelsOptions{
OwnedBy: "openai",
})
for _, m := range models {
fmt.Println(m.ModelID, "-", m.Type)
}

// 取得特定模型
m, err := client.GetModel(ctx, "openai/gpt-4o")
fmt.Println("輸入定價:", m.InputPricePer1M)

RAG 查詢(知識庫)

rag, err := client.QueryRAG(ctx, vecstruct.RAGQueryRequest{
Query: "退款政策",
TopK: 5,
MinSimilarity: 0.3,
})
if err != nil {
log.Fatal(err)
}
for _, r := range rag.Results {
fmt.Printf("[%.3f] %s\n", r.Similarity, r.Content[:80])
}

Memory(長期記憶)

// 新增記憶
importance := 0.8
mem, err := client.CreateMemory(ctx, vecstruct.CreateMemoryRequest{
Content: "使用者偏好繁體中文回覆,技術術語保留英文",
MemoryType: vecstruct.MemoryTypeRule,
Importance: &importance,
})

// 語義搜尋
results, err := client.SearchMemories(ctx, vecstruct.SearchMemoryRequest{
Query: "使用者語言偏好",
TopK: 3,
})
for _, hit := range results.Results {
fmt.Printf("[%.3f] %s\n", hit.FinalScore, hit.Memory.Content)
}

// 其他操作
client.ListMemories(ctx, &vecstruct.ListMemoriesOptions{Page: 1, PageSize: 20})
client.GetMemory(ctx, mem.ID)
client.UpdateMemory(ctx, mem.ID, vecstruct.UpdateMemoryRequest{...})
client.ExtractMemory(ctx, vecstruct.ExtractMemoryRequest{Text: "..."})
client.DeleteMemory(ctx, mem.ID)
client.BatchDeleteMemories(ctx, vecstruct.BatchDeleteMemoriesRequest{...})

Documents(文件管理)

import "os"

f, _ := os.Open("manual.pdf")
defer f.Close()

// 上傳
doc, err := client.UploadDocument(ctx, vecstruct.UploadDocumentRequest{
Filename: "manual.pdf",
Content: f,
Metadata: map[string]any{"team": "support"},
Chunking: &vecstruct.ChunkingOptions{
Strategy: vecstruct.ChunkStrategyRecursive,
Size: 800,
Overlap: 80,
},
})

// 列表 / 取得 / 刪除
list, _ := client.ListDocuments(ctx, &vecstruct.ListDocumentsOptions{Page: 1, PageSize: 20})
detail, _ := client.GetDocument(ctx, doc.ID)
_ = client.DeleteDocument(ctx, doc.ID)

// 啟用 / 停用 / 重新索引
_ = client.DeactivateDocument(ctx, doc.ID)
_ = client.ActivateDocument(ctx, doc.ID)
_ = client.ReindexDocument(ctx, doc.ID)

// 更新切分設定
_ = client.UpdateDocumentChunking(ctx, doc.ID, vecstruct.ChunkingOptions{
Strategy: vecstruct.ChunkStrategySemantic,
})

// 查看段落
chunks, _ := client.ListDocumentChunks(ctx, doc.ID, nil)
fmt.Printf("共 %d 個段落\n", len(chunks.Chunks))

稽核日誌(Audit Logs)

// 列表
logs, err := client.ListAuditLogs(ctx, &vecstruct.ListAuditLogsOptions{
StartTime: "2026-01-01",
EndTime: "2026-01-31",
Action: "gateway.chat",
Page: 1,
PageSize: 50,
})

// 詳情
detail, _ := client.GetAuditLog(ctx, logs.Logs[0].ID)
fmt.Println(detail.Action, detail.Model)

// 匯出
job, _ := client.ExportAuditLogs(ctx, vecstruct.ExportAuditLogsRequest{
StartTime: "2026-01-01",
EndTime: "2026-01-31",
Format: vecstruct.ExportFormatCSV,
})
fmt.Println("匯出 ID:", job.ExportID)

認證資訊

info, err := client.GetAuthInfo(ctx)
if err == nil {
fmt.Println("User ID:", info.UserID)
fmt.Println("Permissions:", info.Permissions)
}

Context、逾時與取消

每個方法都接受 context.Context,用它來設定 deadline 或取消請求:

// 設定 30 秒逾時
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

resp, err := client.CreateChatCompletion(ctx, req)

// 取消串流
ctx, cancel = context.WithCancel(context.Background())
go func() {
time.Sleep(5 * time.Second)
cancel() // 5 秒後取消
}()
stream, _ := client.StreamChatCompletion(ctx, req)

錯誤處理

resp, err := client.CreateChatCompletion(ctx, req)
if err != nil {
if apiErr, ok := vecstruct.IsAPIError(err); ok {
switch {
case apiErr.IsCode(1100): // 未授權
log.Fatal("API Key 無效")
case apiErr.IsCode(1003): // 速率限制
log.Println("已觸發速率限制,請稍後再試")
default:
log.Fatalf("API 錯誤: code=%d %s", apiErr.Code, apiErr.Message)
}
// 回報問題時請附上 RequestID
log.Println("Request ID:", apiErr.RequestID)
}
log.Fatal(err)
}

APIError 包含:

  • HTTPStatus — HTTP 狀態碼
  • Code — Vecstruct 業務錯誤碼
  • Message — 錯誤描述
  • RequestID — 請求 ID(回報問題時附上)
  • Data — 後端額外資料(json.RawMessage

Sentinel 錯誤:

  • vecstruct.ErrMissingAPIKey
  • vecstruct.ErrInvalidBaseURL
  • vecstruct.ErrStreamClosed