04-Azure OpenAI集成

学习目标

  • 掌握 Azure OpenAI 服务的特点和优势
  • 理解 Azure OpenAI 与 OpenAI 的区别
  • 能够在 Spring AI 中集成 Azure OpenAI
  • 掌握 Azure OpenAI 的企业级配置
  • 了解 Azure OpenAI 的安全和合规特性

知识结构

Azure OpenAI集成

Azure OpenAI服务

服务特点

部署模型

定价策略

环境准备

Azure账号

资源创建

密钥管理

Spring AI集成

依赖配置

连接配置

客户端使用

企业级特性

虚拟网络

私有端点

身份认证

实战应用

企业客服

文档处理

数据分析

最佳实践

安全配置

性能优化

成本控制

一、项目场景引入

1.1 实际项目需求

场景一:金融企业AI应用
某银行需要构建智能客服系统,要求:

  • 数据不能离开中国境内
  • 符合金融行业合规要求
  • 需要企业级SLA保障
  • 支持私有网络部署
  • 需要详细的审计日志

场景二:医疗行业AI助手
医疗机构需要AI辅助诊断系统:

  • 患者数据高度敏感
  • 需要符合HIPAA合规
  • 要求数据主权保护
  • 需要高可用性保障
  • 支持本地化部署

场景三:政府部门应用
政府机构需要文档处理系统:

  • 数据安全等级要求高
  • 需要完全可控的部署
  • 要求审计和追溯能力
  • 支持离线运行
  • 符合政府采购要求

1.2 为什么选择 Azure OpenAI

Azure OpenAI 相比直接使用 OpenAI API 有以下优势:

1. 数据主权和合规性

  • 数据存储在指定的 Azure 区域
  • 符合各国数据保护法规
  • 支持 GDPR、HIPAA 等合规要求
  • 提供详细的审计日志

2. 企业级安全

  • 集成 Azure Active Directory
  • 支持虚拟网络和私有端点
  • 提供托管身份认证
  • 支持客户管理的密钥

3. 高可用性和 SLA

  • 99.9% 的可用性保证
  • 多区域部署支持
  • 自动故障转移
  • 企业级技术支持

4. 成本可控

  • 预留容量定价
  • 批量折扣
  • 成本管理工具
  • 详细的使用报告

5. 集成生态

  • 与 Azure 服务无缝集成
  • 统一的身份和访问管理
  • 集中的监控和日志
  • DevOps 工具链支持

1.3 Azure OpenAI vs OpenAI 对比

特性 Azure OpenAI OpenAI
数据位置 可选择区域 美国
合规认证 多种企业认证 基础认证
SLA保障 99.9% 无正式SLA
私有部署 支持 不支持
身份认证 Azure AD集成 API密钥
网络隔离 支持VNet 不支持
审计日志 完整审计 基础日志
技术支持 企业级支持 社区支持
定价模式 灵活定价 按量付费
适用场景 企业应用 个人/小团队

二、Azure OpenAI 服务准备

2.1 创建 Azure 账号

步骤一:注册 Azure 账号

  1. 访问 https://azure.microsoft.com/
  2. 点击"免费开始"
  3. 使用 Microsoft 账号登录或创建新账号
  4. 完成身份验证(需要信用卡验证)
  5. 获得 $200 免费额度(30天有效)

步骤二:申请 Azure OpenAI 访问权限

注意:Azure OpenAI 需要申请才能使用

申请流程:
1. 访问 https://aka.ms/oai/access
2. 填写申请表单
3. 说明使用场景和目的
4. 等待审批(通常1-2个工作日)
5. 收到批准邮件后即可使用

2.2 创建 Azure OpenAI 资源

步骤一:登录 Azure 门户

  1. 访问 https://portal.azure.com/
  2. 使用 Azure 账号登录

步骤二:创建资源

  1. 点击"创建资源"

  2. 搜索"Azure OpenAI"

  3. 点击"创建"

  4. 填写基本信息:

    • 订阅:选择你的订阅
    • 资源组:创建新的或选择现有的
    • 区域:选择离你最近的区域(如 East US、West Europe)
    • 名称:输入唯一的资源名称
    • 定价层:选择 Standard S0
  5. 点击"审阅 + 创建"

  6. 等待部署完成

步骤三:部署模型

  1. 进入创建的 Azure OpenAI 资源
  2. 点击"模型部署"
  3. 点击"创建新部署"
  4. 选择模型:
    • gpt-35-turbo(推荐用于开发)
    • gpt-4(用于生产环境)
  5. 输入部署名称(如:gpt-35-turbo-deployment)
  6. 点击"创建"

2.3 获取连接信息

获取端点和密钥:

  1. 在 Azure OpenAI 资源页面
  2. 点击"密钥和终结点"
  3. 复制以下信息:
    • 终结点(Endpoint):https://your-resource.openai.azure.com/
    • 密钥1(Key 1):your-api-key
    • 区域(Location):eastus

记录部署名称:

  1. 点击"模型部署"
  2. 记录你创建的部署名称
  3. 这个名称将在代码中使用
重要信息记录:
├─ Endpoint: https://your-resource.openai.azure.com/
├─ API Key: your-api-key-here
├─ Deployment Name: gpt-35-turbo-deployment
└─ API Version: 2023-05-15

三、Spring AI 集成 Azure OpenAI

3.1 项目依赖配置

完整的 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 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version>
        <relativePath/>
    </parent>
    
    <groupId>com.example</groupId>
    <artifactId>spring-ai-azure-demo</artifactId>
    <version>1.0.0</version>
    <name>Spring AI Azure OpenAI Integration Demo</name>
    <description>Spring AI Azure OpenAI 集成示例项目</description>
    
    <properties>
        <java.version>17</java.version>
        <spring-ai.version>0.8.1</spring-ai.version>
    </properties>
    
    <dependencies>
        <!-- Spring Boot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <!-- Spring AI Azure OpenAI -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-azure-openai-spring-boot-starter</artifactId>
        </dependency>
        
        <!-- Azure Identity(用于托管身份认证) -->
        <dependency>
            <groupId>com.azure</groupId>
            <artifactId>azure-identity</artifactId>
            <version>1.11.0</version>
        </dependency>
        
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        
        <!-- Spring Boot Test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>

