深度剖析Spring AI源碼(七):化繁為簡,Spring Boot自動配置的實現之秘

深度剖析Spring AI源碼(七):化繁為簡,Spring Boot自動配置的實現之秘

“Any sufficiently advanced technology is indistinguishable from magic.” —— Arthur C. Clarke

Spring Boot的自動配置就是這樣的"魔法"。只需要添加一個依賴,配置幾行YAML,復雜的AI模型和向量數據庫就能自動裝配完成。今天,讓我們揭開這個魔法背后的秘密,看看Spring AI是如何實現"零配置"的AI開發體驗的。

引子:從繁瑣到簡單的跨越

還記得在Spring AI出現之前,集成一個AI模型需要多少步驟嗎?

// 傳統方式 - 繁瑣的手動配置
@Configuration
public class OpenAiConfig {@Beanpublic OpenAiApi openAiApi() {return new OpenAiApi("your-api-key", "https://api.openai.com");}@Beanpublic OpenAiChatModel chatModel(OpenAiApi openAiApi) {return new OpenAiChatModel(openAiApi, OpenAiChatOptions.builder().model("gpt-4").temperature(0.7).maxTokens(1000).build());}@Beanpublic EmbeddingModel embeddingModel(OpenAiApi openAiApi) {return new OpenAiEmbeddingModel(openAiApi, OpenAiEmbeddingOptions.builder().model("text-embedding-ada-002").build());}@Beanpublic VectorStore vectorStore(EmbeddingModel embeddingModel, JdbcTemplate jdbcTemplate) {return PgVectorStore.builder(jdbcTemplate, embeddingModel).tableName("vector_store").initializeSchema(true).build();}@Beanpublic ChatClient chatClient(ChatModel chatModel) {return ChatClient.create(chatModel);}
}

而現在,只需要:

# application.yml
spring:ai:openai:api-key: ${OPENAI_API_KEY}chat:options:model: gpt-4temperature: 0.7vectorstore:pgvector:initialize-schema: true

這就是Spring Boot自動配置的魔力!

自動配置架構全景

讓我們先從架構層面理解Spring AI的自動配置體系:

Core Components
Vector Stores
AI Models
Spring Boot AutoConfiguration
ChatClient Bean
VectorStore Bean
EmbeddingModel Bean
ChatModel Bean
PgVector AutoConfiguration
Chroma AutoConfiguration
Pinecone AutoConfiguration
Qdrant AutoConfiguration
OpenAI AutoConfiguration
Anthropic AutoConfiguration
Azure OpenAI AutoConfiguration
Ollama AutoConfiguration
Spring Boot Starter
AutoConfiguration Classes
Configuration Properties
Conditional Annotations

核心自動配置類深度解析

1. OpenAI自動配置

讓我們深入OpenAI的自動配置實現(位于auto-configurations/models/spring-ai-autoconfigure-model-openai/src/main/java/org/springframework/ai/openai/autoconfigure/OpenAiAutoConfiguration.java):

