在 Java 中构建 Gen AI 功能从未如此简单

发布: (2026年2月11日 GMT+8 06:24)
13 分钟阅读
原文: Dev.to

Source: Dev.to

请提供您希望翻译的具体文本内容,我将为您翻译成简体中文并保持原有的格式。

介绍

构建 Java 生成式 AI 应用过去是一项复杂且充斥大量样板代码的工作。你需要与原始 HTTP 客户端搏斗,手动编写 JSON 负载,解析流式响应,管理 API 密钥,并拼接可观测性——这些都要在编写任何实际 AI 逻辑之前完成。那些日子已经结束。

Genkit Java 是一个开源框架,使得在 Java 中构建 AI 驱动的应用像定义一个函数一样简单。将其与 Google 的 Gemini 模型和 Google Cloud Run 结合使用,你可以在几分钟内而不是几天内,从零开始部署一个生产级的生成式 AI 服务。

这是一个完整、可运行的示例。克隆它,设置你的 API 密钥,然后运行。

谁适合阅读?

如果你是 Java 开发者,你可能已经看到生成式 AI 革命主要在 Python 和 TypeScript 生态中展开。工具、框架、教程——全部倾向于这些生态系统。Java 开发者只能自行从零构建,或使用冗长、底层的 SDK。

示例展示的内容

一个演示通过 Genkit 使用 Gemini 驱动的翻译 AI 流程的 Java 应用程序。示例重点包括:

  • 类型化的流输入 – 一个使用 @JsonProperty 注解的 TranslateRequest 类。
  • 结构化的 LLM 输出 – Gemini 直接返回 TranslateResponse Java 对象(无需手动 JSON 解析)。
  • 类型化的流输出 – 流向调用方返回完整类型的 TranslateResponse

所有代码都集中在一个 Java 文件以及两个模型类中。没有 Spring Boot,没有大量注解,也没有 XML 配置——只有简洁、可读、类型安全的代码。

前置条件

工具最低版本
Java21+(推荐使用 Eclipse Temurin)
Maven3.6+
Node.js18+(用于 Genkit CLI)
Google GenAI API 密钥可在 Google AI Studio 免费获取
Google Cloud SDK仅在部署到 Cloud Run 时需要

安装 Genkit CLI

Genkit CLI 是用于开发和测试 AI 流程的命令行伴侣。

npm install -g genkit

验证安装:

genkit --version

CLI 为 Dev UI 提供动力,并提供无缝的开发体验(下面会详细说明)。


项目结构

genkit-java-getting-started/
├── src/
│   └── main/
│       ├── java/
│       │   └── com/example/
│       │       ├── App.java                # 主应用程序
│       │       ├── TranslateRequest.java   # 类型化流输入
│       │       └── TranslateResponse.java # 类型化流 + LLM 输出
│       └── resources/
│           └── logback.xml                 # 日志配置
├── pom.xml                                 # 包含 Genkit + Jib 的 Maven 配置
├── run.sh                                  # 快速启动脚本
└── README.md                               # 本文档

快速入门

git clone https://github.com/xavidop/genkit-java-getting-started.git
cd genkit-java-getting-started

export GOOGLE_API_KEY=your-api-key-here

genkit start -- mvn compile exec:java

就是这样——两条命令。你的 AI 驱动的 Java 服务器将在 http://localhost:8080 运行,Genkit 开发 UI 可在 http://localhost:4000 访问。

你也可以直接运行应用:

mvn compile exec:java

模型类

TranslateRequest.java – 流输入

package com.example;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;

/**
 * Input for the translate flow.
 */
public class TranslateRequest {

    @JsonProperty(required = true)
    @JsonPropertyDescription("The text to translate")
    private String text;

    @JsonProperty(required = true)
    @JsonPropertyDescription("The target language (e.g., Spanish, French, Japanese)")
    private String language;

    public TranslateRequest() {}

    public TranslateRequest(String text, String language) {
        this.text = text;
        this.language = language;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getLanguage() {
        return language;
    }

    public void setLanguage(String language) {
        this.language = language;
    }

    @Override
    public String toString() {
        return String.format("TranslateRequest{text='%s', language='%s'}", text, language);
    }
}

TranslateResponse.java – 流输出 & LLM 结构化输出

package com.example;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;

/**
 * Structured output for the translate flow.
 */
public class TranslateResponse {

    @JsonProperty(required = true)
    @JsonPropertyDescription("The original text that was translated")
    private String originalText;

    @JsonProperty(required = true)
    @JsonPropertyDescription("The translated text")
    private String translatedText;

    @JsonProperty(required = true)
    @JsonPropertyDescription("The target language")
    private String language;

    public TranslateResponse() {}

    public TranslateResponse(String originalText, String translatedText, String language) {
        this.originalText = originalText;
        this.translatedText = translatedText;
        this.language = language;
    }

    public String getOriginalText() {
        return originalText;
    }

