news 2026/9/16 19:44:55

在 LangChain Go 中使用 Google AlloyDB for PostgreSQL 实现向量相似度检索

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
在 LangChain Go 中使用 Google AlloyDB for PostgreSQL 实现向量相似度检索

在 LangChain Go 中使用 Google AlloyDB for PostgreSQL 实现向量相似度检索

【免费下载链接】langchaingoLangChain for Go, the easiest way to write LLM-based programs in Go项目地址: https://gitcode.com/GitHub_Trending/la/langchaingo

导读

本文基于 examples/google-alloydb-vectorstore-example 示例,完整讲解如何在 LangChain for Go(langchaingo)中接入 Google Cloud 的 AlloyDB for PostgreSQL:从环境变量准备、连接池创建、向量表初始化,到 VertexAI 文本嵌入模型的接入、文档批量写入与带元数据过滤的相似度检索。阅读完本文后,你将掌握一套可直接复制运行的「AlloyDB + VertexAI Embeddings」语义搜索 Go 代码方案,并理解其背后的源码实现原理。

示例概览:在 AlloyDB 上做语义搜索

AlloyDB for PostgreSQL 是 Google Cloud 提供的托管式 PostgreSQL 兼容数据库,内置 pgvector 向量扩展,可原生存储与检索高维向量。LangChain Go 通过vectorstores/alloydbutil/alloydbutil两个包为其提供了完整支持,核心能力包括:

  1. 创建 AlloyDB VectorStore:先通过alloydbutil.PostgresEngine建立到 AlloyDB 数据库的连接池,再初始化一张存放嵌入向量的数据表,最后基于 VertexAI 嵌入模型构建alloydb.VectorStore
  2. 初始化 VertexAI Embeddings:调用llms/googleai/vertex包创建文本嵌入客户端;
  3. 写入样例文档:向向量库中批量插入多条城市数据(城市名、人口、面积等元数据);
  4. 执行相似度检索:先做一次针对 "Japan" 的基础向量检索,再演示如何通过元数据过滤器(如"area" > 1500)做条件筛选。

完整的可运行代码位于 google_alloydb_vectorstore_example.go,其模块依赖声明见 go.mod(依赖 langchaingo v0.1.14-pre.4,以及cloud.google.com/go/alloydbconncloud.google.com/go/vertexaipgx/v5pgvector/pgvector-go等底层库)。

前置准备:环境变量与权限

必须设置的 9 个环境变量

运行示例前需设置以下环境变量(AlloyDB 的相关取值可在 Google Cloud Console 的 AlloyDB 集群页面中找到),其中 8 个为必填,缺失时程序会在getEnvVariables函数中通过log.Fatal直接退出:

环境变量说明示例
PROJECT_IDGCP 项目 IDmy-gcp-project
GOOGLE_CLOUD_LOCATIONVertexAI 模型所在区域(cloud location)us-central1
ALLOYDB_USERNAME数据库用户名postgres
ALLOYDB_PASSWORD数据库密码your-password
ALLOYDB_REGIONAlloyDB 集群所在区域us-central1
ALLOYDB_CLUSTERAlloyDB 集群名称my-cluster
ALLOYDB_INSTANCEAlloyDB 实例名称my-instance
ALLOYDB_DATABASE目标数据库名postgres
ALLOYDB_TABLE向量表名cities

设置命令示例:

export PROJECT_ID=<your project Id> export GOOGLE_CLOUD_LOCATION=<your cloud location> export ALLOYDB_USERNAME=<your user> export ALLOYDB_PASSWORD=<your password> export ALLOYDB_REGION=<your region> export ALLOYDB_CLUSTER=<your cluster> export ALLOYDB_INSTANCE=<your instance> export ALLOYDB_DATABASE=<your database> export ALLOYDB_TABLE=<your tablename>

前置开通项