@AutoConfiguration
@ConditionalOnClass(OpenAiApi.class)
@EnableConfigurationProperties({OpenAiConnectionProperties.class,OpenAiChatProperties.class,OpenAiEmbeddingProperties.class,OpenAiImageProperties.class
})
@ConditionalOnProperty(prefix = OpenAiChatProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
public class OpenAiAutoConfiguration {// 1. 連接詳情Bean - 處理連接信息@Bean@ConditionalOnMissingBean(OpenAiConnectionDetails.class)PropertiesOpenAiConnectionDetails openAiConnectionDetails(OpenAiConnectionProperties properties) {return new PropertiesOpenAiConnectionDetails(properties);}// 2. OpenAI API客戶端Bean@Bean@ConditionalOnMissingBeanpublic OpenAiApi openAiApi(OpenAiConnectionDetails connectionDetails,RestClient.Builder restClientBuilder,ObjectProvider<ObservationRegistry> observationRegistry,ObjectProvider<OpenAiApiObservationConvention> observationConvention) {String apiKey = connectionDetails.getApiKey();if (!StringUtils.hasText(apiKey)) {throw new IllegalArgumentException("OpenAI API key must be set");}String baseUrl = StringUtils.hasText(connectionDetails.getBaseUrl()) ? connectionDetails.getBaseUrl() : OpenAiApi.DEFAULT_BASE_URL;return new OpenAiApi(baseUrl, apiKey, restClientBuilder, observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP),observationConvention.getIfAvailable(() -> null));}// 3. 聊天模型配置@Configuration(proxyBeanMethods = false)@ConditionalOnProperty(prefix = OpenAiChatProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)static class ChatConfiguration {@Bean@ConditionalOnMissingBeanpublic OpenAiChatModel openAiChatModel(OpenAiApi openAiApi,OpenAiChatProperties chatProperties,ObjectProvider<ObservationRegistry> observationRegistry,ObjectProvider<ChatModelObservationConvention> observationConvention) {return OpenAiChatModel.builder().openAiApi(openAiApi).options(chatProperties.getOptions()).observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)).customObservationConvention(observationConvention.getIfAvailable(() -> null)).build();}}// 4. 嵌入模型配置@Configuration(proxyBeanMethods = false)@ConditionalOnProperty(prefix = OpenAiEmbeddingProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)static class EmbeddingConfiguration {@Bean@ConditionalOnMissingBeanpublic OpenAiEmbeddingModel openAiEmbeddingModel(OpenAiApi openAiApi,OpenAiEmbeddingProperties embeddingProperties,ObjectProvider<ObservationRegistry> observationRegistry,ObjectProvider<EmbeddingModelObservationConvention> observationConvention) {return OpenAiEmbeddingModel.builder().openAiApi(openAiApi).options(embeddingProperties.getOptions()).observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)).customObservationConvention(observationConvention.getIfAvailable(() -> null)).build();}}// 5. 圖像模型配置@Configuration(proxyBeanMethods = false)@ConditionalOnProperty(prefix = OpenAiImageProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)static class ImageConfiguration {@Bean@ConditionalOnMissingBeanpublic OpenAiImageModel openAiImageModel(OpenAiApi openAiApi,OpenAiImageProperties imageProperties,ObjectProvider<ObservationRegistry> observationRegistry,ObjectProvider<ImageModelObservationConvention> observationConvention) {return OpenAiImageModel.builder().openAiApi(openAiApi).options(imageProperties.getOptions()).observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)).customObservationConvention(observationConvention.getIfAvailable(() -> null)).build();}}
}

這個配置類的精妙之處:

  • 條件裝配:使用@ConditionalOnClass@ConditionalOnProperty等條件注解
  • 屬性綁定:通過@EnableConfigurationProperties綁定配置屬性
  • 依賴注入:使用ObjectProvider處理可選依賴
  • 模塊化設計:將不同功能分離到內部配置類中

2. 配置屬性類設計

// OpenAI連接屬性
@ConfigurationProperties(OpenAiConnectionProperties.CONFIG_PREFIX)
public class OpenAiConnectionProperties {public static final String CONFIG_PREFIX = "spring.ai.openai";/*** OpenAI API密鑰*/private String apiKey;/*** OpenAI API基礎URL*/private String baseUrl = OpenAiApi.DEFAULT_BASE_URL;/*** 組織ID(可選)*/private String organizationId;/*** 項目ID(可選)*/private String projectId;// getters and setters...
}// OpenAI聊天屬性
@ConfigurationProperties(OpenAiChatProperties.CONFIG_PREFIX)
public class OpenAiChatProperties {public static final String CONFIG_PREFIX = "spring.ai.openai.chat";/*** 是否啟用OpenAI聊天模型*/private boolean enabled = true;/*** 聊天模型選項*/private OpenAiChatOptions options = OpenAiChatOptions.builder().build();// getters and setters...
}

3. 向量存儲自動配置

讓我們看看PgVector的自動配置(位于auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-pgvector/src/main/java/org/springframework/ai/vectorstore/pgvector/autoconfigure/PgVectorStoreAutoConfiguration.java):

@AutoConfiguration(after = DataSourceAutoConfiguration.class)
@ConditionalOnClass({ PgVectorStore.class, JdbcTemplate.class, DataSource.class })
@EnableConfigurationProperties(PgVectorStoreProperties.class)
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.PGVECTOR, matchIfMissing = true)
public class PgVectorStoreAutoConfiguration {// 1. 連接詳情Bean@Bean@ConditionalOnMissingBean(PgVectorStoreConnectionDetails.class)PropertiesPgVectorStoreConnectionDetails pgVectorStoreConnectionDetails(PgVectorStoreProperties properties) {return new PropertiesPgVectorStoreConnectionDetails(properties);}// 2. 批處理策略Bean@Bean@ConditionalOnMissingBean(BatchingStrategy.class)BatchingStrategy batchingStrategy() {return new TokenCountBatchingStrategy();}// 3. PgVector存儲Bean@Bean@ConditionalOnMissingBeanpublic PgVectorStore vectorStore(JdbcTemplate jdbcTemplate,EmbeddingModel embeddingModel,PgVectorStoreProperties properties,ObjectProvider<ObservationRegistry> observationRegistry,ObjectProvider<VectorStoreObservationConvention> customObservationConvention,BatchingStrategy batchingStrategy) {return PgVectorStore.builder(jdbcTemplate, embeddingModel).schemaName(properties.getSchemaName()).tableName(properties.getTableName()).vectorTableName(properties.getVectorTableName()).indexType(properties.getIndexType()).distanceType(properties.getDistanceType()).dimensions(properties.getDimensions() != null ? properties.getDimensions() : embeddingModel.dimensions()).initializeSchema(properties.isInitializeSchema()).removeExistingVectorStoreTable(properties.isRemoveExistingVectorStoreTable()).observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)).customObservationConvention(customObservationConvention.getIfAvailable(() -> null)).batchingStrategy(batchingStrategy).build();}// 4. 內部連接詳情實現private static class PropertiesPgVectorStoreConnectionDetails implements PgVectorStoreConnectionDetails {private final PgVectorStoreProperties properties;PropertiesPgVectorStoreConnectionDetails(PgVectorStoreProperties properties) {this.properties = properties;}@Overridepublic String getSchemaName() {return this.properties.getSchemaName();}@Overridepublic String getTableName() {return this.properties.getTableName();}}
}

