LangChain 详细介绍和 Java 项目使用方式
LangChain是一个用于开发大型语言模型(LLM)应用的框架,其核心价值在于连接LLM与外部数据源和工具。它采用组件化设计,包含模型I/O、数据检索、记忆、代理和链式调用等模块,支持构建复杂的交互式应用。Java版本LangChain4j提供了与Python相似的功能,包括基本模型调用、提示模板、结构化输出解析和检索增强生成(RAG)等能力。通过模块化组合,开发者可以轻松实现基于私有知识库的智
1. 什么是 LangChain?
LangChain 是一个用于开发由大型语言模型 (LLM) 驱动的应用程序的框架。它不是一个单独的模型,而是一个工具包,其核心价值在于将 LLM 与外部数据源和计算工具连接起来,从而创建功能强大、可交互的应用程序。
你可以把它想象成 LLM 世界的 “Spring Framework”,它提供了模块化的组件和设计模式,让开发者能更高效、更结构化地构建应用,而不是直接与原始的 API 调用打交道。
2. 核心设计原理
LangChain 的设计基于几个关键理念:
- 组件化 (Modularity): 它将 LLM 应用开发过程拆解成多个独立的模块(例如:模型 I/O、数据检索、记忆、代理等)。开发者可以像搭积木一样自由组合这些模块。
- 链式调用 (Chains): 这是 LangChain 的命名由来。一个 “链” 是将多个组件(或多个 LLM 调用)按特定顺序串联起来的工作流。例如,一个链可以先后完成“总结用户问题”、“搜索相关文档”、“基于搜索结果生成最终答案”等步骤。
- 数据感知 (Data-aware): LangChain 特别擅长将 LLM 与外部数据源(如你的公司文档、数据库、API)连接起来,让模型能够访问和推理它训练数据之外的信息。
- 代理 (Agents): 这是最强大的概念之一。代理让 LLM 具备决策能力。它可以理解用户请求,然后自主决定调用哪些工具(如计算器、搜索引擎、数据库)来完成任务,并根据工具返回的结果进行下一步行动,直到最终解决问题。
3. 核心模块概念
LangChain 的主要模块包括:
- Model I/O: 与语言模型交互的核心接口。包括模型选择(如 GPT-4, Claude, Llama 2)、提示模板(PromptTemplate)和输出解析器(OutputParser)。
- Retrieval: 从外部数据源获取相关数据。通常涉及文档加载器、文本分割器、向量存储(Vectorstores)和检索器(Retrievers)。这是实现“基于私有知识库问答”的关键。
- Memory: 让链或代理拥有“短期记忆”,能够记住同一会话中的先前交互信息(如聊天历史)。
- Agents: 核心智能体。它由 LLM、其决策所依赖的工具(Tools)集合和一个决定使用哪些工具的策略组成。
- Chains: 将上述所有模块组合在一起的预构建或自定义工作流。
二、LangChain 使用方式 (Java)
虽然 LangChain 最初是用 Python 开发的,并且其生态更活跃,但其 Java 版本 (langchain4j
) 也已经提供了强大的功能,足以构建复杂的应用程序。
项目地址: https://github.com/langchain4j/langchain4j
1. 环境准备
在你的 Java 项目(如 Maven 或 Gradle)中引入依赖。
Maven 依赖:
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>0.29.0</version> <!-- 请查看GitHub获取最新版本 -->
</dependency>
你通常还需要添加特定组件的依赖,例如与 OpenAI 集成的包:
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>0.29.0</version>
</dependency>
2. 核心使用示例
下面通过几个逐步深入的例子来展示如何在 Java 中使用 LangChain4j。
示例 1:最基本的模型调用 (Model I/O)
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.output.Response;
public class BasicExample {
public static void main(String[] args) {
// 1. 创建模型实例,需要配置你的API Key
OpenAiChatModel model = OpenAiChatModel.builder()
.apiKey("your-openai-api-key")
.modelName("gpt-3.5-turbo")
.temperature(0.3)
.build();
// 2. 发送消息并获取响应
Response<String> response = model.generate("你好,请用Java写一个‘Hello World’程序。");
// 3. 输出结果
System.out.println(response.content());
}
}
示例 2:使用提示模板和输出解析 (Model I/O)
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.output.Response;
import dev.langchain4j.model.output.structured.Description;
import dev.langchain4j.model.prompt.Prompt;
import dev.langchain4j.model.prompt.PromptTemplate;
import lombok.Data; // 使用Lombok简化代码
public class PromptTemplateExample {
// 定义一个结构化的输出类
@Data
public static class Recipe {
@Description("菜品的名称")
private String name;
@Description("所需的食材列表")
private List<String> ingredients;
@Description("详细的烹饪步骤")
private List<String> steps;
}
public static void main(String[] args) {
OpenAiChatModel model = OpenAiChatModel.builder().apiKey("demo").build();
// 定义提示模板,使用 Mustache 语法
String template = """
请根据以下主要食材生成一份简单的菜谱。
主要食材:{{ingredient}}
请只输出菜谱信息,不要有其他无关内容。
""";
// 创建 PromptTemplate 对象
PromptTemplate promptTemplate = PromptTemplate.from(template);
// 使用变量渲染模板,生成最终的 Prompt
Prompt prompt = promptTemplate.apply(Collections.singletonMap("ingredient", "西红柿和鸡蛋"));
// 发送请求,并指定希望输出的结构化类型
Response<Recipe> response = model.generate(prompt, Recipe.class);
Recipe recipe = response.content();
System.out.println("菜名: " + recipe.getName());
System.out.println("食材: " + String.join(", ", recipe.getIngredients()));
}
}
示例 3:使用检索器增强生成 (RAG - Retrieval-Augmented Generation)
这是 LangChain 最经典的应用场景:让模型根据你提供的文档来回答问题。
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.retriever.EmbeddingStoreRetriever;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import java.nio.file.Paths;
public class RAGExample {
public static void main(String[] args) {
// 1. 加载文档(例如你的公司手册、产品文档)
Document document = FileSystemDocumentLoader.loadDocument(Paths.get("path/to/your/document.txt"));
// 2. 初始化嵌入模型(用于将文本转换为向量)
EmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder()
.apiKey("your-api-key")
.modelName("text-embedding-ada-002")
.build();
// 3. 初始化一个内存向量数据库(生产环境可用Chroma、Pinecone等)
EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
// 4. 文档注入管道:分割文档 -> 生成向量 -> 存储到向量库
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.documentSplitter(DocumentSplitters.recursive(500, 0)) // 分割成500字符的片段
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.build();
ingestor.ingest(document);
// 5. 创建检索器
var retriever = EmbeddingStoreRetriever.from(embeddingStore, embeddingModel, 2); // 每次检索2个最相关的片段
// 6. 创建聊天模型
var chatModel = OpenAiChatModel.builder().apiKey("your-api-key").build();
// 7. 现在,我们可以提问了。模型会根据检索到的文档片段来回答
String question = "根据文档,我们的退款政策是什么?";
// 先检索相关文档片段
List<TextSegment> relevantSegments = retriever.retrieve(question);
// 构建一个包含上下文的提示
String context = relevantSegments.stream()
.map(TextSegment::text)
.collect(Collectors.joining("\n\n"));
String answer = chatModel.generate("请基于以下上下文回答问题:\n" + context + "\n\n问题:" + question);
System.out.println(answer);
}
}
示例 4:使用代理 (Agent) 和工具 (Tools)
让模型学会使用你提供的工具。
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class AgentToolExample {
// 1. 定义一个工具(函数),代理可以调用它
// 使用 @Tool 注解,Javadoc 或 @P 注解的描述可以帮助模型理解何时以及如何使用此工具
@Tool("获取指定城市的当前时间")
public String getCurrentTimeInCity(@P("城市名称,例如 '北京' 或 'New York'") String city) {
// 这是一个简单的模拟实现。真实场景可以调用世界时间API。
String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
return String.format("城市 %s 的当前时间是:%s (示例数据,实际未查询API)", city, time);
}
public static void main(String[] args) {
AgentToolExample tools = new AgentToolExample();
// 2. 创建模型,并开启工具调用功能
OpenAiChatModel model = OpenAiChatModel.builder()
.apiKey("your-api-key")
.modelName("gpt-3.5-turbo") // 或 "gpt-4",工具调用效果更好
.build();
// 3. 自动将工具绑定到模型上,创建一个具备工具调用能力的代理
// LangChain4j 提供了更高级的 AgentExecutor,这里做简单演示
// 模型会根据问题自动决定是否调用 getCurrentTimeInCity 工具
String answer = model.generate("请问巴黎现在几点了?");
System.out.println(answer);
// 注意:更完整的代理实现需要使用 AiServices 或 AgentExecutor 来自动完成工具绑定和调用循环。
// 具体请参阅 LangChain4j 文档中关于 AiServices 的章节。
}
}
三、总结与注意事项
- Java vs Python: Java 版本的 LangChain4j 功能已经相当丰富,涵盖了核心概念。但其社区和生态(尤其是新工具和集成)可能稍落后于 Python 版本。对于企业级 Java 应用,它是一个非常可靠的选择。
- 生产环境: 示例中的
InMemoryEmbeddingStore
仅用于演示。生产环境应使用持久化的向量数据库,如 Chroma, Pinecone, Weaviate 或 Elasticsearch。 - 最佳实践: 对于复杂应用,建议深入研究
AiServices
(LangChain4j 提供的一种更声明式、更简洁的编程模型)和AgentExecutor
。 - Spring Boot 集成: 你可以轻松地将 LangChain4j 集成到 Spring Boot 应用中,利用其依赖注入和配置管理功能。
希望这份详细的介绍和 Java 示例能帮助你快速上手 LangChain!
更多推荐
所有评论(0)