参照 vectorstores/alloydb/README.md 的 Quick Start 说明,使用本包前需要依次完成:

  1. 创建或选择 GCP 项目;
  2. 为项目启用结算(billing);
  3. 启用 AlloyDB API(alloydb.googleapis.com);
  4. 通过 Cloud SDK 完成应用默认凭证认证(gcloud auth application-default login)。

包内对 Go 版本的要求为Go >= 1.22.0

分步拆解:示例运行流程

第一步:创建 PostgresEngine 连接池

示例首先调用alloydbutil.NewPostgresEngine建立与 AlloyDB 的连接池:

pgEngine, err := alloydbutil.NewPostgresEngine(ctx, alloydbutil.WithUser(username), alloydbutil.WithPassword(password), alloydbutil.WithDatabase(database), alloydbutil.WithAlloyDBInstance(projectID, region, cluster, instance), alloydbutil.WithIPType("PUBLIC"), ) if err != nil { log.Fatal(err) }

从源码看,util/alloydbutil/engine.go 中的createPool函数完成核心工作:它使用alloydbconn.NewDialer创建连接拨号器,将实例 URI 组装为projects/{project}/locations/{region}/clusters/{cluster}/instances/{instance}格式,并通过pgxpool.NewWithConfig构建连接池。WithIPType("PUBLIC")决定使用公网 IP(alloydbconn.WithPublicIP())还是私网 IP(alloydbconn.WithPrivateIP(),需设置PRIVATE),默认值为PUBLIC

关于鉴权,engine.go 中的getUser支持三种方式:

  • 同时提供WithUser+WithPassword:直接使用账号密码认证;
  • 提供WithIAMAccountEmail:使用 IAM 账号邮箱并启用 IAM 认证(alloydbconn.WithIAMAuthN());
  • 都不提供时:通过getServiceAccountEmail从应用默认凭证(ADC)自动获取 IAM 主体邮箱。

此外还提供了WithPool(pool *pgxpool.Pool)选项,可传入自建连接池(如连接 AlloyDB Omni 或自定义池化参数),详见 util/alloydbutil/options.go。

第二步:初始化向量表

通过InitVectorstoreTable创建用于存储向量的数据表,该操作只需在首次使用时执行一次:

vectorstoreTableoptions := alloydbutil.VectorstoreTableOptions{ TableName: table, VectorSize: 768, StoreMetadata: true, OverwriteExisting: true, MetadataColumns: []alloydbutil.Column{ {Name: "area", DataType: "int"}, {Name: "population", DataType: "int"}, }, } err = pgEngine.InitVectorstoreTable(ctx, vectorstoreTableoptions)

需要注意VectorSize必须与所用嵌入模型的输出维度一致——示例使用的text-embedding-005输出 768 维,因此这里设置为 768。OverwriteExisting: true表示若表已存在则先DROP TABLE再重建。

根据 engine.go 的validateVectorstoreTableOptions与建表逻辑,各字段存在以下默认值:

字段默认值说明
SchemaNamepublic数据库 schema
ContentColumnNamecontent文本内容列(TEXT NOT NULL)
EmbeddingColumnembedding向量列(vector(N)NOT NULL)
MetadataJSONColumnlangchain_metadataJSON 元数据列(StoreMetadata为 true 时创建)
IDColumn.Namelangchain_id主键列名
IDColumn.DataTypeUUID主键类型

建表时会先执行CREATE EXTENSION IF NOT EXISTS vector确保 pgvector 扩展存在,MetadataColumns中每个Column(含NameDataTypeNullable)都会成为表中的独立元数据列,Nullable默认按零值处理(即 false 对应NOT NULL)。

第三步:初始化 VertexAI 嵌入模型

示例通过llms/googleai/vertex包初始化 VertexAI 客户端,再包装成embeddings.Embedder

