spring-ai-alibaba使用Agent实现智能机票助手

示例目标是使用 Spring AI Alibaba 框架开发一个智能机票助手,它可以帮助消费者完成机票预定、问题解答、机票改签、取消等动作,具体要求为:

  • 基于 AI 大模型与用户对话,理解用户自然语言表达的需求
  • 支持多轮连续对话,能在上下文中理解用户意图
  • 理解机票操作相关的术语与规范并严格遵守,如航空法规、退改签规则等
  • 在必要时可调用工具辅助完成任务
使用 RAG 增加机票退改签规则

基于以上架构图,应用是由 AI 模型理解用户问题,决策下一步动作、驱动业务流程。但任何一个通用的大模型都能帮我们解决机票相关的问题吗?依赖模型的决策是可靠的吗?比如有用户提出了机票改签的诉求,模型一定是能够很好的理解用户的意图的,这点没有疑问。但它怎么知道当前用户符不符合退票规则呢?要知道每个航空公司的改签规则可能都是不一样的;它怎么知道改签手续费的规定那?在这样一个可能带来经济纠纷、法律风险的应用场景下,AI模型必须要知道改签规则的所有细节,并逐条确认用户信息符合规则后,才能最终作出是否改签的决策。

很显然,单纯依赖 AI 模型本身并不能替我们完成上面的要求,这个时候就要用到 RAG(检索增强)模式了。通过 RAG 我们可以把机票退改签相关的领域知识输入给应用和 AI 模型,让 AI 结合这些规则与要求辅助决策

使用 Function Calling 执行业务动作

AI 智能体可以帮助应用理解用户需求并作出决策,但是它没法代替应用完成决策的执行,决策的执行还是要由应用自己完成,这一点和传统应用并没有区别,不论是智能化的还是预先编排好的应用,都是要由应用本身去调用函数修改数据库记录实现数据持久化。

通过 Spring AI 框架,我们可以将模型的决策转换为对某个具体函数的调用,从而完成机票的最终改签或者退票动作,将用户数据写入数据库,这就是我们前面提到的 Function Calling 模式。

使用 Chat Memory 增加多轮对话能力

最后一点是关于多轮连续对话的支持,我们要记住一点,大模型是无状态的,它看到的只有当前这一轮对话的内容。因此如果要支持多轮对话效果,需要应用每次都要把之前的对话上下文保留下来,并与最新的问题一并作为 prompt 发送给模型。这时,我们可以利用 Spring AI Alibaba 提供的内置 Conversation Memory 支持,方便的维护对话上下文。

总结起来,我们在这个智能机票助手应用中用到了 Spring AI Alibaba 的核心如下能力:

  1. 基本模型对话能力,通过 Chat Model API 与阿里云通义模型交互
  2. Prompt 管理能力
  3. Chat Memory 聊天记忆,支持多轮对话
  4. RAG、Vector Store,机票预定、改签、退票等相关规则

1、jdk17 ,spring-ai-alibaba版本 1.0.0-M6.1,使用阿里云大模型,若使用其他模型添加对应依赖即可

pom文件

	<properties><java.version>17</java.version><vaadin.version>24.4.7</vaadin.version><maven-deploy-plugin.version>3.1.1</maven-deploy-plugin.version></properties><dependencies><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><!-- Other spring dependencies --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency></dependencies>

2、application.properties 内容如下

