资讯动态

Java 17 + Google PaLM API:构建生成式 AI 应用实战

发布时间:2026/8/26 4:43:10 来源:尧图企业网站定制
这次我们来看 Java 开发者如何接入生成式 AI。主角不是 Python、不是 LangChain而是 Google PaLM API 配 Java 17。不用买显卡不用本地拉模型只需要 JDK、Maven 和一个 API Key就可以用 Java 代码发起文本生成、对话、文本向量化等请求。PaLM 是 Google 的大语言模型系列PaLM API 提供的是云上推理服务Java 开发者可以通过 HTTPS 直接调用也可以把它接进 Spring Boot 项目变成自己的 REST 接口。这篇文章会从环境准备、Maven 工程搭建、Java 原生 HttpClient 调用、Spring Boot 接口封装、批量任务、性能观察、常见问题排查几个部分展开。目标很明确读完你能用 Java 写一个能跑的 AI 文本生成服务。1. 核心能力速览能力项说明项目类型Google PaLM API Java 后端集成模型能力text-bison-001 文本生成、chat-bison-001 对话、embedding-gecko-001 文本向量化Java 接入方式官方 Java SDK、Vertex AI SDK、纯 HTTP Spring 生态硬件门槛无需本地 GPU云 API 推理启动方式Spring Boot 启动 / 命令行 Java 工程是否支持 API支持本身是 REST API 服务是否支持批量任务支持Java 端用线程池控制并发适合场景文本摘要、翻译、分类、问答、代码辅助、知识库向量化主要成本API 调用次数和输出 Token 数网络要求需要能访问 Google API 服务这里的重点要提前说清楚PaLM API 是云服务不是本地模型。它对开发者手里的设备要求很低普通开发机就能跑但它对网络环境和 Google Cloud 账号有要求。如果你所在网络环境无法访问 Google API那需要先解决网络连通性问题或者在可连通的环境中进行开发和测试。2. Google PaLM API 与 Java 生态概览Google PaLM API 是 Google 对外提供的大语言模型服务接口早期面向开发者开放的是 PaLM 2 系列模型包括文本生成、对话、嵌入三大类能力。现在 Google AI 侧已经逐步演进到 Gemini 系列模型但 PaLM API 时代的调用方式和集成思路没有变HTTP 请求、消息体、Token 限制、API Key 鉴权。对一个 Java 开发者来说学习 PaLM API 的请求结构本质上是在学习大语言模型服务的通用接入方式。Java 生态接入 PaLM API 主要有三条路接入方式依赖上手难度适用场景官方 Java SDKgoogle-cloud-vertexai 或 generative-ai SDK中等深度集成后续想用 Vertex AI 全流程Google Cloud Vertex AI需要 GCP 项目配置偏高企业级项目需要模型调优、部署管理纯 HTTP RestClient/WebClient/HttpClient无额外 SDK 依赖低快速验证、轻量集成、避免 SDK 版本冲突我推荐大多数 Java 开发者从第三条路开始。原因很简单大模型 API 本身就是 HTTP 接口Java 的 HttpClient 和 Jackson 就能处理不引入额外 SDK减少依赖冲突代码也更可控。3. 适用场景与使用边界PaLM API 适合的 Java 应用场景集中在文本理解和文本生成。典型场景包括文本摘要给一段长文让模型输出要点。翻译助手多语言翻译输出格式可控。内容分类客服工单、用户反馈自动分类。问答机器人基于 chat-bison 构建多轮对话。代码辅助生成代码片段、解释报错信息。知识库向量化用 embedding-gecko-001 把文档转成向量接入向量数据库。同时也要说清楚不适合什么场景。PaLM API 是云端 API不适合需要完全离线运行、数据不能出内网的场景。如果企业数据合规要求严格那应该去看 Google Cloud Vertex AI 的企业版部署或者考虑本地开源模型方案。对个人开发者而言PaLM API 的免费额度适合学习和原型验证进入生产环境前需要关注调用成本和配额限制。合规方面要特别强调几点PaLM API 的请求和数据会进入 Google 的服务端涉及用户隐私、商业机密、个人身份信息的数据不要直接发送。发票、合同、病历等敏感材料不要随便传到公共 API。使用生成式 AI 输出时涉及用户生成内容、版权素材、人脸、声音等必须确认授权发布前要做人工复核。4. 环境准备与前置条件开始写代码前先把环境列出来。下面是通用的检查清单实际版本按你自己机器情况调整。4.1 JDK 与 Java 环境变量推荐 JDK 17Spring Boot 3.x 对 JDK 17 支持较好。如果不用 Spring BootJDK 11 以上也足够。JDK 安装完之后主要确认两个环境变量JAVA_HOME指向 JDK 安装目录。PATH包含 %JAVA_HOME%\bin。很多 Java 新手在配置环境时卡住本质是 JAVA_HOME 配了但 PATH 没配或者配了 PATH 但没重开终端。Windows 上配置完要重启命令行窗口Linux/macOS 要执行source ~/.bashrc或source ~/.zshrc。终端验证java -version javac -version mvn -version能正确输出版本号说明 JDK 和 Maven 环境没问题。4.2 获取 PaLM API KeyPaLM API 的鉴权方式比较简单可以通过 Google AI Studio 获取 API Key。获取后建议用环境变量保存不要硬编码在代码里。在 application.yml 或者 Java 启动脚本中读取环境变量例如export PALM_API_KEY你的APIKeyWindows PowerShell 下$env:PALM_API_KEY你的APIKey4.3 网络访问要求PaLM API 是 Google 的云服务需要开发环境能够访问 Google API 域名。如果你在本地网络环境下无法访问建议在海外云服务器上部署测试或使用可以连通 Google API 的开发环境不要因此打断开发节奏。4.4 开发工具IDEIntelliJ IDEA 或 VS Code 均可。Maven3.8 以上。JDK17。可选Postman 或 curl用于调试接口。5. 快速搭建 Java 工程为了减少配置成本我们直接用 Spring Boot 创建工程。如果你不想用 Spring Boot也可以用最基础的 Maven 工程核心代码是一样的。先创建一个 Maven 项目pom.xml 内容如下?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.2.5/version relativePath/ /parent groupIdcom.example/groupId artifactIdpalm-api-java-demo/artifactId version1.0.0/version namepalm-api-java-demo/name descriptionGenerative AI for Java Developers with Google PaLM API/description properties java.version17/java.version /properties dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.fasterxml.jackson.core/groupId artifactIdjackson-databind/artifactId /dependency /dependencies build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId /plugin /plugins /build /project这个工程依赖很简单只有 Spring Web 和 Jackson。Spring Web 提供 MVC 和 HttpClient 集成所需的基础能力Jackson 用来解析 PaLM API 返回的 JSON。然后在src/main/resources/application.yml中做配置server: port: 8080 palm: api-key: ${PALM_API_KEY} base-url: https://generativelanguage.googleapis.com model: text: text-bison-001 chat: chat-bison-001 embedding: embedding-gecko-001注意palm.api-key是从环境变量PALM_API_KEY读取的不要在 yml 里提交真实 Key。6. 用 Java 调用 PaLM API这里是最核心的部分。我用 Java 自带的java.net.http.HttpClient写一个完整的调用类不依赖第三方 HTTP 库方便你直接复制到工程里使用。6.1 文本生成generateTextPaLM API 的文本生成接口对应text-bison-001模型核心请求结构是prompt.text、temperature、maxOutputTokens。import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; public class PaLMTextClient { private final String apiKey; private final String endpoint; private final ObjectMapper objectMapper new ObjectMapper(); public PaLMTextClient(String apiKey, String baseUrl, String model) { this.apiKey apiKey; this.endpoint baseUrl /v1beta3/models/ model :generateText; } public String generate(String prompt) throws Exception { // 构造请求体 ObjectNode requestBody objectMapper.createObjectNode(); requestBody.putObject(prompt).put(text, prompt); requestBody.put(temperature, 0.7); requestBody.put(maxOutputTokens, 256); HttpRequest request HttpRequest.newBuilder() .uri(URI.create(endpoint)) .timeout(Duration.ofSeconds(30)) .header(Content-Type, application/json) .header(x-goog-api-key, apiKey) .POST(HttpRequest.BodyPublishers.ofString(requestBody.toString())) .build(); HttpClient client HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(10)) .build(); HttpResponseString response client.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() ! 200) { throw new RuntimeException(PaLM API 调用失败状态码 response.statusCode() 响应 response.body()); } JsonNode root objectMapper.readTree(response.body()); return root.path(candidates).path(0).path(output).asText(); } public static void main(String[] args) throws Exception { String apiKey System.getenv(PALM_API_KEY); if (apiKey null || apiKey.isBlank()) { throw new IllegalStateException(请先设置 PALM_API_KEY 环境变量); } PaLMTextClient client new PaLMTextClient(apiKey, https://generativelanguage.googleapis.com, text-bison-001); String result client.generate(用 Java 写一段快速排序的代码并解释其时间复杂度。); System.out.println(result); } }运行这个 main 方法之前确认环境变量已经设置好。输出是一段包含快速排序代码的解释文本。判断是否成功的标准HTTP 状态码 200。candidates[0].output非空。输出文本是要求的内容。常见失败原因API Key 无效或没设置。网络不通。请求体结构不匹配。模型名错误。6.2 对话模型chat-bison对话模型和文本生成模型的请求格式不同使用的是messages数组。import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; public class PaLMChatClient { private final String apiKey; private final String endpoint; private final ObjectMapper objectMapper new ObjectMapper(); public PaLMChatClient(String apiKey, String baseUrl, String model) { this.apiKey apiKey; this.endpoint baseUrl /v1beta3/models/ model :chat; } public String chat(String userMessage) throws Exception { ObjectNode requestBody objectMapper.createObjectNode(); ArrayNode messages requestBody.putArray(messages); ObjectNode message messages.addObject(); message.put(content, userMessage); HttpRequest request HttpRequest.newBuilder() .uri(URI.create(endpoint)) .timeout(Duration.ofSeconds(30)) .header(Content-Type, application/json) .header(x-goog-api-key, apiKey) .POST(HttpRequest.BodyPublishers.ofString(requestBody.toString())) .build(); HttpResponseString response HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() ! 200) { throw new RuntimeException(请求失败 response.statusCode() response.body()); } JsonNode root objectMapper.readTree(response.body()); return root.path(candidates).path(0).path(content).asText(); } public static void main(String[] args) throws Exception { String apiKey System.getenv(PALM_API_KEY); PaLMChatClient client new PaLMChatClient(apiKey, https://generativelanguage.googleapis.com, chat-bison-001); String reply client.chat(解释一下 JVM 的垃圾回收机制); System.out.println(reply); } }chat-bison 支持多轮对话但你需要在 messages 中维护上下文。每轮把用户输入和模型输出都追加进 messages模型才能记住前文。6.3 Embedding 文本向量化embedding-gecko-001 模型可以把文本转成向量用于语义搜索、文本聚类、知识库构建。import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; public class PaLMEmbeddingClient { private final String apiKey; private final String endpoint; private final ObjectMapper objectMapper new ObjectMapper(); public PaLMEmbeddingClient(String apiKey, String baseUrl, String model) { this.apiKey apiKey; this.endpoint baseUrl /v1beta3/models/ model :embedText; } public double[] embed(String text) throws Exception { ObjectNode requestBody objectMapper.createObjectNode(); requestBody.put(text, text); HttpRequest request HttpRequest.newBuilder() .uri(URI.create(endpoint)) .timeout(Duration.ofSeconds(30)) .header(Content-Type, application/json) .header(x-goog-api-key, apiKey) .POST(HttpRequest.BodyPublishers.ofString(requestBody.toString())) .build(); HttpResponseString response HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() ! 200) { throw new RuntimeException(请求失败 response.statusCode() response.body()); } JsonNode root objectMapper.readTree(response.body()); JsonNode embeddingValue root.path(embedding).path(value); double[] vector new double[embeddingValue.size()]; for (int i 0; i embeddingValue.size(); i) { vector[i] embeddingValue.get(i).asDouble(); } return vector; } public static void main(String[] args) throws Exception { String apiKey System.getenv(PALM_API_KEY); PaLMEmbeddingClient client new PaLMEmbeddingClient(apiKey, https://generativelanguage.googleapis.com, embedding-gecko-001); double[] vector client.embed(Java 生成式 AI 入门); System.out.println(向量维度: vector.length); } }向量维度取决于模型版本embedding-gecko-001 输出维度通常为 768 或更高实际值以模型文档为准。得到向量后可以存入向量数据库实现语义相似度检索。7. 集成 Spring Boot 实现 REST 接口上面三个客户端类已经可以独立使用。为了服务化我把它封装成一个 Spring Boot REST 接口。先写配置类读取 application.yml 中的值package com.example.palmdemo.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class PaLMConfig { Value(${palm.api-key}) private String apiKey; Value(${palm.base-url}) private String baseUrl; Bean public PaLMTextClient palmTextClient() { return new PaLMTextClient(apiKey, baseUrl, text-bison-001); } Bean public PaLMChatClient palmChatClient() { return new PaLMChatClient(apiKey, baseUrl, chat-bison-001); } Bean public PaLMEmbeddingClient palmEmbeddingClient() { return new PaLMEmbeddingClient(apiKey, baseUrl, embedding-gecko-001); } }然后写一个 Controllerpackage com.example.palmdemo.controller; import com.example.palmdemo.client.PaLMChatClient; import com.example.palmdemo.client.PaLMEmbeddingClient; import com.example.palmdemo.client.PaLMTextClient; import org.springframework.web.bind.annotation.*; import java.util.Map; RestController RequestMapping(/api/ai) public class AIController { private final PaLMTextClient textClient; private final PaLMChatClient chatClient; private final PaLMEmbeddingClient embeddingClient; public AIController(PaLMTextClient textClient, PaLMChatClient chatClient, PaLMEmbeddingClient embeddingClient) { this.textClient textClient; this.chatClient chatClient; this.embeddingClient embeddingClient; } PostMapping(/generate) public MapString, String generate(RequestBody MapString, String request) throws Exception { String prompt request.get(prompt); if (prompt null || prompt.isBlank()) { return Map.of(error, prompt 不能为空); } String result textClient.generate(prompt); return Map.of(result, result); } PostMapping(/chat) public MapString, String chat(RequestBody MapString, String request) throws Exception { String message request.get(message); if (message null || message.isBlank()) { return Map.of(error, message 不能为空); } String reply chatClient.chat(message); return Map.of(reply, reply); } PostMapping(/embedding) public MapString, Object embedding(RequestBody MapString, String request) throws Exception { String text request.get(text); if (text null || text.isBlank()) { return Map.of(error, text 不能为空); } double[] vector embeddingClient.embed(text); return Map.of(dimension, vector.length, vector, vector); } }启动 Spring Boot 后用 curl 测试curl -X POST http://localhost:8080/api/ai/generate \ -H Content-Type: application/json \ -d {prompt: 介绍一下 Java 21 的虚拟线程}响应会包含模型生成的文本。对这个接口做扩展时要注意两点超时机制PaLM API 调用是远程 IO耗时不确定接口层要保持合理超时避免线程被长时间占用。错误处理不要把 API 异常直接抛给前端应该捕获后返回统一错误结构。8. 批量任务与异步处理文本生成接口虽然一次调用很快但要处理一批文本时串行调用效率很低。Java 侧可以用线程池做并发控制。假设现在有一个批量翻译任务把五句话翻译成英文。用 CompletableFuture 配合固定线程池处理import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class BatchExample { public static void main(String[] args) throws Exception { PaLMTextClient client new PaLMTextClient( System.getenv(PALM_API_KEY), https://generativelanguage.googleapis.com, text-bison-001 ); ListString prompts List.of( 翻译成英文今天天气很好。, 翻译成英文Java 是一门严谨的语言。, 翻译成英文生成式 AI 正在改变软件开发。, 翻译成英文多线程编程需要注意线程安全。, 翻译成英文API 设计要考虑版本兼容性。 ); ExecutorService executor Executors.newFixedThreadPool(3); ListCompletableFutureString futures prompts.stream() .map(prompt - CompletableFuture.supplyAsync(() - { try { long start System.currentTimeMillis(); String result client.generate(prompt); long cost System.currentTimeMillis() - start; System.out.println(任务完成耗时 cost ms); return result; } catch (Exception e) { System.err.println(任务失败 e.getMessage()); return ERROR; } }, executor)) .toList(); for (CompletableFutureString future : futures) { System.out.println(future.get(60, TimeUnit.SECONDS)); } executor.shutdown(); } }批量任务设计时要注意线程池大小不要盲目调大PaLM API 接口有配额限制并发过高会被限流。每个任务建议设置超时时间防止某个请求卡死拖垮整个批量任务。失败任务要单独记录日志做重试补偿。可以先把任务 ID 和参数存到数据库成功后更新状态失败后定时重跑。输出结果和输入参数建议分目录管理方便排查。9. 性能观察与成本控制PaLM API 和本地模型不一样它不占本地 GPU 显存这是它在 Java 开发者中容易推广的原因。但云 API 也有自己的性能指标使用时要关注以下几个维度9.1 延迟一次 generateText 调用的延迟通常在 2 到 10 秒取决于网络质量、模型负载和输出 Token 数量。输出越长耗时越长。在测试阶段可以在代码里记录调用耗时long start System.currentTimeMillis(); String result client.generate(prompt); long cost System.currentTimeMillis() - start; System.out.println(接口耗时: cost ms);如果延迟稳定超过 30 秒就要检查网络链路和请求体中的 maxOutputTokens 设置。9.2 Token 消耗与成本PaLM API 按 Token 计费中文场景下 Token 消耗比英文高因为一个中文汉字可能对应多个 Token。影响 Token 消耗的因素有prompt 长度。maxOutputTokens 设置。对话历史长度。控制成本的思路给每个接口设置合理的maxOutputTokens不要给模型无限输出的空间。需要记忆上下文的场景定期裁剪旧消息。相同 prompt 的请求加一层本地缓存例如对固定模板生成结果做 Redis 缓存。批量任务尽量在低峰时段执行同时关注官方配额说明。9.3 限流与配额PaLM API 有每分钟请求数限制。429 状态码说明请求过于频繁。处理方式有两种在客户端增加重试退避策略。降低线程池并发数。一个简单的重试策略private String generateWithRetry(String prompt, int maxRetries) throws Exception { int retries 0; while (true) { try { return generate(prompt); } catch (Exception e) { retries; if (retries maxRetries) { throw e; } Thread.sleep(1000L * retries); } } }10. 常见问题与排查方法问题现象可能原因排查方式解决方案返回 401 UnauthenticatedAPI Key 错误或没有正确注入检查环境变量 PALM_API_KEY重新生成 API Key重启应用返回 403 Permission DeniedPaLM API 未启用或项目无权访问查看 Google Cloud 控制台启用对应 API确认项目配置返回 429 Resource Exhausted请求频率超过配额查看响应头中的配额信息降低并发加重试退避返回 400 Invalid Argument请求 JSON 格式不对打印请求体日志对照模型接口文档修正字段连接超时网络无法连通 API 服务ping 或 curl 检查域名调整网络环境增加超时时间中文乱码编码没设置 UTF-8观察响应字符集统一使用 UTF-8 编码返回结果为空maxOutputTokens 过小或 prompt 无效打印完整响应 JSON增大 Token 上限修正 promptSpring Boot 启动失败端口被占用或配置缺失查看启动日志换端口检查 yml 配置排查这些问题的思路是统一的先看状态码再看响应体再看日志最后检查配置。不要把精力花在猜测上PaLM API 的响应错误信息已经足够清晰打印出来基本能定位。11. 最佳实践与合规建议工程化使用 PaLM API 时下面这些实践值得长期坚持11.1 API Key 管理不要硬编码 API Key 到代码仓库不要提交到 Git。强烈建议本地开发用环境变量。测试环境用配置文件占位符。生产环境用 Secret Manager 或配置中心。11.2 提示词工程同样的模型prompt 写得好不好结果差异很大。写 prompt 时明确角色、任务、输出格式和约束条件。例如你是一个 Java 技术专家。请解释什么是 JVM 垃圾回收要求 1. 使用通俗易懂的比喻。 2. 说明 CMS 和 G1 的区别。 3. 输出不超过 200 字。这种结构化 prompt 比直接说“介绍一下垃圾回收”更稳定。11.3 输出内容校验模型输出不会永远正确。对生成结果做长度校验、关键字校验、格式校验是必要的。如果输出用于生产系统建议加一层人工审核或规则过滤。11.4 数据隐私不要向 PaLM API 发送未脱敏的隐私数据。如果业务必须处理用户个人信息需要先获得用户授权并确认数据传输方式符合相关合规要求。11.5 版权与来源使用生成式 AI 创造内容时涉及图片、文字、音视频素材必须确认素材来源合法不侵犯第三方版权。涉及真实人物肖像、声音时必须获得明确授权。12. 总结Java 开发者接入生成式 AI 并不复杂。Google PaLM API 提供的是标准 REST 接口Java 通过 HttpClient 加 Jackson 就能完成调用。整个流程里最容易踩的坑有三个环境变量没配好、网络访问不了 Google API、请求响应格式搞错。建议你先从最小工程开始跑通一个 generateText 请求确认 API Key、网络、请求格式都正常再逐步扩展 chat、embedding、批量任务和 Spring Boot 接口。后续如果要把模型能力做得更丰富可以在 PaLM API 基础上继续研究提示词工程、向量数据库、RAG 应用架构这些方向对 Java 开发者来说都是可以继续深入的技术路径。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价