3.2 配置文件设置

application.yml 完整配置:

spring:
  application:
    name: spring-ai-azure-demo
  
  # Spring AI Azure OpenAI 配置
  ai:
    azure:
      openai:
        # Azure OpenAI 端点
        endpoint: ${AZURE_OPENAI_ENDPOINT}
        # API 密钥
        api-key: ${AZURE_OPENAI_API_KEY}
        
        # Chat 模型配置
        chat:
          options:
            # 部署名称(在 Azure 门户中创建的部署名称)
            deployment-name: gpt-35-turbo-deployment
            # API 版本
            api-version: 2023-05-15
            # 温度参数
            temperature: 0.7
            # 最大生成token数
            max-tokens: 1000
            # Top P 采样参数
            top-p: 1.0
            # 频率惩罚
            frequency-penalty: 0.0
            # 存在惩罚
            presence-penalty: 0.0
        
        # Embedding 模型配置
        embedding:
          options:
            deployment-name: text-embedding-ada-002-deployment
            api-version: 2023-05-15

# 服务器配置
server:
  port: 8080

# 日志配置
logging:
  level:
    root: INFO
    com.example: DEBUG
    org.springframework.ai: DEBUG
    com.azure: DEBUG

环境变量配置(.env 文件):

# Azure OpenAI 端点
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/

# Azure OpenAI API 密钥
AZURE_OPENAI_API_KEY=your-api-key-here

# 可选:Azure 租户ID(用于托管身份)
# AZURE_TENANT_ID=your-tenant-id

# 可选:Azure 客户端ID(用于托管身份)
# AZURE_CLIENT_ID=your-client-id

3.3 基础集成代码

项目结构:

spring-ai-azure-demo/
├── src/main/java/com/example/azureai/
│   ├── SpringAiAzureDemoApplication.java
│   ├── controller/
│   │   └── AzureChatController.java
│   ├── service/
│   │   ├── AzureChatService.java
│   │   └── impl/
│   │       └── AzureChatServiceImpl.java
│   ├── config/
│   │   ├── AzureOpenAIConfig.java
│   │   └── SecurityConfig.java
│   └── dto/
│       ├── ChatRequest.java
│       └── ChatResponse.java
├── src/main/resources/
│   ├── application.yml
│   └── application-prod.yml
└── pom.xml

1. 启动类:

package com.example.azureai;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Spring AI Azure OpenAI 集成示例应用
 * 
 * @author Your Name
 * @since 1.0.0
 */
@SpringBootApplication
public class SpringAiAzureDemoApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(SpringAiAzureDemoApplication.class, args);
    }
}

2. 配置类:

package com.example.azureai.config;

import com.azure.ai.openai.OpenAIClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.TokenCredential;
import com.azure.identity.DefaultAzureCredentialBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

/**
 * Azure OpenAI 配置类
 * 支持 API 密钥和托管身份两种认证方式
 * 
 * @author Your Name
 * @since 1.0.0
 */
@Slf4j
@Configuration
public class AzureOpenAIConfig {
    
    @Value("${spring.ai.azure.openai.endpoint}")
    private String endpoint;
    
    @Value("${spring.ai.azure.openai.api-key:}")
    private String apiKey;
    
    /**
     * 使用 API 密钥认证(开发环境)
     */
    @Bean
    @Profile("!prod")
    public OpenAIClient openAIClientWithApiKey() {
        log.info("使用 API 密钥认证连接 Azure OpenAI");
        
        return new OpenAIClientBuilder()
                .endpoint(endpoint)
                .credential(new AzureKeyCredential(apiKey))
                .buildClient();
    }
    
    /**
     * 使用托管身份认证(生产环境)
     */
    @Bean
    @Profile("prod")
    public OpenAIClient openAIClientWithManagedIdentity() {
        log.info("使用托管身份认证连接 Azure OpenAI");
        
        TokenCredential credential = new DefaultAzureCredentialBuilder()
                .build();
        
        return new OpenAIClientBuilder()
                .endpoint(endpoint)
                .credential(credential)
                .buildClient();
    }
}

3. 服务接口:

package com.example.azureai.service;

import com.example.azureai.dto.ChatRequest;
import com.example.azureai.dto.ChatResponse;
import reactor.core.publisher.Flux;

/**
 * Azure Chat 服务接口
 * 
 * @author Your Name
 * @since 1.0.0
 */
public interface AzureChatService {
    
    /**
     * 简单对话
     */
    String simpleChat(String message);
    
    /**
     * 高级对话
     */
    ChatResponse advancedChat(ChatRequest request);
    
    /**
     * 流式对话
     */
    Flux<String> streamChat(String message);
    
    /**
     * 批量处理
     */
    List<String> batchProcess(List<String> messages);
}

4. 服务实现类:

package com.example.azureai.service.impl;

import com.example.azureai.dto.ChatRequest;
import com.example.azureai.dto.ChatResponse;
import com.example.azureai.service.AzureChatService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.azure.openai.AzureOpenAiChatClient;
import org.springframework.ai.azure.openai.AzureOpenAiChatOptions;
import org.springframework.ai.chat.ChatResponse as AiChatResponse;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import java.util.ArrayList;
import java.util.List;

/**
 * Azure Chat 服务实现
 * 项目场景:企业级智能客服系统
 * 功能:处理客户咨询,提供智能回复
 * 
 * @author Your Name
 * @since 1.0.0
 */
@Slf4j
@Service
public class AzureChatServiceImpl implements AzureChatService {
    
    private final AzureOpenAiChatClient chatClient;
    
    @Value("${spring.ai.azure.openai.chat.options.deployment-name}")
    private String deploymentName;
    
    public AzureChatServiceImpl(AzureOpenAiChatClient chatClient) {
        this.chatClient = chatClient;
        log.info("AzureChatService 初始化完成");
    }
    
    @Override
    public String simpleChat(String message) {
        log.info("收到简单对话请求: {}", message);
        
        try {
            Message userMessage = new UserMessage(message);
            Prompt prompt = new Prompt(userMessage);
            
            AiChatResponse response = chatClient.call(prompt);
            String content = response.getResult().getOutput().getContent();
            
            log.info("AI 回复: {}", content);
            return content;
            
        } catch (Exception e) {
            log.error("简单对话失败", e);
            return "抱歉,服务暂时不可用,请稍后再试。";
        }
    }
    
