深度剖析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模型需要多少步骤吗?

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

而现在,只需要:

yaml 复制代码
# application.yml
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      chat:
        options:
          model: gpt-4
          temperature: 0.7
    vectorstore:
      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):

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
    @ConditionalOnMissingBean
    public 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
        @ConditionalOnMissingBean
        public 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
        @ConditionalOnMissingBean
        public 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
        @ConditionalOnMissingBean
        public 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. 配置属性类设计

java 复制代码
// 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):

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
    @ConditionalOnMissingBean
    public 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;
        }
        
        @Override
        public String getSchemaName() {
            return this.properties.getSchemaName();
        }
        
        @Override
        public String getTableName() {
            return this.properties.getTableName();
        }
    }
}

条件注解的巧妙运用

1. 类路径条件

java 复制代码
// 只有当OpenAiApi类存在于类路径时才激活
@ConditionalOnClass(OpenAiApi.class)
public class OpenAiAutoConfiguration {
    // ...
}

// 多个类都必须存在
@ConditionalOnClass({ PgVectorStore.class, JdbcTemplate.class, DataSource.class })
public class PgVectorStoreAutoConfiguration {
    // ...
}

2. 属性条件

java 复制代码
// 基于配置属性的条件装配
@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存在条件

java 复制代码
// 只有当指定Bean不存在时才创建
@Bean
@ConditionalOnMissingBean(OpenAiApi.class)
public OpenAiApi openAiApi(OpenAiConnectionDetails connectionDetails) {
    // ...
}

// 只有当指定Bean存在时才创建
@Bean
@ConditionalOnBean(EmbeddingModel.class)
public VectorStore vectorStore(EmbeddingModel embeddingModel) {
    // ...
}

4. 自定义条件

java 复制代码
// 自定义条件类
public class OpenAiApiKeyCondition implements Condition {
    
    @Override
    public 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. 全局配置

yaml 复制代码
spring:
  ai:
    # 全局AI配置
    retry:
      max-attempts: 3
      backoff-multiplier: 2.0
    observability:
      enabled: true
      include-prompt: false
      include-completion: true

2. 模型特定配置

yaml 复制代码
spring:
  ai:
    openai:
      # OpenAI全局配置
      api-key: ${OPENAI_API_KEY}
      base-url: https://api.openai.com
      organization-id: org-123
      
      chat:
        # 聊天模型配置
        enabled: true
        options:
          model: gpt-4
          temperature: 0.7
          max-tokens: 1000
          top-p: 0.9
          frequency-penalty: 0.1
          presence-penalty: 0.1
          
      embedding:
        # 嵌入模型配置
        enabled: true
        options:
          model: text-embedding-ada-002
          
      image:
        # 图像模型配置
        enabled: false
        options:
          model: dall-e-3
          quality: hd
          size: 1024x1024

3. 向量存储配置

yaml 复制代码
spring:
  ai:
    vectorstore:
      # 向量存储类型选择
      type: pgvector
      
      pgvector:
        # PgVector特定配置
        initialize-schema: true
        schema-name: ai
        table-name: vector_store
        index-type: HNSW
        distance-type: COSINE_DISTANCE
        dimensions: 1536
        
      # 或者选择其他向量存储
      # type: pinecone
      # pinecone:
      #   api-key: ${PINECONE_API_KEY}
      #   index-name: my-index
      #   namespace: default

高级配置特性

1. 配置文件处理器

java 复制代码
@ConfigurationPropertiesBinding
@Component
public class ModelOptionsConverter implements Converter<String, ChatOptions> {
    
    private final ObjectMapper objectMapper;
    
    @Override
    public 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. 环境特定配置

java 复制代码
@Configuration
@Profile("development")
public class DevelopmentAiConfig {
    
