LLM MCP模型上下文协议快速入门(for Java)

news2025/4/20 18:30:30

什么是MCP

Model Control Protocol(MCP)是由AI研究机构Anthropic在2023年第二季度首次提出的新型协议规范,旨在解决大语言模型LLM应用中的上下文管理难题。作为LLM交互领域的创新标准,MCP协议在发布后短短一年内已进行了多次更新,最近一次更新是在2025-03-26(Key Changes - Model Context Protocol),包含 添加了一个基于 OAuth 2.1 的全面的授权框架 等内容变更:

协议定义与核心价值

MCP是一套开放式的通信协议,它通过标准化:

  1. 上下文结构化表示(JSON Schema)
  2. 多轮对话状态跟踪机制
  3. 模型控制指令集

使开发者能够精准控制LLM的上下文窗口,解决传统对话系统中存在的:

  • 上下文丢失(Context Bleeding)
  • 指令冲突
  • 长文本处理低效等痛点

成熟度

目前MCP已被Claude系列模型原生支持,并在Llama 3、Mistral等开源模型中实现兼容。行业分析显示,超过43%的企业级LLM应用已开始采用MCP作为首选上下文管理方案(数据来源:2024 ML Stack调查报告)。

MCP的目标对象

刚开始接触MCP的开发者可能会进入一个误区,以为有了MCP后,LLM是不是可以直接调用MCP Server的能力(API)了,其实并不是,LLM实际上是无法感知MCP的存在的。

MCP(Model Control Protocol)的核心目标对象是LLM应用开发者,而不是LLM(大语言模型)本身。要理解这一点,我们需要明确LLM和LLM应用的区别:  

1. LLM vs. LLM应用

  • LLM(大语言模型):指底层的大模型(如GPT-4、Claude、Llama等),它们负责接收输入并生成文本输出,但本身不具备复杂的状态管理或上下文控制能力。  
  • LLM应用:指基于LLM构建的完整系统,如聊天机器人、AI助手、代码生成工具等。这些应用需要管理多轮对话、维护上下文、处理用户指令,并可能集成外部数据或API。  

2. 为什么LLM不能直接使用MCP

LLM本身是“无状态”的——它们仅对当前输入做出响应,而不会自动记住之前的交互。MCP的作用是让LLM应用能更高效地管理上下文,例如:

  • 维护对话历史(避免超出模型的上下文窗口限制)  
  • 动态调整提示词(prompt),确保LLM获得正确的背景信息  
  • 控制模型行为(如切换模式、调整生成参数)  

MCP协议定义了一套标准化的接口,让LLM应用能以结构化的方式与LLM交互,而不是让LLM自己去解析或执行这些逻辑。  

MCP作为外部协议而非模型内置机制,还有两大更关键原因:

  1. 训练成本问题:若MCP逻辑固化到LLM中,协议每次更新都需重新训练模型,带来极高的计算和迭代成本;

  2. 安全与权限挑战:若LLM直接通过MCP调用三方应用,权限管理(如数据访问、API鉴权)将难以控制,增加滥用风险。

因此,MCP设计为应用层协议,由外部系统管理上下文和资源,既保持LLM的通用性,又避免强耦合带来的运维负担。

3. MCP的目标用户

MCP主要面向:

  • LLM应用开发者:需要构建复杂对话系统或AI代理的工程师  
  • AI平台架构师:设计LLM基础设施,优化上下文管理和推理效率  
  • 企业级AI解决方案:需要稳定、可扩展的LLM交互协议  

简而言之,MCP不是让LLM自己“学会”管理上下文,而是为LLM应用提供一套标准化的控制机制,使开发者能更高效地构建可靠的AI系统。

MCP的主要角色和架构

MCP最核心的两个角色就是MCP客户端MCP服务端。参见:Model Context Protocol (MCP) :: Spring AI Reference

MCP Client

MCP 客户端是模型上下文协议 (MCP) 架构中的关键组件,负责建立和管理与 MCP 服务器的连接。对,你没听错,MCP体系中,客户端才是最复杂的,而且通常这个客户端也是由服务端应用(也就是前面说的LLM应用)来“使用”