    @Override
    public ChatResponse advancedChat(ChatRequest request) {
        log.info("收到高级对话请求: {}", request);
        
        long startTime = System.currentTimeMillis();
        
        try {
            // 构建 Azure OpenAI 选项
            AzureOpenAiChatOptions.Builder optionsBuilder = 
                    AzureOpenAiChatOptions.builder()
                            .withDeploymentName(deploymentName);
            
            if (request.getTemperature() != null) {
                optionsBuilder.withTemperature(request.getTemperature());
            }
            
            if (request.getMaxTokens() != null) {
                optionsBuilder.withMaxTokens(request.getMaxTokens());
            }
            
            AzureOpenAiChatOptions options = optionsBuilder.build();
            
            // 创建提示词
            Message userMessage = new UserMessage(request.getMessage());
            Prompt prompt = new Prompt(userMessage, options);
            
            // 调用 Azure OpenAI API
            AiChatResponse aiResponse = chatClient.call(prompt);
            
            long responseTime = System.currentTimeMillis() - startTime;
            
            // 构建响应
            return ChatResponse.builder()
                    .content(aiResponse.getResult().getOutput().getContent())
                    .model(deploymentName)
                    .totalTokens(aiResponse.getMetadata().getUsage().getTotalTokens())
                    .responseTime(responseTime)
                    .success(true)
                    .build();
            
        } catch (Exception e) {
            log.error("高级对话失败", e);
            
            long responseTime = System.currentTimeMillis() - startTime;
            
            return ChatResponse.builder()
                    .success(false)
                    .errorMessage(e.getMessage())
                    .responseTime(responseTime)
                    .build();
        }
    }
    
    @Override
    public Flux<String> streamChat(String message) {
        log.info("收到流式对话请求: {}", message);
        
        try {
            Prompt prompt = new Prompt(new UserMessage(message));
            
            Flux<AiChatResponse> responseFlux = chatClient.stream(prompt);
            
            return responseFlux
                    .map(response -> response.getResult().getOutput().getContent())
                    .doOnNext(content -> log.debug("流式内容: {}", content))
                    .doOnComplete(() -> log.info("流式对话完成"))
                    .doOnError(error -> log.error("流式对话失败", error));
            
        } catch (Exception e) {
            log.error("流式对话启动失败", e);
            return Flux.error(e);
        }
    }
    
    @Override
    public List<String> batchProcess(List<String> messages) {
        log.info("批量处理 {} 条消息", messages.size());
        
        List<String> results = new ArrayList<>();
        
        for (String message : messages) {
            try {
                String result = simpleChat(message);
                results.add(result);
            } catch (Exception e) {
                log.error("处理消息失败: {}", message, e);
                results.add("处理失败");
            }
        }
        
        return results;
    }
}

5. 控制器:

package com.example.azureai.controller;

import com.example.azureai.dto.ChatRequest;
import com.example.azureai.dto.ChatResponse;
import com.example.azureai.service.AzureChatService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

import java.util.List;

/**
 * Azure Chat 控制器
 * 
 * @author Your Name
 * @since 1.0.0
 */
@Slf4j
@RestController
@RequestMapping("/api/azure/chat")
public class AzureChatController {
    
    private final AzureChatService chatService;
    
    public AzureChatController(AzureChatService chatService) {
        this.chatService = chatService;
    }
    
    @GetMapping("/simple")
    public String simpleChat(@RequestParam String message) {
        log.info("简单对话请求: {}", message);
        return chatService.simpleChat(message);
    }
    
    @PostMapping("/advanced")
    public ChatResponse advancedChat(@RequestBody ChatRequest request) {
        log.info("高级对话请求: {}", request);
        return chatService.advancedChat(request);
    }
    
    @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> streamChat(@RequestParam String message) {
        log.info("流式对话请求: {}", message);
        return chatService.streamChat(message);
    }
    
    @PostMapping("/batch")
    public List<String> batchProcess(@RequestBody List<String> messages) {
        log.info("批量处理请求: {} 条消息", messages.size());
        return chatService.batchProcess(messages);
    }
    
    @GetMapping("/health")
    public String health() {
        return "Azure OpenAI Service OK";
    }
}

四、企业级特性

4.1 虚拟网络集成

Azure OpenAI 支持通过虚拟网络进行私有访问,提高安全性。

配置虚拟网络:

# application-prod.yml
spring:
  ai:
    azure:
      openai:
        endpoint: ${AZURE_OPENAI_ENDPOINT}
        # 使用私有端点
        use-private-endpoint: true
        # 虚拟网络配置
        vnet:
          enabled: true
          subnet-id: /subscriptions/{subscription-id}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}

Java 配置:

@Configuration
public class VNetConfig {
    
    /**
     * 配置私有端点连接
     */
    @Bean
    @Profile("prod")
    public OpenAIClient secureOpenAIClient(
            @Value("${spring.ai.azure.openai.endpoint}") String endpoint) {
        
        // 使用托管身份
        TokenCredential credential = new DefaultAzureCredentialBuilder()
                .build();
        
        // 配置网络选项
        HttpClientOptions clientOptions = new HttpClientOptions()
                .setConnectTimeout(Duration.ofSeconds(30))
                .setReadTimeout(Duration.ofSeconds(60));
        
        return new OpenAIClientBuilder()
                .endpoint(endpoint)
                .credential(credential)
                .clientOptions(clientOptions)
                .buildClient();
    }
}

4.2 托管身份认证

托管身份提供了更安全的认证方式,无需管理密钥。

启用托管身份:

# 在 Azure 门户中为应用启用系统分配的托管身份
# 或使用 Azure CLI
az webapp identity assign --name <app-name> --resource-group <resource-group>

# 为托管身份分配权限
az role assignment create \
  --assignee <managed-identity-principal-id> \
  --role "Cognitive Services OpenAI User" \
  --scope /subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.CognitiveServices/accounts/<openai-resource>

代码配置:

