LangChain.dart 学习笔记

📚 目录

  1. 简介
  2. 核心概念
  3. 包结构
  4. 支持的集成
  5. 快速开始
  6. 核心模块详解
  7. 实战示例
  8. 最佳实践
  9. 学习资源
    10.[call me wechat🌏]: tradingba

🎯 简介

什么是 LangChain.dart?

LangChain.dart 是由 Harrison Chase 创建的流行 Python 框架 LangChain 的非官方 Dart 移植版本。它为开发者提供了一套开箱即用的组件,用于构建基于大语言模型(LLM)的应用程序。

核心优势

  • 🎯 统一接口: 提供统一的 API 与各种 LLM 提供商交互(OpenAI、Google、Mistral、Ollama 等)
  • 🔗 链式调用: 支持通过 LCEL(LangChain Expression Language)将组件链接在一起
  • 🚀 跨平台: 支持 Dart 和 Flutter,可运行在 Android、iOS、Linux、macOS、Web、Windows
  • 📦 模块化设计: 可按需导入所需组件
  • 🔧 丰富的集成: 支持主流 LLM 服务和工具

应用场景

  • 💬 聊天机器人(Chatbots)
  • ❓ 问答系统(Q&A with RAG)
  • 🤖 智能代理(Agents)
  • 📝 文本摘要(Summarization)
  • 🌐 翻译(Translation)
  • 🔍 信息提取(Extraction)
  • 🎯 推荐系统(Recommendation Systems)

🧩 核心概念

LangChain.dart 的组件可以分为三个核心模块:

1. 📃 Model I/O(模型输入输出)

  • 功能: 与各种 LLM 提供商交互的统一 API
  • 包含:
    • 提示模板(Prompt Templates)
    • 示例选择器(Example Selectors)
    • 输出解析器(Output Parsers)
  • 优势: 轻松切换不同的 LLM 提供商

2. 📚 Retrieval(检索)

  • 功能: 实现 RAG(检索增强生成)
  • 包含:
    • 文档加载器(Document Loaders)
    • 文本分割器(Text Splitters)
    • 嵌入模型(Embedding Models)
    • 向量存储(Vector Stores)
    • 检索器(Retrievers)

3. 🤖 Agents(代理)

  • 功能: 基于 LLM 的智能决策机器人
  • 能力: 可以使用工具(web 搜索、计算器、数据库查询等)来完成任务

4. 🔗 LCEL(LangChain Expression Language)

组件间的连接语言,使用管道(pipe)操作符将不同组件串联起来。


📦 包结构

LangChain.dart 采用模块化设计,由多个包组成:

核心包

1. langchain_core

  • 用途: 核心抽象和 LCEL
  • 适用: 构建框架或与 LangChain.dart 互操作
  • 依赖: langchain 已包含此包,无需显式依赖

2. langchain

  • 用途: 高级链、代理、检索算法
  • 适用: 构建 LLM 应用
  • 安装:
    dependencies:
      langchain: ^0.8.0+1
    

3. langchain_community

  • 用途: 第三方集成和社区贡献组件
  • 适用: 需要使用社区提供的集成时
  • 安装:
    dependencies:
      langchain_community: ^0.8.0+1
    

集成包

常用的第三方集成独立包:

包名 用途
langchain_openai OpenAI 集成(GPT-4o, o1, 嵌入, 工具, 视觉, DALL·E 3等)
langchain_google Google 集成(Gemini, PaLM 2, 嵌入, 向量搜索等)
langchain_anthropic Anthropic 集成(Claude 3.5 Sonnet, Opus, Haiku等)
langchain_ollama Ollama 集成(Llama 3.2, Gemma 2, Phi-3.5等)
langchain_mistralai Mistral AI 集成
langchain_firebase Firebase 集成(VertexAI for Firebase)
langchain_chroma Chroma 向量数据库集成
langchain_pinecone Pinecone 向量数据库集成
langchain_supabase Supabase 向量数据库集成

API 客户端包

可独立使用的 API 客户端:

