建旅游規(guī)劃智能體:Java生態(tài)的AI應(yīng)用實踐)
簡介本資源是一個基于Spring AI與Langchain4j構(gòu)建的旅游行程規(guī)劃智能體完整工程面向Java后端開發(fā)者、AI應(yīng)用實踐者及高校課程設(shè)計學(xué)習(xí)者解決個性化旅游方案生成、自然語言交互與行程動態(tài)優(yōu)化等核心問題。壓縮包共69個文件涵蓋12個Java服務(wù)模塊含Agent編排、LLM調(diào)用與工具集成、15個Vue前端頁面行程展示、偏好配置與實時對話、5個JSON配置與示例數(shù)據(jù)、以及UML類圖/用例圖等5張系統(tǒng)設(shè)計圖輔以README、LICENSE和課程大作業(yè)文檔含PDFDOCX整體大小為5.74MB。已有113人下載學(xué)習(xí)提供開箱即用的全棧實現(xiàn)包含可運行的客戶端-服務(wù)端-天氣微服務(wù)三層架構(gòu)、Spring Boot Langchain4j Agent鏈?zhǔn)秸{(diào)用邏輯、基于用戶偏好的多目標(biāo)行程生成策略以及清晰的模塊劃分與工程化目錄結(jié)構(gòu)適合用于AI項目實訓(xùn)、畢業(yè)設(shè)計參考或企業(yè)級智能旅游服務(wù)原型開發(fā)。1. 項目概述當(dāng)AI智能體遇上旅游規(guī)劃最近在搗鼓AI應(yīng)用開發(fā)發(fā)現(xiàn)一個挺有意思的交叉點用Java生態(tài)的AI框架來做一個旅游行程規(guī)劃的智能體。項目名字叫“基于Spring AI和Langchain4j的旅游行程規(guī)劃智能體”聽起來有點學(xué)術(shù)但說白了就是想做一個能理解你模糊的旅行想法然后自動給你生成一份靠譜行程單的“AI小助手”。比如你輸入“我想去個有海、人少、預(yù)算不高還能吃點海鮮的地方玩3天”它就能結(jié)合地理位置、景點信息、用戶偏好甚至實時交通給你規(guī)劃出一條從出發(fā)到返程的詳細路線。為什么用Spring AI和Langchain4j這其實是技術(shù)選型上的一個務(wù)實選擇。Spring AI是Spring官方推出的AI應(yīng)用開發(fā)框架它最大的好處是把對接各種大模型比如OpenAI的GPT、Anthropic的Claude或者阿里、百度的國內(nèi)模型的復(fù)雜過程給標(biāo)準(zhǔn)化、簡單化了讓你用配置和幾個注解就能搞定特別適合已經(jīng)熟悉Spring Boot的Java開發(fā)者快速上手。而Langchain4j你可以把它看作是Java版的LangChain它提供了一套構(gòu)建“智能體”的高級抽象比如工具調(diào)用、記憶管理、工作流編排。用Spring AI處理基礎(chǔ)的模型交互用Langchain4j來構(gòu)建上層的智能規(guī)劃和決策邏輯兩者結(jié)合既能享受Spring生態(tài)的便利又能利用成熟的AI應(yīng)用模式。這個項目適合誰呢首先肯定是Java后端開發(fā)者尤其是對AI應(yīng)用感興趣想找個具體項目練手的。其次是對智能體開發(fā)感興趣的朋友這是一個從理論到實踐的完整案例。最后哪怕你不是開發(fā)者只是對AI如何解決實際問題好奇通過拆解這個項目的思路你也能明白現(xiàn)在的AI技術(shù)到底能做到哪一步以及它是怎么思考的。2. 核心架構(gòu)與設(shè)計思路拆解2.1 智能體工作流設(shè)計一個旅游規(guī)劃智能體它的核心工作流可以抽象為“理解-規(guī)劃-呈現(xiàn)”三個階段。但這三個階段背后需要多個組件的精密配合。首先理解階段。用戶輸入通常是自然語言模糊且充滿主觀偏好。智能體需要做的不僅僅是文本理解更是意圖識別和需求提取。例如“人少”可能對應(yīng)著“非熱門景點”或“錯峰時間”“預(yù)算不高”需要結(jié)合目的地消費水平進行量化。這里我們會利用大模型的思維鏈能力讓模型逐步推理將用戶輸入拆解成結(jié)構(gòu)化的約束條件目的地類型、時間范圍、預(yù)算區(qū)間、興趣標(biāo)簽美食、自然、人文等、同行人員、交通偏好等。這一步的輸出是一個結(jié)構(gòu)化的“旅行需求概要”為后續(xù)規(guī)劃提供明確的輸入。其次規(guī)劃階段。這是最復(fù)雜的部分需要智能體具備“思考”和“執(zhí)行”能力。我們會采用ReAct模式。智能體首先根據(jù)需求概要進行“思考”決定下一步該做什么比如“我需要查詢北京3日游的經(jīng)典景點”。然后它“執(zhí)行”對應(yīng)的工具比如調(diào)用一個“景點知識庫查詢工具”。拿到工具返回的結(jié)果例如故宮、天壇、頤和園的信息后再進行下一輪“思考”“這些景點如何安排在三天內(nèi)比較合理需要考慮地理位置和開放時間”。接著可能調(diào)用“路線規(guī)劃工具”或“地圖API”。這個過程會循環(huán)進行直到生成一個初步的行程草案。Langchain4j的AgentExecutor和Tool抽象完美支持這種模式。最后呈現(xiàn)階段。生成的草案可能還存在時間沖突、交通不現(xiàn)實等問題。我們需要讓大模型扮演一個“挑剔的旅行顧問”對草案進行審查和優(yōu)化。例如檢查景點間的移動時間是否合理午餐時間是否預(yù)留預(yù)算是否超支。優(yōu)化后的行程再通過模板或富文本格式生成最終輸出包括每日的時段安排、活動內(nèi)容、地點、預(yù)估費用和注意事項。2.2 技術(shù)棧選型與組件職責(zé)為什么是Spring AI Langchain4j而不是直接用Python的LangChain對于Java技術(shù)棧的團隊來說維護統(tǒng)一的技術(shù)生態(tài)可以降低學(xué)習(xí)成本和運維復(fù)雜度。這個組合的分工非常清晰Spring AI扮演“連接器”和“基礎(chǔ)層”的角色。模型抽象它定義了ChatClient、EmbeddingClient等通用接口。無論底層是OpenAI、Azure OpenAI還是Ollama本地模型上層的代碼幾乎不用改只需改配置。這對于項目后期切換模型或進行A/B測試非常有利。向量數(shù)據(jù)庫集成Spring AI提供了對PgVectorPostgreSQL擴展、Redis、Chroma等向量庫的便捷支持。我們的景點知識庫、酒店信息等需要語義檢索的數(shù)據(jù)可以很方便地存入和查詢。便捷的配置管理通過application.yml輕松管理不同模型的API Key、Base URL、超時等參數(shù)符合Spring Boot的開發(fā)習(xí)慣。Langchain4j扮演“大腦”和“協(xié)調(diào)器”的角色。智能體框架它提供了構(gòu)建智能體所需的核心組件如Agent、Tool、Memory、PromptTemplate。我們可以用聲明式的方式定義智能體的行為邏輯。工具調(diào)用這是核心。我們將外部能力封裝成Tool。例如AttractionSearchTool基于向量數(shù)據(jù)庫根據(jù)用戶描述如“有歷史感的博物館”語義搜索景點。RoutePlanningTool調(diào)用高德地圖或百度地圖的路徑規(guī)劃API計算兩點間的交通方式和時間。WeatherQueryTool獲取目的地未來幾天的天氣作為規(guī)劃參考。BudgetCalculatorTool根據(jù)景點門票、餐飲人均消費等數(shù)據(jù)粗略估算每日花費。記憶管理智能體需要有短期記憶記住本次對話的上下文和長期記憶記住用戶的長期偏好。Langchain4j提供了ChatMemory機制可以方便地將對話歷史存入Redis或數(shù)據(jù)庫。其他關(guān)鍵組件向量數(shù)據(jù)庫選用PgVector。因為它是PostgreSQL的擴展無需引入新的數(shù)據(jù)庫系統(tǒng)利用現(xiàn)有的PostgreSQL運維經(jīng)驗即可且性能和功能足夠強大。外部API地圖服務(wù)如高德地圖Web服務(wù)API、天氣API等。這些是智能體獲取實時、準(zhǔn)確信息的“眼睛和耳朵”。緩存使用Redis。緩存頻繁查詢的景點信息、路線規(guī)劃結(jié)果大幅降低響應(yīng)延遲和外部API調(diào)用成本。注意工具的設(shè)計原則是“單一職責(zé)”和“無狀態(tài)”。每個工具只做一件事并且不依賴內(nèi)部狀態(tài)。這樣便于測試、復(fù)用和組合。3. 核心細節(jié)解析與實操要點3.1 知識庫構(gòu)建與向量化智能體不能只靠大模型“憑空想象”它需要準(zhǔn)確的知識。因此構(gòu)建一個本地景點/城市知識庫是項目的基石。數(shù)據(jù)來源與處理 數(shù)據(jù)可以從公開的旅游網(wǎng)站、維基百科或購買的專業(yè)數(shù)據(jù)庫獲取。原始數(shù)據(jù)可能是非結(jié)構(gòu)化的HTML、JSON或文本。我們需要將其清洗、轉(zhuǎn)換成結(jié)構(gòu)化的文檔。例如一個景點文檔應(yīng)包含名稱、城市、描述、標(biāo)簽如“歷史”、“自然”、“親子”、開放時間、建議游玩時長、門票價格、經(jīng)緯度坐標(biāo)等。向量化嵌入 這是讓計算機“理解”文本語義的關(guān)鍵。我們使用Spring AI的EmbeddingClient將每個景點的“描述”和“標(biāo)簽”字段轉(zhuǎn)換成高維向量例如1536維。這個過程的核心是選擇一個合適的嵌入模型。對于中文場景我們可能選擇text-embedding-3-small或國內(nèi)的BGE、M3E模型。嵌入模型的質(zhì)量直接決定了后續(xù)語義搜索的準(zhǔn)確度。// 示例使用Spring AI進行文本向量化 Service public class KnowledgeBaseService { Autowired private EmbeddingClient embeddingClient; public void saveAttraction(Attraction attraction) { // 準(zhǔn)備需要被向量化的文本 String textToEmbed attraction.getDescription() String.join( , attraction.getTags()); // 生成向量 ListDouble embedding embeddingClient.embed(textToEmbed); attraction.setEmbedding(embedding); // 保存到帶有PgVector的PostgreSQL attractionRepository.save(attraction); } }向量存儲與檢索 將帶有向量的景點數(shù)據(jù)存入PgVector。檢索時將用戶的查詢?nèi)纭斑m合晚上散步的浪漫地方”同樣向量化然后在數(shù)據(jù)庫中進行余弦相似度計算找出最相似的景點。-- 在PgVector中查詢相似景點的示例SQL SELECT id, name, description, 1 - (embedding ?) as similarity FROM attractions WHERE city ? ORDER BY embedding ? LIMIT 10;這里的是PgVector提供的余弦距離操作符。實操心得嵌入模型的領(lǐng)域適配性很重要。通用模型對“博物館”和“科技館”的區(qū)分可能不夠細。如果條件允許可以用本領(lǐng)域的文本數(shù)據(jù)對開源嵌入模型進行微調(diào)能顯著提升檢索精度。另外向量維度并非越高越好更高的維度意味著更大的存儲和計算開銷需要權(quán)衡。3.2 智能體提示工程與思維鏈設(shè)計智能體的“思考方式”是由我們設(shè)計的提示詞Prompt引導(dǎo)的。一個糟糕的Prompt會讓智能體行為混亂一個優(yōu)秀的Prompt則能讓它像經(jīng)驗豐富的旅行規(guī)劃師一樣工作。系統(tǒng)提示詞設(shè)計 這是智能體的“角色設(shè)定”和“基本原則”。需要清晰定義其身份、目標(biāo)和約束。你是一個專業(yè)的旅行規(guī)劃助手AI。你的目標(biāo)是根據(jù)用戶的需求規(guī)劃一份詳細、可行、個性化的旅行行程。 請遵循以下原則 1. 始終以用戶的安全、舒適和滿意度為第一考量。 2. 規(guī)劃時務(wù)必考慮景點的實際開放時間、地理位置和交通便利性。 3. 合理安排每日活動強度勞逸結(jié)合。 4. 明確標(biāo)出每一項活動的預(yù)估花費。 5. 如果信息不足請主動詢問用戶或使用你擁有的工具進行查詢。 6. 最終輸出一份按時間順序排列的、清晰的行程表。 你的思考過程應(yīng)該是逐步的、推理式的。在最終回答前請先闡述你的規(guī)劃思路。思維鏈與工具調(diào)用提示 在ReAct模式中我們需要引導(dǎo)模型按照“Thought - Action - Observation”的循環(huán)進行。Langchain4j內(nèi)置了相關(guān)的Prompt模板但我們?nèi)孕枰鶕?jù)任務(wù)微調(diào)。關(guān)鍵在于Thought部分要鼓勵模型進行分解推理。例如面對“北京三天文化之旅”的需求理想的思考過程應(yīng)該是Thought: 用戶想要一個北京的文化之旅。首先我需要明確“文化”的具體指向可能包括歷史古跡、博物館、傳統(tǒng)藝術(shù)。我需要查詢北京有哪些頂級的歷史文化景點。我將使用景點搜索工具。然后在Observation工具返回結(jié)果之后繼續(xù)思考Thought: 工具返回了故宮、國家博物館、天壇、頤和園等。我需要考慮這些景點的地理位置。故宮和國家博物館都在市中心可以安排在一天。天壇在南邊頤和園在西邊需要分開安排。接下來我需要調(diào)用路線規(guī)劃工具估算交通時間。注意事項提示詞中的約束條件要具體。比如“明確標(biāo)出預(yù)估花費”這能迫使模型在每一步都調(diào)用預(yù)算計算工具或查詢相關(guān)數(shù)據(jù)而不是憑空捏造。同時要設(shè)定停止條件比如“當(dāng)行程覆蓋了所有主要需求且時間安排合理時輸出最終行程”防止智能體陷入無限循環(huán)。3.3 工具類的具體實現(xiàn)與集成工具是智能體能力的延伸。每個工具都需要實現(xiàn)Langchain4j的Tool接口并通過Tool注解暴露。以RoutePlanningTool為例Component public class RoutePlanningTool { Tool(根據(jù)起點和終點的經(jīng)緯度坐標(biāo)規(guī)劃出行路線并返回主要交通方式、距離和預(yù)估時間。) public RoutePlan planRoute( P(起點緯度) double startLat, P(起點經(jīng)度) double startLng, P(終點緯度) double endLat, P(終點經(jīng)度) double endLng, P(交通方式默認(rèn)為駕車) Optional(defaultValue driving) String mode) { // 1. 參數(shù)校驗 // 2. 構(gòu)建緩存Key例如”startLat,startLng,endLat,endLng,mode“ String cacheKey buildCacheKey(startLat, startLng, endLat, endLng, mode); // 3. 查詢Redis緩存 RoutePlan cachedPlan redisTemplate.opsForValue().get(cacheKey); if (cachedPlan ! null) { return cachedPlan; } // 4. 調(diào)用真實的地圖API如高德地圖 RoutePlan newPlan amapService.calculateRoute(startLat, startLng, endLat, endLng, mode); // 5. 將結(jié)果存入Redis設(shè)置合適的TTL如1小時 redisTemplate.opsForValue().set(cacheKey, newPlan, Duration.ofHours(1)); return newPlan; } }關(guān)鍵點解析Tool注解其中的描述字符串至關(guān)重要。大模型根據(jù)這個描述來決定何時調(diào)用此工具。描述要清晰說明工具的功能、輸入和輸出。P注解用于描述參數(shù)。清晰的參數(shù)名和描述能幫助模型正確填充參數(shù)。緩存機制對于路線規(guī)劃、天氣查詢這類相對穩(wěn)定或調(diào)用成本高的工具必須加入緩存。這能極大提升智能體的響應(yīng)速度并降低API費用。錯誤處理工具內(nèi)部必須有健壯的錯誤處理try-catch。當(dāng)外部API失敗時應(yīng)返回一個友好的錯誤信息給智能體例如“暫時無法獲取路線信息建議手動查詢地圖”而不是拋出異常導(dǎo)致智能體進程崩潰。工具注冊所有這些工具類在Spring Boot中都會被自動掃描并注入到ToolProvider中供AgentExecutor使用。4. 實操過程與核心環(huán)節(jié)實現(xiàn)4.1 項目初始化與環(huán)境配置首先創(chuàng)建一個標(biāo)準(zhǔn)的Spring Boot 3.x項目。在pom.xml中引入關(guān)鍵依賴dependencies !-- Spring AI 核心 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-openai-spring-boot-starter/artifactId /dependency !-- 或使用阿里云等其它模型starter -- !-- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-alibaba-spring-boot-starter/artifactId /dependency -- !-- Langchain4j 集成 Spring Boot -- dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-spring-boot-starter/artifactId version0.30.0/version /dependency !-- 向量數(shù)據(jù)庫支持 (PgVector) -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-pgvector-store-spring-boot-starter/artifactId /dependency !-- PostgreSQL 驅(qū)動 -- dependency groupIdorg.postgresql/groupId artifactIdpostgresql/artifactId scoperuntime/scope /dependency !-- Redis 用于緩存和記憶 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency !-- 其他Web, Lombok, 測試等 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency /dependencies在application.yml中進行配置spring: ai: openai: api-key: ${OPENAI_API_KEY} chat: options: model: gpt-4-turbo # 根據(jù)實際情況選擇模型 vectorstore: pgvector: enabled: true initialize-schema: true # 首次啟動自動創(chuàng)建向量表 datasource: url: jdbc:postgresql://localhost:5432/travel_ai username: postgres password: yourpassword data: redis: host: localhost port: 6379 # Langchain4j 配置 langchain4j: chat-memory: type: redis # 使用Redis存儲對話記憶4.2 智能體組裝與執(zhí)行器配置這是最核心的裝配環(huán)節(jié)。我們將定義一個AgentConfiguration配置類。Configuration public class AgentConfiguration { Autowired private ListTool tools; // 所有被Tool注解的Bean會自動注入到這里 Bean public ChatMemory chatMemory() { // 配置一個基于消息窗口的記憶保留最近10輪對話 return MessageWindowChatMemory.withMaxMessages(10); } Bean public Agent travelPlanningAgent(ChatLanguageModel chatModel, ChatMemory memory) { // 1. 構(gòu)建工具集 ToolSpecification toolSpec ToolUtils.toToolSpecifications(tools); // 2. 定義系統(tǒng)提示詞 String systemPrompt 你是一個專業(yè)的旅行規(guī)劃助手AI。你的目標(biāo)是根據(jù)用戶的需求規(guī)劃一份詳細、可行、個性化的旅行行程。 ... (詳細提示詞同上此處省略) ... 請嚴(yán)格按照以下格式輸出你的思考過程 思考[你的推理過程] 行動工具名(參數(shù)) 觀察[工具返回的結(jié)果] ... (重復(fù)思考-行動-觀察) ... 最終答案[完整的行程規(guī)劃] ; // 3. 使用Langchain4j的流式API構(gòu)建智能體 Agent agent Agent.builder() .chatLanguageModel(chatModel) // Spring AI的ChatClient會自動適配 .chatMemory(memory) .tools(tools) .promptTemplate(systemPrompt) .outputParser(new ReActParser()) // 用于解析模型輸出的ReAct格式 .build(); return agent; } Bean public AgentExecutor agentExecutor(Agent agent) { // AgentExecutor負責(zé)驅(qū)動智能體的思考-執(zhí)行循環(huán) return AgentExecutor.builder() .agent(agent) .maxIterations(15) // 防止無限循環(huán)最多執(zhí)行15輪思考-行動 .build(); } }關(guān)鍵解析ChatLanguageModel這個Bean由Spring AI自動提供它是對底層大模型如OpenAI的抽象。這樣我們的智能體代碼就與具體模型解耦了。maxIterations這是一個非常重要的安全閥。即使提示詞設(shè)計得再好模型也可能陷入邏輯循環(huán)。設(shè)置一個最大迭代次數(shù)當(dāng)達到時強制終止并返回當(dāng)前結(jié)果保證服務(wù)可用性。4.3 服務(wù)層封裝與API暴露智能體組裝好后我們需要一個服務(wù)來調(diào)用它并對外提供HTTP API。Service Slf4j public class TravelPlanningService { Autowired private AgentExecutor agentExecutor; public String planItinerary(String userQuery, String sessionId) { // sessionId用于區(qū)分不同用戶的對話記憶 String prompt 用戶需求 userQuery \n請開始規(guī)劃行程。; try { // 執(zhí)行智能體 AgentResponse response agentExecutor.execute(prompt, sessionId); return response.content(); } catch (MaxIterationsReachedException e) { log.warn(智能體規(guī)劃達到最大迭代次數(shù)會話ID: {}, sessionId); return 行程規(guī)劃過程過于復(fù)雜未能完成。請嘗試更具體或更簡單的需求。; } catch (Exception e) { log.error(行程規(guī)劃失敗會話ID: {}, sessionId, e); return 抱歉規(guī)劃服務(wù)暫時出錯請稍后再試。; } } } RestController RequestMapping(/api/travel) public class TravelPlanningController { Autowired private TravelPlanningService planningService; PostMapping(/plan) public ResponseEntityMapString, String plan(RequestBody PlanRequest request, HttpServletRequest httpRequest) { // 可以使用用戶ID或生成唯一會話ID String sessionId httpRequest.getSession().getId(); String itinerary planningService.planItinerary(request.getQuery(), sessionId); MapString, String response new HashMap(); response.put(sessionId, sessionId); response.put(itinerary, itinerary); return ResponseEntity.ok(response); } }5. 效果優(yōu)化與性能調(diào)優(yōu)5.1 響應(yīng)速度優(yōu)化智能體的ReAct思考過程涉及多次與大模型的交互單次響應(yīng)時間可能在10秒以上用戶體驗不佳。優(yōu)化手段包括并行工具調(diào)用當(dāng)智能體的思考中需要調(diào)用多個獨立的工具時例如同時查詢A景點的信息和B景點的天氣可以設(shè)計支持并行調(diào)用的工具執(zhí)行器而不是串行等待。流式輸出對于最終行程的生成可以采用流式響應(yīng)。智能體每完成一天或一個片段的規(guī)劃就立即返回給前端讓用戶先看到部分結(jié)果而不是等待全部完成。預(yù)計算與緩存熱門路線緩存將“北京3日經(jīng)典游”、“上海迪士尼2日游”等常見需求的完整規(guī)劃結(jié)果緩存起來。當(dāng)識別到類似通用需求時直接返回緩存結(jié)果或在其基礎(chǔ)上微調(diào)。子規(guī)劃緩存將規(guī)劃過程中產(chǎn)生的中間結(jié)果如“故宮到天壇的路線”、“某餐廳的人均消費”等也進行緩存供其他會話或同一會話后續(xù)步驟復(fù)用。模型選擇在保證效果的前提下可以嘗試更快的模型。例如用gpt-4-turbo代替gpt-4或用claude-3-haiku代替claude-3-sonnet進行部分非核心的推理步驟。5.2 規(guī)劃質(zhì)量提升反饋學(xué)習(xí)與記憶引入長期記憶。當(dāng)用戶對生成的行程提出修改意見如“第二天太累了”、“我不喜歡這個餐廳”智能體不僅能修改當(dāng)前行程還應(yīng)將這種偏好“該用戶不喜歡緊湊行程”、“偏好清淡食物”存入與該用戶關(guān)聯(lián)的長期記憶向量化存儲在下次規(guī)劃時優(yōu)先考慮。多方案生成與選擇讓智能體一次性生成2-3個不同風(fēng)格如“緊湊高效型”、“休閑放松型”、“深度文化型”的行程草案并附上簡要的優(yōu)缺點說明讓用戶選擇。這比單一方案更能滿足個性化需求。實時信息集成工具需要獲取實時信息。除了天氣、路況還可以集成“景點實時人流”、“特價門票信息”、“餐廳實時排隊情況”等讓規(guī)劃更具動態(tài)性和可行性。后處理與格式化大模型生成的文本可能格式不統(tǒng)一??梢栽黾右粋€后處理步驟使用固定的模板或規(guī)則引擎將智能體輸出的自然語言行程轉(zhuǎn)換成結(jié)構(gòu)化的JSON或美觀的Markdown/HTML格式方便前端展示。5.3 成本控制與監(jiān)控大模型API調(diào)用是主要成本。必須建立監(jiān)控體系。Token使用監(jiān)控在每次調(diào)用ChatClient后記錄請求和響應(yīng)的Token數(shù)量。可以設(shè)置每日/每用戶的Token消耗閾值超過后降級使用更便宜的模型或返回緩存。工具調(diào)用監(jiān)控記錄每個工具被調(diào)用的頻率和耗時。對于調(diào)用頻繁且結(jié)果變化不大的工具如城市基本信息查詢可以延長其緩存時間。失敗重試與降級對于地圖API、天氣API等第三方服務(wù)調(diào)用失敗應(yīng)有重試機制。若持續(xù)失敗應(yīng)能降級處理例如路線規(guī)劃失敗時改為使用靜態(tài)的交通時間估算值。異步處理對于非常復(fù)雜、耗時的規(guī)劃請求如“規(guī)劃一個環(huán)歐洲一個月的行程”可以改為異步處理。接口立即返回一個任務(wù)ID規(guī)劃完成后通過WebSocket或輪詢通知用戶。避免HTTP請求超時。6. 常見問題與排查技巧實錄在實際開發(fā)和測試中會遇到各種各樣的問題。這里記錄一些典型場景和解決思路。6.1 智能體行為異常問題智能體不調(diào)用工具一直“空想”或者反復(fù)調(diào)用同一個工具陷入循環(huán)。排查檢查提示詞首先確認(rèn)系統(tǒng)提示詞是否明確指令它“使用工具”。在提示詞中強調(diào)“你必須使用我提供的工具來獲取信息”。檢查工具描述查看Tool注解中的描述是否清晰、準(zhǔn)確。模型是根據(jù)描述來決定調(diào)用哪個工具的。描述模糊或與其他工具相似會導(dǎo)致模型困惑。開啟調(diào)試日志將Langchain4j和Spring AI的日志級別調(diào)到DEBUG可以完整看到模型接收的提示詞、返回的思考內(nèi)容以及工具調(diào)用的參數(shù)這是定位問題的黃金手段。簡化測試用一個最簡單的工具和需求進行測試排除復(fù)雜交互帶來的干擾。問題智能體調(diào)用了工具但參數(shù)總是填錯。排查檢查P注解確保每個參數(shù)都有P注解并且value或name清晰。例如P(起點城市的名稱) String startCity。觀察模型輸出從調(diào)試日志中看模型輸出的Action部分參數(shù)是否以正確的格式通常是JSON提供。有時模型會“自作主張”添加額外說明。提供示例在提示詞中加入1-2個工具調(diào)用的正確示例Few-Shot Learning能顯著提升模型調(diào)用工具的準(zhǔn)確性。6.2 性能與穩(wěn)定性問題問題規(guī)劃請求響應(yīng)非常慢甚至超時。排查檢查迭代次數(shù)是否因為提示詞設(shè)計問題導(dǎo)致智能體陷入過多輪迭代查看日志確認(rèn)迭代輪數(shù)。適當(dāng)降低maxIterations。檢查工具耗時為每個工具添加執(zhí)行時間日志??赡苁悄硞€外部API如地圖路徑規(guī)劃響應(yīng)慢??紤]為該工具增加超時設(shè)置和熔斷機制。檢查模型響應(yīng)時間不同模型、不同時段API響應(yīng)速度差異很大。監(jiān)控模型調(diào)用的P99延遲。檢查緩存命中率確認(rèn)Redis緩存是否生效工具結(jié)果是否被有效緩存。問題服務(wù)運行一段時間后內(nèi)存占用很高。排查檢查ChatMemory如果使用內(nèi)存中的ChatMemory且沒有對話數(shù)量或消息數(shù)量的上限長時間運行會導(dǎo)致內(nèi)存累積。務(wù)必使用MessageWindowChatMemory或?qū)捰洃洿鎯Φ絉edis/數(shù)據(jù)庫。檢查大對象緩存是否在內(nèi)存中緩存了過大的對象如完整的景點列表??紤]使用分布式緩存或優(yōu)化數(shù)據(jù)結(jié)構(gòu)。分析堆轉(zhuǎn)儲使用jmap或VisualVM等工具分析內(nèi)存堆找出占用大的對象。6.3 數(shù)據(jù)與知識問題問題智能體推薦的景點或餐廳根本不存在或信息過時。排查知識庫更新建立知識庫的定期更新機制。對于餐廳、門票價格等易變信息更新頻率要高如每周對于景點基本信息可以頻率低一些如每月。置信度過濾在向量檢索時設(shè)置一個相似度閾值如0.75。低于此閾值的結(jié)果認(rèn)為不夠相關(guān)不返回給智能體或者返回時標(biāo)記為“低置信度請核實”。引入來源標(biāo)注工具返回信息時附帶信息來源和時間戳。在最終行程輸出中可以酌情標(biāo)注“信息更新于X年X月”提升可信度。問題智能體規(guī)劃出不合理的行程如一天跨城市跑三個相距很遠的景點。解決在工具中嵌入規(guī)則在RoutePlanningTool中不僅返回時間如果計算出的交通時間超過某個閾值如2小時可以同時返回一個警告“兩地距離較遠單日往返可能過于奔波”。在提示詞中強化約束在系統(tǒng)提示詞中反復(fù)強調(diào)“地理位置鄰近性”、“每日交通總時長控制在X小時內(nèi)”。后置校驗規(guī)則在智能體輸出最終行程后增加一個獨立的“行程合理性校驗”服務(wù)。這個服務(wù)基于一套規(guī)則如每日移動距離上限、景點開放時間沖突檢查對行程進行掃描發(fā)現(xiàn)問題則返回給智能體要求調(diào)整。開發(fā)這樣一個智能體的過程就像是在教一個實習(xí)生如何做旅行規(guī)劃。你需要給它清晰的指令提示詞教會它使用各種工具地圖、數(shù)據(jù)庫告訴它常見的錯誤和原則約束條件并在它犯錯時及時糾正調(diào)試和優(yōu)化。最終當(dāng)它能穩(wěn)定產(chǎn)出高質(zhì)量規(guī)劃時那種成就感是單純調(diào)用API所無法比擬的。這個項目最大的價值不在于最終的應(yīng)用而在于完整經(jīng)歷了一次AI智能體從設(shè)計、開發(fā)、調(diào)試到優(yōu)化的全流程這套方法論可以遷移到客服、編程助手、數(shù)據(jù)分析等任何你能想到的領(lǐng)域。本文還有配套的精品資源點擊獲取