@Configuration
@Profile("prod")
public class ManagedIdentityConfig {
    
    @Bean
    public OpenAIClient managedIdentityClient(
            @Value("${spring.ai.azure.openai.endpoint}") String endpoint) {
        
        log.info("使用托管身份连接 Azure OpenAI");
        
        // 使用默认 Azure 凭据链
        // 会自动尝试:托管身份 -> 环境变量 -> Azure CLI
        TokenCredential credential = new DefaultAzureCredentialBuilder()
                .build();
        
        return new OpenAIClientBuilder()
                .endpoint(endpoint)
                .credential(credential)
                .buildClient();
    }
}

4.3 内容过滤

Azure OpenAI 提供内置的内容过滤功能,符合企业合规要求。

配置内容过滤:

@Service
public class ContentFilterService {
    
    private final AzureOpenAiChatClient chatClient;
    
    /**
     * 带内容过滤的对话
     */
    public ChatResponse chatWithContentFilter(String message) {
        try {
            // Azure OpenAI 会自动应用内容过滤
            AzureOpenAiChatOptions options = AzureOpenAiChatOptions.builder()
                    .withDeploymentName("gpt-35-turbo-deployment")
                    // 内容过滤级别(low, medium, high)
                    .withContentFilterLevel("medium")
                    .build();
            
            Prompt prompt = new Prompt(new UserMessage(message), options);
            AiChatResponse response = chatClient.call(prompt);
            
            // 检查内容过滤结果
            if (response.getMetadata().getContentFilterResults() != null) {
                log.info("内容过滤结果: {}", 
                        response.getMetadata().getContentFilterResults());
            }
            
            return ChatResponse.builder()
                    .content(response.getResult().getOutput().getContent())
                    .success(true)
                    .build();
            
        } catch (ContentFilterException e) {
            log.warn("内容被过滤: {}", e.getMessage());
            return ChatResponse.builder()
                    .success(false)
                    .errorMessage("内容不符合安全策略")
                    .build();
        }
    }
}

4.4 审计和监控

Azure OpenAI 提供完整的审计日志和监控功能。

启用诊断日志:

@Configuration
public class MonitoringConfig {
    
    @Bean
    public ApplicationInsights applicationInsights() {
        // 配置 Application Insights
        TelemetryConfiguration config = TelemetryConfiguration.createDefault();
        config.setInstrumentationKey(System.getenv("APPINSIGHTS_INSTRUMENTATIONKEY"));
        
        return new ApplicationInsights(config);
    }
}

@Service
public class AuditService {
    
    private final TelemetryClient telemetryClient;
    
    public void logApiCall(String userId, String operation, 
                          Map<String, String> properties) {
        // 记录自定义事件
        telemetryClient.trackEvent("AzureOpenAI_APICall", properties, null);
        
        // 记录指标
        telemetryClient.trackMetric("API_Calls", 1.0);
    }
    
    public void logError(String operation, Exception e) {
        telemetryClient.trackException(e);
    }
}

五、实战应用场景

5.1 场景一:金融企业客服系统

业务需求:

  • 符合金融行业合规要求
  • 数据不能离开中国境内
  • 需要完整的审计追踪
  • 高可用性要求

完整实现:

@Service
public class FinancialCustomerService {
    
    private final AzureOpenAiChatClient chatClient;
    private final AuditService auditService;
    private final ComplianceService complianceService;
    
    /**
     * 处理金融咨询
     */
    public ChatResponse handleFinancialQuery(FinancialQueryRequest request) {
        // 1. 合规检查
        if (!complianceService.checkCompliance(request)) {
            return ChatResponse.builder()
                    .success(false)
                    .errorMessage("请求不符合合规要求")
                    .build();
        }
        
        // 2. 审计日志
        auditService.logApiCall(
                request.getUserId(),
                "financial_query",
                Map.of(
                    "query_type", request.getQueryType(),
                    "timestamp", String.valueOf(System.currentTimeMillis())
                )
        );
        
        // 3. 构建系统提示词(金融专业)
        String systemPrompt = """
                你是一个专业的金融客服助手。
                
                职责:
                1. 回答客户关于银行产品和服务的问题
                2. 提供专业、准确的金融建议
                3. 遵守金融行业规范和法律法规
                
                限制:
                1. 不提供具体的投资建议
                2. 不泄露客户隐私信息
                3. 对于复杂问题,建议联系专业理财顾问
                4. 所有建议需符合监管要求
                """;
        
        try {
            // 4. 调用 Azure OpenAI
            AzureOpenAiChatOptions options = AzureOpenAiChatOptions.builder()
                    .withDeploymentName("gpt-4-deployment")
                    .withTemperature(0.3)  // 较低温度,更准确
                    .withMaxTokens(800)
                    .build();
            
            List<Message> messages = List.of(
                    new SystemMessage(systemPrompt),
                    new UserMessage(request.getQuery())
            );
            
            Prompt prompt = new Prompt(messages, options);
            AiChatResponse response = chatClient.call(prompt);
            
            String content = response.getResult().getOutput().getContent();
            
            // 5. 内容审核
            if (!complianceService.validateResponse(content)) {
                log.warn("响应内容不符合合规要求");
                content = "抱歉,我无法回答这个问题。请联系人工客服。";
            }
            
            // 6. 记录响应
            auditService.logApiCall(
                    request.getUserId(),
                    "financial_response",
                    Map.of(
                        "tokens", String.valueOf(response.getMetadata().getUsage().getTotalTokens()),
                        "model", "gpt-4"
                    )
            );
            
            return ChatResponse.builder()
                    .content(content)
                    .success(true)
                    .build();
            
        } catch (Exception e) {
            auditService.logError("financial_query", e);
            return ChatResponse.builder()
                    .success(false)
                    .errorMessage("服务暂时不可用")
                    .build();
        }
    }
}

5.2 场景二:医疗文档处理

业务需求:

  • 处理医疗记录和报告
  • 符合 HIPAA 合规要求
  • 数据加密和隐私保护
  • 支持多语言

实现代码:

@Service
public class MedicalDocumentService {
    
    private final AzureOpenAiChatClient chatClient;
    private final EncryptionService encryptionService;
    
