Golang中LangChain进行文档检索和问答:数据分析实战案例

云信安装大师
90
AI 质量分
2 5 月, 2025
2 分钟阅读
0 阅读

Golang中LangChain进行文档检索和问答:数据分析实战案例

引言

在数据分析领域,我们经常需要从大量文档中快速查找相关信息并获取答案。LangChain是一个强大的框架,可以帮助我们构建这样的文档检索和问答系统。本文将介绍如何在Golang中使用LangChain实现这一功能,并通过一个数据分析实战案例展示完整流程。

准备工作

环境要求

  • Go 1.18+
  • LangChain Go SDK (github.com/tmc/langchaingo)
  • OpenAI API密钥(或其他LLM提供商)
  • 向量数据库(本文使用Pinecone)

安装依赖

代码片段
go get github.com/tmc/langchaingo

完整实现步骤

1. 初始化LangChain环境

代码片段
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/tmc/langchaingo/llms/openai"
    "github.com/tmc/langchaingo/vectorstores/pinecone"
)

func main() {
    // 初始化OpenAI LLM
    llm, err := openai.New(openai.WithModel("gpt-3.5-turbo"))
    if err != nil {
        log.Fatal(err)
    }

    // 初始化Pinecone向量存储
    pineconeAPIKey := "your-pinecone-api-key"
    pineconeIndexName := "your-index-name"
    pineconeEnvironment := "your-environment"

    vectorStore, err := pinecone.New(
        pinecone.WithAPIKey(pineconeAPIKey),
        pinecone.WithIndexName(pineconeIndexName),
        pinecone.WithEnvironment(pineconeEnvironment),
    )
    if err != nil {
        log.Fatal(err)
    }

    ctx := context.Background()

    // 其余代码...
}

2. 加载和预处理文档

代码片段
// 假设我们有一个CSV数据文件需要分析
func loadAndProcessDocuments(filePath string) ([]string, error) {
    // 读取CSV文件
    data, err := os.ReadFile(filePath)
    if err != nil {
        return nil, fmt.Errorf("failed to read file: %w", err)
    }

    // CSV解析和预处理(这里简化处理)
    var documents []string

    // 按行分割,每行作为一个文档
    for _, line := range strings.Split(string(data), "\n") {
        if line != "" {
            documents = append(documents, line)
        }
    }

    return documents, nil
}

3. 创建嵌入并存储到向量数据库

代码片段
func createAndStoreEmbeddings(ctx context.Context, vectorStore *pinecone.Store, documents []string) error {
    for i, doc := range documents {
        err := vectorStore.AddDocuments(ctx, []string{doc}, 
            map[string]interface{}{"doc_id": fmt.Sprintf("doc_%d", i)})

        if err != nil {
            return fmt.Errorf("failed to add document %d: %w", i, err)
        }

        // Pinecone有速率限制,适当延迟
        if i%10 == 0 {
            time.Sleep(1 * time.Second)
        }
    }

    return nil
}

4. 实现问答功能

代码片段
func queryDocuments(ctx context.Context, llm *openai.LLM, vectorStore *pinecone.Store, question string) (string, error) {
    // 1. 在向量数据库中搜索相关文档
    docs, err := vectorStore.SimilaritySearch(ctx, question, 3) // 获取最相关的3个文档

    if err != nil {
        return "", fmt.Errorf("similarity search failed: %w", err)
    }

    // 2. 构建提示词模板
    promptTemplate := `
    请基于以下上下文回答问题:

    上下文:
    {{range .}}
    - {{.}}
    {{end}}

    问题:{{.question}}
    答案:`

    // 3. LLM生成回答

    var contexts []string

    for _, doc := range docs {
        contexts = append(contexts, doc.PageContent)
    }

    data := map[string]interface{}{
        "contexts": contexts,
        "question": question,
    }

    result, err := llm.Call(ctx, promptTemplate, data)

    if err != nil {
        return "", fmt.Errorf("LLM call failed: %w", err)
    }

    return result.String(), nil
}

实战案例:销售数据分析问答系统

假设我们有一个销售数据CSV文件,包含以下列:日期、产品ID、销售额、客户地区。

CSV示例数据:

代码片段
2023-01-01,P001,1500,Northeast
2023-01-02,P002,2300,Southeast
2023-01-03,P001,1800,Northeast

main函数完整实现:

代码片段
func main() {
    ctx := context.Background()

    // 1. 初始化组件(见前面代码)

    // 2.加载和处理文档(CSV文件)
    docs, err := loadAndProcessDocuments("sales_data.csv")

    if err != nil {
        log.Fatal(err)
    }

    //3.创建并存储嵌入

   if err:= createAndStoreEmbeddings(ctx ,vectorStore,docs);err!=nil{
       log.Fatal(err)
   }

   fmt.Println("数据加载完成!可以开始提问了...")

   for{
       fmt.Print("\n请输入您的问题(输入q退出):")
       var question string 
       fmt.Scanln(&question)

       if strings.ToLower(question)=="q"{
           break 
       }

       answer ,err:= queryDocuments(ctx ,llm ,vectorStore ,question )

       if err!=nil{
           log.Printf("查询失败:%v",err )
           continue 
       }

       fmt.Printf("\n答案:%s\n",answer )
   }
}

QA示例交互

代码片段
请输入您的问题(输入q退出):东北地区1月份的销售额是多少?

答案:根据上下文数据,东北地区(Northeast)在2023年1月的销售额如下:
-2023年01月01日:1500元(P001产品)
-2023年01月03日:1800元(P001产品)

东北地区1月份总销售额为3300元。

注意事项和实践经验

  1. 速率限制:Pinecone和OpenAI都有API调用限制,添加适当的延迟以避免错误。

  2. 分块策略:对于大型文档,应该将其分成更小的块(如每500字一块),而不是整篇处理。

  3. 元数据过滤:可以在搜索时添加元数据过滤条件以提高相关性:

    代码片段
    docs ,err:= vectorStore.SimilaritySearch(ctx ,question ,3 ,
        pinecone.WithMetadataFilter(map[string]interface{}{"year":"2023"}))
    
  4. 提示工程:根据你的具体需求调整提示模板以获得更好的回答质量。

  5. 缓存机制:考虑缓存常见问题的答案以减少API调用和成本。

  6. 错误处理:在生产环境中需要更健壮的错误处理和重试机制。

总结

本文展示了如何在Golang中使用LangChain构建一个简单的文档检索和问答系统:

  1. LangChain提供了与各种LLM和向量数据库集成的统一接口
  2. Pinecone等向量数据库可以高效存储和检索文本嵌入
    3.RAG(Retrieval-Augmented Generation)模式结合了检索和生成的优势
    4.Golang的LangChain SDK虽然不如Python版本功能丰富,但基本功能完备

通过这个案例,你可以扩展应用到各种数据分析场景,如日志分析、用户反馈分析等。

原创 高质量