Langchain-Go 学习文档
Langchain-Go 是一个 Go 语言版本的 Langchain,它使得在 Go 应用程序中构建和部署基于大型语言模型(LLM)的应用更加便捷。本文档将介绍 Langchain-Go 的基础概念和常见用法,并提供代码示例。
目录
核心概念
理解以下核心概念是掌握 Langchain-Go 的关键:
LLMs (大型语言模型)
LLMs 是 Langchain 的核心。它们是能够理解和生成人类语言的复杂模型。Langchain-Go 提供了与各种 LLM(例如 OpenAI 的 GPT 系列)交互的接口。
- 作用:执行文本生成、摘要、问答等任务。
- 示例:你可以向 LLM 提问,它会根据其训练数据生成回答。
Chains (链)
Chains 是 Langchain 中执行一系列操作的核心组件。它们可以将多个 LLM 调用或其他操作连接起来,形成一个连贯的执行序列。
- 作用:将复杂的任务分解为一系列更小的、可管理的步骤。
- 类型:
- LLMChain: 最基础的链,接收输入,格式化后传递给 LLM,并返回 LLM 的输出。
- Sequential Chains: 按顺序执行多个链,前一个链的输出可以作为后一个链的输入。
- Router Chains: 根据输入决定调用哪个子链。
Memory (记忆)
Memory 允许 Chains 和 Agents 记住之前的交互信息。这对于构建能够进行连贯对话的应用程序至关重要。
- 作用:在多次交互中保持上下文信息。
- 类型:
- Buffer Memory: 简单地存储所有先前的对话。
- Summary Memory: 对先前的对话进行总结并存储。
- Vector Store Backed Memory: 将对话存储在向量数据库中,以便进行语义搜索。
Agents (代理)
Agents 使用 LLM 来决定采取哪些行动。它们可以访问一系列 Tools,并根据用户的输入和目标来选择合适的工具执行任务。
- 作用:赋予 LLM 执行更广泛任务的能力,例如查找信息、执行代码或与外部 API 交互。
- 核心逻辑:Agent 接收用户输入,LLM 判断下一步行动,选择工具,执行工具,观察结果,然后重复此过程直到任务完成。
Tools (工具)
Tools 是 Agent 可以使用的具体功能。它们是围绕特定任务(如谷歌搜索、数据库查询、API 调用等)封装的函数。
- 作用:扩展 Agent 的能力范围,使其能够与外部世界交互。
- 示例:一个搜索工具可以让 Agent 在互联网上查找信息,一个计算器工具可以让 Agent 执行数学运算。
Embeddings (嵌入)
Embeddings 是将文本转换为数值向量表示的方法。这些向量能够捕捉文本的语义信息。
- 作用:用于文本相似度比较、语义搜索和文本聚类等任务。
- 模型:通常使用专门的嵌入模型(如 OpenAI 的 text-embedding-ada-002)来生成文本嵌入。
#### Vector Stores (向量存储)
Vector Stores (也称为向量数据库) 用于存储和高效查询由 Embeddings 生成的向量。
- 作用:快速找到与给定查询向量最相似的文本片段,是实现语义搜索和 RAG (Retrieval Augmented Generation) 的关键。
- 示例:C
1 hroma, FAISS, Pinecone 等。
基本用法
以下是一些 Langchain-Go 的基本用法示例。
安装
首先,你需要安装 Langchain-Go。你可以使用 go get
命令:
go get github.com/tmc/langchaingo
同时,你也需要安装你想要使用的 LLM 提供商的 SDK,例如 OpenAI:
go get github.com/tmc/langchaingo/llms/openai
使用 LLMs
与 LLM 进行交互是 Langchain-Go 的基础。
package main
import (
"context"
"fmt"
"log"
"github.com/tmc/langchaingo/llms/openai"
"github.com/tmc/langchaingo/llms"
)
func main() {
// 创建一个新的 OpenAI LLM 实例
// 你需要设置你的 OpenAI API 密钥作为环境变量 OPENAI_API_KEY
llm, err := openai.New()
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
prompt := "你好,请介绍一下你自己。"
// 调用 LLM 生成文本
completion, err := llms.GenerateFromSinglePrompt(ctx, llm, prompt)
if err != nil {
log.Fatal(err)
}
fmt.Println(completion)
}
构建简单的 Chain
LLMChain 是最常用的链之一。它接收输入,使用 PromptTemplate 格式化输入,然后将格式化后的提示发送给 LLM。
package main
import (
"context"
"fmt"
"log"
"github.com/tmc/langchaingo/chains"
"github.com/tmc/langchaingo/llms/openai"
"github.com/tmc/langchaingo/prompts"
)
func main() {
llm, err := openai.New()
if err != nil {
log.Fatal(err)
}
// 创建一个提示模板
prompt := prompts.NewPromptTemplate(
"为一个生产{product}的公司写一句标语。",
[]string{"product"},
)
// 创建一个 LLMChain
chain := chains.NewLLMChain(llm, prompt)
ctx := context.Background()
inputs := map[string]any{
"product": "舒适的袜子",
}
// 运行链
result, err := chains.Call(ctx, chain, inputs)
if err != nil {
log.Fatal(err)
}
fmt.Println(result["text"]) // 输出 LLM 生成的标语
}
使用 Memory
Memory 可以让你的链或 Agent 记住之前的对话。
package main
import (
"context"
"fmt"
"log"
"github.com/tmc/langchaingo/chains"
"github.com/tmc/langchaingo/llms/openai"
"github.com/tmc/langchaingo/memory"
"github.com/tmc/langchaingo/prompts"
)
func main() {
llm, err := openai.New()
if err != nil {
log.Fatal(err)
}
// 创建一个 BufferMemory 实例
mem := memory.NewConversationBuffer()
// 创建一个提示模板,包含历史记录
// 注意:在 Langchain-Go 中,通常 Memory 会被 Chain 或 Agent 内部管理,
// PromptTemplate 可能需要特定格式来接收历史信息,这取决于具体的实现。
// 以下是一个概念性的示例,具体实现可能需要查阅 Langchain-Go 的最新文档和示例。
// 实际的 ConversationChain 会自动处理历史记录的注入。
prompt := prompts.NewPromptTemplate(
`以下是人类与AI友好对话的片段。AI健谈,并根据其上下文提供大量具体细节。如果AI不知道问题的答案,它会如实说自己不知道。
当前对话:
{history}
人类: {input}
AI:`,
[]string{"history", "input"},
)
// 创建 ConversationChain (Langchain-Go 中可能有类似的封装)
// 这里我们模拟一个简单的 LLMChain 配合 Memory 使用
// 对于更复杂的对话,可以查找 `ConversationChain` 或类似的实现
conversationChain := chains.NewConversation(llm, mem) // ConversationChain 会自动管理 Memory
ctx := context.Background()
inputs1 := map[string]any{
"input": "你好,我叫小明。",
}
result1, err := chains.Predict(ctx, conversationChain, inputs1) // 使用 Predict 更方便获取文本结果
if err != nil {
log.Fatal(err)
}
fmt.Printf("AI: %s\n", result1)
inputs2 := map[string]any{
"input": "我的名字是什么?",
}
result2, err := chains.Predict(ctx, conversationChain, inputs2)
if err != nil {
log.Fatal(err)
}
fmt.Printf("AI: %s\n", result2) // AI 应该能记住你的名字
// 查看 Memory 中的历史记录
history, err := mem.LoadMemoryVariables(nil)
if err != nil {
log.Fatal(err)
}
fmt.Println("Memory:", history)
}
注意:Langchain-Go 中 Memory 的具体用法和 ConversationChain
的实现细节请参考其官方 GitHub 仓库的示例。
使用 Agents 和 Tools
Agent 使用 LLM 来决定采取哪些行动,并使用 Tool 来执行这些行动。
package main
import (
"context"
"fmt"
"log"
"github.com/tmc/langchaingo/agents"
"github.com/tmc/langchaingo/llms/openai"
"github.com/tmc/langchaingo/tools"
"github.com/tmc/langchaingo/tools/DuckDuckGoSearch" // 假设有这样一个工具
)
// 定义一个简单的计算器工具
type SimpleCalculator struct{}
func (sc *SimpleCalculator) Name() string {
return "SimpleCalculator"
}
func (sc *SimpleCalculator) Description() string {
return "一个简单的计算器,可以执行基本的数学运算,例如:2+2 或 3*5"
}
func (sc *SimpleCalculator) Call(ctx context.Context, input string) (string, error) {
// 在实际应用中,这里会解析 input 并执行计算
// 为简化示例,我们假设输入总是有效的表达式
// 例如,如果 input 是 "2+2", 这里应该返回 "4"
// 这里我们仅作演示,不做实际计算
if input == "2+2" {
return "4", nil
}
if input == "北京今天的天气怎么样?" { // 模拟工具无法处理的情况
return "我只能进行简单的数学运算。", nil
}
return fmt.Sprintf("计算结果: %s (模拟)", input), nil
}
var _ tools.Tool = &SimpleCalculator{} // 确保 SimpleCalculator 实现了 tools.Tool 接口
func main() {
llm, err := openai.New(openai.WithModel("gpt-3.5-turbo-instruct")) // 某些 Agent 类型可能需要 Instruct 模型
if err != nil {
log.Fatal(err)
}
// 创建工具列表
availableTools := []tools.Tool{
&SimpleCalculator{},
// DuckDuckGoSearch.New() // 假设的搜索工具初始化
}
// 创建 Agent 执行器
// Langchain-Go 中的 Agent 实现可能与 Python 版本有所不同,
// ZeroShotReactDescription 是 Python 中常见的一种 Agent 类型。
// 你需要查找 Langchain-Go 中对应的 Agent 实现。
// 这里我们使用一个概念性的 `Executor`,具体请查阅官方文档。
// 示例:创建一个 MRKL Agent (一种常见的 Agent 类型)
// agent := agents.NewMrkl(llm, availableTools, agents.WithMaxIterations(3))
// 下面是一个更通用的 Executor 初始化概念
executor, err := agents.Initialize(
llm,
availableTools,
agents.ZeroShotReactDescription, // 或者其他 Agent 类型
agents.WithMaxIterations(5),
)
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
// query := "2+2 等于多少?"
query := "北京今天的天气怎么样?" // 尝试一个 Agent 可能需要工具但我们没提供合适工具的问题
result, err := executor.Run(ctx, query)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Agent 的最终回答: %s\n", result)
}
注意:Langchain-Go 中 Agent 和 Tool 的具体实现和 API 可能与 Python 版本有差异,请务必参考 Langchain-Go 的官方 GitHub 仓库和示例代码以获取最准确的信息。DuckDuckGoSearch 工具只是一个示例,你可能需要自己实现或寻找已有的工具实现。
使用 Embeddings 和 Vector Stores
Embeddings 和 Vector Stores 用于语义搜索和检索增强生成 (RAG)。
package main
import (
"context"
"fmt"
"log"
"github.com/tmc/langchaingo/documentloaders"
"github.com/tmc/langchaingo/embeddings"
"github.com/tmc/langchaingo/llms/openai" // 用于 Embeddings
"github.com/tmc/langchaingo/schema"
"github.com/tmc/langchaingo/vectorstores"
"github.com/tmc/langchaingo/vectorstores/pinecone" // 示例,或使用内存中的 simple.Store
// "github.com/tmc/langchaingo/vectorstores/simple" // 内存中的 Vector Store
"strings"
)
func main() {
// 1. 创建 Embedder
// 你需要设置 OpenAI API 密钥
llm, err := openai.New()
if err != nil {
log.Fatal(err)
}
embedder, err := embeddings.NewEmbedder(llm) // 使用 OpenAI LLM 作为嵌入器
if err != nil {
log.Fatal(err)
}
// 2. 准备文档
docs := []schema.Document{
{PageContent: "苹果是一种水果。"},
{PageContent: "香蕉也是一种水果。"},
{PageContent: "汽车是一种交通工具。"},
{PageContent: "自行车也是一种交通工具。"},
}
// 3. 创建 Vector Store
// 使用内存中的 simple.Store 作为示例
// store, err := simple.New()
// if err != nil {
// log.Fatal(err)
// }
// 或者使用 Pinecone (需要设置 PINECODE_API_KEY 和 PINECODE_ENVIRONMENT)
// 注意:使用 Pinecone 需要先在 Pinecone 服务上创建索引
store, err := pinecone.New(
context.Background(),
pinecone.WithIndexName("your-pinecone-index-name"), // 替换为你的索引名称
pinecone.WithProjectName("your-pinecone-project-name"), // 替换为你的项目名称
pinecone.WithEmbedder(embedder), // 传入 embedder
pinecone.WithNameSpace("my-namespace"), // 可选的命名空间
)
if err != nil {
// 如果使用 simple.New() 则不需要以上 pinecone 配置
log.Fatalf("Failed to create vector store: %v. If using Pinecone, ensure index and project are set up.", err)
}
// 4. 将文档添加到 Vector Store (包括生成 Embeddings)
// 对于 simple.Store
// err = store.AddDocuments(context.Background(), docs, vectorstores.WithEmbedder(embedder))
// if err != nil {
// log.Fatal(err)
// }
// 对于 Pinecone (通常在创建时已传入 Embedder,AddDocuments 会自动处理)
// 如果 Pinecone 的 AddDocuments 不直接支持 schema.Document 列表,可能需要手动转换或使用其特定方法
// Langchain-Go 的 vectorstores 接口会尝试统一这些操作。
// 以下是通用接口的用法:
_, err = store.AddDocuments(context.Background(), docs) // Embedder 应已在 store 初始化时或通过 Option 设置
if err != nil {
log.Fatal(err)
}
fmt.Println("Documents added to vector store.")
// 5. 执行相似性搜索
query := "关于食物的信息"
numResults := 2 // 希望返回的结果数量
// 使用 VectorStore 进行相似性搜索
similarDocs, err := store.SimilaritySearch(context.Background(), query, numResults)
if err != nil {
log.Fatal(err)
}
fmt.Printf("与 '%s' 相关的文档:\n", query)
for _, doc := range similarDocs {
fmt.Printf("- %s (Score: %f)\n", doc.PageContent, doc.Score) // Score 可能不总是被所有 VectorStore 填充
}
// 示例:使用 TextSplitter 分割长文本
longText := "这是一段非常非常长的文本,它需要被分割成多个小块才能更好地被处理和嵌入。Langchain 提供了多种文本分割器来帮助完成这个任务。"
splitter := documentloaders.NewRecursiveCharacterTextSplitter(
documentloaders.WithChunkSize(20), // 每个块的最大字符数
documentloaders.WithChunkOverlap(5), // 块之间的重叠字符数
)
splitDocs, err := documentloaders.SplitDocuments(splitter, []schema.Document{{PageContent: longText}})
if err != nil {
log.Fatal(err)
}
fmt.Println("\n分割后的文档块:")
for _, sd := range splitDocs {
fmt.Printf("- %s\n", sd.PageContent)
}
}
注意:Vector Store 的具体实现和 API(例如 simple.Store
, pinecone
)可能有所不同。请查阅 Langchain-Go 官方文档和特定 Vector Store 的文档。Pinecone 等云服务需要额外的账户设置和 API 密钥。 doc.Score
的可用性和含义也取决于所使用的具体向量存储。
进阶用法 (概念预览)
Langchain-Go 还支持更多进阶的用法,这里简要介绍一些概念:
- Retrieval Augmented Generation (RAG): 结合了从 Vector Store 中检索到的信息和 LLM 的生成能力,以提供更准确、更具上下文的回答。通常流程是:用户提问 -> 嵌入问题 -> 在 Vector Store 中搜索相关文档 -> 将相关文档和原始问题一起作为上下文提供给 LLM -> LLM 生成最终答案。
- Custom Chains and Agents: 你可以创建自定义的链和 Agent 来满足特定的业务需求。
- Callbacks: 用于在 Langchain 操作的不同阶段(如链开始/结束,LLM 调用开始/结束)执行自定义逻辑,例如日志记录、监控等。
- Parsers (解析器): 用于解析 LLM 的输出,将其转换为结构化的数据或特定的格式。
- More Sophisticated Memory Types: 除了基础的 Buffer Memory,还有如
ConversationSummaryBufferMemory
(总结对话历史)、VectorStoreRetrieverMemory
(从向量存储中检索相关对话片段作为记忆) 等更高级的记忆类型。 - Document Loaders and Text Splitters: 用于加载不同来源的文档(如文本文件、PDF、网页等)并将其分割成适合 LLM 处理的小块。
总结
Langchain-Go 为 Go 开发者提供了一个强大的工具集,用于构建基于 LLM 的应用程序。通过理解其核心概念如 LLMs, Chains, Memory, Agents, Tools, Embeddings 和 Vector Stores,并结合实际代码练习,你将能够有效地利用 Langchain-Go 来开发创新的 AI 应用。
由于 Langchain-Go 仍在快速发展中,建议经常查阅其 官方 GitHub 仓库 (
希望这份学习文档对你有所帮助!🚀