    /**
     * 处理医疗文档
     */
    public DocumentProcessingResult processDocument(MedicalDocument document) {
        // 1. 数据脱敏
        String sanitizedContent = sanitizePatientInfo(document.getContent());
        
        // 2. 加密敏感信息
        String encryptedContent = encryptionService.encrypt(sanitizedContent);
        
        // 3. 文档分析
        String systemPrompt = """
                你是一个医疗文档分析助手。
                
                任务:
                1. 分析医疗文档内容
                2. 提取关键医疗信息
                3. 生成结构化摘要
                
                注意:
                1. 保护患者隐私
                2. 使用专业医疗术语
                3. 标注不确定的信息
                """;
        
        try {
            AzureOpenAiChatOptions options = AzureOpenAiChatOptions.builder()
                    .withDeploymentName("gpt-4-deployment")
                    .withTemperature(0.2)
                    .withMaxTokens(2000)
                    .build();
            
            String userPrompt = String.format("""
                    请分析以下医疗文档并提取关键信息:
                    
                    %s
                    
                    请按以下格式输出:
                    1. 主要诊断
                    2. 症状描述
                    3. 治疗方案
                    4. 注意事项
                    """, encryptedContent);
            
            Prompt prompt = new Prompt(
                    List.of(new SystemMessage(systemPrompt), 
                           new UserMessage(userPrompt)),
                    options
            );
            
            AiChatResponse response = chatClient.call(prompt);
            String analysis = response.getResult().getOutput().getContent();
            
            return DocumentProcessingResult.builder()
                    .analysis(analysis)
                    .success(true)
                    .build();
            
        } catch (Exception e) {
            log.error("文档处理失败", e);
            return DocumentProcessingResult.builder()
                    .success(false)
                    .errorMessage("文档处理失败")
                    .build();
        }
    }
    
    private String sanitizePatientInfo(String content) {
        // 移除或替换患者姓名、身份证号等敏感信息
        return content
                .replaceAll("\\b[A-Z][a-z]+ [A-Z][a-z]+\\b", "[PATIENT_NAME]")
                .replaceAll("\\b\\d{18}\\b", "[ID_NUMBER]")
                .replaceAll("\\b\\d{11}\\b", "[PHONE_NUMBER]");
    }
}

六、成本优化

6.1 预留容量定价

Azure OpenAI 支持预留容量,可以显著降低成本。

配置预留容量:

@Configuration
public class CapacityConfig {
    
    /**
     * 配置预留容量
     */
    @Bean
    public CapacityReservation capacityReservation() {
        return CapacityReservation.builder()
                .deploymentName("gpt-35-turbo-deployment")
                .reservedCapacity(100)  // 预留100个TPM
                .duration(Duration.ofDays(30))
                .build();
    }
}

6.2 成本监控

@Service
public class CostMonitoringService {
    
    private final AtomicLong totalTokens = new AtomicLong(0);
    private final AtomicInteger totalRequests = new AtomicInteger(0);
    
    public void recordUsage(int tokens) {
        totalTokens.addAndGet(tokens);
        totalRequests.incrementAndGet();
    }
    
    public CostReport generateReport() {
        long tokens = totalTokens.get();
        int requests = totalRequests.get();
        
        // Azure OpenAI 定价(示例)
        // GPT-3.5-turbo: $0.002 / 1K tokens
        // GPT-4: $0.06 / 1K tokens
        double cost = (tokens / 1000.0) * 0.002;
        
        return CostReport.builder()
                .totalTokens(tokens)
                .totalRequests(requests)
                .estimatedCost(cost)
                .build();
    }
}

七、常见问题

Q1: Azure OpenAI 和 OpenAI 有什么区别?

A: 主要区别:

  • 数据位置:Azure OpenAI 数据存储在指定区域
  • 合规性:Azure OpenAI 提供更多企业合规认证
  • 安全性:支持虚拟网络、托管身份等企业级安全特性
  • SLA:Azure OpenAI 提供 99.9% 可用性保证
  • 定价:Azure OpenAI 支持预留容量等灵活定价

Q2: 如何申请 Azure OpenAI 访问权限?

A: 申请步骤:

  1. 访问 https://aka.ms/oai/access
  2. 填写申请表单,说明使用场景
  3. 等待审批(通常1-2个工作日)
  4. 收到批准邮件后即可使用

Q3: 如何选择部署区域?

A: 选择建议:

  • 选择离用户最近的区域(降低延迟)
  • 考虑数据合规要求(如数据主权)
  • 检查区域的模型可用性
  • 考虑成本差异(不同区域价格可能不同)

Q4: 托管身份和 API 密钥哪个更好?

A: 推荐使用托管身份:

  • 优点:无需管理密钥、更安全、自动轮换
  • 缺点:配置稍复杂、仅适用于 Azure 环境
  • 建议:生产环境使用托管身份,开发环境使用 API 密钥

八、练习题

基础练习

练习1: 创建 Azure OpenAI 资源并部署模型
练习2: 实现基本的对话功能
练习3: 配置虚拟网络访问

进阶练习

练习4: 实现托管身份认证
练习5: 集成 Application Insights 监控
练习6: 实现内容过滤和合规检查

综合练习

练习7: 开发企业级客服系统
练习8: 实现医疗文档处理系统
练习9: 构建成本监控和优化方案

九、学习检查清单

  • 理解 Azure OpenAI 的特点和优势
  • 能够创建和配置 Azure OpenAI 资源
  • 掌握 API 密钥和托管身份认证
  • 能够配置虚拟网络和私有端点
  • 理解内容过滤和合规要求
  • 能够实现审计和监控
  • 掌握成本优化策略
  • 能够开发企业级应用

十、扩展阅读

  1. Azure OpenAI 官方文档

    • https://learn.microsoft.com/azure/cognitive-services/openai/
  2. Azure 安全最佳实践

    • https://learn.microsoft.com/azure/security/fundamentals/best-practices-and-patterns
  3. 托管身份文档

    • https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/

十一、总结

Azure OpenAI 为企业提供了安全、合规、可控的 AI 解决方案。通过本章学习,你已经掌握了:

  • ✅ Azure OpenAI 的企业级特性
  • ✅ 安全认证和网络配置
  • ✅ 实战应用场景开发
  • ✅ 成本优化和监控