包名 用途
openai_dart OpenAI API 客户端
googleai_dart Google AI API 客户端
anthropic_sdk_dart Anthropic API 客户端
ollama_dart Ollama API 客户端
mistralai_dart Mistral AI API 客户端
vertex_ai GCP Vertex AI API 客户端
chromadb Chroma DB API 客户端
tavily_dart Tavily API 客户端
openai_realtime_dart OpenAI Realtime API 客户端

🔌 支持的集成

Chat Models(聊天模型)

模型 流式 工具 视觉 说明
ChatOpenAI langchain_openai OpenAI Chat API 及兼容服务
ChatGoogleGenerativeAI langchain_google Google AI (Gemini API)
ChatAnthropic langchain_anthropic Anthropic Messages API (Claude)
ChatOllama langchain_ollama Ollama Chat API
ChatFirebaseVertexAI langchain_firebase Vertex AI for Firebase
ChatMistralAI langchain_mistralai - - Mistral Chat API
ChatVertexAI langchain_google - - - GCP Vertex AI Chat API

LLMs(传统语言模型)

注意: 优先使用 Chat Models,因为许多提供商已弃用 LLMs

模型 流式 说明
Ollama langchain_ollama Ollama Completions API
OpenAI langchain_openai OpenAI Completions API
VertexAI langchain_google - GCP Vertex AI Text API

Embedding Models(嵌入模型)

模型 说明
OpenAIEmbeddings langchain_openai OpenAI 嵌入 API
GoogleGenerativeAIEmbeddings langchain_google Google AI 嵌入 API
VertexAIEmbeddings langchain_google GCP Vertex AI 嵌入 API
OllamaEmbeddings langchain_ollama Ollama 嵌入 API
MistralAIEmbeddings langchain_mistralai Mistral 嵌入 API

Vector Stores(向量存储)

存储 说明
MemoryVectorStore langchain 内存向量存储(原型和测试)
Chroma langchain_chroma Chroma 集成
Pinecone langchain_pinecone Pinecone 集成
Supabase langchain_supabase Supabase Vector 集成
ObjectBoxVectorStore langchain_community ObjectBox 集成
VertexAIMatchingEngine langchain_google Vertex AI Vector Search

Tools(工具)

工具 说明
CalculatorTool langchain_community 计算数学表达式
TavilySearchResultsTool langchain_community Tavily 搜索引擎查询
TavilyAnswerTool langchain_community Tavily 搜索引擎答案
OpenAIDallETool langchain_openai OpenAI DALL-E 图像生成

🚀 快速开始

1. 安装依赖

pubspec.yaml 中添加依赖:

dependencies:
  langchain: ^0.8.0+1
  langchain_openai: ^0.8.0+1  # 如果使用 OpenAI
  langchain_google: ^0.8.0+1  # 如果使用 Google
  langchain_community: ^0.8.0+1  # 如果需要社区组件

2. 基础示例:调用 LLM

import 'package:langchain_google/langchain_google.dart';

void main() async {
  // 创建模型实例
  final model = ChatGoogleGenerativeAI(
    apiKey: 'YOUR_GOOGLE_API_KEY',
  );
  
  // 创建提示
  final prompt = PromptValue.string('Hello world!');
  
  // 调用模型
  final result = await model.invoke(prompt);
  
  print(result);
  // 输出: Hello everyone! I'm new here and excited to be part of this community.
}

3. 简单链式调用

import 'package:langchain/langchain.dart';
import 'package:langchain_openai/langchain_openai.dart';

void main() async {
  // 创建提示模板
  final promptTemplate = ChatPromptTemplate.fromTemplate(
    '讲一个关于{topic}的笑话',
  );
  
  // 创建模型
  final model = ChatOpenAI(
    apiKey: 'YOUR_OPENAI_API_KEY',
    defaultOptions: ChatOpenAIOptions(
      model: 'gpt-4',
      temperature: 0.8,
    ),
  );
  
  // 创建输出解析器
  const outputParser = StringOutputParser<ChatResult>();
  
  // 构建链:提示模板 -> 模型 -> 输出解析器
  final chain = promptTemplate.pipe(model).pipe(outputParser);
  
  // 执行链
  final result = await chain.invoke({'topic': '程序员'});
  
  print(result);
}

🔍 核心模块详解

Model I/O(模型输入输出)