llm, err := vertex.New(ctx, googleai.WithCloudProject(projectID), googleai.WithCloudLocation(cloudLocation), googleai.WithDefaultModel("text-embedding-005"), ) if err != nil { log.Fatal(err) } e, err := embeddings.NewEmbedder(llm) if err != nil { log.Fatal(err) }

这里使用的模型为 Google 的text-embedding-005,区域由GOOGLE_CLOUD_LOCATION指定。embeddings.NewEmbedder将 LLM 包装为统一的Embedder接口(提供EmbedDocumentsEmbedQuery),使得上层 VectorStore 无需关心具体嵌入模型实现。

第四步:创建 VectorStore

vs, err := alloydb.NewVectorStore(pgEngine, e, table, alloydb.WithMetadataColumns([]string{"area", "population"}), ) if err != nil { log.Fatal(err) }

NewVectorStore位于 vectorstores/alloydb/vectorstore.go,内部通过 vectorstore_options.go 的applyAlloyDBVectorStoreOptions校验三个必填项(连接池、嵌入器、表名)并填充默认配置:默认 schemapublic、默认列名langchain_id/content/embedding/langchain_metadata、默认返回条数k=4、默认距离策略为余弦距离(CosineDistance)。

WithMetadataColumns是关键选项:它声明哪些元数据字段以独立列存储。结合 vectorstore.go 的generateAddDocumentsQuery可知,插入文档时这些字段会作为单独的 SQL 列写入,而其余元数据则会序列化为 JSON 存入langchain_metadata列。相比把所有元数据塞进 JSON,独立列在过滤检索时能获得显著的查询性能提升——这也是该包「Improved metadata handling」的核心设计之一。

第五步:批量写入文档

_, err = vs.AddDocuments(ctx, []schema.Document{ {PageContent: "Tokyo", Metadata: map[string]any{"population": 38, "area": 2190}}, {PageContent: "Paris", Metadata: map[string]any{"population": 11, "area": 105}}, {PageContent: "Sao Paulo", Metadata: map[string]any{"population": 22.6, "area": 1523}}, }) if err != nil { log.Fatal(err) }

从 vectorstore.go 的实现看,AddDocuments的执行流程为:

  1. 抽取所有文档的PageContent调用embedder.EmbedDocuments一次性生成向量;
  2. 为每个文档生成 ID:优先读取Metadata["id"],否则使用uuid.New()生成 UUID;
  3. 将内容、向量、元数据组装为 INSERT 语句,并通过pgx.Batch批量提交到连接池,保证写入效率。

第六步:相似度检索与元数据过滤

基础检索:

docs, err := vs.SimilaritySearch(ctx, "Japan", 0) if err != nil { log.Fatal(err) } fmt.Println("Docs:", docs)

带过滤条件的检索:

filter := "\"area\" > 1500" filteredDocs, err := vs.SimilaritySearch(ctx, "Japan", 0, vectorstores.WithFilters(filter)) if err != nil { log.Fatal(err) } fmt.Println("FilteredDocs:", filteredDocs)

第二个参数0表示 top-K 条数,由于 VectorStore 默认k=4SimilaritySearch内部忽略该参数(见 vectorstore.go),实际返回条数由WithK选项控制。

从源码看,SimilaritySearch的底层 SQL 形如:

SELECT content, langchain_metadata, cosine_distance(embedding, '<query_vector>') AS distance FROM "public"."<table>" WHERE "area" > 1500 ORDER BY embedding <=> '<query_vector>' LIMIT $1::int;

