
go整合向量数据库ChromaDB
启动ChromaDB服务
shell
# 1. 拉取指定版本的镜像
docker pull chromadb/chroma:1.0.8
# 2. 运行该版本容器
docker run -d -p 8000:8000 chromadb/chroma:1.0.8http://127.0.0.1:8000/docs/#/ 启动成功会访问成功,api文档示例
http://localhost:8000/api/v2/heartbeat 心跳接口
测试代码。
go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
// --- 配置和全局变量 ---
var (
baseURL string
client *http.Client
defaultTenant = "default_tenant"
defaultDB = "default_database"
)
// --- 数据结构 ---
type CreateCollectionV2Req struct {
Name string `json:"name"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
}
type CreateCollectionV2Resp struct {
ID string `json:"id"`
Name string `json:"name"`
Tenant string `json:"tenant"`
Database string `json:"database"`
}
type AddRecordsV2Req struct {
IDs []string `json:"ids"`
Embeddings [][]float32 `json:"embeddings"`
Documents []string `json:"documents,omitempty"`
Metadatas []map[string]interface{} `json:"metadatas,omitempty"`
}
type QueryV2Req struct {
QueryEmbeddings [][]float32 `json:"query_embeddings"`
NRResults int `json:"n_results"`
Include []string `json:"include,omitempty"`
}
type QueryV2Resp struct {
IDs [][]string `json:"ids"`
Documents [][]string `json:"documents"`
Distances [][]float32 `json:"distances"`
Metadatas [][]map[string]interface{} `json:"metadatas,omitempty"`
}
// 存储集合信息
var currentCollection struct {
ID string
Name string
Tenant string
Database string
}
func main() {
baseURL = "http://127.0.0.1:8000"
client = &http.Client{Timeout: 10 * time.Second}
fmt.Printf("🔗 连接 ChromaDB v2: %s\n", baseURL)
// 1. 心跳检测
if !heartbeat() {
fmt.Println("❌ 无法连接到 ChromaDB")
return
}
fmt.Println("✅ 服务连接正常")
// 2. 获取或创建集合
collectionName := "my-go-collection"
if err := getOrCreateCollection(collectionName); err != nil {
fmt.Printf("❌ 获取/创建集合失败: %v\n", err)
return
}
fmt.Printf("✅ 集合已就绪,ID: %s, 名称: %s\n", currentCollection.ID, currentCollection.Name)
// 3. 添加数据(使用完整的路径)
if err := addData(); err != nil {
fmt.Printf("❌ 添加数据失败: %v\n", err)
return
}
fmt.Println("✅ 数据添加成功")
// 4. 查询数据
queryData()
}
// 心跳检测
func heartbeat() bool {
resp, err := client.Get(baseURL + "/api/v2/heartbeat")
if err != nil {
return false
}
defer resp.Body.Close()
return resp.StatusCode == http.StatusOK
}
// 获取或创建集合
func getOrCreateCollection(name string) error {
// 先尝试获取已存在的集合
err := getCollection(name)
if err == nil {
fmt.Printf("📂 找到已存在的集合: %s (ID: %s)\n", name, currentCollection.ID)
return nil
}
// 集合不存在,创建新集合
fmt.Printf("📂 集合 '%s' 不存在,正在创建...\n", name)
return createCollection(name)
}
// 获取已存在的集合
func getCollection(name string) error {
url := fmt.Sprintf("%s/api/v2/tenants/%s/databases/%s/collections",
baseURL, defaultTenant, defaultDB)
resp, err := client.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
}
// 解析集合列表
var collections []CreateCollectionV2Resp
if err := json.Unmarshal(body, &collections); err != nil {
return err
}
// 查找指定名称的集合
for _, col := range collections {
if col.Name == name {
currentCollection.ID = col.ID
currentCollection.Name = col.Name
currentCollection.Tenant = col.Tenant
currentCollection.Database = col.Database
return nil
}
}
return fmt.Errorf("集合 '%s' 不存在", name)
}
// 创建新集合
func createCollection(name string) error {
url := fmt.Sprintf("%s/api/v2/tenants/%s/databases/%s/collections",
baseURL, defaultTenant, defaultDB)
reqBody := CreateCollectionV2Req{
Name: name,
Metadata: map[string]interface{}{
"description": "Go 客户端测试集合",
"created_at": time.Now().Format(time.RFC3339),
},
}
jsonData, _ := json.Marshal(reqBody)
fmt.Printf("📤 创建集合请求: %s\n", string(jsonData))
resp, err := client.Post(url, "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
}
// 解析响应获取集合信息
var result CreateCollectionV2Resp
if err := json.Unmarshal(body, &result); err != nil {
return err
}
currentCollection.ID = result.ID
currentCollection.Name = result.Name
currentCollection.Tenant = result.Tenant
currentCollection.Database = result.Database
fmt.Printf("📥 创建成功: ID=%s, Name=%s, Tenant=%s, Database=%s\n",
result.ID, result.Name, result.Tenant, result.Database)
return nil
}
// 添加数据 - 使用完整的 API 路径
func addData() error {
// 关键修正:使用完整的路径包含 tenant 和 database
url := fmt.Sprintf("%s/api/v2/tenants/%s/databases/%s/collections/%s/add",
baseURL,
currentCollection.Tenant,
currentCollection.Database,
currentCollection.ID)
fmt.Printf("\n📤 添加数据到集合: %s\n", currentCollection.Name)
fmt.Printf("🔗 完整 URL: %s\n", url)
reqBody := AddRecordsV2Req{
IDs: []string{"doc1", "doc2"},
Embeddings: [][]float32{
{0.1, 0.2, 0.3, 0.4, 0.5},
{0.6, 0.7, 0.8, 0.9, 1.0},
},
Documents: []string{
"Go 语言是并发的王者",
"ChromaDB 是一个向量数据库",
},
Metadatas: []map[string]interface{}{
{"source": "go-demo", "language": "go", "type": "programming"},
{"source": "go-demo", "topic": "database", "type": "technology"},
},
}
jsonData, err := json.Marshal(reqBody)
if err != nil {
return err
}
fmt.Printf("📦 请求体: %s\n", string(jsonData))
resp, err := client.Post(url, "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
fmt.Printf("📥 响应状态: %d\n", resp.StatusCode)
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
}
if len(body) > 0 {
fmt.Printf("📥 响应内容: %s\n", string(body))
}
return nil
}
// 查询数据 - 使用完整的 API 路径
func queryData() {
url := fmt.Sprintf("%s/api/v2/tenants/%s/databases/%s/collections/%s/query",
baseURL,
currentCollection.Tenant,
currentCollection.Database,
currentCollection.ID)
fmt.Printf("\n🔍 查询 URL: %s\n", url)
reqBody := QueryV2Req{
QueryEmbeddings: [][]float32{{0.1, 0.2, 0.3, 0.4, 0.5}},
NRResults: 3,
Include: []string{"documents", "distances", "metadatas"},
}
jsonData, _ := json.Marshal(reqBody)
fmt.Printf("🔍 查询请求: %s\n", string(jsonData))
resp, err := client.Post(url, "application/json", bytes.NewBuffer(jsonData))
if err != nil {
fmt.Printf("❌ 查询失败: %v\n", err)
return
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusOK {
fmt.Printf("❌ 查询失败: HTTP %d - %s\n", resp.StatusCode, string(body))
return
}
var result QueryV2Resp
if err := json.Unmarshal(body, &result); err != nil {
fmt.Printf("❌ 解析失败: %v\n原始响应: %s\n", err, string(body))
return
}
// 显示结果
if len(result.Documents) > 0 && len(result.Documents[0]) > 0 {
fmt.Println("\n🎉 查询成功!找到以下结果:")
for i, doc := range result.Documents[0] {
distance := float32(0)
if len(result.Distances) > 0 && len(result.Distances[0]) > i {
distance = result.Distances[0][i]
}
// 显示元数据(如果有)
metadata := ""
if len(result.Metadatas) > 0 && len(result.Metadatas[0]) > i {
if lang, ok := result.Metadatas[0][i]["language"]; ok {
metadata = fmt.Sprintf(" [语言: %v]", lang)
}
}
fmt.Printf(" %d.%s %s (距离: %.4f)\n", i+1, metadata, doc, distance)
}
} else {
fmt.Println("\n⚠️ 未找到相关结果")
}
}结果
text
🔗 连接 ChromaDB v2: http://127.0.0.1:8000
✅ 服务连接正常
📂 集合 'my-go-collection' 不存在,正在创建...
📤 创建集合请求: {"name":"my-go-collection","metadata":{"created_at":"2026-04-05T16:21:22+08:00","description":"Go 客户端测试集合"}}
📥 创建成功: ID=29578383-f2a0-4e6c-a02a-5490554493d8, Name=my-go-collection, Tenant=default_tenant, Database=default_database
✅ 集合已就绪,ID: 29578383-f2a0-4e6c-a02a-5490554493d8, 名称: my-go-collection
📤 添加数据到集合: my-go-collection
🔗 完整 URL: http://127.0.0.1:8000/api/v2/tenants/default_tenant/databases/default_database/collections/29578383-f2a0-4e6c-a02a-5490554493d8/add
📦 请求体: {"ids":["doc1","doc2"],"embeddings":[[0.1,0.2,0.3,0.4,0.5],[0.6,0.7,0.8,0.9,1]],"documents":["Go 语言是并发的王者","ChromaDB 是一个向量数据库"],"metadatas":[{"language":"go","source":"go-demo","type":"programming"},{"source":"go-demo","topic":"database","type":"technology"}]}
📥 响应状态: 201
📥 响应内容: {}
✅ 数据添加成功
🔍 查询 URL: http://127.0.0.1:8000/api/v2/tenants/default_tenant/databases/default_database/collections/29578383-f2a0-4e6c-a02a-5490554493d8/query
🔍 查询请求: {"query_embeddings":[[0.1,0.2,0.3,0.4,0.5]],"n_results":3,"include":["documents","distances","metadatas"]}
🎉 查询成功!找到以下结果:
1. [语言: go] Go 语言是并发的王者 (距离: 0.0000)
2. ChromaDB 是一个向量数据库 (距离: 1.2500)