继续学习下一章节:Ollama 本地模型集成,探索本地部署方案!

十二、高级配置

12.1 多区域部署

为了提高可用性,可以配置多区域部署。

@Configuration
public class MultiRegionConfig {
    
    @Bean
    public List<AzureOpenAiChatClient> multiRegionClients() {
        List<AzureOpenAiChatClient> clients = new ArrayList<>();
        
        // 主区域
        clients.add(createClient(
            "https://primary.openai.azure.com/",
            System.getenv("PRIMARY_API_KEY")
        ));
        
        // 备用区域
        clients.add(createClient(
            "https://secondary.openai.azure.com/",
            System.getenv("SECONDARY_API_KEY")
        ));
        
        return clients;
    }
    
    private AzureOpenAiChatClient createClient(String endpoint, String apiKey) {
        OpenAIClient client = new OpenAIClientBuilder()
                .endpoint(endpoint)
                .credential(new AzureKeyCredential(apiKey))
                .buildClient();
        
        return new AzureOpenAiChatClient(client);
    }
}

12.2 负载均衡

@Service
public class LoadBalancerService {
    
    private final List<AzureOpenAiChatClient> clients;
    private final AtomicInteger counter = new AtomicInteger(0);
    
    public LoadBalancerService(List<AzureOpenAiChatClient> clients) {
        this.clients = clients;
    }
    
    /**
     * 轮询选择客户端
     */
    public AzureOpenAiChatClient getClient() {
        int index = counter.getAndIncrement() % clients.size();
        return clients.get(index);
    }
    
    /**
     * 带故障转移的调用
     */
    public ChatResponse callWithFailover(Prompt prompt) {
        for (AzureOpenAiChatClient client : clients) {
            try {
                AiChatResponse response = client.call(prompt);
                return ChatResponse.builder()
                        .content(response.getResult().getOutput().getContent())
                        .success(true)
                        .build();
            } catch (Exception e) {
                log.warn("客户端调用失败,尝试下一个", e);
            }
        }
        
        return ChatResponse.builder()
                .success(false)
                .errorMessage("所有区域都不可用")
                .build();
    }
}

12.3 批量处理优化

@Service
public class BatchProcessingService {
    
    private final AzureOpenAiChatClient chatClient;
    private final ExecutorService executor;
    
    public BatchProcessingService(AzureOpenAiChatClient chatClient) {
        this.chatClient = chatClient;
        this.executor = Executors.newFixedThreadPool(10);
    }
    
    /**
     * 并行批量处理
     */
    public List<CompletableFuture<String>> batchProcessAsync(
            List<String> messages) {
        
        return messages.stream()
                .map(message -> CompletableFuture.supplyAsync(
                        () -> processMessage(message), 
                        executor))
                .collect(Collectors.toList());
    }
    
    private String processMessage(String message) {
        try {
            Prompt prompt = new Prompt(new UserMessage(message));
            AiChatResponse response = chatClient.call(prompt);
            return response.getResult().getOutput().getContent();
        } catch (Exception e) {
            log.error("处理消息失败: {}", message, e);
            return "处理失败";
        }
    }
    
    /**
     * 等待所有任务完成
     */
    public List<String> waitForAll(
            List<CompletableFuture<String>> futures) {
        
        return futures.stream()
                .map(CompletableFuture::join)
                .collect(Collectors.toList());
    }
}

十三、性能优化

13.1 连接池配置

@Configuration
public class ConnectionPoolConfig {
    
    @Bean
    public HttpClient httpClient() {
        ConnectionPoolManager poolManager = new ConnectionPoolManager();
        poolManager.setMaxConnections(100);
        poolManager.setMaxConnectionsPerRoute(20);
        poolManager.setConnectionTimeout(Duration.ofSeconds(30));
        
        return HttpClient.newBuilder()
                .connectionPoolManager(poolManager)
                .build();
    }
}

13.2 请求超时配置

spring:
  ai:
    azure:
      openai:
        # 连接超时(毫秒)
        connect-timeout: 30000
        # 读取超时(毫秒)
        read-timeout: 60000
        # 写入超时(毫秒)
        write-timeout: 60000

13.3 响应缓存策略

@Service
public class CacheStrategyService {
    
    private final CacheManager cacheManager;
    
    /**
     * 智能缓存策略
     */
    @Cacheable(
        value = "azure-chat-responses",
        key = "#message",
        condition = "#message.length() < 500",
        unless = "#result == null"
    )
    public String chatWithSmartCache(String message) {
        // 短消息才缓存
        // 避免缓存过大的响应
        return callAzureOpenAI(message);
    }
    
    /**
     * 分层缓存
     */
    public String chatWithTieredCache(String message) {
        // L1: 本地缓存(快速)
        String cached = localCache.get(message);
        if (cached != null) {
            return cached;
        }
        
        // L2: Redis 缓存(共享)
        cached = redisCache.get(message);
        if (cached != null) {
            localCache.put(message, cached);
            return cached;
        }
        
        // L3: 调用 API
        String result = callAzureOpenAI(message);
        
        // 写入缓存
        redisCache.put(message, result);
        localCache.put(message, result);
        
        return result;
    }
}

十四、安全最佳实践

14.1 密钥轮换

@Service
public class KeyRotationService {
    
    private volatile String currentApiKey;
    private volatile String nextApiKey;
    
    @Scheduled(cron = "0 0 0 * * ?")  // 每天凌晨
    public void rotateKeys() {
        log.info("开始密钥轮换");
        
        try {
            // 1. 从 Key Vault 获取新密钥
            String newKey = keyVaultClient.getSecret("azure-openai-key-new");
            
            // 2. 更新下一个密钥
            nextApiKey = newKey;
            
            // 3. 等待一段时间,确保所有请求使用新密钥
            Thread.sleep(60000);
            
            // 4. 切换到新密钥
            currentApiKey = nextApiKey;
            
            // 5. 删除旧密钥
            keyVaultClient.deleteSecret("azure-openai-key-old");
            
            log.info("密钥轮换完成");
            
        } catch (Exception e) {
            log.error("密钥轮换失败", e);
        }
    }
    