1. Prompt Templates(提示模板)

提示模板用于格式化输入,支持变量替换:

// 简单字符串模板
final promptTemplate = ChatPromptTemplate.fromTemplate(
  'Tell me a joke about {topic}',
);

// 多消息模板
final promptTemplate = ChatPromptTemplate.fromTemplates([
  (ChatMessageType.system, 'You are a helpful assistant'),
  (ChatMessageType.human, '{input}'),
]);

// 使用模板
final formattedPrompt = promptTemplate.format({'topic': 'cats'});

2. Output Parsers(输出解析器)

解析模型输出为结构化数据:

// 字符串输出解析器
const stringParser = StringOutputParser<ChatResult>();
final result = await model.pipe(stringParser).invoke(prompt);

// JSON 输出解析器
// 自定义解析器可以将输出解析为特定数据结构

3. Chat Models 使用

final model = ChatOpenAI(
  apiKey: apiKey,
  defaultOptions: ChatOpenAIOptions(
    model: 'gpt-4o',
    temperature: 0.7,
    maxTokens: 1000,
  ),
);

// 单次调用
final response = await model.invoke(
  PromptValue.string('你好'),
);

// 流式调用
final stream = model.stream(
  PromptValue.string('写一首诗'),
);
await for (final chunk in stream) {
  print(chunk);
}

Retrieval(检索 - RAG)

完整的 RAG 流程

import 'package:langchain/langchain.dart';
import 'package:langchain_openai/langchain_openai.dart';

Future<void> ragExample() async {
  // 1. 创建向量存储并添加文档
  final vectorStore = MemoryVectorStore(
    embeddings: OpenAIEmbeddings(apiKey: openaiApiKey),
  );
  
  await vectorStore.addDocuments(
    documents: [
      Document(pageContent: 'LangChain was created by Harrison'),
      Document(pageContent: 'David ported LangChain to Dart in LangChain.dart'),
    ],
  );

  // 2. 定义检索链
  final retriever = vectorStore.asRetriever();
  final setupAndRetrieval = Runnable.fromMap<String>({
    'context': retriever.pipe(
      Runnable.mapInput(
        (docs) => docs.map((d) => d.pageContent).join('\n'),
      ),
    ),
    'question': Runnable.passthrough(),
  });

  // 3. 构建 RAG 提示模板
  final promptTemplate = ChatPromptTemplate.fromTemplates([
    (
      ChatMessageType.system,
      'Answer the question based on only the following context:\n{context}'
    ),
    (ChatMessageType.human, '{question}'),
  ]);

  // 4. 定义最终链
  final model = ChatOpenAI(apiKey: openaiApiKey);
  const outputParser = StringOutputParser<ChatResult>();
  
  final chain = setupAndRetrieval
      .pipe(promptTemplate)
      .pipe(model)
      .pipe(outputParser);

  // 5. 运行管道
  final res = await chain.invoke('Who created LangChain.dart?');
  print(res);
  // 输出: David created LangChain.dart
}

Document Loaders(文档加载器)

// 加载文本文件
final loader = TextLoader('path/to/file.txt');
final documents = await loader.load();

// 加载 JSON 文件
final jsonLoader = JsonLoader('path/to/data.json');
final jsonDocs = await jsonLoader.load();

Text Splitters(文本分割器)

// 按字符分割
final splitter = CharacterTextSplitter(
  chunkSize: 1000,
  chunkOverlap: 200,
);
final chunks = await splitter.splitDocuments(documents);

// 递归分割
final recursiveSplitter = RecursiveCharacterTextSplitter(
  chunkSize: 1000,
  chunkOverlap: 200,
);

Embeddings(嵌入)

// OpenAI 嵌入
final embeddings = OpenAIEmbeddings(
  apiKey: apiKey,
  model: 'text-embedding-3-small',
);

// 嵌入文档
final docEmbeddings = await embeddings.embedDocuments([
  'This is a document',
  'This is another document',
]);

// 嵌入查询
final queryEmbedding = await embeddings.embedQuery('search query');

Agents(代理)

代理可以根据用户输入自主决定使用哪些工具:

