资讯动态

langchaingo 与 Chroma 向量存储实战指南:从城市数据检索看 Go 语义搜索的完整链路

发布时间:2026/9/15 12:35:00 来源:尧图企业网站定制
langchaingo 与 Chroma 向量存储实战指南从城市数据检索看 Go 语义搜索的完整链路【免费下载链接】langchaingoLangChain for Go, the easiest way to write LLM-based programs in Go项目地址: https://gitcode.com/GitHub_Trending/la/langchaingo导读本文以 langchaingo 仓库中的 Chroma 向量存储示例 为骨架完整拆解创建向量存储、写入带元数据的文档、执行带分数阈值与元数据过滤的相似度搜索这一端到端流程。你不仅能直接跑通示例程序还能深入 chroma 包 的源码实现理解距离函数、分数阈值、命名空间与过滤器在底层是如何协作的从而在自己的 Go 应用中落地语义搜索与 RAG 检索。示例概览一个基于城市信息的 Chroma 向量存储examples/chroma-vectorstore-example/目录下的示例演示了如何使用 langchaingo 的 Chroma 集成程序向向量存储写入一批城市文档每篇文档包含城市名称PageContent以及人口population单位百万和面积area单位平方公里两类元数据随后执行三种不同的相似度查询并打印结果。整个示例围绕以下四个阶段展开向量存储创建通过环境变量CHROMA_URL、OPENAI_API_KEY配置并连接 Chroma 服务文档写入向集合添加 13 篇城市文档及其元数据相似度搜索执行三种带不同选项数量限制、分数阈值、元数据过滤的查询结果展示按查询用例分组输出命中的城市名称。环境准备与依赖示例是一个独立的 Go module其 go.mod 声明了以下关键依赖github.com/tmc/langchaingolangchaingo 主库github.com/amikos-tech/chroma-goChroma 官方 Go 客户端被vectorstores/chroma包封装使用github.com/google/uuid用于生成命名空间与文档 ID。运行示例需要准备两部分环境一个可访问的 Chroma 服务下文给出 Docker 启动方式以及一个 OpenAI API Key用于将文本编码为向量。langchaingo 的 chroma 包 定义了三个环境变量常量全部可以通过环境变量注入环境变量用途默认行为CHROMA_URLChroma 服务地址必须设置否则返回invalid options: missing chroma URL错误OPENAI_API_KEYOpenAI API Key用于文本向量化与WithOpenAIAPIKey二选一二者皆无则报错OPENAI_ORGANIZATIONOpenAI 组织 ID可选为空时跳过第一步创建 Chroma 向量存储示例通过chroma.New创建存储实例见 chroma_vectorstore_example.gostore, errNs : chroma.New( chroma.WithChromaURL(os.Getenv(CHROMA_URL)), chroma.WithOpenAIAPIKey(os.Getenv(OPENAI_API_KEY)), chroma.WithDistanceFunction(chroma_go.COSINE), chroma.WithNameSpace(uuid.New().String()), ) if errNs ! nil { log.Fatalf(new: %v\n, errNs) }可用构造选项所有选项均在 vectorstores/chroma/options.go 中定义采用函数式选项模式选项作用默认值 / 说明WithChromaURL(url)指定 Chroma 服务地址必填未显式传入时回退读取CHROMA_URL环境变量仍为空则报错WithOpenAIAPIKey(key)指定 OpenAI API Key未设置时回退读取OPENAI_API_KEY环境变量WithOpenAIOrganization(id)指定 OpenAI 组织 ID可选WithDistanceFunction(fn)设置向量距离函数默认L2示例使用COSINEWithNameSpace(nameSpace)设置命名空间即 Chroma 集合名默认langchainWithEmbedder(e)注入自定义 Embedder未设置时使用 OpenAI Embedding 函数WithIncludes(includes)控制查询返回字段文档、元数据、距离等默认由内部决定底层发生了什么chroma.Newchroma.go内部依次完成应用所有选项并做校验URL 缺失或既无 API Key 也无自定义 Embedder 时返回ErrInvalidOptions创建 Chroma 客户端并发送Heartbeat请求确认服务可达决定 Embedding 函数若用户通过WithEmbedder注入了自定义embeddings.Embedder则通过 embedder.go 中的chromaGoEmbedder适配器将其包装为 chroma-go 的EmbeddingFunction实现EmbedDocuments、EmbedQuery、EmbedRecords否则创建 OpenAI Embedding 函数调用CreateCollection获取或创建以命名空间命名的集合。值得注意的一点示例中使用了uuid.New().String()作为命名空间意味着每次运行都会创建全新的随机集合不会与历史数据互相污染非常适合演示与测试场景。第二步向向量存储添加文档示例使用AddDocuments批量写入 13 篇城市文档chroma_vectorstore_example.go_, errAd : store.AddDocuments(context.Background(), []schema.Document{ {PageContent: Tokyo, Metadata: meta{population: 9.7, area: 622}}, {PageContent: Kyoto, Metadata: meta{population: 1.46, area: 828}}, {PageContent: Hiroshima, Metadata: meta{population: 1.2, area: 905}}, {PageContent: Kazuno, Metadata: meta{population: 0.04, area: 707}}, {PageContent: Nagoya, Metadata: meta{population: 2.3, area: 326}}, {PageContent: Toyota, Metadata: meta{population: 0.42, area: 918}}, {PageContent: Fukuoka, Metadata: meta{population: 1.59, area: 341}}, {PageContent: Paris, Metadata: meta{population: 11, area: 105}}, {PageContent: London, Metadata: meta{population: 9.5, area: 1572}}, {PageContent: Santiago, Metadata: meta{population: 6.9, area: 641}}, {PageContent: Buenos Aires, Metadata: meta{population: 15.5, area: 203}}, {PageContent: Rio de Janeiro, Metadata: meta{population: 13.7, area: 1200}}, {PageContent: Sao Paulo, Metadata: meta{population: 22.6, area: 1523}}, }) if errAd ! nil { log.Fatalf(AddDocument: %v\n, errAd) }AddDocuments 的底层处理AddDocumentschroma.go的实现要点选项约束若调用时携带了Embedder、ScoreThreshold或Filters选项会直接返回ErrUnsupportedOptions——这些选项仅用于查询场景文档 ID每篇文档由uuid.New().String()生成随机 ID源码注释中标注为 TODO希望未来使用更有意义的 ID元数据拷贝通过maps.Copy深拷贝文档元数据避免后续写入污染调用方持有的 map命名空间注入若设置了命名空间且配置了nameSpaceKey默认键名为nameSpace元数据中会额外写入该键值对用于区分同一集合内的不同命名空间写入集合调用 chroma-go 客户端的col.Add(ctx, nil, metadatas, texts, ids)完成向量化入库。第三步三种相似度搜索示例将三种查询组织成统一的用例结构chroma_vectorstore_example.go每种用例由名称、查询文本、目标文档数量以及搜索选项构成exampleCases : []exampleCase{ { name: Up to 5 Cities in Japan, query: Which of these are cities are located in Japan?, numDocuments: 5, options: []vectorstores.Option{ vectorstores.WithScoreThreshold(0.8), }, }, { name: A City in South America, query: Which of these are cities are located in South America?, numDocuments: 1, options: []vectorstores.Option{ vectorstores.WithScoreThreshold(0.8), }, }, { name: Large Cities in South America, query: Which of these are cities are located in South America?, numDocuments: 100, options: []vectorstores.Option{ vectorstores.WithFilters(filter{ $and: []filter{ {area: filter{$gte: 1000}}, {population: filter{$gte: 13}}, }, }), }, }, }三种查询的设计意图分别为Up to 5 Cities in Japan检索日本城市最多返回 5 篇且要求相似度分数不低于 0.8A City in South America检索南美城市仅返回最相关的 1 篇同样设置 0.8 的分数阈值Large Cities in South America检索南美大城市通过$and组合两个数值条件——area 1000且population 13百万不设返回数量上限100 远大于数据量。随后循环执行查询并暂存结果results : make([][]schema.Document, len(exampleCases)) for ecI, ec : range exampleCases { docs, errSs : store.SimilaritySearch(ctx, ec.query, ec.numDocuments, ec.options...) if errSs ! nil { log.Fatalf(query1: %v\n, errSs) } results[ecI] docs }SimilaritySearch 的核心实现SimilaritySearchchroma.go的处理逻辑值得仔细阅读解析选项若显式传入Embedder选项会报错Chroma 查询的向量化由创建集合时绑定的 Embedding 函数负责校验分数阈值阈值必须落在[0, 1]区间否则返回ErrInvalidScoreThreshold对应测试 TestSimilaritySearchWithInvalidScoreThreshold用-0.8和1.8验证了越界报错若配置了命名空间键会将命名空间过滤条件与用户过滤器通过$and合并见getNamespacedFilter保证查询只命中当前命名空间调用 chroma-go 的collection.Query发起查询并校验返回的Documents、Metadatas、Distances三者长度一致否则返回ErrUnexpectedResponseLength距离转分数Chroma 返回的是距离值langchaingo 统一换算为相似度分数score 1.0 - distanceCOSINE 距离下分数越接近 1 表示越相似并过滤掉低于阈值的文档返回schema.Document其中Score字段携带换算后的相似度分数。过滤器语法vectorstores.WithFilters接收map[string]any底层透传给 Chroma 的元数据过滤。示例展示了$and与$gte的组合从 chroma_test.go 可以看到更多受支持的算子例如$eq精确相等匹配如{location: {$eq: patio}}$in枚举匹配如{location: {$in: []string{office, kitchen}}}$gte/$lte等数值比较算子。测试 TestChromaAsRetrieverWithMetadataFilters 还验证了$and组合$eq与$gte的多条件过滤场景。第四步结果展示查询完成后示例将每类用例的命中城市以逗号分隔打印chroma_vectorstore_example.gofmt.Printf(Results:\n) for ecI, ec : range exampleCases { texts : make([]string, len(results[ecI])) for docI, doc : range results[ecI] { texts[docI] doc.PageContent } fmt.Printf(%d. case: %s\n, ecI1, ec.name) fmt.Printf( result: %s\n, strings.Join(texts, , )) }运行示例Docker 启动 Chroma 并执行vectorstores/chroma/README.md 提供了完整的本地运行指引。目前 Chroma 仅支持客户端/服务端模式因此在本地启动服务最便捷的方式是 Docker$ docker run -p 8000:8000 ghcr.io/chroma-core/chroma:0.5.0服务就绪后设置环境变量并直接运行示例$ export CHROMA_URLhttp://localhost:8000 $ export OPENAI_API_KEYYourOpenApiKeyGoesHere $ go run ./examples/chroma-vectorstore-example/chroma_vectorstore_example.go预期的输出如下Results: 1. case: Up to 5 Cities in Japan result: Tokyo, Nagoya, Kyoto, Fukuoka, Hiroshima 2. case: A City in South America result: Buenos Aires 3. case: Large Cities in South America result: Sao Paulo, Rio de Janeiro可以看到日本查询返回了 5 座城市且均为日本城市南美单城查询命中了布宜诺斯艾利斯带过滤条件的查询则精确命中area 1000且population 13的圣保罗与里约热内卢验证了元数据过滤在数值场景下的有效性。进阶把 Chroma 接入检索问答链Chroma 向量存储不仅支持直接查询还可以通过 vectorstores.ToRetriever 包装为schema.Retriever接入 langchaingo 的链式调用。chroma 包的测试充分演示了这一用法result, err : chains.Run( context.TODO(), chains.NewRetrievalQAFromLLM( llm, vectorstores.ToRetriever(s, 5, vectorstores.WithScoreThreshold(0.8)), ), What colors is each piece of furniture next to the desk?, )相关测试见 TestChromaAsRetrieverWithScoreThreshold 与 TestChromaAsRetrieverWithMetadataFilterEqualsClause。ToRetriever接受向量存储、返回文档数量与查询选项其GetRelevantDocuments内部实际调用的仍是SimilaritySearch因此分数阈值、过滤器、命名空间等选项在 RAG 场景下同样生效。VectorStore接口本身非常简洁vectorstores/vectorstores.go只要求实现AddDocuments与SimilaritySearch两个方法这也是它能够统一接入检索链、并可方便替换为其他后端如 pgvector、weaviate 等的原因。测试验证与注意事项vectorstores/chroma/chroma_test.go 中的测试通过httprr录制回放机制运行依赖CHROMA_URL与OPENAI_API_KEY环境变量未设置时测试会静默跳过。无 Docker 环境下测试还会尝试通过 testcontainers 自动拉起chromadb/chroma:0.4.24容器。使用 chroma 包时需要注意几个已由源码确认的约束URL 必须显式提供WithChromaURL与环境变量CHROMA_URL至少其一否则初始化失败API Key 与自定义 Embedder 至少其一OPENAI_API_KEY与WithEmbedder都缺失时初始化失败分数阈值必须落在[0, 1]越界会直接报错AddDocuments 不支持查询类选项携带ScoreThreshold、Filters、Embedder选项调用AddDocuments会返回ErrUnsupportedOptions命名空间需配合键名使用WithNameSpace仅设置命名空间而nameSpaceKey为空时AddDocuments会报错默认键名为nameSpace正常路径无需关心。小结从本示例可以提炼出在 Go 中接入 Chroma 的完整心智模型用chroma.New配合选项完成连接与集合创建用AddDocuments写入带元数据的文档用SimilaritySearch结合WithScoreThreshold与WithFilters实现精度可控、条件可组合的语义检索最后通过ToRetriever无缝接入问答链。示例中的城市数据虽然简单但其元数据 数值过滤 分数阈值的组合方式可以直接迁移到电商商品检索、文档知识库问答、日志异常匹配等真实场景。【免费下载链接】langchaingoLangChain for Go, the easiest way to write LLM-based programs in Go项目地址: https://gitcode.com/GitHub_Trending/la/langchaingo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价