    public String getCurrentKey() {
        return currentApiKey;
    }
}

14.2 请求签名

@Component
public class RequestSignatureInterceptor implements ClientHttpRequestInterceptor {
    
    @Override
    public ClientHttpResponse intercept(
            HttpRequest request,
            byte[] body,
            ClientHttpRequestExecution execution) throws IOException {
        
        // 添加时间戳
        String timestamp = String.valueOf(System.currentTimeMillis());
        request.getHeaders().add("X-Timestamp", timestamp);
        
        // 生成签名
        String signature = generateSignature(body, timestamp);
        request.getHeaders().add("X-Signature", signature);
        
        return execution.execute(request, body);
    }
    
    private String generateSignature(byte[] body, String timestamp) {
        // 使用 HMAC-SHA256 生成签名
        String data = new String(body) + timestamp;
        return HmacUtils.hmacSha256Hex(secretKey, data);
    }
}

14.3 IP 白名单

@Configuration
public class IpWhitelistConfig {
    
    @Bean
    public FilterRegistrationBean<IpWhitelistFilter> ipFilter() {
        FilterRegistrationBean<IpWhitelistFilter> registration = 
                new FilterRegistrationBean<>();
        
        registration.setFilter(new IpWhitelistFilter());
        registration.addUrlPatterns("/api/*");
        registration.setOrder(1);
        
        return registration;
    }
}

public class IpWhitelistFilter implements Filter {
    
    private static final Set<String> WHITELIST = Set.of(
        "192.168.1.0/24",
        "10.0.0.0/8"
    );
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                        FilterChain chain) throws IOException, ServletException {
        
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String clientIp = getClientIp(httpRequest);
        
        if (!isWhitelisted(clientIp)) {
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
            httpResponse.getWriter().write("Access denied");
            return;
        }
        
        chain.doFilter(request, response);
    }
    
    private boolean isWhitelisted(String ip) {
        // 检查 IP 是否在白名单中
        return WHITELIST.stream()
                .anyMatch(range -> isInRange(ip, range));
    }
}

十五、故障排查

15.1 常见错误码

@Service
public class ErrorHandlingService {
    
    public ChatResponse handleError(Exception e) {
        if (e instanceof ResourceNotFoundException) {
            return ChatResponse.builder()
                    .success(false)
                    .errorCode("RESOURCE_NOT_FOUND")
                    .errorMessage("Azure OpenAI 资源未找到")
                    .build();
        }
        
        if (e instanceof AuthenticationException) {
            return ChatResponse.builder()
                    .success(false)
                    .errorCode("AUTHENTICATION_FAILED")
                    .errorMessage("认证失败,请检查密钥或托管身份配置")
                    .build();
        }
        
        if (e instanceof QuotaExceededException) {
            return ChatResponse.builder()
                    .success(false)
                    .errorCode("QUOTA_EXCEEDED")
                    .errorMessage("配额已用完,请升级套餐或等待重置")
                    .build();
        }
        
        if (e instanceof RateLimitException) {
            return ChatResponse.builder()
                    .success(false)
                    .errorCode("RATE_LIMIT")
                    .errorMessage("请求过于频繁,请稍后再试")
                    .build();
        }
        
        return ChatResponse.builder()
                .success(false)
                .errorCode("UNKNOWN_ERROR")
                .errorMessage("未知错误:" + e.getMessage())
                .build();
    }
}

15.2 诊断日志

@Aspect
@Component
public class DiagnosticLoggingAspect {
    
    @Around("@annotation(com.example.azureai.annotation.Diagnostic)")
    public Object logDiagnostics(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        
        log.info("=== 诊断开始 ===");
        log.info("方法: {}", methodName);
        log.info("参数: {}", Arrays.toString(args));
        
        long startTime = System.currentTimeMillis();
        
        try {
            Object result = joinPoint.proceed();
            
            long duration = System.currentTimeMillis() - startTime;
            log.info("执行成功,耗时: {}ms", duration);
            log.info("返回值: {}", result);
            
            return result;
            
        } catch (Exception e) {
            long duration = System.currentTimeMillis() - startTime;
            log.error("执行失败,耗时: {}ms", duration);
            log.error("异常信息: ", e);
            
            throw e;
        } finally {
            log.info("=== 诊断结束 ===");
        }
    }
}

15.3 健康检查

@Component
public class AzureOpenAIHealthIndicator implements HealthIndicator {
    
    private final AzureOpenAiChatClient chatClient;
    
    @Override
    public Health health() {
        try {
            // 发送测试请求
            Prompt testPrompt = new Prompt(new UserMessage("test"));
            AiChatResponse response = chatClient.call(testPrompt);
            
            if (response != null) {
                return Health.up()
                        .withDetail("status", "Azure OpenAI 服务正常")
                        .withDetail("model", "gpt-35-turbo")
                        .build();
            }
            
            return Health.down()
                    .withDetail("status", "Azure OpenAI 服务异常")
                    .build();
            
        } catch (Exception e) {
            return Health.down()
                    .withDetail("status", "Azure OpenAI 服务不可用")
                    .withDetail("error", e.getMessage())
                    .build();
        }
    }
}

十六、生产部署

16.1 Docker 部署

Dockerfile:

FROM openjdk:17-jdk-slim

WORKDIR /app

COPY target/spring-ai-azure-demo-1.0.0.jar app.jar

# 使用托管身份,不需要在镜像中包含密钥
ENV AZURE_CLIENT_ID=${AZURE_CLIENT_ID}
ENV AZURE_TENANT_ID=${AZURE_TENANT_ID}

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]

docker-compose.yml:

version: '3.8'

services:
  azure-ai-app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - AZURE_OPENAI_ENDPOINT=${AZURE_OPENAI_ENDPOINT}
      - AZURE_CLIENT_ID=${AZURE_CLIENT_ID}
      - AZURE_TENANT_ID=${AZURE_TENANT_ID}
    networks:
      - ai-network
    restart: unless-stopped

networks:
  ai-network:
    driver: bridge

16.2 Kubernetes 部署

deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: azure-ai-app
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: azure-ai-app
  template:
    metadata:
      labels:
        app: azure-ai-app
        aadpodidbinding: azure-openai-identity
    spec:
      containers:
      - name: app
        image: myregistry.azurecr.io/azure-ai-app:latest
        ports:
        - containerPort: 8080
        env:
        - name: SPRING_PROFILES_ACTIVE
          value: "prod"
        - name: AZURE_OPENAI_ENDPOINT
          valueFrom:
            configMapKeyRef:
              name: azure-config
              key: endpoint
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "1Gi"
            cpu: "1000m"
        livenessProbe:
          httpGet:
            path: /actuator/health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /actuator/health/readiness
            port: 8080
          initialDelaySeconds: 20
          periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: azure-ai-service
  namespace: production
spec:
  selector:
    app: azure-ai-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  type: LoadBalancer

16.3 CI/CD 配置

Azure DevOps Pipeline:

trigger:
  branches:
    include:
    - main

pool:
  vmImage: 'ubuntu-latest'

variables:
  imageName: 'azure-ai-app'
  containerRegistry: 'myregistry.azurecr.io'

stages:
- stage: Build
  jobs:
  - job: BuildJob
    steps:
    - task: Maven@3
      inputs:
        mavenPomFile: 'pom.xml'
        goals: 'clean package'
        options: '-DskipTests'
    
    - task: Docker@2
      inputs:
        command: 'buildAndPush'
        repository: '$(imageName)'
        dockerfile: 'Dockerfile'
        containerRegistry: '$(containerRegistry)'
        tags: |
          $(Build.BuildId)
          latest

- stage: Deploy
  dependsOn: Build
  jobs:
  - deployment: DeployJob
    environment: 'production'
    strategy:
      runOnce:
        deploy:
          steps:
          - task: Kubernetes@1
            inputs:
              connectionType: 'Azure Resource Manager'
              azureSubscription: 'MyAzureSubscription'
              azureResourceGroup: 'my-resource-group'
              kubernetesCluster: 'my-aks-cluster'
              command: 'apply'
              arguments: '-f deployment.yaml'

十七、面试准备

17.1 常见面试题

Q1: Azure OpenAI 和 OpenAI 的主要区别是什么?

A: 主要区别包括:

  1. 数据位置:Azure OpenAI 可以选择数据存储区域
  2. 合规性:Azure OpenAI 提供更多企业合规认证
  3. 安全性:支持虚拟网络、托管身份等企业级安全特性
  4. SLA:Azure OpenAI 提供 99.9% 可用性保证
  5. 集成:与 Azure 生态系统无缝集成

Q2: 如何在项目中实现托管身份认证?

A: 实现步骤:

  1. 在 Azure 门户为应用启用托管身份
  2. 为托管身份分配 “Cognitive Services OpenAI User” 角色
  3. 在代码中使用 DefaultAzureCredentialBuilder
  4. 配置 OpenAIClientBuilder 使用托管身份
  5. 部署到 Azure 环境(App Service、AKS 等)

Q3: 如何优化 Azure OpenAI 的成本?

A: 优化策略:

  1. 选择合适的模型(GPT-3.5 vs GPT-4)
  2. 使用预留容量定价
  3. 实施响应缓存
  4. 优化提示词长度
  5. 实施配额管理
  6. 监控和分析使用情况

Q4: 如何保证 Azure OpenAI 应用的高可用性?

A: 高可用性方案:

  1. 多区域部署
  2. 实现故障转移机制
  3. 配置负载均衡
  4. 实施重试策略
  5. 监控和告警
  6. 定期健康检查

17.2 项目经验描述模板

模板:

在[项目名称]项目中,我负责集成 Azure OpenAI 服务。

技术选型:
- 选择 Azure OpenAI 而非 OpenAI API,因为:
  1. 数据合规要求(数据不能离境)
  2. 企业级安全需求(虚拟网络、托管身份)
  3. SLA 保证(99.9% 可用性)

实现方案:
1. 使用 Spring AI 框架集成 Azure OpenAI
2. 配置托管身份认证,避免密钥管理
3. 实现多区域部署,提高可用性
4. 使用 Redis 缓存,降低成本 30%
5. 集成 Application Insights 监控

遇到的挑战:
1. 初期 API 调用延迟较高
   - 解决:配置连接池,启用 HTTP/2
2. 成本超出预算
   - 解决:实施缓存策略,优化提示词
3. 偶尔出现超时
   - 解决:实现重试机制,配置故障转移

项目成果:
- 响应时间从 3s 降低到 1s
- 成本降低 40%
- 可用性达到 99.95%
- 支持 1000+ 并发用户

十八、总结与展望

18.1 核心要点

通过本章学习,你已经掌握了:

  1. Azure OpenAI 基础

    • 服务特点和优势
    • 资源创建和配置
    • 模型部署和管理
  2. Spring AI 集成

    • 依赖配置
    • 认证方式(API 密钥、托管身份)
    • 基本使用方法
  3. 企业级特性

    • 虚拟网络集成
    • 内容过滤
    • 审计和监控
  4. 生产实践

    • 多区域部署
    • 负载均衡
    • 故障转移
    • 成本优化

18.2 最佳实践总结

  1. 安全性

    • 使用托管身份而非 API 密钥
    • 配置虚拟网络和私有端点
    • 实施 IP 白名单
    • 定期轮换密钥
  2. 可靠性

    • 多区域部署
    • 实现故障转移
    • 配置重试机制
    • 监控和告警
  3. 性能

    • 使用连接池
    • 实施缓存策略
    • 优化提示词
    • 批量处理
  4. 成本

    • 选择合适的模型
    • 使用预留容量
    • 实施配额管理
    • 监控使用情况

18.3 下一步学习

完成本章后,建议:

  1. 实践项目

    • 开发一个企业级应用
    • 部署到 Azure 环境
    • 实施监控和优化
  2. 深入学习

    • Azure 安全最佳实践
    • Kubernetes 部署
    • DevOps 流程
  3. 持续关注

    • Azure OpenAI 新功能
    • 定价变化
    • 最佳实践更新

恭喜你完成了 Azure OpenAI 集成的学习!

你已经掌握了企业级 AI 应用开发的核心技能。

继续学习下一章节:Ollama 本地模型集成,探索本地部署方案!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