最近在做一个无人机租赁相关的项目,客户希望引入AI能力来提升用户体验和运营效率。调研了一圈,发现将大语言模型(LLM)与业务系统结合,特别是通过 LangChain 和 Agent 来构建智能交互和决策流程,是一个非常契合的方向。这不仅能实现智能客服、个性化推荐,还能自动化处理一些复杂的租赁审批和调度任务。
本文就将围绕这个“AI无人机租赁系统”,从零开始,手把手带你完成一个集成了 AI、LangChain 和 Agent 概念的可运行原型。我会详细拆解设计思路、技术选型、核心代码实现,并提供完整的源码和关键配置。无论你是想用于毕业设计、课程作业,还是作为面试项目来展示你的全栈和AI应用能力,这篇文章都能给你提供一个清晰的路线图和可直接复用的代码库。
1. 系统核心概念与技术栈解析
在动手编码之前,我们需要先理解这个系统要做什么,以及为什么选择这些技术。
1.1 项目愿景与核心功能
我们设想中的AI无人机租赁系统,不仅仅是一个简单的物品租赁网站。它应该具备以下智能化特征:
- 智能客服与导览:用户可以用自然语言询问“有什么适合航拍的无人机?”、“租一台续航2小时以上的无人机多少钱?”,系统能理解并给出精准回答和推荐。
- 个性化租赁方案推荐:根据用户输入的预算、使用场景(如航拍、测绘、巡检)、经验等级,AI能自动组合无人机机型、保险套餐、备用电池等,生成最优租赁方案。
- 自动化流程处理:对于租赁申请,AI Agent可以自动核查用户信用信息(模拟)、无人机库存状态,并做出初步的通过/拒绝决策,将复杂任务交由人工复审。
- 动态定价与调度建议:结合天气、节假日、区域热度等因素,AI可以为租赁定价提供调整建议,并为无人机的归还、充电、调度提供智能提醒。
1.2 为什么是 LangChain + Agent?
要实现上述功能,直接调用大模型API(如 OpenAI GPT、文心一言)是远远不够的。我们需要一个框架来“武装”大模型,让它能使用工具、访问知识、处理长流程。这就是 LangChain 和 Agent 的用武之地。
- LangChain:是一个用于开发由语言模型驱动的应用程序的框架。它提供了丰富的模块,如
Models(对接各种LLM)、Prompts(提示词管理)、Chains(任务链)、Agents(智能代理)、Memory(记忆)等。它像“乐高积木”一样,让我们能快速搭建复杂的AI应用。 - Agent:是 LangChain 中的核心概念之一。你可以把它理解为一个“具备执行能力的AI大脑”。用户提出一个复杂请求(如“帮我租一台无人机”),Agent会自己思考:“要完成这个任务,我需要先查库存,再算价格,最后创建订单。我有‘查询库存工具’、‘计算价格工具’和‘创建订单工具’。”然后它会自主调用这些工具,一步步完成任务。
技术栈选型:
- 后端:Spring Boot。Java生态成熟,适合构建稳健的业务系统,处理订单、用户、支付等核心逻辑。
- AI层:Python + LangChain。Python是AI领域的事实标准,LangChain生态丰富。两者通过HTTP API(如FastAPI)进行通信。
- 大模型:OpenAI GPT-3.5/4 API 或 国内可替代的如 文心一言、通义千问、智谱GLM 的API。本文示例将使用OpenAI格式的API进行演示。
- 数据库:MySQL。存储用户、设备、订单等结构化数据。
- 向量数据库:Chroma(轻量级,适合演示)。用于存储无人机产品说明书、租赁条款等非结构化文本,实现基于语义的智能检索。
- 前端:Vue.js / React + Ant Design(可选)。为了聚焦后端与AI集成,前端我们仅提供简单的API调用示例。
2. 环境准备与项目初始化
“工欲善其事,必先利其器”。我们先搭建好开发环境。
2.1 软件与环境清单
请确保你的开发机上已安装以下软件:
- JDK 8 或 11:推荐 OpenJDK 11。
- Maven 3.6+:用于管理Java项目依赖。
- Python 3.8+:推荐 Python 3.9 或 3.10。
- MySQL 5.7+:用于业务数据存储。
- IDE:IntelliJ IDEA(Java)、PyCharm/VSCode(Python)。
- API密钥:准备一个可用的 OpenAI API Key,或国内大模型的对应API Key。
2.2 创建项目骨架
我们将创建两个独立的项目(或模块):一个Spring Boot后端项目,一个Python AI服务项目。
1. 创建Spring Boot项目使用 Spring Initializr (start.spring.io) 或 IDE 创建项目。
- Group:
com.aidrone - Artifact:
drone-rental-system - 依赖:
Spring Web,Spring Data JPA,MySQL Driver,Lombok。
创建后的项目结构大致如下:
drone-rental-backend/ ├── src/ │ ├── main/ │ │ ├── java/com/aidrone/ │ │ │ ├── controller/ # 控制器 │ │ │ ├── service/ # 业务层 │ │ │ ├── repository/ # 数据访问层 │ │ │ ├── entity/ # 实体类 │ │ │ └── config/ # 配置类 │ │ └── resources/ │ │ ├── application.properties │ │ └── ... │ └── test/ └── pom.xml2. 创建Python AI服务项目创建一个新的目录,并初始化虚拟环境。
mkdir drone-rental-ai cd drone-rental-ai python -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # Mac/Linux: source venv/bin/activate创建项目文件结构:
drone-rental-ai/ ├── app/ │ ├── __init__.py │ ├── main.py # FastAPI 主应用 │ ├── agents/ # Agent 定义 │ │ ├── __init__.py │ │ └── rental_agent.py │ ├── tools/ # Agent 可用的工具 │ │ ├── __init__.py │ │ ├── inventory_tool.py │ │ └── pricing_tool.py │ ├── chains/ # 业务处理链 │ └── knowledge/ # 知识库相关 ├── requirements.txt └── .env # 存储API密钥等敏感信息3. 安装Python依赖在requirements.txt中写入:
fastapi==0.104.1 uvicorn[standard]==0.24.0 langchain==0.0.350 openai==0.28.0 chromadb==0.4.18 pymysql==1.1.0 python-dotenv==1.0.0 pydantic==2.5.0然后安装:pip install -r requirements.txt
3. 核心模块设计与实现
接下来,我们分步实现系统的核心模块。
3.1 后端基础业务模块(Spring Boot)
首先,我们实现最基础的无人机、用户、订单管理功能。
1. 数据库表设计(Entity)创建对应的JPA实体类。
// 文件:src/main/java/com/aidrone/entity/Drone.java package com.aidrone.entity; import lombok.Data; import javax.persistence.*; import java.math.BigDecimal; @Entity @Data @Table(name = "drone") public class Drone { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; // 型号名,如 DJI Mavic 3 private String type; // 类型,如航拍、测绘 private BigDecimal rentalPricePerHour; // 每小时租金 private Integer maxFlightTime; // 最大续航(分钟) private Integer stock; // 库存数量 private String description; // 详细描述 }// 文件:src/main/java/com/aidrone/entity/RentalOrder.java package com.aidrone.entity; import lombok.Data; import javax.persistence.*; import java.math.BigDecimal; import java.time.LocalDateTime; @Entity @Data @Table(name = "rental_order") public class RentalOrder { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private Long userId; private Long droneId; private LocalDateTime startTime; private LocalDateTime endTime; private BigDecimal totalPrice; private String status; // PENDING, CONFIRMED, IN_USE, COMPLETED, CANCELLED }2. 数据访问层(Repository)
// 文件:src/main/java/com/aidrone/repository/DroneRepository.java package com.aidrone.repository; import com.aidrone.entity.Drone; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import java.util.List; public interface DroneRepository extends JpaRepository<Drone, Long> { List<Drone> findByType(String type); List<Drone> findByRentalPricePerHourLessThanEqual(BigDecimal maxPrice); // 复杂查询示例:根据类型和最小续航查询 @Query("SELECT d FROM Drone d WHERE d.type = :type AND d.maxFlightTime >= :minFlightTime") List<Drone> findAvailableByTypeAndFlightTime(@Param("type") String type, @Param("minFlightTime") Integer minFlightTime); }3. 业务逻辑层(Service)与控制器(Controller)实现基本的CRUD和查询API,这部分是标准Spring Boot开发,代码较长,此处给出一个查询无人机的API示例。
// 文件:src/main/java/com/aidrone/controller/DroneController.java package com.aidrone.controller; import com.aidrone.entity.Drone; import com.aidrone.service.DroneService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("/api/drones") public class DroneController { @Autowired private DroneService droneService; @GetMapping("/search") public List<Drone> searchDrones(@RequestParam(required = false) String type, @RequestParam(required = false) Integer minFlightTime) { return droneService.searchDrones(type, minFlightTime); } // 其他CRUD接口... }4. 配置文件application.properties:
spring.datasource.url=jdbc:mysql://localhost:3306/drone_rental?useSSL=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=yourpassword spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true启动Spring Boot应用,确保基础API可以访问。
3.2 Python AI服务:工具(Tools)定义
Agent的强大之处在于能使用工具。我们先为Agent创建几个关键工具。这些工具本质上是Python函数,Agent在思考后可以调用它们。
1. 查询无人机库存工具这个工具将调用我们刚才写的Spring Boot后端API。
# 文件:app/tools/inventory_tool.py import requests from langchain.tools import tool from pydantic import BaseModel, Field # 定义工具的输入参数模型 class InventoryCheckInput(BaseModel): drone_type: str = Field(description="无人机类型,例如:航拍、测绘") min_flight_time: int = Field(description="要求的最小续航时间(分钟)") @tool(args_schema=InventoryCheckInput) def check_drone_availability(drone_type: str, min_flight_time: int) -> str: """ 根据类型和最小续航时间查询可用的无人机列表。 返回无人机的型号、价格和库存信息。 """ try: # 调用后端API。注意:这里需要替换为你的实际后端地址 response = requests.get( "http://localhost:8080/api/drones/search", params={"type": drone_type, "minFlightTime": min_flight_time} ) response.raise_for_status() drones = response.json() if not drones: return f"当前没有符合条件(类型:{drone_type}, 最小续航:{min_flight_time}分钟)的可用无人机。" result_lines = [f"找到 {len(drones)} 款符合条件的无人机:"] for drone in drones: result_lines.append(f"- {drone['name']}: 时租¥{drone['rentalPricePerHour']}, 续航{drone['maxFlightTime']}分钟, 库存{drone['stock']}台。") return "\n".join(result_lines) except requests.exceptions.RequestException as e: return f"查询库存时发生网络错误:{e}"2. 计算租赁价格工具
# 文件:app/tools/pricing_tool.py from langchain.tools import tool from pydantic import BaseModel, Field class PriceCalculationInput(BaseModel): drone_id: int = Field(description="无人机ID") rental_hours: int = Field(description="租赁小时数") @tool(args_schema=PriceCalculationInput) def calculate_rental_price(drone_id: int, rental_hours: int) -> str: """ 根据无人机ID和租赁时长计算预估总价。 这是一个简化版本,实际中需要调用后端API获取无人机单价。 """ # 模拟从数据库或缓存获取单价,这里用固定值演示 # 真实场景应调用 GET /api/drones/{id} price_per_hour = 150.0 # 假设单价150元/小时 total_price = price_per_hour * rental_hours return f"无人机(ID:{drone_id})租赁{rental_hours}小时,预估总价为:¥{total_price:.2f}元。"3.3 Python AI服务:构建智能代理(Agent)
现在,我们将大模型和工具组合起来,创建一个能自主决策的Agent。
# 文件:app/agents/rental_agent.py import os from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain_openai import ChatOpenAI from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.memory import ConversationBufferMemory from dotenv import load_dotenv # 加载环境变量,里面应有 OPENAI_API_KEY load_dotenv() # 1. 导入我们定义的工具 from app.tools.inventory_tool import check_drone_availability from app.tools.pricing_tool import calculate_rental_price def create_rental_agent(): """ 创建并返回一个无人机租赁助手Agent。 """ # 2. 初始化大语言模型 # 注意:如果你使用国内模型,需要替换为对应的ChatModel,例如 ChatZhipuAI llm = ChatOpenAI( model="gpt-3.5-turbo-1106", # 或 "gpt-4" temperature=0, # 降低随机性,让回答更确定 openai_api_key=os.getenv("OPENAI_API_KEY"), # 如果使用国内模型,可能需要配置 base_url 等参数 # base_url="https://api.openai.com/v1", # 替换为对应模型的地址 ) # 3. 定义工具列表 tools = [check_drone_availability, calculate_rental_price] # 4. 构建提示词模板,指导Agent的行为 prompt = ChatPromptTemplate.from_messages([ ("system", """ 你是一个专业的无人机租赁助手。你的职责是帮助用户查询可租赁的无人机、计算价格,并提供租赁建议。 请根据用户的问题,选择性地使用你拥有的工具来获取准确信息。 如果你没有合适的工具来回答用户的问题,请礼貌地告知用户你无法处理该请求,并建议其联系人工客服。 你的回答应友好、专业且简洁。 """), MessagesPlaceholder(variable_name="chat_history"), # 预留历史消息的位置 ("human", "{input}"), MessagesPlaceholder(variable_name="agent_scratchpad"), # Agent思考过程的位置 ]) # 5. 创建记忆,让Agent能记住对话上下文 memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True) # 6. 创建Agent agent = create_openai_tools_agent(llm, tools, prompt) # 7. 将Agent封装成执行器 agent_executor = AgentExecutor( agent=agent, tools=tools, memory=memory, verbose=True, # 设置为True可以在控制台看到Agent的思考过程,调试时非常有用 handle_parsing_errors=True # 处理解析错误 ) return agent_executor # 全局Agent实例(简单示例,生产环境需考虑并发和生命周期) rental_agent = create_rental_agent()3.4 Python AI服务:提供API接口
最后,我们用 FastAPI 创建一个Web服务,暴露Agent的能力。
# 文件:app/main.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel from app.agents.rental_agent import rental_agent app = FastAPI(title="AI无人机租赁助手API") class ChatRequest(BaseModel): message: str user_id: str = None # 可选,用于区分不同用户的对话历史 class ChatResponse(BaseModel): response: str agent_thoughts: str = None # 可选,返回Agent的思考链,用于调试 @app.post("/chat", response_model=ChatResponse) async def chat_with_agent(request: ChatRequest): """ 与无人机租赁助手对话。 """ try: # 调用Agent执行器 result = rental_agent.invoke({"input": request.message}) response_text = result.get("output", "抱歉,我没有得到有效的回复。") # 可以从result中提取更多信息,比如中间步骤,这里简单返回 return ChatResponse(response=response_text) except Exception as e: # 记录日志 print(f"Agent执行出错: {e}") raise HTTPException(status_code=500, detail=f"处理您的请求时出现错误: {str(e)}") @app.get("/health") async def health_check(): return {"status": "healthy"} if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)现在,启动你的AI服务:
cd drone-rental-ai uvicorn app.main:app --reload --host 0.0.0.0 --port 8000访问http://localhost:8000/docs可以看到自动生成的API文档。
4. 系统联调与测试
让我们测试一下整个流程是否跑通。
4.1 准备测试数据
在MySQL中插入一些测试无人机数据(可以通过Spring Boot启动自动生成,或手动插入):
INSERT INTO drone (name, type, rental_price_per_hour, max_flight_time, stock, description) VALUES ('DJI Mavic 3 Pro', '航拍', 200.00, 46, 5, '旗舰级航拍无人机,哈苏相机'), ('DJI Air 3', '航拍', 120.00, 38, 8, '中端航拍无人机,双摄系统'), ('DJI Matrice 350 RTK', '测绘', 500.00, 55, 2, '行业级无人机,高精度测绘'), ('Autel EVO Lite+', '航拍', 100.00, 40, 3, '4K航拍无人机,便携性强');4.2 测试Agent对话
使用curl或 Postman 调用AI服务的/chat接口。
请求示例:
curl -X POST "http://localhost:8000/chat" \ -H "Content-Type: application/json" \ -d '{ "message": "我想租一台用于航拍的无人机,续航最好在40分钟以上,有什么推荐吗?" }'预期响应:
{ "response": "找到 2 款符合条件的无人机:\n- DJI Mavic 3 Pro: 时租¥200.0, 续航46分钟, 库存5台。\n- Autel EVO Lite+: 时租¥100.0, 续航40分钟, 库存3台。\n您可以根据预算和喜好进行选择。" }再次提问(测试记忆和工具链):
curl -X POST "http://localhost:8000/chat" \ -H "Content-Type: application/json" \ -d '{ "message": "如果我租DJI Mavic 3 Pro,租3个小时要多少钱?" }'预期响应: Agent会先回忆上下文(知道我们在讨论Mavic 3 Pro),然后调用calculate_rental_price工具(虽然我们示例工具是模拟的,但逻辑正确),返回计算出的价格。
5. 进阶功能与优化方向
一个基础的原型已经完成。要让其更完善,可以考虑以下方向:
5.1 集成向量知识库(RAG)
将无人机说明书、租赁协议、常见问题(FAQ)文档转换成向量,存入ChromaDB。当用户问及“炸机了怎么办?”或“你们的保险覆盖哪些情况?”时,Agent可以先从知识库中检索相关片段,再结合检索到的信息生成回答。
核心步骤:
- 文档加载与分割(使用 LangChain 的
TextLoader和RecursiveCharacterTextSplitter)。 - 文本嵌入(使用
OpenAIEmbeddings或HuggingFaceEmbeddings)。 - 向量存储(使用
Chroma)。 - 创建检索链,并将其作为一个工具提供给Agent。
5.2 实现更复杂的订单创建Agent
创建一个专门的“订单创建Agent”,它拥有更多工具:
get_user_credit_tool: 查询用户信用分。check_drone_availability_by_id_tool: 精确查询某台无人机档期。create_order_tool: 调用后端API创建订单。 这个Agent可以处理从询价到下单的完整流程。
5.3 前端集成
开发一个简单的前端页面(Vue/React),提供一个聊天窗口。前端通过WebSocket或轮询调用/chatAPI,实现一个交互式的AI租赁助手界面。
5.4 系统稳定性与性能
- 错误处理与降级:在Agent工具调用失败时(如后端API超时),应有友好的降级回复,而不是抛出异常。
- 对话记忆管理:当前使用内存存储对话,生产环境需换成Redis等外部存储,并设置会话过期时间。
- 提示词工程优化:不断优化System Prompt,让Agent更精准、更安全,避免幻觉和无关输出。
- API密钥管理:使用环境变量或专业的密钥管理服务,切勿将密钥硬编码在代码中。
6. 常见问题与排查思路
在开发过程中,你可能会遇到以下问题:
| 问题现象 | 可能原因 | 排查思路 |
|---|---|---|
| Spring Boot 启动失败,数据库连接错误 | 1. MySQL服务未启动。 2. application.properties中的数据库URL、用户名、密码错误。3. 数据库 drone_rental不存在。 | 1. 检查MySQL服务状态。 2. 核对配置文件。 3. 登录MySQL,执行 CREATE DATABASE drone_rental;。 |
| Python AI服务启动失败,提示缺少模块 | 1. 虚拟环境未激活。 2. requirements.txt中的依赖未安装完全。 | 1. 确认终端前缀有(venv)。2. 重新运行 pip install -r requirements.txt。 |
调用/chatAPI 返回"OpenAI API key not provided" | 1. 未设置OPENAI_API_KEY环境变量。2. .env文件未加载或格式错误。 | 1. 检查是否在项目根目录创建了.env文件,内容为OPENAI_API_KEY=sk-xxx。2. 确认代码中 load_dotenv()已执行。 |
| Agent 回答 “我没有工具处理这个问题” | 1. 用户问题超出已定义工具的范围。 2. 提示词(System Prompt)未引导Agent正确使用工具。 | 1. 检查工具函数的description是否清晰。2. 优化System Prompt,明确Agent的职责和可用工具。 |
| Agent 调用工具时,后端API返回404 | 1. Spring Boot 后端服务未运行。 2. 工具中调用的API路径错误。 | 1. 确保后端在localhost:8080运行。2. 使用Postman直接测试后端API是否正常。 |
| 对话没有记忆上下文 | ConversationBufferMemory未正确配置或每次请求创建了新实例。 | 确保create_rental_agent中创建的memory对象被AgentExecutor复用,并且API端点使用的是全局的rental_agent实例。 |
7. 项目总结与学习收获
通过这个“AI无人机租赁系统”的原型实现,我们完成了一次从传统业务系统到智能化应用的跃迁。你不仅实践了Spring Boot和Python的协同开发,更重要的是掌握了如何利用LangChain框架将大语言模型转化为能解决实际业务问题的智能体(Agent)。
核心收获:
- 解耦设计:业务逻辑(Java后端)与AI能力(Python服务)分离,通过API通信,架构清晰,易于维护和扩展。
- Agent思维:学会了如何将复杂任务分解,并通过定义“工具”来赋予大模型执行能力,这是构建实用AI应用的关键。
- 工程化实践:涵盖了环境搭建、依赖管理、API设计、错误处理等全流程,是一个完整的全栈+AI项目经验。
如何用于毕设/面试:
- 毕设:你可以在此基础上,深化任意一个进阶方向。例如,实现完整的RAG知识库,并撰写对比实验报告;或者实现一个多Agent协作系统(如询价Agent、风控Agent、调度Agent)。
- 面试:在介绍项目时,重点突出你的架构设计能力(为什么拆分成两个服务)、技术选型思考(为什么用LangChain而不是直接调API)、问题解决能力(在集成中遇到了什么坑,如何解决的)。你完全可以自信地说,你实现了一个具备初步自主决策能力的AI业务系统。
项目的完整源码,包含了更详细的注释和一些额外的工具示例,你可以在此基础上继续探索,比如接入微信小程序、增加语音交互、实现更复杂的多轮谈判Agent等。技术的价值在于解决实际问题,希望这个项目能成为你探索AI应用世界的一块坚实跳板。