import 'package:langchain/langchain.dart';
import 'package:langchain_openai/langchain_openai.dart';
import 'package:langchain_community/langchain_community.dart';

Future<void> agentExample() async {
  // 1. 定义工具
  final tools = [
    CalculatorTool(),
    Tool(
      name: 'search',
      description: 'Useful for searching the web',
      func: (input) async => 'Search results for: $input',
    ),
  ];

  // 2. 创建代理
  final llm = ChatOpenAI(
    apiKey: apiKey,
    defaultOptions: ChatOpenAIOptions(
      model: 'gpt-4',
      temperature: 0,
    ),
  );

  final agent = OpenAIFunctionsAgent.fromLLMAndTools(
    llm: llm,
    tools: tools,
  );

  // 3. 创建执行器
  final executor = AgentExecutor(agent: agent);

  // 4. 运行代理
  final result = await executor.run(
    'What is 25 * 4? Then search for information about that number.',
  );
  
  print(result);
}

💡 实战示例

示例 1: 简单问答

import 'package:langchain/langchain.dart';
import 'package:langchain_openai/langchain_openai.dart';

Future<void> simpleQA() async {
  final model = ChatOpenAI(
    apiKey: 'YOUR_API_KEY',
    defaultOptions: ChatOpenAIOptions(model: 'gpt-4'),
  );
  
  final prompt = PromptValue.chat([
    ChatMessage.system('You are a helpful assistant.'),
    ChatMessage.humanText('What is the capital of France?'),
  ]);
  
  final response = await model.invoke(prompt);
  print(response.output.content);
}

示例 2: 流式聊天

Future<void> streamingChat() async {
  final model = ChatOpenAI(
    apiKey: 'YOUR_API_KEY',
    defaultOptions: ChatOpenAIOptions(model: 'gpt-4'),
  );
  
  final prompt = PromptValue.string('Write a long story about a robot.');
  
  final stream = model.stream(prompt);
  
  await for (final chunk in stream) {
    // 实时输出每个 token
    stdout.write(chunk.output.content);
  }
}

示例 3: 使用工具的聊天

Future<void> chatWithTools() async {
  final model = ChatOpenAI(
    apiKey: 'YOUR_API_KEY',
    defaultOptions: ChatOpenAIOptions(
      model: 'gpt-4',
      tools: [
        // 定义工具
        ChatTool(
          type: 'function',
          function: {
            'name': 'get_weather',
            'description': 'Get the weather for a location',
            'parameters': {
              'type': 'object',
              'properties': {
                'location': {
                  'type': 'string',
                  'description': 'The city name',
                },
              },
              'required': ['location'],
            },
          },
        ),
      ],
    ),
  );
  
  final response = await model.invoke(
    PromptValue.string('What\'s the weather in Beijing?'),
  );
  
  // 处理工具调用
  if (response.output.toolCalls.isNotEmpty) {
    final toolCall = response.output.toolCalls.first;
    print('Model wants to call: ${toolCall.name}');
    print('With arguments: ${toolCall.arguments}');
  }
}

示例 4: 多模态(视觉)

Future<void> visionExample() async {
  final model = ChatOpenAI(
    apiKey: 'YOUR_API_KEY',
    defaultOptions: ChatOpenAIOptions(
      model: 'gpt-4-vision-preview',
    ),
  );
  
  final prompt = PromptValue.chat([
    ChatMessage.human(
      ChatMessageContent.multiModal([
        ChatMessageContent.text('What is in this image?'),
        ChatMessageContent.image(
          mimeType: 'image/jpeg',
          data: base64Image, // base64 编码的图片
        ),
      ]),
    ),
  ]);
  
  final response = await model.invoke(prompt);
  print(response.output.content);
}

示例 5: 文档问答系统