    @Bean
    @Primary
    public 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
    @Primary
    public ChatModel prodChatModel() {
        // 生产环境使用更稳定的模型
        return OpenAiChatModel.builder()
            .options(OpenAiChatOptions.builder()
                .model("gpt-4")
                .temperature(0.3)  // 生产环境需要更稳定的输出
                .build())
            .build();
    }
}

3. 动态配置刷新

java 复制代码
@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

xml 复制代码
<!-- 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. 自定义自动配置类

java 复制代码
@AutoConfiguration
@ConditionalOnClass(CustomAiService.class)
@EnableConfigurationProperties(CustomAiProperties.class)
@ConditionalOnProperty(prefix = "custom.ai", name = "enabled", havingValue = "true", matchIfMissing = true)
public class CustomAiAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public 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. 配置属性类

java 复制代码
@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();
    
    @Data
    public static class Cache {
        private boolean enabled = false;
        private long maxSize = 1000;
        private Duration ttl = Duration.ofMinutes(30);
    }
    
    @Data
    public static class Retry {
        private int maxAttempts = 3;
        private Duration backoff = Duration.ofSeconds(1);
        private double multiplier = 2.0;
    }
}

4. 注册自动配置

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

最佳实践与技巧

1. 配置验证

java 复制代码
@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";
    
    @Valid
    private ChatOptions chatOptions = new ChatOptions();
    
    @Data
    public 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. 配置元数据

json 复制代码
// 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. 条件配置调试

java 复制代码
// 启用自动配置调试
@SpringBootApplication
@EnableAutoConfiguration
public class Application {
    
    public static void main(String[] args) {
        System.setProperty("debug", "true");  // 启用调试模式
        SpringApplication.run(Application.class, args);
    }
}

或者在配置文件中:

yaml 复制代码
debug: true
logging:
  level:
    org.springframework.boot.autoconfigure: DEBUG
    org.springframework.ai.autoconfigure: DEBUG

小结

Spring AI的自动配置体系是一个设计精良的"魔法系统":

  1. 条件装配:智能的条件注解确保只在需要时才激活配置
  2. 属性绑定:类型安全的配置属性绑定
  3. 模块化设计:清晰的模块划分和依赖关系
  4. 可扩展性:易于创建自定义的自动配置
  5. 开发体验:丰富的IDE支持和配置提示

这套自动配置机制让AI应用的开发变得前所未有的简单,开发者可以专注于业务逻辑,而不是繁琐的配置工作。从添加依赖到运行AI应用,往往只需要几分钟时间。

下一章,我们将探索Spring AI的可观测性体系,看看如何监控和调试AI应用,确保生产环境的稳定运行。


思考题:如果让你设计一个自动配置框架,你会如何平衡灵活性和简单性?Spring Boot的自动配置机制给了你什么启发?

相关推荐
黎燃8 小时前
短视频平台内容推荐算法优化:从协同过滤到多模态深度学习
人工智能
飞哥数智坊9 小时前
多次尝试用 CodeBuddy 做小程序,最终我放弃了
人工智能·ai编程
后端小肥肠10 小时前
别再眼馋 10w + 治愈漫画!Coze 工作流 3 分钟出成品,小白可学
人工智能·aigc·coze
昵称为空C13 小时前
SpringBoot3 http接口调用新方式RestClient + @HttpExchange像使用Feign一样调用
spring boot·后端
唐某人丶13 小时前
教你如何用 JS 实现 Agent 系统(2)—— 开发 ReAct 版本的“深度搜索”
前端·人工智能·aigc
FIT2CLOUD飞致云13 小时前
九月月报丨MaxKB在不同规模医疗机构的应用进展汇报
人工智能·开源
阿里云大数据AI技术13 小时前
【新模型速递】PAI-Model Gallery云上一键部署Qwen3-Next系列模型
人工智能
袁庭新14 小时前
全球首位AI机器人部长,背负反腐重任
人工智能·aigc
机器之心14 小时前
谁说Scaling Law到头了?新研究:每一步的微小提升会带来指数级增长
人工智能·openai
算家计算14 小时前
AI配音革命!B站最新开源IndexTTS2本地部署教程:精准对口型,情感随心换
人工智能·开源·aigc