首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【AMD ROCm 实战】AMD ROCm + Spring Boot + Spring AI:AMD GPU 加速的本地大模型应用全链路实战

【AMD ROCm 实战】AMD ROCm + Spring Boot + Spring AI:AMD GPU 加速的本地大模型应用全链路实战

作者头像
行者全栈架构师
发布2026-06-30 14:24:27
发布2026-06-30 14:24:27
1510
举报

💡 摘要: 公司要求所有AI应用数据不出内网,NVIDIA A100 一卡难求且价格翻倍,用CPU跑Qwen2.5-7B一个Token要2秒,用户等一个回答要40秒——这不是AI应用,是折磨用户。本文基于我在金融系统内网AI改造中的真实项目经验,介绍如何用 AMD ROCm + Ollama + Spring Boot + Spring AI 构建 AMD GPU 加速的本地大模型应用:ROCm 环境搭建与 GPU 架构兼容、Ollama ROCm 模式部署与量化模型选型、Spring AI 对接 Ollama 的对话/Embedding/Function Calling 全链路、UMA 统一内存架构跑 70B 大模型的实测数据、多 AMD GPU 负载均衡方案。

📅 技术栈版本: Spring Boot 3.4.x | Spring AI 1.0.x | ROCm 7.x | Ollama 0.20.x | JDK 17+ | 更新时间: 2026-06

一、为什么选择 AMD ROCm 做 Java 本地 AI

1.1 企业内网 AI 的三重困境

去年负责一个金融系统的内网 AI 改造项目,要求所有数据不出内网。看似简单,实则处处碰壁:

困境

具体表现

影响

GPU 短缺

NVIDIA A100/H100 价格翻倍,交期3个月+

项目启动延迟

云端不可用

金融监管要求数据不出内网

无法调用 OpenAI/通义等云端 API

CPU 太慢

Qwen2.5-7B 在 CPU 上推理 ~2s/Token

40秒才出完一个回答,用户无法接受

1.2 AMD ROCm 的三个关键优势

2026年的 ROCm 7.x 已经不是2023年那个"勉强能用"的状态了:

优势

说明

对Java开发者意味着什么

生态成熟

PyTorch/Ollama/LM Studio 一等公民支持

不用改代码,直接跑

UMA统一内存

128GB统一内存,GPU可直接访问

单机跑70B+模型,无需多卡

成本优势

RX 7900 XTX 24GB 仅 ~6000元

同等显存成本是NVIDIA的1/3

NVIDIA RTX 4090 24GB 约 13000元,AMD RX 7900 XTX 24GB 约 6000元。对预算有限的企业,AMD 的性价比优势明显。

1.3 整体技术架构

二、AMD ROCm 环境搭建

2.1 支持的 GPU 架构

ROCm 不支持所有 AMD 显卡。选错卡,装不上驱动,一切白费。

GPU系列

架构代号

ROCm支持

推荐型号

RX 7000 (RDNA3)

gfx1100/gfx1101

官方支持

RX 7900 XTX 24GB

RX 9000 (RDNA4)

gfx1200

ROCm 6.2+ 扩展支持

RX 9070 XT

Radeon PRO W7800

gfx1101

官方支持

W7800 32GB

MI300X (CDNA3)

gfx942

完整支持

MI300X 192GB

RX 6000 (RDNA2)

gfx1030

社区支持(不稳定)

不推荐生产

2.2 Ubuntu 安装 ROCm 7.x

ROCm 在 Linux 上性能最好、兼容性最稳定。Windows 通过 HIP SDK 也能跑,但性能约低 15-20%。