Future<void> documentQA() async {
  // 1. 加载文档
  final loader = TextLoader('knowledge_base.txt');
  final documents = await loader.load();
  
  // 2. 分割文档
  final splitter = RecursiveCharacterTextSplitter(
    chunkSize: 500,
    chunkOverlap: 50,
  );
  final chunks = await splitter.splitDocuments(documents);
  
  // 3. 创建向量存储
  final embeddings = OpenAIEmbeddings(apiKey: apiKey);
  final vectorStore = MemoryVectorStore(embeddings: embeddings);
  await vectorStore.addDocuments(documents: chunks);
  
  // 4. 创建 QA 链
  final retriever = vectorStore.asRetriever(
    searchKwargs: {'k': 3}, // 检索前3个最相关的文档
  );
  
  final qaPrompt = ChatPromptTemplate.fromTemplates([
    (
      ChatMessageType.system,
      'Use the following context to answer the question:\n\n{context}'
    ),
    (ChatMessageType.human, '{question}'),
  ]);
  
  final model = ChatOpenAI(apiKey: apiKey);
  const parser = StringOutputParser<ChatResult>();
  
  final qaChain = Runnable.fromMap({
    'context': retriever.pipe(
      Runnable.mapInput((docs) => docs.map((d) => d.pageContent).join('\n\n')),
    ),
    'question': Runnable.passthrough(),
  }).pipe(qaPrompt).pipe(model).pipe(parser);
  
  // 5. 提问
  final answer = await qaChain.invoke('What is LangChain?');
  print(answer);
}

示例 6: 会话记忆

Future<void> conversationWithMemory() async {
  final model = ChatOpenAI(apiKey: apiKey);
  
  // 创建会话记忆
  final memory = ConversationBufferMemory();
  
  // 定义对话链
  final prompt = ChatPromptTemplate.fromTemplates([
    (ChatMessageType.system, 'You are a helpful assistant.'),
    (ChatMessageType.human, '{history}\nHuman: {input}'),
  ]);
  
  final chain = prompt.pipe(model);
  
  // 多轮对话
  final inputs = [
    'My name is John',
    'What is my name?',
    'What is 2+2?',
  ];
  
  for (final input in inputs) {
    final history = await memory.loadMemoryVariables();
    final result = await chain.invoke({
      'input': input,
      'history': history['history'] ?? '',
    });
    
    // 保存到记忆
    await memory.saveContext(
      inputValues: {'input': input},
      outputValues: {'output': result.output.content},
    );
    
    print('Human: $input');
    print('AI: ${result.output.content}\n');
  }
}

🎯 最佳实践

1. API Key 管理

// ❌ 不要硬编码 API Key
final model = ChatOpenAI(apiKey: 'sk-...');

// ✅ 使用环境变量
final apiKey = Platform.environment['OPENAI_API_KEY']!;
final model = ChatOpenAI(apiKey: apiKey);

// ✅ 使用 flutter_dotenv
import 'package:flutter_dotenv/flutter_dotenv.dart';

await dotenv.load();
final apiKey = dotenv.env['OPENAI_API_KEY']!;

2. 错误处理

try {
  final result = await model.invoke(prompt);
  print(result);
} on LLMException catch (e) {
  print('LLM Error: ${e.message}');
} on HttpException catch (e) {
  print('Network Error: $e');
} catch (e) {
  print('Unexpected Error: $e');
}

3. 选择合适的模型

// 对于简单任务,使用较小的模型
final simpleModel = ChatOpenAI(
  apiKey: apiKey,
  defaultOptions: ChatOpenAIOptions(model: 'gpt-3.5-turbo'),
);

// 对于复杂任务,使用更强大的模型
final advancedModel = ChatOpenAI(
  apiKey: apiKey,
  defaultOptions: ChatOpenAIOptions(model: 'gpt-4'),
);

4. 控制输出长度和随机性

final model = ChatOpenAI(
  apiKey: apiKey,
  defaultOptions: ChatOpenAIOptions(
    model: 'gpt-4',
    temperature: 0.0,  // 0=确定性,1=更随机
    maxTokens: 500,    // 限制输出长度
    topP: 0.95,        // nucleus sampling
  ),
);

5. 向量存储选择

  • 开发/测试: 使用 MemoryVectorStore(内存存储)
  • 生产环境: 使用 ChromaPineconeSupabase(持久化存储)
// 开发环境
final devStore = MemoryVectorStore(embeddings: embeddings);

// 生产环境
final prodStore = Chroma(
  embeddings: embeddings,
  collectionName: 'my_collection',
);

6. 文本分割策略

