Milvus安装
Milvus教程:milvus.io/docs/zh/
本地化界面工具:zilliz.com.cn/attu
安装Milvus(docker方式)
// 下载安装脚本
curl -sfL https://raw.githubusercontent.com/milvus-io/milvus/master/scripts/standalone_embed.sh -o standalone_embed.sh
// 启动docker容器
bash standalone_embed.sh start
启动后:
- 服务端口:19530
- Web访问:http://127.0.0.1:9091/webui/
安装远程连接工具
-
根据自己的系统选择对应版本下载 github.com/zilliztech/…
-
登录,首次访问正常不需要账号密码,如果提示可以使用下面的账号密码: user: root password: Milvus
-
登录成功后记得先修改密码:
Eino开发
使用上面安装的Milvus作为向量数据库,Eino的RAG相关components已经集成了Milvus,可以很方便的使用Milvus实现Embedding、索引和检索功能。
Embedding
这里的Embedding模型使用Ollama下的qwen3-embedding:4b。
func getEmbedder(ctx context.Context) *ollama.Embedder {
embedder, err := ollama.NewEmbedder(ctx, &ollama.EmbeddingConfig{
BaseURL: ollamaBaseURL,
Model: ollamaEmbeddingModel,
Timeout: 10 * time.Second,
})
if err != nil {
log.Fatalf("NewEmbedder of ollama error: %v", err)
}
log.Printf("===== call Embedder directly =====")
return embedder
}
func embedding(ctx context.Context, text string) {
embedder := getEmbedder(ctx)
if embedder == nil {
return
}
vectors, err := embedder.EmbedStrings(ctx, []string{text})
if err != nil {
log.Fatalf("EmbedStrings of Ollama failed, err=%v", err)
}
log.Printf("vectors : %v", vectors)
}
Indexer
将文档先进行向量化,再将向量结果存储到Mlivus并构建索引。
func indexer(ctx context.Context, docs []*schema.Document) {
cli, err := client.NewClient(ctx, client.Config{
Address: milvusAddr,
Username: milvusUsername,
Password: milvusPassword,
})
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
defer cli.Close()
embedder := getEmbedder(ctx)
if embedder == nil {
return
}
indexer, err := milvus.NewIndexer(ctx, &milvus.IndexerConfig{
Client: cli,
Embedding: embedder,
})
if err != nil {
log.Fatalf("Failed to create indexer: %v", err)
return
}
log.Printf("Indexer created success")
ids, err := indexer.Store(ctx, docs)
if err != nil {
log.Fatalf("Failed to store: %v", err)
}
log.Printf("Store success, ids: %v", ids)
}
Retriever
通过关键词实现基于向量相似度的文档检索
func retriever(ctx context.Context, query string) {
cli, err := client.NewClient(ctx, client.Config{
Address: milvusAddr,
Username: milvusUsername,
Password: milvusPassword,
})
if err != nil {
log.Fatalf("Failed to create client: %v", err)
return
}
defer cli.Close()
embedder := getEmbedder(ctx)
if embedder == nil {
return
}
// Create a retriever
retriever, err := milvusretriever.NewRetriever(ctx, &milvusretriever.RetrieverConfig{
Client: cli,
Collection: "",
Partition: nil,
VectorField: "",
OutputFields: []string{
"id",
"content",
"metadata",
},
DocumentConverter: nil,
MetricType: "",
TopK: 0,
ScoreThreshold: 5,
Sp: nil,
Embedding: embedder,
})
if err != nil {
log.Fatalf("Failed to create retriever: %v", err)
return
}
// Retrieve documents
documents, err := retriever.Retrieve(ctx, query)
if err != nil {
log.Fatalf("Failed to retrieve: %v", err)
return
}
// Print the documents
for i, doc := range documents {
fmt.Printf("Document %d:\n", i)
fmt.Printf("title: %s\n", doc.ID)
fmt.Printf("content: %s\n", doc.Content)
fmt.Printf("metadata: %v\n", doc.MetaData)
}
}
完整代码
package main
import (
"context"
"fmt"
"log"
"os"
"time"
"github.com/cloudwego/eino-ext/components/embedding/ollama"
"github.com/cloudwego/eino-ext/components/indexer/milvus"
milvusretriever "github.com/cloudwego/eino-ext/components/retriever/milvus"
"github.com/cloudwego/eino/schema"
"github.com/milvus-io/milvus-sdk-go/v2/client"
)
var (
milvusAddr = os.Getenv("MILVUS_ADDR") // http://112.126.xx.xxx:19530
milvusUsername = os.Getenv("MILVUS_USERNAME") // root
milvusPassword = os.Getenv("MILVUS_PASSWORD") // password123
ollamaBaseURL = os.Getenv("OLLAMA_BASE_URL") // http://localhost:11434
ollamaEmbeddingModel = os.Getenv("OLLAMA_EMBED_MODEL") // qwen3-embedding:4b
)
func getEmbedder(ctx context.Context) *ollama.Embedder {
embedder, err := ollama.NewEmbedder(ctx, &ollama.EmbeddingConfig{
BaseURL: ollamaBaseURL,
Model: ollamaEmbeddingModel,
Timeout: 10 * time.Second,
})
if err != nil {
log.Fatalf("NewEmbedder of ollama error: %v", err)
}
log.Printf("===== call Embedder directly =====")
return embedder
}
func embedding(ctx context.Context, text string) {
embedder := getEmbedder(ctx)
if embedder == nil {
return
}
vectors, err := embedder.EmbedStrings(ctx, []string{text})
if err != nil {
log.Fatalf("EmbedStrings of Ollama failed, err=%v", err)
}
log.Printf("vectors : %v", vectors)
}
func indexer(ctx context.Context, docs []*schema.Document) {
cli, err := client.NewClient(ctx, client.Config{
Address: milvusAddr,
Username: milvusUsername,
Password: milvusPassword,
})
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
defer cli.Close()
embedder := getEmbedder(ctx)
if embedder == nil {
return
}
indexer, err := milvus.NewIndexer(ctx, &milvus.IndexerConfig{
Client: cli,
Embedding: embedder,
})
if err != nil {
log.Fatalf("Failed to create indexer: %v", err)
return
}
log.Printf("Indexer created success")
ids, err := indexer.Store(ctx, docs)
if err != nil {
log.Fatalf("Failed to store: %v", err)
}
log.Printf("Store success, ids: %v", ids)
}
func retriever(ctx context.Context, query string) {
cli, err := client.NewClient(ctx, client.Config{
Address: milvusAddr,
Username: milvusUsername,
Password: milvusPassword,
})
if err != nil {
log.Fatalf("Failed to create client: %v", err)
return
}
defer cli.Close()
embedder := getEmbedder(ctx)
if embedder == nil {
return
}
// Create a retriever
retriever, err := milvusretriever.NewRetriever(ctx, &milvusretriever.RetrieverConfig{
Client: cli,
Collection: "",
Partition: nil,
VectorField: "",
OutputFields: []string{
"id",
"content",
"metadata",
},
DocumentConverter: nil,
MetricType: "",
TopK: 0,
ScoreThreshold: 5,
Sp: nil,
Embedding: embedder,
})
if err != nil {
log.Fatalf("Failed to create retriever: %v", err)
return
}
// Retrieve documents
documents, err := retriever.Retrieve(ctx, query)
if err != nil {
log.Fatalf("Failed to retrieve: %v", err)
return
}
// Print the documents
for i, doc := range documents {
fmt.Printf("Document %d:\n", i)
fmt.Printf("title: %s\n", doc.ID)
fmt.Printf("content: %s\n", doc.Content)
fmt.Printf("metadata: %v\n", doc.MetaData)
}
}
func main() {
ctx := context.Background()
// Embedding:将文本转换成向量
text := "你好,听说你是房产经纪人 可以推荐我一些适合的房源吗?"
embedding(ctx, text)
// 将文档先转换成向量再索引到 Milvus 中
indexer(ctx, []*schema.Document{
{
ID: "milvus-1",
Content: "milvus is an open-source vector database",
MetaData: map[string]any{
"h1": "milvus",
"h2": "open-source",
"h3": "vector database",
},
},
{
ID: "milvus-2",
Content: "milvus is a distributed vector database",
},
})
// 从 Milvus 中检索向量
retriever(ctx, "milvus")
}