條件注解的巧妙運用

1. 類路徑條件

// 只有當OpenAiApi類存在于類路徑時才激活
@ConditionalOnClass(OpenAiApi.class)
public class OpenAiAutoConfiguration {// ...
}// 多個類都必須存在
@ConditionalOnClass({ PgVectorStore.class, JdbcTemplate.class, DataSource.class })
public class PgVectorStoreAutoConfiguration {// ...
}

2. 屬性條件

// 基于配置屬性的條件裝配
@ConditionalOnProperty(prefix = "spring.ai.openai.chat", name = "enabled", havingValue = "true", matchIfMissing = true  // 屬性不存在時默認為true
)
static class ChatConfiguration {// ...
}// 向量存儲類型選擇
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.PGVECTOR,matchIfMissing = true
)
public class PgVectorStoreAutoConfiguration {// ...
}

3. Bean存在條件

// 只有當指定Bean不存在時才創建
@Bean
@ConditionalOnMissingBean(OpenAiApi.class)
public OpenAiApi openAiApi(OpenAiConnectionDetails connectionDetails) {// ...
}// 只有當指定Bean存在時才創建
@Bean
@ConditionalOnBean(EmbeddingModel.class)
public VectorStore vectorStore(EmbeddingModel embeddingModel) {// ...
}

4. 自定義條件

// 自定義條件類
public class OpenAiApiKeyCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {Environment environment = context.getEnvironment();// 檢查API密鑰是否配置String apiKey = environment.getProperty("spring.ai.openai.api-key");if (StringUtils.hasText(apiKey)) {return true;}// 檢查環境變量String envApiKey = environment.getProperty("OPENAI_API_KEY");return StringUtils.hasText(envApiKey);}
}// 使用自定義條件
@Conditional(OpenAiApiKeyCondition.class)
@Bean
public OpenAiChatModel openAiChatModel() {// ...
}

配置屬性的層次化設計

1. 全局配置

spring:ai:# 全局AI配置retry:max-attempts: 3backoff-multiplier: 2.0observability:enabled: trueinclude-prompt: falseinclude-completion: true

