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!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