前言
在上一篇文章中,我們見證了@AiService
注解的驚人威力。僅僅通過定義一個Java接口,我們就實現了一個功能完備的AI聊天服務。這感覺就像魔法一樣!
但作為專業的工程師,我們知道“任何足夠先進的技術,都與魔法無異”。今天,我們的任務就是揭開這層魔法的面紗,深入理解其背后支撐我們與AI進行高質量對話的三大支柱:
- 語言模型 (Models):AI的“大腦”,我們如何理解并與它交互。
- 提示模板 (Prompt Templates):控制我們對AI“說什么”的藝術,實現動態、可復用的指令。
- 輸出解析器 (Output Parsers):馴服AI的“輸出”,讓它返回我們需要的Java對象,而不僅僅是文本。
掌握了這三者,你將從一個簡單的AI“調用者”,蛻變為一個能精確控制AI行為的“指揮家”。
第一部分:再探模型 (Models) - AI的“大腦”
在application.properties
中,我們配置了langchain4j.open-ai.chat-model.*
等屬性,并通過LangChain4jConfig
創建了一個ChatLanguageModel
類型的Bean。
ChatLanguageModel
是LangChain4j中的一個核心接口,它代表了所有聊天式AI模型(如GPT-3.5/4, DeepSeek-Chat)的統一抽象。你可以把它想象成Java JDBC規范中的DataSource
接口,它為所有不同廠商的數據庫提供了統一的訪問標準。
我們配置的OpenAiChatModel
是這個接口的一個具體實現。如果我們想換成Google的Gemini模型,只需引入langchain4j-google-vertex-ai
依賴,并創建一個VertexAiChatModel
的Bean即可,而我們上層的業務代碼(如Assistant
接口)幾乎無需改動。這就是面向接口編程的威力。
核心概念:
- ChatLanguageModel: 用于一次請求-響應的交互。
- StreamingChatLanguageModel:
ChatLanguageModel
的子接口,用于流式響應。AI的回答會一個詞一個詞地“流”回來,能極大地提升用戶體驗,我們將在后續文章中探討它。
第二部分:提示模板 (Prompt Templates) - 控制AI的“輸入”
在上一篇中,我們使用了簡單的assistant.chat(userMessage)
。LangChain4j只是將userMessage
作為用戶提問直接發給了AI。但如果我們想讓AI扮演特定角色,或者根據多個動態參數來提問呢?這時就需要提示模板。
在LangChain4j中,我們可以通過@UserMessage
注解和{{...}}
占位符來創建強大的提示模板。
實戰:創建一個食譜生成器
讓我們來改造Assistant
接口,讓它能根據菜系和原料生成食譜。
-
修改
Assistant
接口package com.example.aidemoapp.service;import dev.langchain4j.service.SystemMessage; import dev.langchain4j.service.UserMessage; import dev.langchain4j.service.spring.AiService;@AiService public interface Assistant {@SystemMessage("You are a polite assistant")String chat(String userMessage);// 新增一個使用模板的方法@UserMessage("""請創建一個 {{dish_type}} 菜肴的食譜。 主要食材是:{{ingredients}}。 請提供包含標題、簡要描述、所需食材列表以及逐步操作說明的完整食譜。""")String createRecipe(@V("dish_type") String dish_type, @V("ingredients") String ingredients); }
代碼解析:
- 我們在
@UserMessage
注解中使用了Java 15的文本塊(三引號),方便編寫多行提示。 {{dish_type}}
和{{ingredients}}
是占位符。- LangChain4j會自動將
createRecipe
方法的dish_type
參數值填充到{{dish_type}}
占位符中,ingredients
參數同理。
- 我們在
-
在
ChatController
中調用新方法package com.example.aidemoapp.controller;// ... imports ...@RestController @RequestMapping("/api/v2/chat") @RequiredArgsConstructor public class ChatController {private final Assistant assistant;@GetMappingpublic String chat(@RequestParam("message") String message) {return assistant.chat(message);}@GetMapping("/recipe")public String recipe(@RequestParam String dishType, @RequestParam String ingredients) {return assistant.createRecipe(dishType, ingredients);} }
現在,當你請求GET /api/v2/chat/recipe?dishType=Sichuan&ingredients=tofu,garlic,chili
時,LangChain4j會向AI發送一個被完整填充的、結構化的Prompt,從而得到一個高質量的食譜。
第三部分:輸出解析器 (Output Parsers) - 控制AI的“輸出”
上面的食譜生成器返回的是一個長字符串。在真實應用中,我們更希望得到一個結構化的Java對象(POJO),以便于在前端展示或進行后續處理。
LangChain4j的AiServices
能做到這一點!只要你將方法的返回類型從String
改為一個自定義的Java類,LangChain4j就會自動指示AI以JSON格式輸出,并自動將JSON反序列化為你的Java對象。這就是輸出解析器的魔力!
實戰:將食譜輸出為Java對象
-
創建
Recipe
POJO
在com.example.aidemoapp
下創建dto
包,并新建Recipe.java
類。package com.example.aidemoapp.dto;import lombok.Data; import java.util.List;@Data // Lombok注解,自動生成getter, setter, toString等 public class Recipe {private String title;private String description;private List<String> ingredients;private List<String> instructions; }
-
再次修改
Assistant
接口
我們將createRecipe
方法的返回類型改為Recipe
。// ... imports ... import com.example.aidemoapp.dto.Recipe; // 引入Recipe類@AiService public interface Assistant {@SystemMessage("You are a polite assistant")String chat(String userMessage);// 新增一個使用模板的方法@UserMessage("""請創建一個 {{dish_type}} 菜肴的食譜。 主要食材是:{{ingredients}}。 請提供包含標題、簡要描述、所需食材列表以及逐步操作說明的完整食譜。""")Recipe createRecipe(@V("dish_type") String dish_type, @V("ingredients") String ingredients); }
提示詞增強:我們明確在提示中要求AI以JSON格式返回,并描述了JSON的結構。雖然LangChain4j在很多情況下會自動處理,但明確地指示AI可以極大地提高成功率和穩定性。
-
修改
ChatController
// ... imports ... import com.example.aidemoapp.dto.Recipe;// ... public class ChatController {// ... chat和recipe方法 ...@GetMapping("/recipe-object")public Recipe recipeObject(@RequestParam String dishType, @RequestParam String ingredients) {return assistant.createRecipeAsObject(dishType, ingredients);} }
由于
@RestController
的存在,Spring Boot會自動將返回的Recipe
對象序列化為JSON字符串,作為HTTP響應返回給前端。
現在,當你請求GET /api/v2/chat/recipe-object?dishType=Italian&ingredients=pasta,tomatoes,basil
時,你將直接得到一個干凈的、結構化的JSON響應!
源碼獲取
本文中所有實戰代碼均已同步更新至Gitee倉庫,方便您下載、運行和學習。
源碼地址:https://gitee.com/chaocloud/springboot-langchain4j-demo
總結
今天,我們揭開了LangChain4j高效開發的神秘面紗。我們學習了:
- Models是連接AI大腦的統一接口。
- Prompt Templates (
@UserMessage
和{{...}}
) 讓我們能精確地、動態地控制輸入。 - Output Parsers (通過改變返回類型) 讓我們能將AI的輸出從非結構化的文本,轉換為結構化的、可被程序直接利用的Java對象。
我們已經從簡單的“你問我答”進化到了可以與AI進行可預測、結構化交互的新階段。但這還不夠,我們的AI助手還是“金魚般的記憶”,每次對話都是一次全新的開始。如何讓它記住上下文,進行真正的多輪對話呢?
下一篇預告:
《Java大模型開發入門 (7/15):讓AI擁有記憶 - 使用LangChain4j實現多輪對話》—— 我們將為我們的Assistant
裝上“記憶芯片”,探索LangChain4j中的ChatMemory
機制,打造一個能真正聯系上下文的智能聊天機器人!