1. LangChain Go 简介
LangChain Go 是 LangChain 框架的 Go 语言实现版本,它为开发者提供了一套完整的工具链来构建基于大语言模型(LLM)的应用程序。LangChain Go 继承了 LangChain 的核心理念,旨在简化与各种 AI 模型的集成和交互过程。
主要特点
- 模块化设计:提供了清晰的模块化架构,包括 llms、Prompts、Memory、Chains 等核心组件
- 多模型支持:支持 OpenAI、Anthropic、Cohere、HuggingFace 等多种主流 AI 服务提供商
- 链式调用:支持复杂的链式操作,可以将多个步骤组合成一个完整的工作流
- 内存管理:提供多种内存管理策略,支持对话历史的持久化和管理
- Go 语言优势:充分利用 Go 语言的并发特性和性能优势
核心概念
- LLM(Large Language Model):大语言模型的抽象接口
- Prompt:用于与模型交互的提示模板
- Chain:将多个组件串联起来的执行链
- Memory:用于存储和管理对话历史的组件
- Agent:能够使用工具并做出决策的智能代理
2. 安装和基本使用
安装
1 2
| go mod init your-project go get github.com/tmc/langchaingo
|
基本使用示例
2.1 调用 OpenAI 模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package main
import ( "context" "fmt" "log" "os"
"github.com/tmc/langchaingo/llms" "github.com/tmc/langchaingo/llms/openai" )
func main() { os.Setenv("OPENAI_API_KEY", "your-api-key") llm, err := openai.New() if err != nil { log.Fatal(err) } ctx := context.Background() completion, err := llm.Call(ctx, "什么是 Go 语言?") if err != nil { log.Fatal(err) } fmt.Println(completion) }
|
2.2 配置不同的模型
OpenAI 配置
1 2 3 4 5 6 7 8 9 10 11
| import "github.com/tmc/langchaingo/llms/openai"
llm, err := openai.New()
llm, err := openai.New( openai.WithModel("gpt-4"), openai.WithTemperature(0.7), openai.WithMaxTokens(1000), )
|
Anthropic Claude 配置
1 2 3 4 5 6 7 8 9
| import "github.com/tmc/langchaingo/llms/anthropic"
os.Setenv("ANTHROPIC_API_KEY", "your-anthropic-key")
llm, err := anthropic.New( anthropic.WithModel("claude-3-sonnet-20240229"), anthropic.WithTemperature(0.5), )
|
Cohere 配置
1 2 3 4 5 6 7 8
| import "github.com/tmc/langchaingo/llms/cohere"
os.Setenv("COHERE_API_KEY", "your-cohere-key")
llm, err := cohere.New( cohere.WithModel("command"), cohere.WithTemperature(0.8), )
|
本地模型(Ollama)配置
1 2 3 4 5 6
| import "github.com/tmc/langchaingo/llms/ollama"
llm, err := ollama.New( ollama.WithServerURL("http://localhost:11434"), ollama.WithModel("llama2"), )
|
国产大模型配置
DeepSeek 配置
DeepSeek 提供了兼容 OpenAI API 的接口,可以通过 OpenAI 包来配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import "github.com/tmc/langchaingo/llms/openai"
llm, err := openai.New( openai.WithModel("deepseek-chat"), openai.WithBaseURL("https://api.deepseek.com/v1"), openai.WithToken("your-deepseek-api-key"), openai.WithTemperature(0.7), openai.WithMaxTokens(2000), )
llmCoder, err := openai.New( openai.WithModel("deepseek-coder"), openai.WithBaseURL("https://api.deepseek.com/v1"), openai.WithToken("your-deepseek-api-key"), )
|
智谱 AI (GLM) 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| llm, err := openai.New( openai.WithModel("glm-4"), openai.WithBaseURL("https://open.bigmodel.cn/api/paas/v4"), openai.WithToken("your-zhipu-api-key"), openai.WithTemperature(0.8), )
llmVision, err := openai.New( openai.WithModel("glm-4v"), openai.WithBaseURL("https://open.bigmodel.cn/api/paas/v4"), openai.WithToken("your-zhipu-api-key"), )
|
阿里通义千问配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| llm, err := openai.New( openai.WithModel("qwen-turbo"), openai.WithBaseURL("https://dashscope.aliyuncs.com/compatible-mode/v1"), openai.WithToken("your-dashscope-api-key"), openai.WithTemperature(0.7), )
llmPlus, err := openai.New( openai.WithModel("qwen-plus"), openai.WithBaseURL("https://dashscope.aliyuncs.com/compatible-mode/v1"), openai.WithToken("your-dashscope-api-key"), )
|
月之暗面 Kimi 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| llm, err := openai.New( openai.WithModel("moonshot-v1-8k"), openai.WithBaseURL("https://api.moonshot.cn/v1"), openai.WithToken("your-moonshot-api-key"), openai.WithTemperature(0.3), )
llmLong, err := openai.New( openai.WithModel("moonshot-v1-128k"), openai.WithBaseURL("https://api.moonshot.cn/v1"), openai.WithToken("your-moonshot-api-key"), )
|
零一万物 Yi 配置
1 2 3 4 5 6 7 8
| llm, err := openai.New( openai.WithModel("yi-34b-chat-0205"), openai.WithBaseURL("https://api.lingyiwanwu.com/v1"), openai.WithToken("your-yi-api-key"), openai.WithTemperature(0.7), openai.WithMaxTokens(1500), )
|
多模型管理和切换
在实际应用中,你可能需要根据不同的场景使用不同的模型。以下是一个多模型管理的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| type ModelManager struct { models map[string]llms.Model }
func NewModelManager() *ModelManager { return &ModelManager{ models: make(map[string]llms.Model), } }
func (mm *ModelManager) InitModels() error { openaiLLM, err := openai.New( openai.WithModel("gpt-4"), openai.WithToken(os.Getenv("OPENAI_API_KEY")), ) if err != nil { return err } mm.models["openai"] = openaiLLM
deepseekLLM, err := openai.New( openai.WithModel("deepseek-chat"), openai.WithBaseURL("https://api.deepseek.com/v1"), openai.WithToken(os.Getenv("DEEPSEEK_API_KEY")), ) if err != nil { return err } mm.models["deepseek"] = deepseekLLM
zhipuLLM, err := openai.New( openai.WithModel("glm-4"), openai.WithBaseURL("https://open.bigmodel.cn/api/paas/v4"), openai.WithToken(os.Getenv("ZHIPU_API_KEY")), ) if err != nil { return err } mm.models["zhipu"] = zhipuLLM
return nil }
func (mm *ModelManager) GetModel(name string) (llms.Model, error) { model, exists := mm.models[name] if !exists { return nil, fmt.Errorf("model %s not found", name) } return model, nil }
func main() { manager := NewModelManager() err := manager.InitModels() if err != nil { log.Fatal(err) }
model, err := manager.GetModel("deepseek") if err != nil { log.Fatal(err) }
result, err := model.Call(context.Background(), "你好,请介绍一下自己") if err != nil { log.Fatal(err) } fmt.Println(result) }
|
模型配置最佳实践
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| type ModelConfig struct { Name string `yaml:"name"` Model string `yaml:"model"` BaseURL string `yaml:"base_url"` APIKey string `yaml:"api_key"` Temperature float64 `yaml:"temperature"` MaxTokens int `yaml:"max_tokens"` Timeout int `yaml:"timeout"` }
type Config struct { Models []ModelConfig `yaml:"models"` }
func LoadModelsFromConfig(configPath string) (map[string]llms.Model, error) { data, err := ioutil.ReadFile(configPath) if err != nil { return nil, err }
var config Config err = yaml.Unmarshal(data, &config) if err != nil { return nil, err }
models := make(map[string]llms.Model) for _, modelConfig := range config.Models { var llm llms.Model var err error
if modelConfig.BaseURL != "" { llm, err = openai.New( openai.WithModel(modelConfig.Model), openai.WithBaseURL(modelConfig.BaseURL), openai.WithToken(modelConfig.APIKey), openai.WithTemperature(modelConfig.Temperature), openai.WithMaxTokens(modelConfig.MaxTokens), ) } else { llm, err = openai.New( openai.WithModel(modelConfig.Model), openai.WithToken(modelConfig.APIKey), openai.WithTemperature(modelConfig.Temperature), openai.WithMaxTokens(modelConfig.MaxTokens), ) }
if err != nil { return nil, fmt.Errorf("failed to create model %s: %w", modelConfig.Name, err) }
models[modelConfig.Name] = llm }
return models, nil }
|
配置文件示例 (config.yaml):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| models: - name: "openai" model: "gpt-4" api_key: "${OPENAI_API_KEY}" temperature: 0.7 max_tokens: 2000 timeout: 30
- name: "deepseek" model: "deepseek-chat" base_url: "https://api.deepseek.com/v1" api_key: "${DEEPSEEK_API_KEY}" temperature: 0.7 max_tokens: 2000
- name: "zhipu" model: "glm-4" base_url: "https://open.bigmodel.cn/api/paas/v4" api_key: "${ZHIPU_API_KEY}" temperature: 0.8 max_tokens: 1500
- name: "kimi" model: "moonshot-v1-8k" base_url: "https://api.moonshot.cn/v1" api_key: "${MOONSHOT_API_KEY}" temperature: 0.3 max_tokens: 1000
|
3. 核心子包详解
3.1 Prompts 包
Prompts 包提供了强大的提示模板功能,支持动态参数替换和复杂的提示构建。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import "github.com/tmc/langchaingo/prompts"
template := prompts.NewPromptTemplate( "请回答关于 {{.topic}} 的问题:{{.question}}", []string{"topic", "question"}, )
prompt, err := template.Format(map[string]any{ "topic": "Go 语言", "question": "什么是 goroutine?", })
chatTemplate := prompts.NewChatPromptTemplate([]prompts.MessageFormatter{ prompts.NewSystemMessagePromptTemplate("你是一个专业的 Go 语言专家", nil), prompts.NewHumanMessagePromptTemplate("请解释:{{.concept}}", []string{"concept"}), })
|
3.2 Memory 包
Memory 包提供了多种内存管理策略,用于维护对话历史和上下文。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import ( "github.com/tmc/langchaingo/memory" "github.com/tmc/langchaingo/schema" )
bufferMemory := memory.NewConversationBuffer()
windowMemory := memory.NewConversationWindowBuffer(5)
summaryMemory := memory.NewConversationSummaryBuffer(llm, 1000)
bufferMemory.SaveContext( context.Background(), map[string]any{"input": "你好"}, map[string]any{"output": "你好!有什么可以帮助你的吗?"}, )
messages, err := bufferMemory.ChatHistory.Messages(context.Background())
|
3.3 Chains 包
Chains 包允许将多个组件串联起来,创建复杂的处理流程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import "github.com/tmc/langchaingo/chains"
llmChain := chains.NewLLMChain(llm, template)
conversationChain := chains.NewConversation(llm, bufferMemory)
sequentialChain := chains.NewSequentialChain([]chains.Chain{ chain1, chain2, chain3, })
result, err := llmChain.Call(context.Background(), map[string]any{ "topic": "微服务", "question": "什么是服务发现?", })
|
3.4 Agents 包
Agents 包提供了智能代理功能,能够使用工具并做出决策。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import ( "github.com/tmc/langchaingo/agents" "github.com/tmc/langchaingo/tools" )
calculator := tools.Calculator{} webSearch := tools.SerpAPI{APIKey: "your-serpapi-key"}
agent := agents.NewZeroShotReactDescription( llm, []tools.Tool{calculator, webSearch}, agents.WithMaxIterations(5), )
result, err := agent.Call(context.Background(), map[string]any{ "input": "2023年世界杯冠军是哪个国家?请计算该国家人口的平方根。", })
|
4. 高级特性和最佳实践
4.1 流式响应
1 2 3 4 5 6 7 8 9 10 11
| stream, err := llm.GenerateContent( context.Background(), []llms.MessageContent{ llms.TextParts(llms.ChatMessageTypeHuman, "写一首关于 Go 语言的诗"), }, llms.WithStreamingFunc(func(ctx context.Context, chunk []byte) error { fmt.Print(string(chunk)) return nil }), )
|
4.2 错误处理和重试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| import "github.com/tmc/langchaingo/llms"
llm, err := openai.New( openai.WithRetryPolicy(llms.RetryPolicy{ MaxRetries: 3, Backoff: llms.ExponentialBackoff, }), )
result, err := llm.Call(ctx, prompt) if err != nil { switch { case errors.Is(err, llms.ErrRateLimited): time.Sleep(time.Minute) return retry() case errors.Is(err, llms.ErrInvalidRequest): return handleInvalidRequest(err) default: return err } }
|
4.3 自定义工具
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import "github.com/tmc/langchaingo/tools"
type WeatherTool struct{}
func (w WeatherTool) Name() string { return "weather" }
func (w WeatherTool) Description() string { return "获取指定城市的天气信息。输入:城市名称" }
func (w WeatherTool) Call(ctx context.Context, input string) (string, error) { return fmt.Sprintf("%s 的天气:晴朗,25°C", input), nil }
|
4.4 文档处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import ( "github.com/tmc/langchaingo/documentloaders" "github.com/tmc/langchaingo/textsplitter" "github.com/tmc/langchaingo/vectorstores" )
loader := documentloaders.NewText("document.txt") docs, err := loader.Load(context.Background())
splitter := textsplitter.NewRecursiveCharacter() chunks, err := splitter.SplitDocuments(docs)
vectorStore := vectorstores.NewInMemory(embeddings) err = vectorStore.AddDocuments(context.Background(), chunks)
|
4.5 配置管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| type Config struct { OpenAI struct { APIKey string `yaml:"api_key"` Model string `yaml:"model"` Temperature float64 `yaml:"temperature"` } `yaml:"openai"` Memory struct { Type string `yaml:"type"` WindowSize int `yaml:"window_size"` } `yaml:"memory"` }
func loadConfig() *Config { config := &Config{} config.OpenAI.APIKey = os.Getenv("OPENAI_API_KEY") config.OpenAI.Model = getEnvOrDefault("OPENAI_MODEL", "gpt-3.5-turbo") return config }
|
5. 实际应用场景
5.1 智能客服系统
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| type CustomerService struct { llm llms.Model memory memory.ConversationBuffer chain chains.Chain }
func (cs *CustomerService) HandleQuery(ctx context.Context, userInput string) (string, error) { result, err := cs.chain.Call(ctx, map[string]any{ "input": userInput, }) if err != nil { return "", err } return result["output"].(string), nil }
|
5.2 代码生成助手
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| func generateCode(ctx context.Context, requirement string) (string, error) { template := prompts.NewPromptTemplate(` 作为一个专业的 Go 语言开发者,请根据以下需求生成代码:
需求:{{.requirement}}
请提供: 1. 完整的 Go 代码实现 2. 必要的注释 3. 使用示例
代码:`, []string{"requirement"})
chain := chains.NewLLMChain(llm, template) result, err := chain.Call(ctx, map[string]any{ "requirement": requirement, }) return result["text"].(string), err }
|
5.3 文档问答系统
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| type DocumentQA struct { vectorStore vectorstores.VectorStore llm llms.Model retriever vectorstores.Retriever }
func (dqa *DocumentQA) Answer(ctx context.Context, question string) (string, error) { docs, err := dqa.retriever.GetRelevantDocuments(ctx, question) if err != nil { return "", err } context := "" for _, doc := range docs { context += doc.PageContent + "\n" } prompt := fmt.Sprintf(` 基于以下上下文回答问题:
上下文: %s
问题:%s
答案:`, context, question) return dqa.llm.Call(ctx, prompt) }
|
6. 性能优化建议
6.1 连接池管理
1 2 3 4 5 6 7 8 9 10 11
| llm, err := openai.New( openai.WithHTTPClient(&http.Client{ Transport: &http.Transport{ MaxIdleConns: 100, MaxIdleConnsPerHost: 10, IdleConnTimeout: 90 * time.Second, }, Timeout: 30 * time.Second, }), )
|
6.2 缓存策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import "github.com/patrickmn/go-cache"
type CachedLLM struct { llm llms.Model cache *cache.Cache }
func (c *CachedLLM) Call(ctx context.Context, prompt string) (string, error) { if cached, found := c.cache.Get(prompt); found { return cached.(string), nil } result, err := c.llm.Call(ctx, prompt) if err != nil { return "", err } c.cache.Set(prompt, result, cache.DefaultExpiration) return result, nil }
|
6.3 并发处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| func processBatch(ctx context.Context, prompts []string) ([]string, error) { results := make([]string, len(prompts)) errors := make([]error, len(prompts)) var wg sync.WaitGroup semaphore := make(chan struct{}, 10) for i, prompt := range prompts { wg.Add(1) go func(index int, p string) { defer wg.Done() semaphore <- struct{}{} defer func() { <-semaphore }() result, err := llm.Call(ctx, p) results[index] = result errors[index] = err }(i, prompt) } wg.Wait() for _, err := range errors { if err != nil { return nil, err } } return results, nil }
|
7. 总结
LangChain Go 为 Go 开发者提供了一个强大而灵活的框架来构建基于大语言模型的应用程序。通过其模块化的设计,开发者可以:
- 快速集成:轻松集成多种主流 AI 服务提供商
- 灵活组合:通过 Chains 和 Agents 构建复杂的工作流
- 内存管理:有效管理对话历史和上下文
- 工具扩展:方便地添加自定义工具和功能
关键优势
- 性能优异:充分利用 Go 语言的并发特性
- 类型安全:编译时类型检查,减少运行时错误
- 易于部署:单一二进制文件,部署简单
- 生态丰富:与 Go 生态系统无缝集成
最佳实践总结
- 合理使用内存管理:根据应用场景选择合适的内存策略
- 错误处理:实现完善的错误处理和重试机制
- 性能优化:使用连接池、缓存和并发控制
- 安全考虑:妥善管理 API 密钥和敏感信息
- 监控日志:添加适当的日志和监控
LangChain Go 正在快速发展,随着 AI 技术的不断进步,它将为 Go 开发者提供更多强大的功能和可能性。建议开发者持续关注其更新,并在实际项目中积极实践和探索。