2. 模型特定配置

spring:ai:openai:# OpenAI全局配置api-key: ${OPENAI_API_KEY}base-url: https://api.openai.comorganization-id: org-123chat:# 聊天模型配置enabled: trueoptions:model: gpt-4temperature: 0.7max-tokens: 1000top-p: 0.9frequency-penalty: 0.1presence-penalty: 0.1embedding:# 嵌入模型配置enabled: trueoptions:model: text-embedding-ada-002image:# 圖像模型配置enabled: falseoptions:model: dall-e-3quality: hdsize: 1024x1024

3. 向量存儲配置

spring:ai:vectorstore:# 向量存儲類型選擇type: pgvectorpgvector:# PgVector特定配置initialize-schema: trueschema-name: aitable-name: vector_storeindex-type: HNSWdistance-type: COSINE_DISTANCEdimensions: 1536# 或者選擇其他向量存儲# type: pinecone# pinecone:#   api-key: ${PINECONE_API_KEY}#   index-name: my-index#   namespace: default

高級配置特性

1. 配置文件處理器

@ConfigurationPropertiesBinding
@Component
public class ModelOptionsConverter implements Converter<String, ChatOptions> {private final ObjectMapper objectMapper;@Overridepublic ChatOptions convert(String source) {try {// 支持JSON字符串配置return objectMapper.readValue(source, OpenAiChatOptions.class);} catch (Exception e) {throw new IllegalArgumentException("Invalid model options: " + source, e);}}
}// 使用示例
spring:ai:openai:chat:options: '{"model":"gpt-4","temperature":0.7,"maxTokens":1000}'

2. 環境特定配置

@Configuration
@Profile("development")
public class DevelopmentAiConfig {@Bean@Primarypublic ChatModel devChatModel() {// 開發環境使用更便宜的模型return OpenAiChatModel.builder().options(OpenAiChatOptions.builder().model("gpt-3.5-turbo").temperature(0.9)  // 開發時可以更有創意.build()).build();}
}@Configuration
@Profile("production")
public class ProductionAiConfig {@Bean@Primarypublic ChatModel prodChatModel() {// 生產環境使用更穩定的模型return OpenAiChatModel.builder().options(OpenAiChatOptions.builder().model("gpt-4").temperature(0.3)  // 生產環境需要更穩定的輸出.build()).build();}
}

3. 動態配置刷新

@Component
@RefreshScope  // 支持配置刷新
public class RefreshableAiService {@Value("${spring.ai.openai.chat.options.temperature:0.7}")private double temperature;@Value("${spring.ai.openai.chat.options.model:gpt-3.5-turbo}")private String model;private final ChatModel chatModel;public RefreshableAiService(ChatModel chatModel) {this.chatModel = chatModel;}public String chat(String message) {// 使用動態配置ChatOptions options = OpenAiChatOptions.builder().model(model).temperature(temperature).build();return chatModel.call(new Prompt(message, options)).getResult().getOutput().getContent();}
}

自定義自動配置

1. 創建自定義Starter

<!-- pom.xml -->
<project><groupId>com.example</groupId><artifactId>custom-ai-spring-boot-starter</artifactId><version>1.0.0</version><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-core</artifactId></dependency></dependencies>
</project>

2. 自定義自動配置類

@AutoConfiguration
@ConditionalOnClass(CustomAiService.class)
@EnableConfigurationProperties(CustomAiProperties.class)
@ConditionalOnProperty(prefix = "custom.ai", name = "enabled", havingValue = "true", matchIfMissing = true)
public class CustomAiAutoConfiguration {@Bean@ConditionalOnMissingBeanpublic CustomAiService customAiService(CustomAiProperties properties,ObjectProvider<ChatModel> chatModel,ObjectProvider<EmbeddingModel> embeddingModel) {return CustomAiService.builder().chatModel(chatModel.getIfAvailable()).embeddingModel(embeddingModel.getIfAvailable()).properties(properties).build();}@Bean@ConditionalOnMissingBean@ConditionalOnProperty(prefix = "custom.ai.cache", name = "enabled", havingValue = "true")public CacheManager aiCacheManager(CustomAiProperties properties) {CaffeineCacheManager cacheManager = new CaffeineCacheManager();cacheManager.setCaffeine(Caffeine.newBuilder().maximumSize(properties.getCache().getMaxSize()).expireAfterWrite(properties.getCache().getTtl()));return cacheManager;}
}

3. 配置屬性類

@ConfigurationProperties("custom.ai")
@Data
public class CustomAiProperties {/*** 是否啟用自定義AI服務*/private boolean enabled = true;/*** 服務名稱*/private String serviceName = "CustomAI";/*** 緩存配置*/private Cache cache = new Cache();/*** 重試配置*/private Retry retry = new Retry();@Datapublic static class Cache {private boolean enabled = false;private long maxSize = 1000;private Duration ttl = Duration.ofMinutes(30);}@Datapublic static class Retry {private int maxAttempts = 3;private Duration backoff = Duration.ofSeconds(1);private double multiplier = 2.0;}
}

4. 注冊自動配置

# src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.ai.autoconfigure.CustomAiAutoConfiguration

最佳實踐與技巧

1. 配置驗證

@ConfigurationProperties("spring.ai.openai")
@Validated
public class OpenAiProperties {@NotBlank(message = "OpenAI API key must not be blank")private String apiKey;@URL(message = "Base URL must be a valid URL")private String baseUrl = "https://api.openai.com";@Validprivate ChatOptions chatOptions = new ChatOptions();@Datapublic static class ChatOptions {@DecimalMin(value = "0.0", message = "Temperature must be >= 0.0")@DecimalMax(value = "2.0", message = "Temperature must be <= 2.0")private Double temperature = 0.7;@Min(value = 1, message = "Max tokens must be >= 1")@Max(value = 4096, message = "Max tokens must be <= 4096")private Integer maxTokens = 1000;}
}

2. 配置元數據

// src/main/resources/META-INF/spring-configuration-metadata.json
{"groups": [{"name": "spring.ai.openai","type": "org.springframework.ai.openai.OpenAiProperties","description": "OpenAI configuration properties."}],"properties": [{"name": "spring.ai.openai.api-key","type": "java.lang.String","description": "OpenAI API key.","sourceType": "org.springframework.ai.openai.OpenAiProperties"},{"name": "spring.ai.openai.chat.options.temperature","type": "java.lang.Double","description": "Controls randomness in the output. Higher values make output more random.","sourceType": "org.springframework.ai.openai.OpenAiChatOptions","defaultValue": 0.7}],"hints": [{"name": "spring.ai.openai.chat.options.model","values": [{"value": "gpt-4","description": "GPT-4 model"},{"value": "gpt-3.5-turbo","description": "GPT-3.5 Turbo model"}]}]
}

3. 條件配置調試

// 啟用自動配置調試
@SpringBootApplication
@EnableAutoConfiguration
public class Application {public static void main(String[] args) {System.setProperty("debug", "true");  // 啟用調試模式SpringApplication.run(Application.class, args);}
}

或者在配置文件中:

debug: true
logging:level:org.springframework.boot.autoconfigure: DEBUGorg.springframework.ai.autoconfigure: DEBUG

小結

Spring AI的自動配置體系是一個設計精良的"魔法系統":