// 对于代码文档
final codeSplitter = RecursiveCharacterTextSplitter(
  chunkSize: 1000,
  chunkOverlap: 200,
  separators: ['\n\n', '\n', ' ', ''],
);

// 对于普通文本
final textSplitter = CharacterTextSplitter(
  chunkSize: 500,
  chunkOverlap: 50,
);

7. 优化检索质量

// 增加检索的文档数量
final retriever = vectorStore.asRetriever(
  searchKwargs: {
    'k': 5,  // 检索前5个最相关的文档
  },
);

// 使用重排序提高准确性
// 或添加过滤条件
final retriever = vectorStore.asRetriever(
  searchKwargs: {
    'k': 10,
    'filter': {'source': 'official_docs'},
  },
);

8. 链式调用优化

// 使用 Runnable.fromMap 组织复杂的数据流
final complexChain = Runnable.fromMap({
  'processed_input': Runnable.mapInput((input) => processInput(input)),
  'context': retriever,
  'original_query': Runnable.passthrough(),
})
  .pipe(promptTemplate)
  .pipe(model)
  .pipe(outputParser);

📖 学习资源

官方资源

示例项目

相关项目

学习路径建议

  1. 入门阶段

    • 阅读官方文档的 "Getting Started" 部分
    • 运行简单的 LLM 调用示例
    • 了解基本的提示模板使用
  2. 进阶阶段

    • 学习 LCEL(链式表达语言)
    • 实践 RAG(检索增强生成)
    • 尝试构建简单的问答系统
  3. 高级阶段

    • 深入学习 Agents(代理)
    • 集成多个工具和数据源
    • 优化性能和成本
  4. 实战项目

    • 构建聊天机器人
    • 开发文档问答系统
    • 创建智能助手应用

🔧 常见问题

Q1: 如何选择合适的 LLM 提供商?

A: 根据需求选择:

  • OpenAI: 最强大,但成本较高
  • Google (Gemini): 性价比高,多模态能力强
  • Anthropic (Claude): 适合复杂推理和长文本
  • Ollama: 本地运行,隐私性好,免费

Q2: RAG 和直接调用 LLM 有什么区别?

A:

  • 直接调用: 依赖模型的预训练知识,可能有时效性问题
  • RAG: 从外部知识库检索相关信息,然后传给 LLM,更准确、更新

Q3: 如何降低 API 调用成本?

A:

  • 使用较小的模型(如 GPT-3.5 而非 GPT-4)
  • 减少 maxTokens 限制
  • 使用缓存避免重复调用
  • 批量处理请求
  • 考虑使用本地模型(Ollama)

Q4: 如何处理中文?

A: 所有主流模型都支持中文,但注意:

  • 中文 token 计数通常比英文多
  • 提示模板可以直接使用中文
  • 选择支持中文的嵌入模型

Q5: Flutter 应用中如何使用?

A:

// 在 Flutter 中使用与普通 Dart 项目相同
import 'package:langchain/langchain.dart';
import 'package:langchain_openai/langchain_openai.dart';

class ChatScreen extends StatefulWidget {
  // ... Flutter UI 代码
  
  Future<void> sendMessage(String message) async {
    final model = ChatOpenAI(apiKey: apiKey);
    final response = await model.invoke(PromptValue.string(message));
    setState(() {
      // 更新 UI
    });
  }
}

📊 版本信息

  • 当前版本: 0.8.0+1
  • 发布时间: 2024年10月17日
  • 许可证: MIT
  • 发布者: langchaindart.dev
  • 平台支持: Android, iOS, Linux, macOS, Web, Windows

🤝 贡献

LangChain.dart 欢迎贡献者!


📝 总结

LangChain.dart 是在 Dart/Flutter 生态系统中构建 LLM 应用的强大工具。它提供了:

✅ 统一的 API 接口
✅ 丰富的集成选项
✅ 强大的链式调用能力
✅ 完整的 RAG 支持
✅ 灵活的 Agent 系统
✅ 跨平台支持

通过学习和实践 LangChain.dart,你可以快速构建各种基于 LLM 的应用,如聊天机器人、问答系统、智能助手等。


最后更新: 2025年12月8日
笔记版本: v1.0

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容