代码语言:javascript
复制
# Step1: 添加ROCm仓库
sudo apt update
wget https://repo.radeon.com/amdgpu-install/latest/ubuntu/noble/amdgpu-install_*.deb
sudo apt install ./amdgpu-install_*.deb
# Step2: 安装ROCm
sudo amdgpu-install --usecase=rocm
# Step3: 添加用户到渲染组(否则无权限访问GPU)
sudo usermod -aG render,video {spring-ai.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

4.2 应用配置

代码语言:javascript
复制
spring:
  ai:
    ollama:
      # Ollama服务地址(本地部署)
      base-url: http://localhost:11434
      chat:
        model: qwen2.5:7b
        options:
          temperature: 0.7
          top-p: 0.9
          num-predict: 2048      # 最大生成Token数
      embedding:
        model: bge-m3
        options:
          dimensions: 1024
  # PGVector向量库配置
  datasource:
    url: jdbc:postgresql://localhost:5432/ai_knowledge
    username: postgres
    password: your_password

4.3 对话服务

代码语言:javascript
复制
@Service
@Slf4j
public class ChatService {
    private final ChatClient chatClient;
    public ChatService(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder
                .defaultSystem("你是一个专业的金融分析师助手,用中文回答问题。" +
                               "回答要准确、专业,引用具体数据。")
                .build();
    }
    /**
     * 单轮对话
     */
    public String chat(String userMessage) {
        return chatClient.prompt()
                .user(userMessage)
                .call()
                .content();
    }
    /**
     * 流式对话(SSE推送,用户无需等待完整回答)
     */
    public Flux<String> chatStream(String userMessage) {
        return chatClient.prompt()
                .user(userMessage)
                .stream()
                .content();
    }
}

4.4 对话 REST 接口

代码语言:javascript
复制
@RestController
@RequestMapping("/api/chat")
public class ChatController {
    @Autowired
    private ChatService chatService;
    /**
     * 同步对话
     */
    @PostMapping
    public ResponseEntity<Map<String, String>> chat(
            @RequestBody Map<String, String> request) {
        String answer = chatService.chat(request.get("message"));
        return ResponseEntity.ok(Map.of("answer", answer));
    }
    /**
     * 流式对话(SSE)
     */
    @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> chatStream(@RequestParam String message) {
        return chatService.chatStream(message);
    }
}

4.5 RAG 知识库问答

企业场景下,AI 不能只靠模型自身知识,必须结合企业内部文档。RAG(检索增强生成)是标配。

代码语言:javascript
复制
@Service
@Slf4j
public class RagService {
    private final ChatClient chatClient;
    private final VectorStore vectorStore;
    private final EmbeddingModel embeddingModel;
    public RagService(ChatClient.Builder chatClientBuilder,
                      VectorStore vectorStore,
                      EmbeddingModel embeddingModel) {
        this.chatClient = chatClientBuilder.build();
        this.vectorStore = vectorStore;
        this.embeddingModel = embeddingModel;
    }
    /**
     * 导入文档到向量库
     */
    public void importDocument(String content, Map<String, Object> metadata) {
        // 文本分片
        List<Document> documents = List.of(
            new Document(content, metadata)
        );
        // 自动向量化并存入PGVector
        vectorStore.add(documents);
        log.info("文档导入成功, metadata={}", metadata);
    }
    /**
     * RAG问答:检索相关文档 + 生成回答
     */
    public String ask(String question) {
        // 1. 从向量库检索相关文档(Top 5)
        List<Document> relevantDocs = vectorStore.similaritySearch(
            SearchRequest.builder()
                .query(question)
                .topK(5)
                .similarityThreshold(0.7)
                .build()
        );
        // 2. 拼接检索到的文档内容
        String context = relevantDocs.stream()
                .map(Document::getText)
                .collect(Collectors.joining("\n\n"));
        // 3. 基于检索结果生成回答
        return chatClient.prompt()
                .system("基于以下参考资料回答用户问题。如果资料中没有相关信息," +
                        "请说明,不要编造答案。\n\n参考资料:\n{context}")
                .user(question)
                .variables(Map.of("context", context))
                .call()
                .content();
    }
}

4.6 Function Calling(工具调用)

大模型本身无法查询数据库、调用API。Spring AI 的 Function Calling 让模型能自动调用你注册的 Java 方法。

代码语言:javascript
复制
@Configuration
public class FunctionConfig {
    /**
     * 注册一个查询股票行情的函数
     * 模型会根据用户问题自动决定是否调用
     */
    @Bean
    @Description("查询指定股票代码的最新行情信息,包括当前价格、涨跌幅、成交量")
    public Function<StockRequest, StockResponse> stockQuery() {
        return request -> {
            // 实际业务中调用行情API
            StockResponse response = new StockResponse();
            response.setCode(request.code());
            response.setPrice(125.80);
            response.setChangePercent(-1.23);
            response.setVolume(15680000L);
            return response;
        };
    }
    public record StockRequest(
        @Description("股票代码,如 600519") String code
    ) {}
    @Data
    public static class StockResponse {
        private String code;
        private double price;
        private double changePercent;
        private long volume;
    }
}

使用 Function Calling:

代码语言:javascript
复制
@Service
public class SmartChatService {
    private final ChatClient chatClient;
    public SmartChatService(ChatClient.Builder builder) {
        this.chatClient = builder
                .defaultFunctions("stockQuery")  // 注册函数
                .build();
    }
    public String chat(String message) {
        // 用户问:"贵州茅台今天涨了吗?"
        // 模型会自动调用 stockQuery("600519"),然后基于结果回答
        return chatClient.prompt()
                .user(message)
                .call()
                .content();
    }
}

五、UMA 架构实测:单机跑 70B 模型

5.1 UMA vs 传统离散 GPU

维度

离散GPU (RTX 4090 24GB)

UMA (Ryzen AI Max+ 128GB)

显存容量

24GB(硬上限)

64-120GB(可配置)

70B模型运行

❌ 放不下(需2-3卡)

✅ 单机可运行

CPU↔GPU数据传输

PCIe ~12GB/s + 拷贝延迟

零拷贝,无传输延迟

硬件成本

~13000元 × 2-3

单机 ~15000元

5.2 Ollama 在 UMA 上跑 Qwen2.5-72B

代码语言:javascript
复制
# 拉取72B量化模型
ollama pull qwen2.5:72b
# 运行(Ollama自动识别UMA,混合加载)
ollama run qwen2.5:72b --verbose
# --verbose 输出示例:
# loaded 72B model
# GPU offload layers: 40/80 (UMA partial offload)
# GPU memory: 58GB / 64GB
# CPU memory: 22GB
# eval speed: 4.2 tok/s

72B 模型在 24GB 独立显卡上完全放不下。UMA 的 64GB GPU 可访问内存 + CPU 补充加载,实现了单机运行 70B 级模型。虽然速度只有 4.2 tok/s,但比"跑不了"强太多。

5.3 各模型在 UMA 上的实测数据

测试环境:AMD Ryzen AI Max+ 395,128GB 统一内存,GPU 可访问 64GB

模型

量化

GPU层

CPU层

生成速度

质量

Qwen2.5-7B

Q4_K_M

全部

0

35 tok/s

★★★★

Qwen2.5-14B

Q4_K_M

全部

0

22 tok/s

★★★★☆

Qwen2.5-32B

Q4_K_M

全部

0

10 tok/s

★★★★★

Qwen2.5-72B

Q4_K_M

40/80

40/80

4.2 tok/s

★★★★★

Qwen3.5-122B (MoE)

Q3_K_M

部分

部分

2.8 tok/s

★★★★★

六、多 AMD GPU 负载均衡

6.1 多卡环境配置

企业场景可能配置多张 AMD 显卡,需要合理分配模型到不同 GPU。Ollama 支持多 GPU 自动分配,也可手动指定。

代码语言:javascript
复制
# 查看所有GPU
rocm-smi
# 期望输出:
# GPU[0]: AMD Radeon RX 7900 XTX (gfx1100) 24GB
# GPU[1]: AMD Radeon RX 7900 XTX (gfx1100) 24GB
# 指定使用的GPU(逗号分隔)
export ROCR_VISIBLE_DEVICES=0,1
# Ollama自动将模型分配到多张GPU
ollama run qwen2.5:32b --verbose
# 输出: GPU offload layers: 60/60 (split across 2 GPUs)

6.2 多实例负载均衡

单实例 Ollama 同时处理多个请求时,GPU 显存会被多个上下文占用。部署多个 Ollama 实例,通过 Nginx 负载均衡,可提升并发能力。

代码语言:javascript
复制
# docker-compose.yml
services:
  ollama-1:
    image: ollama/ollama:rocm
    devices:
      - /dev/dri/renderD128    # GPU 0
    ports:
      - "11434:11434"
    volumes:
      - ollama_data:/root/.ollama
  ollama-2:
    image: ollama/ollama:rocm
    devices:
      - /dev/dri/renderD129    # GPU 1
    ports:
      - "11435:11434"
    volumes:
      - ollama_data:/root/.ollama
volumes:
  ollama_data:

Spring AI 配置负载均衡:

代码语言:javascript
复制
spring:
  ai:
    ollama:
      # 多实例时,通过Nginx代理
      base-url: http://ollama-lb:11434

Nginx 负载均衡:

代码语言:javascript
复制
upstream ollama_cluster {
    least_conn;
    server 127.0.0.1:11434;
    server 127.0.0.1:11435;
}
server {
    listen 11434;
    location / {
        proxy_pass http://ollama_cluster;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}

七、踩坑实录:5个 AMD ROCm + Spring AI 常见问题

踩坑1:ROCm 安装后 Ollama 仍然用 CPU 推理

问题:ROCm 已安装,但 ollama run --verbose 显示 CPU only

原因:用户未加入 render 组,Ollama 进程无权访问 GPU 设备。

解决

代码语言:javascript
复制
# 添加用户到render组
sudo usermod -aG render,video $LOGNAME
# 重新登录(关键!组变更需要重新登录生效)
logout
# 验证GPU权限
ls -la /dev/dri/renderD*
# 期望: crw-rw---- render组可读写
# 重启Ollama
systemctl restart ollama

踩坑2:HSA_OVERRIDE 设置错误导致 GPU 崩溃

问题:设置 HSA_OVERRIDE_GFX_VERSION 后,GPU 初始化失败。

原因:版本号格式错误或与实际架构不匹配。

解决:对照架构代号表设置正确版本:

代码语言:javascript
复制
# ✅ 正确格式
export HSA_OVERRIDE_GFX_VERSION=10.3.0   # gfx1030 (RDNA2)
# ❌ 错误格式
export HSA_OVERRIDE_GFX_VERSION=1030     # 缺少点号
export HSA_OVERRIDE_GFX_VERSION=11.0.0   # RDNA3的gfx1100不能这样设

踩坑3:Spring AI 流式响应中文乱码

问题:SSE 流式返回中文内容时,前端显示乱码。

解决:确保 Spring MVC 的 SSE 编码配置正确:

代码语言:javascript
复制
@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> chatStream(@RequestParam String message) {
    return chatService.chatStream(message)
            .map(chunk -> ServerSentEvent.<String>builder()
                    .data(chunk)
                    .build());
}

踩坑4:PGVector Embedding 维度不匹配

问题:BGE-M3 输出 1024 维向量,但 PGVector 建表时用了 768 维。

解决:确保 spring.ai.ollama.embedding.options.dimensions 与向量表维度一致:

代码语言:javascript
复制
-- 创建向量表时指定正确维度
CREATE TABLE vector_store (
    id UUID PRIMARY KEY,
    content TEXT,
    metadata JSONB,
    embedding VECTOR(1024)   -- BGE-M3 输出1024维
);
代码语言:javascript
复制
spring:
  ai:
    ollama:
      embedding:
        options:
          dimensions: 1024    # 必须与向量表维度一致

踩坑5:72B 模型在 24GB 显卡上 OOM

问题:Qwen2.5-72B Q4_K_M 需要约 40GB 显存,24GB 显卡放不下。

解决:Ollama 支持自动 CPU/GPU 混合加载,但需要足够系统内存:

代码语言:javascript
复制
# 设置Ollama使用CPU补充加载
export OLLAMA_NUM_GPU=40    # 只将40层放到GPU,其余CPU处理
# 需要足够的系统内存(至少64GB)
# 24GB GPU + 40GB CPU内存 ≈ 64GB 总需求
# 查看系统可用内存
free -h

如果系统内存不足,只能降低模型参数量(使用 32B 或 14B)。

八、最佳实践总结

8.1 模型选型决策树

代码语言:javascript
复制
你的显存是多少?
├── 8GB(RX 7600)
│   └── Qwen2.5-7B Q4_K_M(4.5GB)
├── 16GB(RX 7800 XT)
│   └── Qwen2.5-14B Q4_K_M(8.5GB)
├── 24GB(RX 7900 XTX)
│   └── Qwen2.5-32B Q4_K_M(18GB)
├── 32GB(Radeon PRO W7800)
│   └── Qwen2.5-32B Q5_K_M(22GB)
├── 64GB+ UMA(Ryzen AI Max+)
│   └── Qwen2.5-72B Q4_K_M(混合加载)
└── 192GB(MI300X)
    └── Qwen2.5-72B Q8_0(全精度)

8.2 生产环境检查清单

  • ROCm 版本 ≥ 7.x,rocminfo 能正确识别 GPU
  • 当前用户在 rendervideo 组中
  • Ollama --verbose 输出确认 GPU offload 生效
  • 模型量化等级与显存容量匹配
  • Spring AI 的 dimensions 配置与向量表一致
  • SSE 流式响应编码正确处理中文
  • Ollama 服务设置 systemd 开机自启
  • 监控 GPU 显存使用率,设置告警阈值

8.3 AMD vs NVIDIA 选型参考

维度

AMD ROCm

NVIDIA CUDA

生态成熟度

良好(2026年已大幅改善)

极好

性价比

高(同显存成本低40-60%)

UMA大模型

✅ Ryzen AI Max+ 128GB

❌ 无UMA方案

Windows支持

WSL2/HIP SDK,稍弱

原生支持

社区资源

较少但快速增长

丰富

适用场景

预算敏感/内网部署/大模型

全场景

📜 真实性声明: 本文所有内容均基于作者在2026年Q2期间使用 AMD ROCm + Spring AI 构建内网AI应用的真实开发实践。性能数据来自实际测试环境(RX 7900 XTX / Ryzen AI Max+ 395),踩坑经验来自部署过程中的真实问题。ROCm 7.x 的生态成熟度评价基于2026年6月的实际体验。

互动话题

  1. 你在 AMD GPU 上跑大模型遇到过什么问题?ROCm 的体验如何?
  2. Spring AI 对接 Ollama,你更倾向同步还是流式?
  3. 企业内网部署 AI 应用,你有什么实战经验?欢迎评论区交流!
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-06-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 行者架构谈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、为什么选择 AMD ROCm 做 Java 本地 AI
    • 1.1 企业内网 AI 的三重困境
    • 1.2 AMD ROCm 的三个关键优势
    • 1.3 整体技术架构
  • 二、AMD ROCm 环境搭建
    • 2.1 支持的 GPU 架构
    • 2.2 Ubuntu 安装 ROCm 7.x
    • 4.2 应用配置
    • 4.3 对话服务
    • 4.4 对话 REST 接口
    • 4.5 RAG 知识库问答
    • 4.6 Function Calling(工具调用)
  • 五、UMA 架构实测:单机跑 70B 模型
    • 5.1 UMA vs 传统离散 GPU
    • 5.2 Ollama 在 UMA 上跑 Qwen2.5-72B
    • 5.3 各模型在 UMA 上的实测数据
  • 六、多 AMD GPU 负载均衡
    • 6.1 多卡环境配置
    • 6.2 多实例负载均衡
  • 七、踩坑实录:5个 AMD ROCm + Spring AI 常见问题
    • 踩坑1:ROCm 安装后 Ollama 仍然用 CPU 推理
    • 踩坑2:HSA_OVERRIDE 设置错误导致 GPU 崩溃
    • 踩坑3:Spring AI 流式响应中文乱码
    • 踩坑4:PGVector Embedding 维度不匹配
    • 踩坑5:72B 模型在 24GB 显卡上 OOM
  • 八、最佳实践总结
    • 8.1 模型选型决策树
    • 8.2 生产环境检查清单
    • 8.3 AMD vs NVIDIA 选型参考
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档