# spring.ai.chat.client.enabled=false
server.port=19000
spring.threads.virtual.enabled=truespring.mvc.static-path-pattern=/templates/**
spring.thymeleaf.cache=false
###################
# Anthropic Claude 3
#################### spring.ai.anthropic.api-key=${ANTHROPIC_API_KEY}
# spring.ai.openai.chat.options.model=llama3-70b-8192
# spring.ai.anthropic.chat.options.model=claude-3-5-sonnet-20240620###################
# Groq
#################### spring.ai.openai.api-key=${GROQ_API_KEY}
# spring.ai.openai.base-url=https://api.groq.com/openai
# spring.ai.openai.chat.options.model=llama3-70b-8192###################
# dashscope
###################
spring.ai.dashscope.api-key=${AI_DASHSCOPE_API_KEY}
spring.ai.dashscope.chat.options.model=qwen-plus
spring.ai.dashscope.embedding.enabled=true
spring.ai.dashscope.embedding.options.model=text-embedding-v2###################
# OpenAI
###################
# spring.ai.openai.chat.options.functions=getBookingDetails,changeBooking,cancelBooking
# spring.ai.openai.chat.enabled=false# Disable the OpenAI embedding when the local huggingface embedding (e.g. spring-ai-transformers-spring-boot-starter) is used.
# spring.ai.openai.embedding.enabled=false###################
# Azure OpenAI
###################
# spring.ai.azure.openai.api-key=${AZURE_OPENAI_API_KEY}
# spring.ai.azure.openai.endpoint=${AZURE_OPENAI_ENDPOINT}
# spring.ai.azure.openai.chat.options.deployment-name=gpt-4o###################
# Mistral AI
#################### spring.ai.mistralai.api-key=${MISTRAL_AI_API_KEY}
# spring.ai.mistralai.chat.options.model=mistral-small-latest# spring.ai.mistralai.chat.options.model=mistral-small-latest
# spring.ai.mistralai.chat.options.functions=getBookingDetails,changeBooking,cancelBooking
# # spring.ai.retry.on-client-errors=true
# # spring.ai.retry.exclude-on-http-codes=429###################
# Vertex AI Gemini
#################### spring.ai.vertex.ai.gemini.project-id=${VERTEX_AI_GEMINI_PROJECT_ID}
# spring.ai.vertex.ai.gemini.location=${VERTEX_AI_GEMINI_LOCATION}
# spring.ai.vertex.ai.gemini.chat.options.model=gemini-1.5-pro-001
# # spring.ai.vertex.ai.gemini.chat.options.model=gemini-1.5-flash-001
# spring.ai.vertex.ai.gemini.chat.options.transport-type=REST# spring.ai.vertex.ai.gemini.chat.options.functions=getBookingDetails,changeBooking,cancelBooking###################
#  Milvus Vector Store
###################
# Change the dimentions to 384 if the local huggingface embedding (e.g. spring-ai-transformers-spring-boot-starter) is used.
# spring.ai.vectorstore.milvus.embedding-dimension=384###################
# PGVector
###################
# spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
# spring.datasource.username=postgres
# spring.datasource.password=postgres###################
# QDrant
###################
# spring.ai.vectorstore.qdrant.host=localhost
# spring.ai.vectorstore.qdrant.port=6334###################
# Chroma
###################
# spring.ai.vectorstore.chroma.client.host=http://localhost
# spring.ai.vectorstore.chroma.client.port=8000

3、知识库文本文件  terms-of-service.txt  内容如下

These Terms of Service govern your experience with Funnair. By booking a flight, you agree to these terms.1. Booking Flights
- Book via our website or mobile app.
- Full payment required at booking.
- Ensure accuracy of personal information (Name, ID, etc.) as corrections may incur a $25 fee.2. Changing Bookings
- Changes allowed up to 24 hours before flight.
- Change via online or contact our support.
- Change fee: $50 for Economy, $30 for Premium Economy, Free for Business Class.3. Cancelling Bookings
- Cancel up to 48 hours before flight.
- Cancellation fees: $75 for Economy, $50 for Premium Economy, $25 for Business Class.
- Refunds processed within 7 business days.

4、初始化向量库和对话记忆等

package ai.spring.demo.ai.playground.config;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.reader.TextReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.web.client.RestClient;@Configuration
public class InitConfig {private static final Logger logger = LoggerFactory.getLogger(InitConfig.class);@Beanpublic VectorStore vectorStore(EmbeddingModel embeddingModel) {//初始化向量库return SimpleVectorStore.builder(embeddingModel).build();}@BeanCommandLineRunner ingestTermOfServiceToVectorStore(VectorStore vectorStore,@Value("classpath:rag/terms-of-service.txt") Resource termsOfServiceDocs) {//加载机票票务相关知识到向量库return args -> {// Ingest the document into the vector storevectorStore.write(new TokenTextSplitter().transform(new TextReader(termsOfServiceDocs).read()));vectorStore.similaritySearch("Cancelling Bookings").forEach(doc -> {logger.info("Similar Document: {}", doc.getText());});};}@Beanpublic ChatMemory chatMemory() {//对话记忆return new InMemoryChatMemory();}@Bean@ConditionalOnMissingBeanpublic RestClient.Builder restClientBuilder() {return RestClient.builder();}}

5、机票信息、机票类型、机票状态、等相关实体类

package ai.spring.demo.ai.playground.data;public enum BookingClass {
//	机票类型 头等 商务FIRST ,BUSINESS}
package ai.spring.demo.ai.playground.data;public enum BookingStatus {
//机票状态 已确认  已使用 已取消CONFIRMED, COMPLETED, CANCELLED}

package ai.spring.demo.ai.playground.data;import java.time.LocalDate;/*** 机票信息*/
public class Booking {/*** 订单号*/private String bookingNumber;/*** 订单日期*/private LocalDate date;/*** 购票信息*/private Customer customer;/*** 出发城市*/private String from;/*** 到达城市*/private String to;/*** 票务状态*/private BookingStatus bookingStatus;/*** 票务种类*/private BookingClass bookingClass;public Booking(String bookingNumber, LocalDate date, Customer customer, BookingStatus bookingStatus, String from,String to, BookingClass bookingClass) {this.bookingNumber = bookingNumber;this.date = date;this.customer = customer;this.bookingStatus = bookingStatus;this.from = from;this.to = to;this.bookingClass = bookingClass;}public String getBookingNumber() {return bookingNumber;}public void setBookingNumber(String bookingNumber) {this.bookingNumber = bookingNumber;}public LocalDate getDate() {return date;}public void setDate(LocalDate date) {this.date = date;}public Customer getCustomer() {return customer;}public void setCustomer(Customer customer) {this.customer = customer;}public BookingStatus getBookingStatus() {return bookingStatus;}public void setBookingStatus(BookingStatus bookingStatus) {this.bookingStatus = bookingStatus;}public String getFrom() {return from;}public void setFrom(String from) {this.from = from;}public String getTo() {return to;}public void setTo(String to) {this.to = to;}public BookingClass getBookingClass() {return bookingClass;}public void setBookingClass(BookingClass bookingClass) {this.bookingClass = bookingClass;}}
package ai.spring.demo.ai.playground.data;import java.util.ArrayList;
import java.util.List;/*** 购票信息*/
public class Customer {/*** 购票人姓名*/private String name;/*** 购票人的票务信息*/private List<Booking> bookings = new ArrayList<>();public Customer() {}public Customer(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}public List<Booking> getBookings() {return bookings;}public void setBookings(List<Booking> bookings) {this.bookings = bookings;}}