它实现了协议的客户端功能,处理以下操作:

  • 协议版本协商以确保与服务器的兼容性
  • 能力协商以确定可用功能
  • 消息传输和 JSON-RPC 通信
  • 工具发现和执行
  • 资源访问和管理
  • 提示系统交互
  • 可选功能:
    • 根部管理
    • 采样支持
  • 同步和异步操作
  • 通信选择:
    • 基于 Stdio 的传输,用于基于进程的通信
    • 基于  SSE 客户端传输

你可以看到,通常是MCP客户端在“调用” LLM 和 MCP服务端 

MCP Server

MCP 服务器是模型上下文协议 (MCP) 架构中的基础组件,为客户端提供:

  • 资源:上下文和数据,供用户或 AI 模型使用。它们通常是 只读的,AI 模型可以读取资源数据,但不会直接修改或执行它们,所以一般是指数据库查询。
  • 提示:为用户提供模板化的消息和工作流程
  • 工具:AI模型执行的功能。它们通常是 动态的、有副作用的(如修改数据、发送消息、触发操作),所以一般是指AI调用

它实现了协议的服务器端,负责:

  • 服务器端协议操作实现

    • 工具曝光和发现

    • 基于 URI 访问的资源管理

    • 及时提供和处理模板

    • 与客户进行能力谈判

    • 结构化日志记录和通知

  • 并发客户端连接管理

  • 同步和异步 API 支持

  • 通信实施:

    • 基于 Stdio 的传输,用于基于进程的通信

    • 基于 SSE 服务器传输

通常来说MCP服务器是不直接使用LLM的(当然,如果你这个MCP服务器也是另一些MCP服务器的MCP客户端时也有可能需要直接使用LLM),它通常是我们常见的一个个业务系统。

这里需要特殊说明的是如果MCP客户端和MCP服务器是部署在一起的,那么可以使用Stdio( Standard Input/Output(标准输入/输出) 的缩写,指计算机程序与外部环境(如终端、文件或其他程序)进行数据交互的标准方式。它是操作系统提供的基础通信机制,几乎所有编程语言都支持 stdio 操作)的方式来进行通信。

一言以蔽之

通过MCP的角色、架构分析,大家应该有所感知,MCP就是通过定义一套标准协议,同时标准化通过LLM来使用应用能力来解决我们之前直接使用LLM去编排Function Call难度大、复杂度高以及效率低的问题

实战:构建MCP客户端和服务器(for Java)

说的再多都是虚的,得眼见为实,这里我们通过构建两个Spring应用来演示如何在本地来使用MCP。Spring框架早已提供对调用LLM能力的封装:Spring AI API :: Spring AI Reference,这里我们就使用Spring框架来构建MCP客户端和MCP服务器。

构建MCP服务器

MCP服务器相对比较简单,它负责把业务功能封装成一个个原子能力,供MCP客户端来使用,新建一个Maven项目mcp-server,pom.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.manzhizhen.mcp</groupId>
        <artifactId>mcp-study</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>mcp-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>mcp-server</name>
    <description>Demo project for mcp</description>

    <properties>
        <java.version>21</java.version>
        <spring-ai.version>1.0.0-M7</spring-ai.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

这里和常规的Spring Boot项目不同的是加了spring-ai的依赖,而且我们计划使用SSE来进行通信(Stdio方式生产不常用):

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
        </dependency>

接着,我们Copy官方的天气预报例子,构建一个通过经纬度查询天气预报(getWeatherForecastByLocation),另一个通过美国州代码来查询天气预报的接口(getAlerts),注意,这属于上面提到的MCP服务器提供的“工具Tool”类型。