  1. 條件裝配:智能的條件注解確保只在需要時才激活配置
  2. 屬性綁定:類型安全的配置屬性綁定
  3. 模塊化設計:清晰的模塊劃分和依賴關系
  4. 可擴展性:易于創建自定義的自動配置
  5. 開發體驗:豐富的IDE支持和配置提示

這套自動配置機制讓AI應用的開發變得前所未有的簡單,開發者可以專注于業務邏輯,而不是繁瑣的配置工作。從添加依賴到運行AI應用,往往只需要幾分鐘時間。

下一章,我們將探索Spring AI的可觀測性體系,看看如何監控和調試AI應用,確保生產環境的穩定運行。


思考題:如果讓你設計一個自動配置框架,你會如何平衡靈活性和簡單性?Spring Boot的自動配置機制給了你什么啟發?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/96810.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/96810.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/96810.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

PNP機器人介紹:全球知名具身智能/AI機器人實驗室介紹之多倫多大學機器人研究所

PNP機器人介紹&#xff1a;全球知名具身智能/AI機器人實驗室介紹之多倫多大學機器人研究所1&#xff0c;多倫多大學機器人研究所介紹多倫多大學機器人研究所&#xff08;University of Toronto Robotics Institute, 簡稱UTRI&#xff09;是加拿大規模最大、跨學科最多樣化的機器…

計算機網絡-1——第一階段

文章目錄一、網絡結構體系1.1 OSI七層模型&#xff08;理論標準&#xff09;2. TCP/IP 四層模型&#xff08;實際應用&#xff09;二、計算機網絡設備三、網絡的分類及IP地址介紹3.1 網絡分類3.2 IP地址介紹四、常見協議4.1 TCP協議與UDP協議4.1.1 TCP協議4.1.2 UDP協議4.1.3 T…

數據結構青銅到王者第三話---ArrayList與順序表(2)

續接上一話&#xff1a; 目錄 一、ArrayList的使用&#xff08;續&#xff09; 1、ArrayList的擴容機制&#xff08;續&#xff09; 五、ArrayList的相關練習 1、楊輝三角 2、簡單的洗牌算法 六、ArrayList的問題及思考 一、ArrayList的使用&#xff08;續&#xff09; …

[Vid-LLM] docs | 視頻理解任務

鏈接&#xff1a;https://github.com/yunlong10/Awesome-LLMs-for-Video-Understanding docs&#xff1a;Vid-LLM 本項目是關于視頻大語言模型(Vid-LLMs)的全面綜述與精選列表。 探討了這些智能系統如何處理和理解視頻內容&#xff0c;詳細介紹了它們多樣的架構與訓練方法、旨…

構建高可用Agent狀態管理API:Gin+GORM全流程解析

繼寫給 Javaer 看的 Go Gin 教程 之后新寫一篇真實的go開發教程:技術棧?&#xff1a;Go 1.21 Gin 1.9 GORM 2.0 MySQL 5.7 Docker一、技術選型&#xff1a;為什么是GinGORM&#xff1f;1.?性能與簡潔性平衡???Gin?&#xff1a;基于httprouter的高性能框架&#xff0c…

[Java惡補day51] 46. 全排列

給定一個不含重復數字的數組 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意順序 返回答案。 示例 1&#xff1a; 輸入&#xff1a;nums [1,2,3] 輸出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 示例 2&#xff1a; 輸入&#xff1a;nums …

《李沐讀論文》系列筆記:論文讀寫與研究方法【更新中】

一、如何讀論文讀三遍&#xff1a;1. 第一遍讀完標題和摘要后&#xff0c;直接跳到結論&#xff0c;這幾個部分讀完就大概知道文章在講什么東西了&#xff0c;之后還可以看一下正文中的圖表&#xff0c;判斷一下這篇文章是否適合自己&#xff0c;是否要繼續讀&#xff1b;2. 第…

使用 gemini 來分析 github 項目

https://github.com/bravenewxyz/agent-c角色扮演&#xff1a; 你是一位頂級的軟件架構師和代碼審查專家&#xff0c;擁有超過20年的復雜系統設計和分析經驗。你尤其擅長快速洞察一個陌生代碼庫的核心設計思想、關鍵實現和創新之處。我的目標&#xff1a; 我正在研究以下這個 G…

20.15 Hugging Face Whisper-large-v2中文微調實戰:LoRA+混合精度單卡訓練指南,3倍效率省90%顯存

Hugging Face Whisper-large-v2中文微調實戰:LoRA+混合精度單卡訓練指南,3倍效率省90%顯存 from transformers import Seq2SeqTrainingArguments, Seq2SeqTrainer# 訓練參數配置(以中文語音識別任務為例) training_args = Seq2SeqTrainingArguments(output_dir="./wh…

GitGithub相關(自用,持續更新update 8/23)

文章目錄Git常見命令1. 推送空提交2. 提交Clean-PR3. 回退add操作4. 交互式rebase4.1 切換模式4.2 保存與退出4.3 注意Rebase5. 合并多個commit問題一&#xff1a;Clone Github報錯The TLS connection was non-properly terminated.TLS握手報錯原因解決問題二&#xff1a;Faile…

改華為智能插座為mqtt本地控制

華為插座1. 打開插座后蓋板&#xff0c;取出主板2.取下主板上的82663焊上esp32c3 supermini,熱熔膠粘上&#xff0c;焊接電源正負極&#xff0c;及第5腳4.取下電源板阻容降壓全部。因此電路不能提供足夠電流給esp32工作。5.外接小型ac-dc電源5v6.刷代碼Mqtt插座成品特別提醒&am…

2.4G和5G位圖說明列表,0xff也只是1-8號信道而已

根據你提供的 SDK 代碼&#xff0c;0xFF 僅表示啟用 1 到 8 號信道&#xff08;即 2.4GHz 頻段的信道&#xff09;。這是因為每個 BIT(x) 是一個位標志&#xff0c;0xFF 在二進制中對應的是 11111111&#xff0c;即啟用信道 1 至 8。對于 5GHz 信道&#xff0c;你需要確保傳輸的…

【網絡運維】Shell 腳本編程: for 循環與 select 循環

Shell 腳本編程&#xff1a; for 循環與 select 循環 循環語句命令常用于重復執行一條指令或一組指令&#xff0c;直到條件不再滿足時停止&#xff0c;Shell腳本語言的循環語句常見的有while、until、for及select循環語句。 本文將詳細介紹Shell編程中for循環和select循環的各種…

線性回歸入門:從原理到實戰的完整指南

線性回歸入門&#xff1a;從原理到實戰的完整指南線性回歸是機器學習中最基礎、最實用的算法之一 —— 它通過構建線性模型擬合數據&#xff0c;不僅能解決回歸預測問題&#xff0c;還能為復雜模型&#xff08;如神經網絡、集成算法&#xff09;提供基礎思路。今天我們從 “直線…

積分排行樣式

這個排名需要考慮不同child的位置<view class"pm-top"><!--背景 podiumtree 或 podium--><image class"podium-bg" :src"podium" mode"widthFix"></image><view class"podium-list"><vi…

【機器學習入門】1.1 緒論:從數據到智能的認知革命

引言&#xff1a;什么是機器學習&#xff1f;想象一下&#xff0c;當你在郵箱中看到一封郵件時&#xff0c;系統能自動識別出它是垃圾郵件&#xff1b;當你在購物網站瀏覽商品時&#xff0c;平臺能精準推薦你可能感興趣的物品&#xff1b;當自動駕駛汽車行駛在道路上時&#xf…

iptables 防火墻技術詳解

目錄 前言 1 iptables概述 1.1 Netfilter與iptables關系 1.1.1 Netfilter 1.1.2 iptables 1.1.3 兩者關系 2 iptables的表、鏈結構 2.1 四表五鏈結構介紹 2.1.1 基本概念 2.1.2 四表功能*** 2.1.3 五鏈功能*** 2.2 數據包過濾的匹配流程*** 2.2.1 規則表應用順序*…

SOME/IP-SD報文中 Entry Format(條目格式)-理解筆記3

&#x1f3af; 一、核心目標&#xff1a;解決“找服務”的問題 想象一下&#xff0c;一輛現代汽車里有上百個智能設備&#xff08;ECU&#xff09;&#xff0c;比如&#xff1a; 自動駕駛控制器&#xff08;需要“車速”服務&#xff09;中控大屏&#xff08;需要“導航”和“音…

AAA服務器技術

一、AAA認證架構理解AAA基本概念與架構先介紹&#xff1a; AAA是什么&#xff08;認證、授權、計費&#xff09;重點理解&#xff1a; 為什么需要AAA&#xff1f;它的三大功能分別解決什么問題&#xff1f;關聯后續&#xff1a; 這是所有后續協議&#xff08;RADIUS/TACACS&…

客戶生命周期價值幫助HelloFresh優化其營銷支出

1 引言 了解客戶的長期價值對HelloFresh至關重要。客戶生命周期價值&#xff08;CLV&#xff09;代表了客戶與公司關系的整個過程中所產生的總價值。通過預測這一指標&#xff0c;我們可以更明智地決定如何分配營銷資源&#xff0c;以獲得最大的影響。 在本文中&#xff0c;我…