下面的类 是模拟数据库

package ai.spring.demo.ai.playground.data;import java.util.ArrayList;
import java.util.List;/*** 模拟数据库表 包含票务相关信息*/
public class BookingData {private List<Customer> customers = new ArrayList<>();private List<Booking> bookings = new ArrayList<>();public List<Customer> getCustomers() {return customers;}public void setCustomers(List<Customer> customers) {this.customers = customers;}public List<Booking> getBookings() {return bookings;}public void setBookings(List<Booking> bookings) {this.bookings = bookings;}}

6、机票服务类(包含数据初始化、退票、改签等业务方法)、智能体工具和智能体实现

package ai.spring.demo.ai.playground.services;import ai.spring.demo.ai.playground.data.*;
import ai.spring.demo.ai.playground.services.BookingTools.BookingDetails;import org.springframework.stereotype.Service;import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;/*** 模拟票务业务层*/
@Service
public class FlightBookingService {private final BookingData db;public FlightBookingService() {// 机票预定等服务db = new BookingData();//初始化机票票务信息 模拟数据库initDemoData();}private void initDemoData() {//模拟数据库List<String> names = List.of("赵敏", "周芷若", "小昭", "阿秀", "黄蓉","穆念慈","陆无双","程英","郭芙","郭襄","钟灵","曾柔","双儿");List<String> airportCodes = List.of("北京", "上海", "广州", "深圳", "杭州", "南京", "青岛", "成都", "武汉", "西安", "重庆", "大连","天津");Random random = new Random();var customers = new ArrayList<Customer>();var bookings = new ArrayList<Booking>();for (int i = 0; i < 13; i++) {String name = names.get(i);String from = airportCodes.get(random.nextInt(airportCodes.size()));String to = airportCodes.get(random.nextInt(airportCodes.size()));BookingClass bookingClass = BookingClass.values()[random.nextInt(BookingClass.values().length)];Customer customer = new Customer();customer.setName(name);LocalDate date = LocalDate.now().plusDays(2 * (i + 1));Booking booking = new Booking("10" + (i + 1), date, customer, BookingStatus.CONFIRMED, from, to,bookingClass);customer.getBookings().add(booking);customers.add(customer);bookings.add(booking);}// Reset the database on each startdb.setCustomers(customers);db.setBookings(bookings);}/*** 获取数据库所有票务信息* @return*/public List<BookingDetails> getBookings() {return db.getBookings().stream().map(this::toBookingDetails).toList();}/*** 根据订单号 合购票者姓名查找票务信息* @param bookingNumber* @param name* @return*/private Booking findBooking(String bookingNumber, String name) {return db.getBookings().stream().filter(b -> b.getBookingNumber().equalsIgnoreCase(bookingNumber)).filter(b -> b.getCustomer().getName().equalsIgnoreCase(name)).findFirst().orElseThrow(() -> new IllegalArgumentException("Booking not found"));}/*** 根据订单号 合购票者姓名查找票务信息* @param bookingNumber* @param name* @return*/public BookingDetails getBookingDetails(String bookingNumber, String name) {var booking = findBooking(bookingNumber, name);return toBookingDetails(booking);}/*** 改签票务* @param bookingNumber* @param name* @param newDate* @param from* @param to*/public void changeBooking(String bookingNumber, String name, String newDate, String from, String to) {var booking = findBooking(bookingNumber, name);if (booking.getDate().isBefore(LocalDate.now().plusDays(1))) {throw new IllegalArgumentException("Booking cannot be changed within 24 hours of the start date.");}booking.setDate(LocalDate.parse(newDate));booking.setFrom(from);booking.setTo(to);}/*** 退票* @param bookingNumber* @param name*/public void cancelBooking(String bookingNumber, String name) {var booking = findBooking(bookingNumber, name);if (booking.getDate().isBefore(LocalDate.now().plusDays(2))) {throw new IllegalArgumentException("Booking cannot be cancelled within 48 hours of the start date.");}booking.setBookingStatus(BookingStatus.CANCELLED);}private BookingDetails toBookingDetails(Booking booking) {return new BookingDetails(booking.getBookingNumber(), booking.getCustomer().getName(), booking.getDate(),booking.getBookingStatus(), booking.getFrom(), booking.getTo(), booking.getBookingClass().toString());}}
package ai.spring.demo.ai.playground.services;import java.time.LocalDate;
import java.util.function.Function;import ai.spring.demo.ai.playground.data.BookingStatus;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Description;
import org.springframework.core.NestedExceptionUtils;@Configuration
public class BookingTools {private static final Logger logger = LoggerFactory.getLogger(BookingTools.class);@Autowiredprivate FlightBookingService flightBookingService;/*** 获取票务信息工具请求* @param bookingNumber* @param name*/public record BookingDetailsRequest(String bookingNumber, String name) {}/*** 改签票务工具请求* @param bookingNumber* @param name* @param date* @param from* @param to*/public record ChangeBookingDatesRequest(String bookingNumber, String name, String date, String from, String to) {}/*** 退票工具请求* @param bookingNumber* @param name*/public record CancelBookingRequest(String bookingNumber, String name) {}/*** 获取票务信息工具返回* @param bookingNumber* @param name* @param date* @param bookingStatus* @param from* @param to* @param bookingClass*/@JsonInclude(Include.NON_NULL)public record BookingDetails(String bookingNumber, String name, LocalDate date, BookingStatus bookingStatus,String from, String to, String bookingClass) {}/*** 获取机票预定详细信息 工具* @return*/@Bean@Description("获取机票预定详细信息")public Function<BookingDetailsRequest, BookingDetails> getBookingDetails() {return request -> {try {return flightBookingService.getBookingDetails(request.bookingNumber(), request.name());}catch (Exception e) {logger.warn("Booking details: {}", NestedExceptionUtils.getMostSpecificCause(e).getMessage());return new BookingDetails(request.bookingNumber(), request.name(), null, null, null, null, null);}};}/*** 修改机票预定日期工具* @return*/@Bean@Description("修改机票预定日期")public Function<ChangeBookingDatesRequest, String> changeBooking() {return request -> {flightBookingService.changeBooking(request.bookingNumber(), request.name(), request.date(), request.from(),request.to());return "";};}/*** 取消机票预定 工具* @return*/@Bean@Description("取消机票预定")public Function<CancelBookingRequest, String> cancelBooking() {return request -> {flightBookingService.cancelBooking(request.bookingNumber(), request.name());return "";};}}

/** Copyright 2024-2024 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package ai.spring.demo.ai.playground.services;import java.time.LocalDate;import reactor.core.publisher.Flux;import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.stereotype.Service;import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;/*** 智能机票助手 agent*/
@Service
public class CustomerSupportAssistant {private final ChatClient chatClient;public CustomerSupportAssistant(ChatClient.Builder modelBuilder, VectorStore vectorStore, ChatMemory chatMemory) {// 初始化 Agent 智能体this.chatClient = modelBuilder.defaultSystem("""您是“Funnair”航空公司的客户聊天支持代理。请以友好、乐于助人且愉快的方式来回复。您正在通过在线聊天系统与客户互动。您能够支持已有机票的预订详情查询、机票日期改签、机票预订取消等操作,其余功能将在后续版本中添加,如果用户问的问题不支持请告知详情。在提供有关机票预订详情查询、机票日期改签、机票预订取消等操作之前,您必须始终从用户处获取以下信息:预订号、客户姓名。在询问用户之前,请检查消息历史记录以获取预订号、客户姓名等信息,尽量避免重复询问给用户造成困扰。在更改预订之前,您必须确保条款允许这样做。如果更改需要收费,您必须在继续之前征得用户同意。使用提供的功能获取预订详细信息、更改预订和取消预订。如果需要,您可以调用相应函数辅助完成。请讲中文。今天的日期是 {current_date}.""").defaultAdvisors(//对话记忆new PromptChatMemoryAdvisor(chatMemory), // Chat Memory// new VectorStoreChatMemoryAdvisor(vectorStore)),//RAG知识库new QuestionAnswerAdvisor(vectorStore, SearchRequest.builder().topK(4).similarityThresholdAll().build()), // RAG// new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults()// 	.withFilterExpression("'documentType' == 'terms-of-service' && region in ['EU', 'US']")),// loggernew SimpleLoggerAdvisor())//定义工具  对应 BookingTools中的三个方法.defaultFunctions("getBookingDetails", "changeBooking", "cancelBooking") // FUNCTION CALLING.build();}public Flux<String> chat(String chatId, String userMessageContent) {return this.chatClient.prompt()
//				current_date  defaultSystem中的变量.system(s -> s.param("current_date", LocalDate.now().toString())).user(userMessageContent).advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId).param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)).stream().content();}}

7、机票列表接口和智能体对话接口

package ai.spring.demo.ai.playground.client;import ai.spring.demo.ai.playground.services.BookingTools.BookingDetails;
import ai.spring.demo.ai.playground.services.FlightBookingService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.List;@Controller
@RequestMapping("/")
public class BookingController {private final FlightBookingService flightBookingService;public BookingController(FlightBookingService flightBookingService) {this.flightBookingService = flightBookingService;}@RequestMapping("/")public String index() {return "index";}/*** 获取数据库所有票务信息* @return*/@RequestMapping("/api/bookings")@ResponseBodypublic List<BookingDetails> getBookings() {return flightBookingService.getBookings();}}

package ai.spring.demo.ai.playground.client;import ai.spring.demo.ai.playground.services.CustomerSupportAssistant;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;@RequestMapping("/api/assistant")
@RestController
public class AssistantController {private final CustomerSupportAssistant agent;public AssistantController(CustomerSupportAssistant agent) {this.agent = agent;}@RequestMapping(path="/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<String> chat(String chatId, String userMessage) {return agent.chat(chatId, userMessage);}}

8、页面展示如下

访问  http://127.0.0.1:19000/

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/76962.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

嵌入式C语言高级编程:OOP封装、TDD测试与防御性编程实践

一、面向对象编程(OOP) 尽管 C 语言并非面向对象编程语言&#xff0c;但借助一些编程技巧&#xff0c;也能实现面向对象编程&#xff08;OOP&#xff09;的核心特性&#xff0c;如封装、继承和多态。 1.1 封装 封装是把数据和操作数据的函数捆绑在一起&#xff0c;对外部隐藏…

蓝桥杯 web 常考到的一些知识点

filter&#xff1a;filter方法创建一个新数组&#xff0c;其包含通过所提供函数实现的测试的所有元素。这个 方法不会改变原数组&#xff0c;而是返回一个新的数组。 map&#xff1a;map方法创建一个新数组&#xff0c;其结果是该数组中的每个元素都调用一个提供的函数后的 返回…

音视频小白系统入门笔记-0

本系列笔记为博主学习李超老师课程的课堂笔记&#xff0c;仅供参阅 音视频小白系统入门课 音视频基础ffmpeg原理 绪论 ffmpeg推流 ffplay/vlc拉流 使用rtmp协议 ffmpeg -i <source_path> -f flv rtmp://<rtmp_server_path> 为什么会推流失败&#xff1f; 默认…

mysql按条件三表并联查询

下面为你呈现一个 MySQL 按条件三表并联查询的示例。假定有三个表&#xff1a;students、courses 和 enrollments&#xff0c;它们的结构和关联如下&#xff1a; students 表&#xff1a;包含学生的基本信息&#xff0c;有 student_id 和 student_name 等字段。courses 表&…

UML之序列图的消息

序列图表现各参与者之间为完成某个行为而发生的交互及其时间顺序&#xff0c;序列图中的交互通过消息实现。消息是从一条生命线到另一条生命线的通信&#xff0c;它们通常是水平或倾斜向下的箭头&#xff0c;从发送方生命线离开&#xff0c;到达接收方生命线。如果需要&#xf…

UniAD:自动驾驶的统一架构 - 创新与挑战并存

引言 自动驾驶技术正经历一场架构革命。传统上&#xff0c;自动驾驶系统采用模块化设计&#xff0c;将感知、预测和规划分离为独立组件。而上海人工智能实验室的OpenDriveLab团队提出的UniAD&#xff08;Unified Autonomous Driving&#xff09;则尝试将这些任务整合到一个统一…

如何写好合同管理系统需求分析

引言 在当今企业数字化转型的浪潮中&#xff0c;合同管理系统作为企业法律合规和商业运营的重要支撑工具&#xff0c;其需求分析的准确性和完整性直接关系到系统建设的成败。本文基于Volere需求过程方法论&#xff0c;结合江铃汽车集团合同管理系统需求规格说明书实践案例&…

libevent服务器附带qt界面开发(附带源码)

本章是入门章节&#xff0c;讲解如何实现一个附带界面的服务器&#xff0c;后续会完善与优化 使用qt编译libevent源码演示视频qt的一些知识 1.主要功能有登录界面 2.基于libevent实现的服务器的业务功能 使用qt编译libevent 下载这个&#xff0c;其他版本也可以 主要是github上…

八、自动化函数

1.元素的定位 web自动化测试的操作核心是能够找到页面对应的元素&#xff0c;然后才能对元素进行具体的操作。 常见的元素定位方式非常多&#xff0c;如id,classname,tagname,xpath,cssSelector 常用的主要由cssSelector和xpath 1.1 cssSelector选择器 选择器的功能&#x…

Web三漏洞学习(其二:sql注入)

靶场&#xff1a;NSSCTF 、云曦历年考核题 二、sql注入 NSSCTF 【SWPUCTF 2021 新生赛】easy_sql 这题虽然之前做过&#xff0c;但为了学习sql&#xff0c;整理一下就再写一次 打开以后是杰哥的界面 注意到html网页标题的名称是 “参数是wllm” 那就传参数值试一试 首先判…

单片机非耦合业务逻辑框架

在小型单片机项目开发初期&#xff0c;由于业务逻辑相对简单&#xff0c;我们往往较少关注程序架构层面的设计。 然而随着项目经验的积累&#xff0c;开发者会逐渐意识到模块间的耦合问题&#xff1a;当功能迭代时&#xff0c;一处修改可能引发连锁反应。 此时&#xff0c;构…

Zookeeper三台服务器三节点集群部署(docker-compose方式)

1. 准备工作 - 服务器:3 台服务器,IP 地址分别为 `10.10.10.11`、`10.10.10.12`、`10.10.10.13`。 - 安装 Docker:确保每台服务器已安装 Docker 和 Docker Compose。 - 网络通信:确保三台服务器之间可以通过 IP 地址互相访问,并开放以下端口: - `2181`:Zookeeper 客户…

Mac关闭sip方法

Mac关闭sip方法 导航 文章目录 Mac关闭sip方法导航完整操作流程图详细步骤 完整操作流程图 这东西是我在网上搬运下来的&#xff0c;但是我在为业务实操过程中&#xff0c;根据实操情况还是有新的注意点的 详细步骤 1.在「关于本机」-「系统报告」-「软件」;查看SIP是否开启…

C++| 深入剖析std::list底层实现:链表结构与内存管理机制

引言 std::list的底层实现基于双向链表&#xff0c;其设计哲学与std::vector截然不同。本文将深入探讨其节点结构、内存分配策略及迭代器实现原理&#xff0c;揭示链表的性能优势和潜在代价。 1. 底层数据结构&#xff1a;双向链表 每个std::list节点包含&#xff1a; 数据域…

汉诺塔问题——用贪心算法解决

目录 一&#xff1a;起源 二&#xff1a;问题描述 三&#xff1a;规律 三&#xff1a;解决方案 递归算法 四&#xff1a;代码实现 复杂度分析 一&#xff1a;起源 汉诺塔&#xff08;Tower of Hanoi&#xff09;问题起源于一个印度的古老传说。在世界中心贝拿勒斯&#…

【Python】Python 100题 分类入门练习题 - 新手友好

Python 100题 分类入门练习题 - 新手友好篇 - 整合篇 一、数学问题题目1&#xff1a;组合数字题目2&#xff1a;利润计算题目3&#xff1a;完全平方数题目4&#xff1a;日期天数计算题目11&#xff1a;兔子繁殖问题题目18&#xff1a;数列求和题目19&#xff1a;完数判断题目21…

【linux】--- 进程概念

进程概念 1.认识冯诺依曼结构2. 操作系统&#xff08;Operator system)2.1 概念2.2 设计OS的目的2.3 理解操作系统2.4 如何理解管理2.5 理解系统调用和库函数 3. 进程3.1 基本概念和基本操作3.1.1 描述进程 - PCB3.1.2 task_struct3.1.3 查看进程 3.2 进程状态3.2.1 运行&&…

算法堆排序记录

【算法】排序算法之堆排序 - 知乎 应用场景&#xff1a;获取第n个大或者小的数 操作步骤&#xff1a; 1、将数组构造成堆 2、调整根节点为最大堆 ->倒序对每个根节点执行最大化 ->根节点最大化过程中如果发生交换&#xff0c;需要保证子节点也为最大堆&#xff08;执行…

STM32 模块化开发实战指南:系列介绍

本文是《STM32 模块化开发实战指南》系列的导读篇,旨在介绍整个系列的写作目的、适用读者、技术路径和每一篇的主题规划。适合从事 STM32、裸机或 RTOS 嵌入式开发的个人开发者、初创工程师或企业项目团队。 为什么要写这个系列? 在嵌入式开发中,很多人刚开始都是从点亮一个…

【眼底辅助诊断开放平台】项目笔记

这是一个标题 任务一前端页面开发&#xff1a;后端接口配置&#xff1a; 任务二自行部署接入服务 日志修改样式和解析MD文档接入服务 Note前端登陆不进去/更改后端api接口304 Not Modifiedlogin.cache.jsonERR_CONNECTION_TIMED_OUT跨域一般提交格式proxy.ts src/coponents 目录…