我们先通过 org.springframework.ai.tool.annotation.Tool 注解完成工具的定义(参考 https://github.com/spring-projects/spring-ai-examples/tree/main/model-context-protocol/weather/starter-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/server):

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.RestClientException;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WeatherService {

    private final RestClient restClient;

    public WeatherService() {
        this.restClient = RestClient.builder()
                .baseUrl("https://api.weather.gov")
                .defaultHeader("Accept", "application/geo+json")
                .defaultHeader("User-Agent", "WeatherApiClient/1.0 (835576511@qq.com)")
                .build();
    }

    /**
     * Get forecast for a specific latitude/longitude
     * @param latitude Latitude
     * @param longitude Longitude
     * @return The forecast for the given location
     * @throws RestClientException if the request fails
     */
    @Tool(description = "Get weather forecast for a specific latitude/longitude")
    public String getWeatherForecastByLocation(
            double latitude,   // Latitude coordinate
            double longitude   // Longitude coordinate
    ) {
        log.info("Fetching forecast for coordinates: {}, {}", latitude, longitude);
        var points = restClient.get()
                .uri("/points/{latitude},{longitude}", latitude, longitude)
                .retrieve()
                .body(Points.class);

        var forecast = restClient.get().uri(points.properties().forecast()).retrieve().body(Forecast.class);

        String forecastText = forecast.properties().periods().stream().map(p -> {
            return String.format("""
                            %s:
                            Temperature: %s %s
                            Wind: %s %s
                            Forecast: %s
                            """, p.name(), p.temperature(), p.temperatureUnit(), p.windSpeed(), p.windDirection(),
                    p.detailedForecast());
        }).collect(Collectors.joining());

        return forecastText;
    }

    /**
     * Get alerts for a specific area
     * @param state Area code. Two-letter US state code (e.g. CA, NY)
     * @return Human readable alert information
     * @throws RestClientException if the request fails
     */
    @Tool(description = "Get weather alerts for a US state")
    public String getAlerts(
            @ToolParam(description = "Two-letter US state code (e.g. CA, NY)") String state) {

        log.info("Fetching alerts for state: {}", state);

        Alert alert = restClient.get().uri("/alerts/active/area/{state}", state).retrieve().body(Alert.class);

        return alert.features()
                .stream()
                .map(f -> String.format("""
					Event: %s
					Area: %s
					Severity: %s
					Description: %s
					Instructions: %s
					""", f.properties().event(), f.properties.areaDesc(), f.properties.severity(),
                        f.properties.description(), f.properties.instruction()))
                .collect(Collectors.joining("\n"));
    }


    @JsonIgnoreProperties(ignoreUnknown = true)
    public record Points(@JsonProperty("properties") Props properties) {
        @JsonIgnoreProperties(ignoreUnknown = true)
        public record Props(@JsonProperty("forecast") String forecast) {
        }
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    public record Forecast(@JsonProperty("properties") Props properties) {
        @JsonIgnoreProperties(ignoreUnknown = true)
        public record Props(@JsonProperty("periods") List<Period> periods) {
        }

        @JsonIgnoreProperties(ignoreUnknown = true)
        public record Period(@JsonProperty("number") Integer number, @JsonProperty("name") String name,
                             @JsonProperty("startTime") String startTime, @JsonProperty("endTime") String endTime,
                             @JsonProperty("isDaytime") Boolean isDayTime,
                             @JsonProperty("temperature") Integer temperature,
                             @JsonProperty("temperatureUnit") String temperatureUnit,
                             @JsonProperty("temperatureTrend") String temperatureTrend,
                             @JsonProperty("probabilityOfPrecipitation") Map probabilityOfPrecipitation,
                             @JsonProperty("windSpeed") String windSpeed,
                             @JsonProperty("windDirection") String windDirection,
                             @JsonProperty("icon") String icon, @JsonProperty("shortForecast") String shortForecast,
                             @JsonProperty("detailedForecast") String detailedForecast) {
        }
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    public record Alert(@JsonProperty("features") List<Feature> features) {

        @JsonIgnoreProperties(ignoreUnknown = true)
        public record Feature(@JsonProperty("properties") Properties properties) {
        }

        @JsonIgnoreProperties(ignoreUnknown = true)
        public record Properties(@JsonProperty("event") String event, @JsonProperty("areaDesc") String areaDesc,
                                 @JsonProperty("severity") String severity,
                                 @JsonProperty("description") String description,
                                 @JsonProperty("instruction") String instruction) {
        }
    }
}

@Tool是 Spring AI 项目中的一个注解,用于将 Java 方法标记为可由 AI 模型(如 OpenAI、Azure OpenAI 或其他支持的 AI 服务)调用的工具(Tool)。它的主要作用是将你的方法暴露给 MCP客户端,使它够动态调用这些方法来完成特定任务。其中 @Tool 完成方法整体的功能描述,而@ToolParam 可以进一步完成参数的说明,如果你参数名足够清晰,也可以不用加@ToolParam。

同时在我们的Spring Boot启动类中增加ToolCallbackProvider,这样才能真正把Tool暴露出去给MCP Client调用:

import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@Slf4j
@SpringBootApplication
public class McpServerApplication {

	public static void main(String[] args) {
		log.info("McpServerApplication 启动啦");
		SpringApplication.run(McpServerApplication.class, args);
	}

	/**
	 * Tools
	 * Allows servers to expose tools that can be invoked by language models.
	 * The auto-configuration will automatically register the tool callbacks as MCP tools.
	 * You can have multiple beans producing ToolCallbacks. The auto-configuration will merge them.
	 * @param weatherService
	 * @return
	 */
	@Bean
	public ToolCallbackProvider weatherTools(WeatherService weatherService) {
		return  MethodToolCallbackProvider.builder().toolObjects(weatherService).build();
	}
}

细心的朋友会发现,前面不是说有Stdio和SSE两种方式来暴露吗?目前看代码上没有体现?其实前面在pom.xml中我们依赖的spring-ai-starter-mcp-server-webmvc里面就依赖了:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

这里面就支持了SSE的实现,我们只需要在application.yml配置文件中配置一下即可:

server:
  port: 8090

spring:
  application:
    name: mcp-server
  main:
    banner-mode: off
  ai:
    mcp:
      server:
        name: mcp-server
        version: 1.0.0
        type: SYNC
        sse-message-endpoint: /mcp/messages

这里的 sse-message-endpoint 就是配置SSE的path。注意这里暴露的是8090端口。到这里,一个简单的MCP Server就构建完成了。

构建MCP客户端

前面说过通常MCP客户端是需要使用LLM的,这里我们首选DeepSeek,然后在DeepSeek开放平台官网创建Api Keys 再充10块钱,这样你就有了可用DeepSeek Api Key了:

同样,我们建一个Maven项目叫做mcp-client,pom.xml配置如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.manzhizhen.mcp</groupId>
        <artifactId>mcp-study</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>mcp-client</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>mcp-client</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>22</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-openai</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>33.3.1-jre</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>

其中和其他项目不同的是我们依赖了:

        
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-openai</artifactId>
        </dependency>

一个是为了支持mcp-client,一个是为了支持我们调用DeepSeek。由于只是做一个简单的演示,我们决定使用IDEA的控制台作为输入,来当做一个天气预报咨询平台。我们只需要修改启动类即可:

import io.modelcontextprotocol.client.McpSyncClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;

import java.util.List;
import java.util.Scanner;


@Slf4j
@SpringBootApplication
public class McpClientSseApplication {

	public static void main(String[] args) {
		SpringApplication.run(McpClientSseApplication.class, args);
	}


	@Bean
	public CommandLineRunner interactiveChatRunner(
			ChatClient.Builder chatClientBuilder,
			ToolCallbackProvider tools,
			ConfigurableApplicationContext context
	) {
		return args -> {
			var chatClient = chatClientBuilder
					.defaultTools(tools)
					.build();

			Scanner scanner = new Scanner(System.in); // 用于读取控制台输入

			System.out.println("=== 聊天模式已启动(输入 'exit' 退出) ===");

			while (true) {
				System.out.print("\n>>> 你的问题: ");
				String userInput = scanner.nextLine().trim();

				// 输入 "exit" 退出聊天
				if ("exit".equalsIgnoreCase(userInput)) {
					System.out.println(">>> 聊天结束,程序退出。");
					break;
				}

				// 空输入则跳过
				if (userInput.isEmpty()) {
					continue;
				}

				// 调用 AI 并打印回复
				System.out.println("\n>>> AI 回复: " + chatClient.prompt(userInput).call().content());
			}

			context.close(); // 关闭 Spring 上下文
		};
	}
}

可以看到,为了能不断的在控制台提问,我们写了一个while循环,当你输入exit才退出。

这里有一个关键,就是不管我们mcp-client连接了多少个mcp-server以及使用了多少个mcp-server的能力(例如Tool),我们都不需要去太关心细节,一行代码“chatClient.prompt(userInput).call().content()”就搞定,mcp内置的库类会去调用AI来根据你的问题“合理”的使用mcp-server提供的一个或者多个能力来完成任务,之前用Function Call可没有这么丝滑

对,mcp-client修改这一个类即可,接下来我们配置下application.yml:

spring:
  application:
    name: mcp-client
  ai:
    mcp:
      client:
        toolcallback:
          enabled: true
        enabled: true
        name: my-mcp-client
        version: 1.0.0
        request-timeout: 30s
        type: SYNC  # or ASYNC for reactive applications
        sse:
          connections:
            server1:
              url: http://localhost:8090

    openai:
      api-key: 这里填写你的DeepSeek api key
      base-url: https://api.deepseek.com
      chat:
        options:
          model: deepseek-chat
          temperature: 0.7
      embedding:
        enabled: false

可以看到,我们最重要的是要配置mcp-server的地址(这里由于mcp-server和mcp-client部署在一起,所以用的是localhost)以及我们的openai的类型和对于的api key。到这里,整个mcp-client示例我们也写完了。

看看效果

先运行mcp-server,再运行mcp-client,如果启动都没问题,那么我们在mcp-client的控制台可以进行天气预报咨询了:

>>> 你的问题: 帮我查下 纬度 (lat): 40.7128,经度 (lon): -74.0060 的天气

>>> AI 回复: 以下是纬度 40.7128,经度 -74.0060 的天气预报:

### 今天
- **温度**: 80°F
- **风速**: 10 到 23 mph,西南风
- **预报**: 上午8点前可能有零星小雨,随后可能有零星阵雨和雷暴。部分晴天,最高气温接近80°F。西南风10至23 mph,阵风高达39 mph。降水概率20%。

### 今晚
- **温度**: 57°F
- **风速**: 15 到 22 mph,西风
- **预报**: 凌晨2点前可能有零星阵雨和雷暴。大部分多云,最低气温约57°F,夜间气温升至62°F左右。西风15至22 mph,阵风高达38 mph。降水概率20%。

### 周日
- **温度**: 63°F
- **风速**: 15 到 20 mph,西北风
- **预报**: 大部分晴天,最高气温接近63°F。西北风15至20 mph。

...

可以看到我的问题携带了经纬度,所以最终是mcp-server的WeatherService#getWeatherForecastByLocation 被调用了。

>>> 你的问题: 美国 WA 州 天气预报

>>> AI 回复: 以下是美国华盛顿州(WA)的天气预报:

### 今晚
- **温度**: 44°F  
- **风速**: 9 mph 西北风  
- **预报**: 多云,最低气温约44°F。西北风约9 mph,阵风高达22 mph。

### 周六
- **温度**: 54°F  
- **风速**: 9至13 mph 西北风  
- **预报**: 大部分晴天,最高气温约54°F,下午气温降至约52°F。西北风9至13 mph,阵风高达29 mph。

### 周六晚
- **温度**: 38°F  
- **风速**: 10 mph 西北风  
- **预报**: 部分多云,最低气温约38°F。西北风约10 mph,阵风高达28 mph。

...

这个问题很明显想引导mcp-client去使用mcp-server的WeatherService#getAlerts,但由于getAlerts没有查到华盛顿州的数据,所以mcp-client最终通过DeepSeek拿到华盛顿州的经纬度47.7511, -120.7401 去调用了getWeatherForecastByLocation方法,真聪明!!!

总结

欢迎加作者WX sugarmq 一起来探讨技术话题。

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

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

相关文章

支持向量机(SVM):原理、应用与深入解析

内容摘要 本文深入探讨支持向量机&#xff08;SVM&#xff09;。阐述其作为分类算法在小样本、非线性及高维模式识别中的优势&#xff0c;详细介绍SVM基本概念、能解决的问题、核函数作用、对偶问题引入及常见核函数等内容&#xff0c;同时分析其优缺点&#xff0c;并与逻辑回…

chapter32_SpringMVC与DispatcherServlet

一、简介 从本章节开始进入SpringMVC的学习&#xff0c;SpringMVC最重要的类就是DispatcherServlet DispatcherServlet的本质是一个Servlet&#xff0c;回顾一下Servlet JavaWeb就是基于Servlet的Servlet接口有5个方法Servlet实现类是HttpServlet&#xff0c;自定义的Servle…

spring security解析

Spring Security 中文文档 :: Spring Security Reference 1. 密码存储 最早是明文存储&#xff0c;但是攻击者获得数据库的数据后就能得到用户密码。 于是将密码单向hash后存储&#xff0c;然后攻击者利用彩虹表&#xff08;算法高级&#xff08;23&#xff09;-彩虹表&…

STM32单片机C语言

1、stdint.h简介 stdint.h 是从 C99 中引进的一个标准 C 库的文件 路径&#xff1a;D:\MDK5.34\ARM\ARMCC\include 大家都统一使用一样的标准&#xff0c;这样方便移植 配置MDK支持C99 位操作 如何给寄存器某个值赋值 举个例子&#xff1a;uint32_t temp 0; 宏定义 带参…

多模态融合(十一): SwinFusion——武汉大学马佳义团队(二)

目录 一.摘要 二. Introduction 三. Related Work A. 特定任务图像融合方法 B. 通用图像融合方法 C. 视觉 Transformer 四.方法 A. 整体框架 B. 损失函数 C.解析 1. 整体框架 2. 特征提取 3. 注意力引导的跨域融合 五. 实验结果与讨论 A. 实验配置 B. 实现…

IDEA202403常用快捷键【持续更新】

文章目录 一、全局搜索二、美化格式三、替换四、Git提交五、代码移动六、调试运行 在使用IDEA进行程序开发&#xff0c;快捷键会让这个过程更加酸爽&#xff0c;下面记录各种快捷键的功能。 一、全局搜索 快捷键功能说明Shift Shift全局搜索Ctrl N搜索Java类 二、美化格式 …

从 LabelImg 到 Label Studio!AI 数据标注神器升级,Web 版真香

视频讲解&#xff1a; 从 LabelImg 到 Label Studio&#xff01;AI 数据标注神器升级&#xff0c;Web 版真香 Label Studio 支持图像、文本、音频、视频、时间序列等多类型数据标注&#xff0c;覆盖计算机视觉&#xff08;目标检测、语义分割&#xff09;、自然语言处理&#x…

【ESP32】ESP-IDF开发 | 低功耗蓝牙开发 | GAP协议 + 设备扫描例程

1. 简介 1.1 GAP协议 GAP&#xff08;General Access Protocol&#xff09;&#xff0c;全称通用访问协议&#xff0c;它定义了低功耗蓝牙设备的发现流程&#xff0c;设备管理和设备连接的建立。 低功耗蓝牙设备定义了4种角色&#xff1a; 广播者&#xff08;Broadcaster&…

网络开发基础(游戏)之 Socket API

Socket简介 Socket (套接字)是网络编程的基础&#xff0c;在 C# 中通过 System.Net.Sockets 命名空间提供了一套完整的 API 来实现网络通信。 网络上的两个程序通过一个双向的通信连接实现数据交换&#xff0c; 这个连接的一端称为一个Socket。 一个Socket包含了进行网络通信必…

行为审计软件:企业合规与内部监控的数字守门人

在当今高度数字化的商业环境中&#xff0c;企业运营产生的电子数据呈指数级增长&#xff0c;员工行为也日益复杂多样。行为审计软件应运而生&#xff0c;成为现代企业管理不可或缺的工具。这类软件通过系统化记录、分析和报告组织内部用户活动&#xff0c;帮助企业管理风险、确…

bat脚本转换为EXE应用程序文件

很多时候,我们使用电脑时会编辑bat脚本文件 很多时候&#xff0c;我们制作的玩笑&#xff0c;病毒也会使用这个格式. 但这个格式也有很多缺点 1,如果是需要管理员运行的程序,需要费劲的自己使用管理员身份运行 2,文件并不为大家所熟知,认同度不高 3,可以非常轻松的看到原代…

细说STM32单片机FreeRTOS任务管理API函数vTaskList()的使用方法

目录 一、函数vTaskList() 1、 函数说明 2、返回的字符串表格说明 3、函数的使用方法 二、 vTaskList()的应用示例 1、示例功能、项目设置 2、软件设计 &#xff08;1&#xff09;main.c &#xff08;2&#xff09;freertos.c &#xff08;3&#xff09;FreeRTOSConf…

DNS主从同步

安装软件 主配置中完成DNS解析&#xff1a;192.168.131.134 [rootlocalhost ~]# mount /dev/sr0 /mnt [rootlocalhost ~]# vim /etc/yum.repos.d/myrepo.repo [base] namebase baseurl/mnt/BaseOS gpgchcek0 enable1 [base2] namebase2 baseurl/mnt/AppStream gpgchcek0 enab…

双指针算法(部分例题解析)

快慢指针左右指针 前言 双指针&#xff0c;它通过设置两个指针来遍历数据&#xff0c;从而实现高效的查找、排序、去重等操作。双指针算法的核心在于通过合理地移动这两个指针&#xff0c;减少不必要的遍历&#xff0c;提高算法的效率。 283. 移动零 - 力扣&#xff08;LeetCo…

解决Windows打印问题的集成软件

家里或公司电脑经常为连不上打印机而烦恼&#xff0c;今天给大家推荐一款修复打印工具&#xff0c;该工具是采用易语言开发的集成化打印机故障修复软件&#xff0c;专为解决 Windows 系统&#xff08;含 32/64 位 Windows 7/10/11&#xff09;中因权限配置、服务异常、补丁缺失…

警惕阿里云中的yum update操作不当导致:/sbin/init被清空导致Linux无法正常启动

由于使用阿里云进行部署测试&#xff0c;因而会对yum update进行操作&#xff0c;这两天更新了systemd-239-82.0.3.4.al8.2.x86_64&#xff0c;但存在报错&#xff0c;然后进行yum history undo和清空yum cache&#xff0c;但出现操作Linux命令行无效。具体来说&#xff0c;几个…

关系型数据库MYSQL(续)

目录 三.MySQL事务原理分析 1.事务是什么&#xff1f; 2.执行事务的目的是什么&#xff1f; 3.事务是由什么组成的&#xff1f; 4.事务的特征是什么&#xff1f; 5.事务控制语句 6.ACID特性 6.1原子性&#xff08;A&#xff09; 6.2隔离性&#xff08;I&#xff09; …

WInform当今技术特性分析

Windows Forms (WinForms) 技术特性分析 引言 Windows Forms (WinForms) 作为微软最早推出的基于.NET的图形用户界面开发框架&#xff0c;已经存在了20多年。在如今充满了各种现代UI框架的软件开发生态系统中&#xff0c;WinForms仍然保持着其独特的地位。本文将深入分析WinF…

运筹学之模拟退火

目录 一、历史二、精髓思想三、案例与代码实现 一、历史 问&#xff1a;谁在什么时候提出模拟退火&#xff1f;答&#xff1a;模拟退火算法&#xff08;Simulated Annealing&#xff0c;SA&#xff09;是由斯图尔特柯尔斯基&#xff08;Scott Kirkpatrick&#xff09; 等人在 …

树莓派5-开发应用笔记

0.树莓派系统目录 /home&#xff1a;用户目录。 除了root用户外&#xff0c;其他所有的使用者的数据都存放在这个目录下&#xff0c;在树莓派的系统中&#xff0c;/home目录中有一个pi的子目录,这个就是pi用户的默认目录。 /bin&#xff1a; 主要放置系统的必备执行文件目录。 …