📚 目录
🎯 简介
什么是 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(内存存储) -
生产环境: 使用
Chroma、Pinecone或Supabase(持久化存储)
// 开发环境
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);
📖 学习资源
官方资源
- 📚 官方文档
- 💻 GitHub 仓库
- 📝 官方博客
- 💬 Discord 社区
- 🔍 API 参考
示例项目
相关项目
- LangChain (Python) - 原始 Python 项目
- LangChain.js - JavaScript 移植
- LangChain.go - Go 移植
- LangChain.rb - Ruby 移植
学习路径建议
-
入门阶段
- 阅读官方文档的 "Getting Started" 部分
- 运行简单的 LLM 调用示例
- 了解基本的提示模板使用
-
进阶阶段
- 学习 LCEL(链式表达语言)
- 实践 RAG(检索增强生成)
- 尝试构建简单的问答系统
-
高级阶段
- 深入学习 Agents(代理)
- 集成多个工具和数据源
- 优化性能和成本
-
实战项目
- 构建聊天机器人
- 开发文档问答系统
- 创建智能助手应用
🔧 常见问题
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 欢迎贡献者!
- 📖 贡献指南
- 💬 加入 Discord
- 💰 赞助项目
📝 总结
LangChain.dart 是在 Dart/Flutter 生态系统中构建 LLM 应用的强大工具。它提供了:
✅ 统一的 API 接口
✅ 丰富的集成选项
✅ 强大的链式调用能力
✅ 完整的 RAG 支持
✅ 灵活的 Agent 系统
✅ 跨平台支持
通过学习和实践 LangChain.dart,你可以快速构建各种基于 LLM 的应用,如聊天机器人、问答系统、智能助手等。
最后更新: 2025年12月8日
笔记版本: v1.0