其中cosine_distance<=>运算符由距离策略决定。默认的余弦距离对应CosineDistance;包内还提供了欧氏距离(Euclideanl2_distance/<->)与内积(InnerProductinner_product/<#>),可通过WithDistanceStrategy切换,三种策略定义于 distance_strategy.go。过滤条件opts.Filters会被直接拼接进WHERE子句(仅当非空时生效),因此可以书写任意的 SQL 条件表达式。

检索结果的Score字段即距离值,Metadatalangchain_metadataJSON 列反序列化得到(见 processResultsToDocuments)。

如何运行示例

进入示例目录后执行:

go run google_alloydb_vectorstore_example.go

运行成功后,控制台会依次打印基础检索结果(Docs:)与过滤检索结果(FilteredDocs:)。由于写入的 Tokyo(area 2190)与 Sao Paulo(area 1523)满足"area" > 1500条件而 Paris(area 105)不满足,两条检索结果集合将呈现明显差异,直观展示元数据过滤的效果。

更进一步:AlloyDB 的索引与扩展能力

除示例覆盖的能力外,vectorstores/alloydb还面向大规模检索场景提供索引管理能力(见 vectorstore.go):

  • ApplyVectorIndex/DropVectorIndex/IsValidIndex/ReIndex:创建、删除、校验、重建向量索引;
  • 支持 HNSW、IVFFlat、IVF 与 AlloyDB 专属的ScaNN索引(创建 ScaNN 时自动执行CREATE EXTENSION IF NOT EXISTS alloydb_scann),各索引的参数结构(如HNSWOptions{M, EfConstruction}IVFOptions{Lists, Quantizer}SCANNOptions{NumLeaves, Quantizer})定义于 distance_strategy.go;
  • 支持CONCURRENTLY并发建索引与部分索引(partial index),以充分利用 AlloyDB 的扩展索引能力。

此外,同一PostgresEngine还提供InitChatHistoryTable方法(见 engine.go),可初始化聊天历史表,与 memory 模块配合实现会话记忆持久化,适合在此基础上构建带记忆的 RAG 应用。

小结

通过本示例可以确认:在 LangChain Go 中接入 AlloyDB for PostgreSQL 完成语义检索,只需「环境变量 → PostgresEngine → 建表 → VertexAI Embedder → VectorStore → 增/查」六步。其价值在于将 IAM 安全连接、pgvector 向量存储、独立元数据列过滤与 VertexAI 嵌入能力封装成统一、简洁的 Go API,开发者无需手工编写连接管理代码或 SQL 建表语句。如需深入了解接口细节,可继续阅读 vectorstores/alloydb/README.md、vectorstores/alloydb/vectorstore.go 与 util/alloydbutil/engine.go。

【免费下载链接】langchaingoLangChain for Go, the easiest way to write LLM-based programs in Go项目地址: https://gitcode.com/GitHub_Trending/la/langchaingo

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 19:43:32

MTK DRM显示驱动初始化:从Component机制到KMS对象创建全解析

第一次碰MTK平台的DRM显示驱动&#xff0c;大多数人都是在probe流程里迷路的。顶层明明挂着标准drm_driver的皮&#xff0c;真正干活的却是一套叫component的机制——匹配、绑定、拆解绕一大圈&#xff0c;最后才回到KMS对象的创建。再加上MTK显示管线本身又是OVL、RDMA、COLOR…

作者头像 李华
网站建设 2026/9/16 19:42:14

国产Linux系统上用pyenv实现Python多版本隔离管理实战

先说一个我自己的踩坑经历。去年在一台统信UOS 20机器上部署数据分析服务&#xff0c;项目依赖锁文件要求Python 3.10&#xff0c;机器自带的是Python 3.7。当时图省事&#xff0c;直接改了系统Python的软链接&#xff0c;结果重启后桌面环境直接起不来了。后来才搞清楚&#x…

作者头像 李华
网站建设 2026/9/16 19:41:32

智能算法在栅格地图路径规划中的对比与应用

1. 项目背景与核心价值在机器人导航、物流配送和自动驾驶等领域&#xff0c;路径规划始终是核心问题之一。二维栅格地图作为最常见的环境建模方式&#xff0c;其路径优化效果直接影响系统性能。传统算法如A*、Dijkstra在复杂环境中容易陷入局部最优&#xff0c;而智能优化算法因…

作者头像 李华