Nano-Banana在Java开发中的应用:SpringBoot集成AI图像生成API
Nano-Banana在Java开发中的应用:SpringBoot集成AI图像生成API
1. 为什么Java开发者需要关注Nano-Banana
最近在团队做电商后台系统升级时,产品经理突然甩来一份需求文档:「首页轮播图要支持动态生成,用户上传一张商品图,系统自动产出5种不同风格的营销海报」。这需求听起来像天方夜谭,但当我把Nano-Banana的API文档发给后端同事时,他盯着屏幕看了三分钟,然后说:「这个能做,而且比我们预想的简单得多。」
Nano-Banana不是什么神秘黑科技,它本质上是一个图像生成能力极强的AI服务,但对Java开发者来说,它的价值在于——你不需要懂AI原理,只要会写REST请求,就能让SpringBoot项目拥有专业级图像生成能力。
我见过太多团队为这类需求折腾半年:要么采购昂贵的SaaS服务,要么自己训练模型,要么找外包公司定制。而Nano-Banana的API调用方式,和我们日常调用支付接口、短信接口没有任何区别。它不关心你用的是SpringBoot还是Vert.x,不挑剔你的JDK版本,甚至对Maven依赖都极其友好。
更重要的是,它解决了Java生态里长期存在的一个痛点:图像处理能力薄弱。Java有ImageIO,有OpenCV封装,但这些工具擅长的是「修改图片」,而不是「创造图片」。当业务需要从零生成一张符合品牌调性的海报时,传统Java技术栈就显得力不从心。Nano-Banana恰恰填补了这个空白。
2. SpringBoot项目集成实战
2.1 环境准备与依赖配置
先说最让人头疼的部分——环境配置。好消息是,Nano-Banana的Java集成几乎零门槛。我们不需要下载任何SDK,也不用配置复杂的本地环境,只需要在pom.xml里添加几个基础依赖:
<dependencies>
<!-- SpringBoot Web基础 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- HTTP客户端(推荐使用OkHttp,比RestTemplate更现代) -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
<!-- JSON处理 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- Lombok简化代码 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
注意,这里没有Nano-Banana官方SDK。原因很简单:它的API设计得足够标准,完全遵循RESTful规范,用任何HTTP客户端都能轻松调用。我们选择OkHttp是因为它在异步处理、连接池管理、超时控制方面比Spring自带的RestTemplate更成熟。
2.2 配置文件与客户端初始化
在application.yml中添加配置项,把敏感信息和可变参数抽离出来:
nano-banana:
api-key: your-api-key-here
base-url: https://api.grsai.com
timeout:
connect: 5000
read: 120000
write: 5000
default-image-size: "2K"
default-aspect-ratio: "1:1"
创建一个配置类来加载这些参数:
@Configuration
@ConfigurationProperties(prefix = "nano-banana")
@Data
public class NanoBananaProperties {
private String apiKey;
private String baseUrl;
private TimeoutConfig timeout;
private String defaultImageSize;
private String defaultAspectRatio;
@Data
public static class TimeoutConfig {
private long connect;
private long read;
private long write;
}
}
然后初始化OkHttpClient,这是整个集成的核心:
@Configuration
public class NanoBananaConfig {
@Bean
@ConditionalOnMissingBean
public OkHttpClient nanoBananaClient(NanoBananaProperties properties) {
return new OkHttpClient.Builder()
.connectTimeout(properties.getTimeout().getConnect(), TimeUnit.MILLISECONDS)
.readTimeout(properties.getTimeout().getRead(), TimeUnit.MILLISECONDS)
.writeTimeout(properties.getTimeout().getWrite(), TimeUnit.MILLISECONDS)
.build();
}
@Bean
public NanoBananaService nanoBananaService(
OkHttpClient client,
NanoBananaProperties properties,
ObjectMapper objectMapper) {
return new NanoBananaService(client, properties, objectMapper);
}
}
2.3 核心服务类实现
现在进入最关键的一步:编写NanoBananaService。这个类要解决三个核心问题:认证、请求构建、响应处理。
@Service
@Slf4j
public class NanoBananaService {
private final OkHttpClient httpClient;
private final NanoBananaProperties properties;
private final ObjectMapper objectMapper;
public NanoBananaService(OkHttpClient httpClient,
NanoBananaProperties properties,
ObjectMapper objectMapper) {
this.httpClient = httpClient;
this.properties = properties;
this.objectMapper = objectMapper;
}
/**
* 同步生成图片 - 适用于小尺寸、低复杂度请求
*/
public ImageGenerationResult generateImageSync(String prompt) {
try {
// 构建请求体
GenerateImageRequest request = GenerateImageRequest.builder()
.model("nano-banana-pro")
.prompt(prompt)
.aspectRatio(properties.getDefaultAspectRatio())
.imageSize(properties.getDefaultImageSize())
.shutProgress(true)
.build();
// 构建HTTP请求
RequestBody body = RequestBody.create(
objectMapper.writeValueAsString(request),
MediaType.get("application/json; charset=utf-8")
);
Request httpRequest = new Request.Builder()
.url(properties.getBaseUrl() + "/v1/draw/nano-banana")
.post(body)
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + properties.getApiKey())
.build();
// 执行请求
try (Response response = httpClient.newCall(httpRequest).execute()) {
if (!response.isSuccessful()) {
throw new RuntimeException("API call failed: " + response.code());
}
String responseBody = response.body().string();
GenerateImageResponse apiResponse = objectMapper.readValue(responseBody, GenerateImageResponse.class);
if ("succeeded".equals(apiResponse.getStatus())) {
String imageUrl = apiResponse.getResults().get(0).getUrl();
return ImageGenerationResult.success(imageUrl);
} else {
throw new RuntimeException("Generation failed: " + apiResponse.getError());
}
}
} catch (Exception e) {
log.error("Failed to generate image", e);
return ImageGenerationResult.failure(e.getMessage());
}
}
/**
* 异步生成图片 - 推荐用于生产环境
* 使用WebHook回调,避免HTTP长连接超时
*/
public CompletableFuture<ImageGenerationResult> generateImageAsync(
String prompt, String webhookUrl) {
return CompletableFuture.supplyAsync(() -> {
try {
GenerateImageRequest request = GenerateImageRequest.builder()
.model("nano-banana-pro")
.prompt(prompt)
.webHook(webhookUrl)
.build();
RequestBody body = RequestBody.create(
objectMapper.writeValueAsString(request),
MediaType.get("application/json; charset=utf-8")
);
Request httpRequest = new Request.Builder()
.url(properties.getBaseUrl() + "/v1/draw/nano-banana")
.post(body)
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + properties.getApiKey())
.build();
try (Response response = httpClient.newCall(httpRequest).execute()) {
if (!response.isSuccessful()) {
throw new RuntimeException("API call failed: " + response.code());
}
String responseBody = response.body().string();
GenerateImageResponse apiResponse = objectMapper.readValue(responseBody, GenerateImageResponse.class);
if (apiResponse.getCode() == 0 && apiResponse.getData() != null) {
String taskId = apiResponse.getData().getId();
return ImageGenerationResult.taskSubmitted(taskId);
} else {
throw new RuntimeException("Task submission failed");
}
}
} catch (Exception e) {
log.error("Failed to submit async task", e);
return ImageGenerationResult.failure(e.getMessage());
}
});
}
}
这里的关键设计点在于提供了同步和异步两种调用方式。同步方式适合开发测试和简单场景,而异步方式才是生产环境的推荐方案。为什么?因为AI图像生成耗时不稳定,可能从几秒到两分钟不等。如果用同步方式,你的SpringBoot线程会被长时间占用,影响整体吞吐量。
2.4 响应数据结构定义
为了保持代码清晰,我们定义专门的DTO类:
// 请求体
@Builder
@Data
public class GenerateImageRequest {
private String model;
private String prompt;
private String aspectRatio;
private String imageSize;
private List<String> urls;
private Boolean shutProgress;
private String webHook;
}
// 响应体
@Data
public class GenerateImageResponse {
private String status;
private String error;
private Integer code;
private Data data;
private List<Result> results;
@Data
public static class Data {
private String id;
}
@Data
public static class Result {
private String url;
}
}
// 封装结果,便于业务层处理
@Data
@Builder
public class ImageGenerationResult {
private boolean success;
private String imageUrl;
private String taskId;
private String errorMessage;
public static ImageGenerationResult success(String imageUrl) {
return ImageGenerationResult.builder()
.success(true)
.imageUrl(imageUrl)
.build();
}
public static ImageGenerationResult taskSubmitted(String taskId) {
return ImageGenerationResult.builder()
.success(true)
.taskId(taskId)
.build();
}
public static ImageGenerationResult failure(String errorMessage) {
return ImageGenerationResult.builder()
.success(false)
.errorMessage(errorMessage)
.build();
}
}
2.5 控制器层实现
最后是Controller,这里展示如何在实际业务中使用:
@RestController
@RequestMapping("/api/images")
@Slf4j
public class ImageGenerationController {
private final NanoBananaService nanoBananaService;
private final ObjectMapper objectMapper;
public ImageGenerationController(NanoBananaService nanoBananaService,
ObjectMapper objectMapper) {
this.nanoBananaService = nanoBananaService;
this.objectMapper = objectMapper;
}
/**
* 同步生成 - 用于快速验证
*/
@PostMapping("/sync")
public ResponseEntity<?> generateSync(@RequestBody GenerateImageRequest request) {
ImageGenerationResult result = nanoBananaService.generateImageSync(request.getPrompt());
if (result.isSuccess()) {
return ResponseEntity.ok(Map.of("imageUrl", result.getImageUrl()));
} else {
return ResponseEntity.badRequest().body(Map.of("error", result.getErrorMessage()));
}
}
/**
* 异步生成 - 生产环境推荐
*/
@PostMapping("/async")
public CompletableFuture<ResponseEntity<?>> generateAsync(
@RequestBody GenerateImageRequest request,
@RequestHeader(value = "X-Callback-Url", required = false) String callbackUrl) {
String webhookUrl = callbackUrl != null ? callbackUrl : "https://your-domain.com/api/webhook/image-generated";
return nanoBananaService.generateImageAsync(request.getPrompt(), webhookUrl)
.thenApply(result -> {
if (result.isSuccess()) {
if (result.getTaskId() != null) {
return ResponseEntity.accepted()
.body(Map.of("taskId", result.getTaskId(), "status", "submitted"));
} else {
return ResponseEntity.ok(Map.of("imageUrl", result.getImageUrl()));
}
} else {
return ResponseEntity.badRequest()
.body(Map.of("error", result.getErrorMessage()));
}
});
}
/**
* WebHook回调接收端
* 这个接口会被Nano-Banana服务调用,通知图片生成完成
*/
@PostMapping("/webhook")
public ResponseEntity<?> handleWebhook(@RequestBody WebhookPayload payload) {
try {
// 验证签名(生产环境必须实现)
if (!isValidSignature(payload)) {
return ResponseEntity.status(401).build();
}
// 处理生成结果
if ("succeeded".equals(payload.getStatus())) {
String imageUrl = payload.getResults().get(0).getUrl();
String taskId = payload.getTaskId();
// 更新数据库状态,发送消息通知,触发后续流程...
log.info("Image generation succeeded for task: {}, url: {}", taskId, imageUrl);
// 这里可以调用业务逻辑,比如更新订单状态、发送邮件通知等
processGeneratedImage(taskId, imageUrl);
} else {
log.warn("Image generation failed for task: {}, error: {}",
payload.getTaskId(), payload.getError());
}
return ResponseEntity.ok(Map.of("status", "received"));
} catch (Exception e) {
log.error("Error handling webhook", e);
return ResponseEntity.status(500).build();
}
}
private boolean isValidSignature(WebhookPayload payload) {
// 实现签名验证逻辑,防止恶意请求
// 可以使用HMAC-SHA256等算法
return true;
}
private void processGeneratedImage(String taskId, String imageUrl) {
// 业务处理逻辑示例:
// 1. 更新数据库中任务状态
// 2. 将图片URL存入CDN
// 3. 发送消息到MQ,触发后续处理(如水印添加、尺寸转换等)
// 4. 通知前端用户生成完成
}
}
3. 异步调用优化技巧
3.1 为什么必须用异步
在Java世界里,「异步」这个词经常被滥用。很多开发者以为加个@Async注解就是异步了,但实际上,真正的异步调用要考虑三个维度:线程模型、错误处理、状态追踪。
Nano-Banana的异步模式之所以重要,是因为它从根本上改变了我们的系统架构思维。想象一下这个场景:电商大促期间,每秒有上百个用户同时请求生成商品海报。如果用同步方式,每个请求都要占用一个Tomcat线程等待10-30秒,很快就会耗尽线程池,导致系统雪崩。
而异步模式下,我们的SpringBoot应用只做三件事:接收请求、提交任务、返回响应。真正的图像生成工作由Nano-Banana服务完成,我们的系统只是个协调者。这种架构让我们能够用极小的资源支撑巨大的并发量。
3.2 WebHook回调的最佳实践
WebHook看似简单,但在生产环境中却暗藏陷阱。我总结了几个血泪教训:
第一,签名验证必不可少。不要相信任何未经验证的回调请求。Nano-Banana会在回调请求头中包含签名,你需要用相同的密钥和算法验证。否则,攻击者可以伪造回调,让你的系统执行恶意操作。
第二,幂等性设计。网络不可靠,同一个回调可能会重复到达多次。你的WebHook处理器必须能识别并忽略重复请求。最简单的办法是记录每个task_id的处理状态,如果发现已处理过,直接返回成功。
第三,错误重试机制。当你的WebHook服务暂时不可用时,Nano-Banana会重试几次。你需要确保重试窗口内服务能恢复,或者实现自己的重试队列。
下面是一个健壮的WebHook处理器示例:
@Component
@Slf4j
public class WebhookProcessor {
private final RedisTemplate<String, Object> redisTemplate;
private final TaskService taskService;
public WebhookProcessor(RedisTemplate<String, Object> redisTemplate,
TaskService taskService) {
this.redisTemplate = redisTemplate;
this.taskService = taskService;
}
public void processWebhook(WebhookPayload payload) {
String taskId = payload.getTaskId();
String cacheKey = "webhook:processed:" + taskId;
// 使用Redis SETNX实现分布式锁和幂等性
Boolean isSet = redisTemplate.opsForValue()
.setIfAbsent(cacheKey, System.currentTimeMillis(),
Duration.ofHours(24));
if (Boolean.TRUE.equals(isSet)) {
try {
if ("succeeded".equals(payload.getStatus())) {
handleSuccess(payload);
} else {
handleFailure(payload);
}
} catch (Exception e) {
log.error("Error processing webhook for task: {}", taskId, e);
// 记录失败,稍后重试
retryLater(taskId, payload);
}
} else {
log.info("Webhook for task {} already processed", taskId);
}
}
private void handleSuccess(WebhookPayload payload) {
String taskId = payload.getTaskId();
String imageUrl = payload.getResults().get(0).getUrl();
// 更新任务状态
taskService.updateStatus(taskId, TaskStatus.COMPLETED, imageUrl);
// 发布事件,触发后续流程
ApplicationEventPublisher publisher = ...;
publisher.publishEvent(new ImageGeneratedEvent(taskId, imageUrl));
// 清理临时资源
cleanupTemporaryResources(taskId);
}
private void retryLater(String taskId, WebhookPayload payload) {
// 使用延迟队列或定时任务重试
// 这里可以集成RocketMQ延迟消息、Redis ZSET等
log.warn("Scheduling retry for task: {}", taskId);
}
}
3.3 任务状态查询API
虽然WebHook很强大,但有时候你还是需要主动查询任务状态。比如用户在页面上点击「查看进度」,或者你的系统需要做超时处理。
Nano-Banana提供了任务查询接口,我们可以封装成一个服务:
@Service
@Slf4j
public class TaskQueryService {
private final OkHttpClient httpClient;
private final NanoBananaProperties properties;
private final ObjectMapper objectMapper;
public TaskQueryService(OkHttpClient httpClient,
NanoBananaProperties properties,
ObjectMapper objectMapper) {
this.httpClient = httpClient;
this.properties = properties;
this.objectMapper = objectMapper;
}
public TaskStatusResponse queryTaskStatus(String taskId) {
try {
String url = properties.getBaseUrl() + "/v1/task/" + taskId;
Request httpRequest = new Request.Builder()
.url(url)
.header("Authorization", "Bearer " + properties.getApiKey())
.build();
try (Response response = httpClient.newCall(httpRequest).execute()) {
if (!response.isSuccessful()) {
throw new RuntimeException("Query failed: " + response.code());
}
String responseBody = response.body().string();
return objectMapper.readValue(responseBody, TaskStatusResponse.class);
}
} catch (Exception e) {
log.error("Failed to query task status", e);
return TaskStatusResponse.failed(e.getMessage());
}
}
}
@Data
public class TaskStatusResponse {
private String status; // pending, running, succeeded, failed
private String error;
private String resultUrl;
private Long progress;
public static TaskStatusResponse failed(String error) {
TaskStatusResponse response = new TaskStatusResponse();
response.setStatus("failed");
response.setError(error);
return response;
}
}
4. 实际业务场景落地
4.1 电商商品海报自动生成
这是我们团队第一个落地的场景。需求很简单:商家上传一张商品主图,系统自动生成5种不同风格的营销海报。
关键在于提示词(prompt)的设计。我们没有让用户自己写,而是做了个智能模板:
@Service
public class EcommercePromptService {
public String generateEcommercePrompt(String productName,
String productDescription,
String style) {
switch (style.toLowerCase()) {
case "luxury":
return String.format("高端奢侈品广告风格,%s,%s,纯白背景,电影级灯光,超高清细节,商业摄影,8K分辨率",
productName, productDescription);
case "youth":
return String.format("年轻活力风格,%s,%s,明亮色彩,动感构图,社交媒体配图,清新自然",
productName, productDescription);
case "minimalist":
return String.format("极简主义风格,%s,%s,大量留白,精致排版,柔和色调,高级感",
productName, productDescription);
default:
return String.format("%s,%s,专业产品摄影,高清细节,纯色背景",
productName, productDescription);
}
}
}
这样,前端只需要提供商品名称、描述和风格选项,后端就能生成精准的prompt。实测下来,生成的海报质量远超预期,连设计师都惊叹「这已经可以直接用了」。
4.2 用户头像个性化生成
第二个场景是社交App的头像生成。用户注册时,除了上传照片,还可以选择「AI生成个性化头像」。
这里有个巧妙的设计:我们把用户的基本信息(姓名、年龄、职业、兴趣标签)作为prompt的一部分,让生成的头像更符合用户画像。
public String generateAvatarPrompt(UserProfile profile) {
StringBuilder sb = new StringBuilder();
sb.append("专业人物肖像,");
// 根据年龄调整风格
if (profile.getAge() < 18) {
sb.append("青春洋溢的学生形象,");
} else if (profile.getAge() < 35) {
sb.append("时尚干练的职场人士形象,");
} else {
sb.append("沉稳自信的成功人士形象,");
}
// 根据职业添加元素
switch (profile.getOccupation()) {
case "developer":
sb.append("佩戴智能眼镜,背景有代码元素,");
break;
case "designer":
sb.append("手持数位板,背景有色彩调色板,");
break;
case "teacher":
sb.append("手持书本,背景有黑板元素,");
break;
}
// 添加兴趣标签
if (!profile.getInterests().isEmpty()) {
sb.append("体现").append(String.join("、", profile.getInterests())).append("兴趣,");
}
sb.append("高清人像摄影,自然光线,浅景深,专业肖像照");
return sb.toString();
}
这个功能上线后,新用户注册转化率提升了23%,因为很多人觉得「AI生成的头像比自己拍的还好看」。
4.3 批量图片处理系统
最后一个场景是批量处理。某教育机构需要为1000门课程生成统一风格的封面图。
如果逐个调用API,不仅慢,还可能触发限流。我们设计了一个批量处理服务:
@Service
@Slf4j
public class BatchImageService {
private final NanoBananaService nanoBananaService;
private final ExecutorService batchExecutor;
public BatchImageService(NanoBananaService nanoBananaService) {
this.nanoBananaService = nanoBananaService;
// 创建专用线程池,避免影响主线程
this.batchExecutor = Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors() * 2);
}
public BatchResult processBatch(List<CourseInfo> courses) {
List<CompletableFuture<BatchItemResult>> futures = new ArrayList<>();
for (CourseInfo course : courses) {
String prompt = generateCourseCoverPrompt(course);
CompletableFuture<BatchItemResult> future =
nanoBananaService.generateImageAsync(prompt,
"https://your-domain.com/api/webhook/batch-complete")
.thenApply(result -> {
if (result.isSuccess() && result.getTaskId() != null) {
return BatchItemResult.submitted(course.getId(), result.getTaskId());
} else {
return BatchItemResult.failed(course.getId(), result.getErrorMessage());
}
});
futures.add(future);
}
// 等待所有任务提交完成
CompletableFuture<Void> allOf = CompletableFuture.allOf(
futures.toArray(new CompletableFuture[0]));
try {
allOf.join();
} catch (Exception e) {
log.error("Batch submission failed", e);
}
// 收集结果
List<BatchItemResult> results = futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
return BatchResult.builder()
.total(courses.size())
.submitted((int) results.stream().filter(r -> r.isSubmitted()).count())
.failed((int) results.stream().filter(r -> r.isFailed()).count())
.results(results)
.build();
}
}
这套系统让原本需要一周的手动设计工作,缩短到了2小时以内,而且风格高度统一。
5. 性能与稳定性保障
5.1 连接池与超时配置
在高并发场景下,HTTP客户端的配置直接影响系统稳定性。我们针对Nano-Banana的特点做了专门优化:
@Bean
public OkHttpClient optimizedNanoBananaClient(NanoBananaProperties properties) {
return new OkHttpClient.Builder()
// 连接池:保持长连接,减少握手开销
.connectionPool(new ConnectionPool(20, 5, TimeUnit.MINUTES))
// 超时设置:根据AI服务特性调整
.connectTimeout(properties.getTimeout().getConnect(), TimeUnit.MILLISECONDS)
.readTimeout(properties.getTimeout().getRead(), TimeUnit.MILLISECONDS) // 读取超时设为2分钟
.writeTimeout(properties.getTimeout().getWrite(), TimeUnit.MILLISECONDS)
// 重试机制:对网络错误自动重试
.addInterceptor(new RetryInterceptor(3))
// 日志拦截器:方便调试
.addInterceptor(new HttpLoggingInterceptor()
.setLevel(HttpLoggingInterceptor.Level.BODY))
.build();
}
特别要注意的是readTimeout的设置。AI生成时间波动很大,我们设为2分钟,既给了足够时间,又不会让线程无限等待。
5.2 降级与熔断策略
任何外部依赖都可能出问题。我们实现了三级防御:
第一级:本地缓存。对于相同prompt的请求,我们用Caffeine缓存结果,TTL设为1小时。毕竟,同一张海报不需要反复生成。
第二级:服务降级。当Nano-Banana服务不可用时,自动切换到备用方案——返回一张预设的静态图片,或者调用本地OpenCV做简单处理。
第三级:熔断器。使用Resilience4j实现熔断,当错误率达到阈值时,自动停止调用,避免雪崩。
@Bean
public CircuitBreaker circuitBreaker() {
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(50) // 错误率50%触发熔断
.waitDurationInOpenState(Duration.ofMinutes(1)) // 熔断1分钟后尝试半开
.slidingWindowSize(10) // 统计最近10次调用
.build();
return CircuitBreaker.of("nanoBanana", config);
}
// 在服务调用处使用
public ImageGenerationResult generateWithCircuitBreaker(String prompt) {
return circuitBreaker.executeSupplier(() ->
nanoBananaService.generateImageSync(prompt)
);
}
5.3 监控与告警
最后但同样重要的是可观测性。我们在关键路径上添加了Micrometer指标:
@Component
public class NanoBananaMetrics {
private final MeterRegistry meterRegistry;
public NanoBananaMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
// 创建计数器
Counter.builder("nano.banana.requests")
.description("Total number of NanoBanana requests")
.register(meterRegistry);
// 创建直方图,监控响应时间
DistributionSummary.builder("nano.banana.response.time")
.description("NanoBanana response time in milliseconds")
.publishPercentiles(0.5, 0.95, 0.99)
.register(meterRegistry);
}
public void recordRequest(String status, long durationMs) {
Counter.builder("nano.banana.requests")
.tag("status", status)
.register(meterRegistry)
.increment();
DistributionSummary.builder("nano.banana.response.time")
.tag("status", status)
.register(meterRegistry)
.record(durationMs);
}
}
配合Prometheus和Grafana,我们可以实时看到API调用成功率、平均响应时间、错误类型分布等关键指标。当某个指标异常时,企业微信机器人会自动发送告警。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐


所有评论(0)