    public void setOriginalText(String originalText) {
        this.originalText = originalText;
    }

    public String getTranslatedText() {
        return translatedText;
    }

    public void setTranslatedText(String translatedText) {
        this.translatedText = translatedText;
    }

    public String getLanguage() {
        return language;
    }

    public void setLanguage(String language) {
        this.language = language;
    }

    @Override
    public String toString() {
        return String.format(
            "TranslateResponse{originalText='%s', translatedText='%s', language='%s'}",
            originalText, translatedText, language);
    }
}

注意: @JsonPropertyDescription 注解至关重要。Genkit 会将它们作为 JSON 架构的一部分传递给 Gemini,使模型能够准确了解每个字段的含义。


现在,你拥有一个干净、可直接运行的 Java 项目,演示了类型化输入、结构化 LLM 输出,以及使用 Genkit 的最小样板开发体验。祝编码愉快!

Genkit Java 设置

Genkit genkit = Genkit.builder()
    .options(GenkitOptions.builder()
        .devMode(true)
        .reflectionPort(3100)
        .build())
    .plugin(GoogleGenAIPlugin.create())
    .plugin(jetty)
    .build();
  • GoogleGenAIPlugin 会自动读取你的 GOOGLE_API_KEY
  • JettyPlugin 负责处理 HTTP。
  • Genkit 将所有组件串联起来。

定义 translate 流程

genkit.defineFlow(
    "translate",
    TranslateRequest.class,      // typed input
    TranslateResponse.class,     // typed output
    (ctx, request) -> {
        String prompt = String.format(
            "Translate the following text to %s.\n\nText: %s",
            request.getLanguage(),
            request.getText()
        );

        return genkit.generate(
            GenerateOptions.builder()
                .model("googleai/gemini-3-flash-preview")
                .prompt(prompt)
                .outputClass(TranslateResponse.class)   // Gemini returns a typed object!
                .config(GenerationConfig.builder()
                    .temperature(0.1)
                    .build())
                .build()
        );
    }
);

正在发生什么?

步骤说明
TranslateRequest.class 作为流的输入Genkit 会自动将传入的 JSON 反序列化为 TranslateRequest 对象——无需手动 Map.get() 强制转换。
TranslateResponse.class 作为流的输出流返回一个类型化对象,Genkit 会将其序列化为 JSON 作为 HTTP 响应返回。
outputClass(TranslateResponse.class) 在生成调用中Genkit 将从 TranslateResponse 推导出的 JSON schema 发送给 Gemini。Gemini 返回结构化 JSON,Genkit 再将其反序列化回 TranslateResponse 对象——无需手动解析。
单个 defineFlow 调用• 在 Genkit 的内部注册表中注册该流
• 将其暴露为 POST /api/flows/translate 端点
• 在 Dev UI 中可见
• 自动添加完整的 OpenTelemetry 跟踪
• 自动追踪 token 使用量、延迟和错误率

对比 使用 Spring Boot 编写控制器 + 服务 + DTO + 配置 + 异常处理器来实现相同功能时,Genkit 可以消除所有这些样板代码。

开发体验

  • 浏览所有流程 – 例如,查看 translate 流程及其类型化的输入/输出模式。
  • 交互式运行流程 – 填写 TranslateRequest JSON,点击 Run,即可即时看到 TranslateResponse(无需 curl)。
  • 检查追踪 – 查看调用了哪个模型、其输入/输出、执行时间以及 token 使用情况。
  • 查看已注册的模型和工具 – 列出所有可用的 Gemini 模型以及您定义的自定义工具。
  • 测试工具调用 – 实时观察 Gemini 决定调用您的工具。
  • 管理数据集和评估 – 创建测试数据集并评估 AI 输出。

使用 Jib 构建和部署

该项目使用 Jib 直接从 Maven 构建并推送容器镜像——无需 Dockerfile,也不需要 Docker 守护进程。

# Set your GCP project
export PROJECT_ID=$(gcloud config get-value project)
export REGION=us-central1

# Build the container image and push it to Google Container Registry
# (Jib does everything from Maven, no Docker needed!)
mvn compile jib:build -Djib.to.image=gcr.io/$PROJECT_ID/genkit-java-app

# Deploy to Cloud Run
gcloud run deploy genkit-java-app \
  --image gcr.io/$PROJECT_ID/genkit-java-app \
  --region $REGION \
  --platform managed \
  --allow-unauthenticated \
  --set-env-vars "GOOGLE_API_KEY=$GOOGLE_API_KEY" \
  --memory 512Mi \
  --cpu 1

为什么使用 Jib?

