ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

在 Go 中集成 Pinecone 向量数据库:基于 langchaingo 的向量存储实战指南

在 Go 中集成 Pinecone 向量数据库:基于 langchaingo 的向量存储实战指南 在 Go 中集成 Pinecone 向量数据库基于 langchaingo 的向量存储实战指南【免费下载链接】langchaingoLangChain for Go, the easiest way to write LLM-based programs in Go项目地址: https://gitcode.com/GitHub_Trending/la/langchaingo导读本文以 langchaingo 仓库中的 pinecone-vectorstore-example 示例为蓝本完整讲解如何在 Go 应用中把OpenAI Embedding 模型与Pinecone 向量数据库组合起来从初始化 Embedder、创建带自定义配置的 Pinecone Store、批量写入带元数据的文档到执行基础相似度搜索、带分数阈值搜索、以及结合元数据过滤器的复合查询。读完本文你将掌握 langchaingovectorstores/pinecone包的完整调用链与底层实现原理能直接在自己的 Go 项目中落地向量检索能力。示例概览用 7 座城市构建一个可检索的向量库这个示例的核心思路非常直观把「东京、巴黎、伦敦、圣地亚哥、布宜诺斯艾利斯、里约热内卢、圣保罗」这 7 个城市名作为文档写入 Pinecone每个城市附带population人口单位百万和area面积单位平方公里两个元数据字段随后用自然语言查询如 japan、only cities in south america执行相似度搜索并观察分数阈值与元数据过滤器如何收窄结果。整个流程覆盖了 langchaingo 向量存储体系的四个关键环节配置 OpenAI Embedding使用text-embedding-3-small模型把文本转成向量初始化 Pinecone Store通过pinecone.New搭配若干With*选项完成配置写入文档AddDocuments自动完成「文本 → 向量 → upsert 到索引」的全过程相似度检索SimilaritySearch支持基础搜索、WithScoreThreshold阈值过滤、WithFilters元数据过滤三种形态。示例主程序位于 examples/pinecone-vectorstore-example/pinecone_vectorstore_example.go其go.mod依赖github.com/tmc/langchaingo与github.com/google/uuid用于生成命名空间/向量 ID。环境准备与运行方式运行示例前需要满足两个前置条件设置 OpenAI API Key 环境变量OPENAI_API_KEY会被 OpenAI 客户端自动读取示例通过openai.New创建 Embedding 客户端替换 Pinecone API Key示例代码中以占位符YOUR_API_KEY形式硬编码在pinecone.WithAPIKey(...)中运行前必须替换为真实 Key。在 examples/pinecone-vectorstore-example 目录下直接执行go run pinecone_vectorstore_example.go示例本身没有为搜索结果做断言运行成功后会直接打印三次SimilaritySearch返回的文档切片fmt.Println(docs)便于直观观察不同检索形态的输出差异。关于 API Key 的两种提供方式从源码看API Key 并不强制要求写死在代码里。vectorstores/pinecone/options.go 中applyClientOptions的逻辑是若未通过WithAPIKey提供 Key则自动读取PINECONE_API_KEY环境变量若两者皆无返回ErrInvalidOptions: missing api key。因此更安全的做法是export OPENAI_API_KEYsk-... export PINECONE_API_KEYpc-... go run pinecone_vectorstore_example.go单元测试 vectorstores/pinecone/pinecone_unit_test.go 中的TestEnvironmentVariableHandling验证了「选项优先于环境变量」这一优先级规则与源码行为一致。第一步创建 OpenAI Embedding 客户端llm, err : openai.New(openai.WithEmbeddingModel(text-embedding-3-small)) // 指定你偏好的 embedding 模型 if err ! nil { log.Fatal(err) } e, err : embeddings.NewEmbedder(llm) if err ! nil { log.Fatal(err) }这里的关键点是 langchaingo 的抽象层次OpenAI 客户端实现的是EmbedderClient接口CreateEmbedding(ctx, texts)而 embeddings/embedding.go 中的NewEmbedder将其包装为EmbedderImpl提供EmbedDocuments与EmbedQuery两个方法同时内置了StripNewLines默认去除换行与BatchSize默认分批大小两个影响嵌入行为的选项。后续 Pinecone Store 只依赖embeddings.Embedder接口因此可以无缝替换为其他 Embedding 提供方如 HuggingFace、Cohere、Jina 等体现了接口驱动的可插拔设计。构造 Pinecone Store 的四个必填/可选选项store, err : pinecone.New( pinecone.WithHost(https://api.pinecone.io), pinecone.WithEmbedder(e), pinecone.WithAPIKey(YOUR_API_KEY), pinecone.WithNameSpace(uuid.New().String()), ) if err ! nil { log.Fatal(err) }对照 vectorstores/pinecone/options.go 的校验逻辑各选项说明如下选项是否必填作用与实现细节WithHost(host)必填设置 Pinecone 索引主机地址实现内部会用strings.TrimPrefix剥离https://前缀见单元测试TestEdgeCases对 host 剥离行为的验证WithEmbedder(e)必填设置用于文本向量化的 EmbedderAddDocuments与SimilaritySearch都会调用它WithAPIKey(key)二选一显式设置 API Key不传则回退到PINECONE_API_KEY环境变量WithNameSpace(ns)建议设置设置 upsert/查询的目标命名空间示例用uuid.New().String()生成随机命名空间避免污染已有数据WithTextKey(key)可选设置元数据中保存原文的键名默认值为text三者缺任一时pinecone.New都会返回包装了ErrInvalidOptions的错误对应错误消息 missing host / missing embedder / missing api key这些分支在 pinecone_unit_test.go 的TestApplyClientOptions与TestNew中均有覆盖。New内部还会调用官方 SDKpinecone.NewClient创建 gRPC 客户端因此 Store 结构体中同时持有 host、apiKey、nameSpace、textKey 与 embedder 等字段见 vectorstores/pinecone/pinecone.go 的Store定义。第二步写入带元数据的文档_, err store.AddDocuments(context.Background(), []schema.Document{ { PageContent: Tokyo, Metadata: map[string]any{ population: 38, area: 2190, }, }, { PageContent: Paris, Metadata: map[string]any{ population: 11, area: 105, }, }, { PageContent: London, Metadata: map[string]any{ population: 9.5, area: 1572, }, }, { PageContent: Santiago, Metadata: map[string]any{ population: 6.9, area: 641, }, }, { PageContent: Buenos Aires, Metadata: map[string]any{ population: 15.5, area: 203, }, }, { PageContent: Rio de Janeiro, Metadata: map[string]any{ population: 13.7, area: 1200, }, }, { PageContent: Sao Paulo, Metadata: map[string]any{ population: 22.6, area: 1523, }, }, }) if err ! nil { log.Fatal(err) }AddDocuments 的底层流程从 pinecone.go 的AddDocuments实现可以梳理出完整的内部调用链通过s.client.IndexWithNamespace(s.host, nameSpace)建立与指定命名空间的索引连接注意命名空间优先级vectorstores.WithNameSpace选项优先于 Store 构造时的命名空间见getNameSpace与TestGetNameSpace提取所有PageContent组成文本切片调用s.embedder.EmbedDocuments(ctx, texts)批量生成向量若返回向量数量与文档数不符返回ErrEmbedderWrongNumberVectors把每个文档的Metadata复制一份并额外写入metadata[s.textKey] texts[i]——即默认在元数据里塞入text键保存原文这是查询时还原PageContent的关键为每个向量生成uuid.New().String()作为 ID构造 PineconeVector含 Id、Values、Metadata调用indexConn.UpsertVectors批量写入。可以看到元数据在这里扮演双重角色既用于查询时的过滤条件也携带原文以便检索结果反序列化回schema.Document。第三步三类相似度检索实战3.1 基础相似度搜索docs, err : store.SimilaritySearch(ctx, japan, 1) fmt.Println(docs)返回与 japan 最相似的 1 条文档。SimilaritySearch内部会先建立索引连接再用s.embedder.EmbedQuery(ctx, query)把查询文本向量化最后调用indexConn.QueryByVectorValues携带TopK、Filter、IncludeMetadata: true、IncludeValues: true发起查询把返回的 Matches 转回[]schema.Document含PageContent、Metadata与Score字段。3.2 带分数阈值的搜索docs, err store.SimilaritySearch(ctx, only cities in south america, 10, vectorstores.WithScoreThreshold(0.80)) fmt.Println(docs)WithScoreThreshold(0.80)只保留相似度分数 ≥ 0.8 的结果。其底层行为在getDocumentsFromMatches中实现scoreThreshold 0时返回全部匹配否则只追加match.Score scoreThreshold的文档。同时getScoreThreshold会校验阈值必须落在[0, 1]区间越界即返回ErrInvalidScoreThresholdvectorstores/pinecone/pinecone_unit_test.go 的TestGetScoreThreshold与TestSimilaritySearchWithInvalidScoreThreshold均验证了这一边界行为。注意Pinecone 的相似度分数含义取决于索引配置的度量方式如 cosine / dot product示例中使用的余弦相似度下0.80 是一个相对严格的相关性门槛。3.3 分数阈值 元数据过滤的复合搜索filter : map[string]interface{}{ $and: []map[string]interface{}{ { area: map[string]interface{}{ $gte: 1000, }, }, { population: map[string]interface{}{ $gte: 15.5, }, }, }, } docs, err store.SimilaritySearch(ctx, only cities in south america, 10, vectorstores.WithScoreThreshold(0.80), vectorstores.WithFilters(filter)) fmt.Println(docs)这段复合查询表达的是在 only cities in south america 的语义检索基础上同时要求area ≥ 1000且population ≥ 15.5。其底层实现是createProtoStructFilter先把 Go 的map[string]any过滤器json.Marshal序列化再反序列化进structpb.Struct最终随QueryByVectorValues请求一并下发。这正是 Pinecone 官方元数据过滤语法在 Go 中的落地形态——支持$eq、$ne、$gt、$gte、$lt、$lte、$in、$nin、$and、$or等运算符的嵌套组合。vectorstores.WithFilters与WithScoreThreshold、WithNameSpace等都定义在通用选项文件 vectorstores/options.go 中属于整个 langchaingo 向量存储体系的公共配置入口Store.getOptions会把它们逐一应用到每次调用上见TestGetOptions。从示例到生产更多可验证的进阶用法示例只演示了向量存储最基础的能力仓库测试与源码还提供了两个可以平滑升级到生产场景的方向1. 把 Store 包装为 Retriever接入 RAG 链路vectorstores/vectorstores.go 提供的ToRetriever(store, numDocuments, options...)可以把任何实现VectorStore接口的存储AddDocumentsSimilaritySearch转换为schema.Retriever从而直接喂给chains.NewRetrievalQAFromLLM做问答。集成测试 vectorstores/pinecone/pinecone_test.go 中的TestPineconeAsRetriever、TestPineconeAsRetrieverWithScoreThreshold展示了「Pinecone 检索 OpenAI 生成」的完整 RAG 链路TestPineconeAsRetrieverWithMetadataFilterEqualsClause与TestPineconeAsRetrieverWithMetadataFilterInClause则验证了$eq、$in单字段过滤的正确性。2. 过滤、命名空间与存储级选项可逐次覆盖选项体系支持「存储级默认值 调用级覆盖」AddDocuments与SimilaritySearch均可传入vectorstores.Option例如写入时用vectorstores.WithNameSpace(id)为单次操作指定命名空间而 Store 构造时的WithNameSpace只作为兜底TestGetNameSpace中 option overrides store namespace 即验证此规则。vectorstores.Options还包含WithDeduplicater写入前去重的回调用于避免重复生成 Embedding 的浪费等进阶选项可根据业务需要自行选用。小结这个示例虽然体量不大却完整串联了 langchaingo 向量存储体系的四个层次Embedder向量化→ VectorStore抽象接口→ Pinecone Store具体实现→ Retriever检索组件。对照源码可以看到AddDocuments的「文本 → 向量 → 携带元数据 upsert」链路位于 vectorstores/pinecone/pinecone.go选项校验、环境变量回退、textKey 默认值等细节在 vectorstores/pinecone/options.go通用选项与 Retriever 抽象分别在 vectorstores/options.go 与 vectorstores/vectorstores.go集成测试覆盖了分数阈值边界、$eq/$in/$and/$gte过滤及 RAG 问答场景见 vectorstores/pinecone/pinecone_test.go 与单元测试 vectorstores/pinecone/pinecone_unit_test.go。如果你需要在 Go 应用中为 LLM 提供长期记忆、语义检索或 RAG 知识库从复制这个示例开始把城市数据换成你的业务文档、把过滤器换成你的业务字段即可快速获得一套可运行的向量检索方案。【免费下载链接】langchaingoLangChain for Go, the easiest way to write LLM-based programs in Go项目地址: https://gitcode.com/GitHub_Trending/la/langchaingo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表