  • 无需 Dockerfile – 镜像直接从 Maven 项目构建。
  • 无需 Docker 守护进程 – 机器上不必安装 Docker。
  • 快速重建 – 依赖、类和资源分层;仅重建已更改的层。
  • 可复现的构建 – 确定性强,独立于本地 Docker 环境。
  • 直接推送 – 镜像直接发送到 GCR/Artifact Registry,无需本地 docker push

可选:构建本地 Docker 镜像(需要 Docker)

mvn compile jib:dockerBuild -Djib.to.image=genkit-java-app

Source:

测试 Translate 流程

服务器启动后,发送 TranslateRequest JSON 负载并接收结构化的 TranslateResponse

示例请求

curl -X POST http://localhost:8080/api/flows/translate \
  -H "Content-Type: application/json" \
  -d '{"text":"Building AI applications has never been easier","language":"Spanish"}'

示例响应

{
  "originalText": "Building AI applications has never been easier",
  "translatedText": "Construir aplicaciones de IA nunca ha sido tan fácil",
  "language": "Spanish"
}

尝试其他语言

法语

curl -X POST http://localhost:8080/api/flows/translate \
  -H "Content-Type: application/json" \
  -d '{"text":"Genkit makes Java AI development simple","language":"French"}'

日语

curl -X POST http://localhost:8080/api/flows/translate \
  -H "Content-Type: application/json" \
  -d '{"text":"Hello world","language":"Japanese"}'

注意: 响应始终是一个 结构化的 JSON 对象,而不是原始字符串。这是使用 outputClass(TranslateResponse.class) 的结果:Gemini 返回结构化数据,Genkit 会自动将其反序列化为你的 Java 类。

生产级特性

当您使用 Genkit 时,您获得的不仅仅是 API 调用的薄包装:

  • OpenTelemetry 跟踪 用于每一次流程执行

    • 按流程和模型调用的延迟跟踪
    • 令牌使用情况(输入 / 输出 / “思考” 令牌)
    • 错误率和失败跟踪
    • 完整的跨度层级,展示执行路径
  • 模型切换 – 只需一行代码即可更换底层模型:

// Switch from Gemini to OpenAI
.plugin(OpenAIPlugin.create());

// Or use Anthropic Claude
.plugin(AnthropicPlugin.create());

Genkit 提供了一个面向生产的框架,用于构建、测试和部署 AI 驱动的 Java 应用程序,具备最小的样板代码和最大的可观测性。

Genkit Java 入门

// Or run locally with Ollama
.plugin(OllamaPlugin.create())

Genkit 支持 10+ 模型提供商、向量数据库(Pinecone、Weaviate、PostgreSQL)、Firebase 集成等。对于 Java 开发者来说,这正是 Genkit 大显身手的地方:flows、generate 调用,甚至 LLM 响应都是完整类型化的。

定义类型化 Flow

// The flow takes a TranslateRequest and returns a TranslateResponse
genkit.defineFlow(
    "translate",
    TranslateRequest.class,
    TranslateResponse.class,
    /* … */
);

生成类型化响应

// The LLM returns a TranslateResponse directly—no string parsing required
genkit.generate(
    GenerateOptions.builder()
        .outputClass(TranslateResponse.class)
        .build()
);

Genkit 根据你的 @JsonProperty@JsonPropertyDescription 注解生成 JSON 架构并发送给 Gemini,从而模型返回的结构化数据可以直接映射到你的 Java 类。无需对象强制转换、无需 response.getText() + objectMapper.readValue(),也不会出现运行时意外。


本项目涵盖内容

  • RAG – 检索增强生成,使用向量存储(Firestore、Pinecone、pgvector、Weaviate)
  • 多代理编排 – 协调多个 AI 代理
  • 聊天会话 – 多轮对话并保持会话持久性
  • 评估 – 类 RAGAS 的指标,用于衡量 AI 输出质量
  • MCP 集成 – 连接到模型上下文协议(Model Context Protocol)服务器
  • Spring Boot – 对现有 Spring 应用使用 Spring 插件而非 Jetty
  • Firebase – 以 Cloud Functions 部署,并使用 Firestore 向量搜索

深入了解完整的 Genkit Java 文档和 samples 目录,以进一步探索。

为什么使用 Genkit Java?

  • 类型化的输入/输出消除解析错误。
  • 结构化的 LLM 响应直接映射到 Java 类。
  • 内置可观测性,便于调试。
  • 无缝部署到云平台。

结果: 使用最少的代码构建强大的生成式 AI 应用。

您可以在 GitHub 仓库 中找到此示例的完整代码。

祝编码愉快!

0 浏览
Back to Blog

相关文章

阅读更多 »

模块-01--面试题 _JAVA

1. Java 中有多少种数据类型?‑ 基本数据类型 共 8 种:byte、short、int、long、float、double、char、boolean ‑ 非基本引用数据类型:...

超级简易 Java Web Scraping (Jsoup)

添加 Jsoup xml org.jsoup jsoup 1.17.2 创建一个最小的爬虫 在本例中,我们将打印页面中所有链接的文本和 URL: java import org.jsoup.Jsoup; im...