Spring AI与Ollama本地大模型开发实战:构建智能问答系统的完整指南

1. 环境准备与工具选型

在开始构建基于Spring AI和Ollama的问答系统前,我们需要确保开发环境配置正确。与传统的云服务调用不同,本地大模型部署对硬件有一定要求:

硬件建议配置

  • GPU:NVIDIA显卡(RTX 3060及以上)能显著加速推理
  • 内存:至少16GB(7B模型需8GB,13B模型需16GB)
  • 存储:SSD硬盘,预留20GB空间用于模型文件

软件环境准备

  1. 安装Ollama服务(支持Windows/macOS/Linux):

    # Linux/macOS安装命令
    curl -fsSL https://ollama.com/install.sh | sh
    
    # Windows可通过官网下载安装包
    
  2. 下载大语言模型(以通义千问7B为例):

    ollama pull qwen:7b
    
  3. 验证模型运行:

    ollama run qwen:7b
    > 你好
    

提示:首次运行模型时会自动下载权重文件,下载速度取决于网络环境。国内用户可配置镜像源加速下载。

2. Spring项目初始化与配置

使用Spring Initializr创建项目时,需特别注意依赖选择:

关键依赖

<dependencies>
    <!-- Spring Boot基础依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Spring AI核心库 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-core</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </dependency>
    
    <!-- Ollama集成starter -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </dependency>
</dependencies>

<!-- 必须添加的仓库配置 -->
<repositories>
    <repository>
        <id>spring-snapshots</id>
        <url>https://repo.spring.io/snapshot</url>
        <releases><enabled>false</enabled></releases>
    </repository>
</repositories>

application.yml配置示例

spring:
  ai:
    ollama:
      base-url: http://localhost:11434
      chat:
        options:
          model: qwen:7b
          temperature: 0.7  # 控制生成文本的随机性
          num-predict: 512  # 最大输出token数

3. 核心接口开发实战

3.1 基础问答接口实现

创建REST控制器处理简单问答请求:

@RestController
@RequestMapping("/api/chat")
public class ChatController {
    
    private final OllamaChatClient chatClient;

    public ChatController(OllamaChatClient chatClient) {
        this.chatClient = chatClient;
    }

    @GetMapping("/simple")
    public String simpleChat(@RequestParam String message) {
        Prompt prompt = new Prompt(message);
        return chatClient.call(prompt).getResult().getOutput().getContent();
    }
}

3.2 流式响应实现

对于长文本生成场景,流式响应能显著提升用户体验:

@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamChat(@RequestParam String message) {
    return chatClient.stream(new Prompt(message))
            .map(response -> response.getResult().getOutput().getContent());
}

3.3 带上下文的对话管理

实现多轮对话需要维护对话历史:

@Service
@Scope(value = WebApplicationContext.SCOPE_SESSION, 
       proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ConversationService {
    
    private final List<Message> history = new ArrayList<>();
    
    public String chatWithContext(String userInput) {
        // 添加用户消息到历史
        history.add(new UserMessage(userInput));
        
        // 构建包含历史的prompt
        Prompt prompt = new Prompt(history);
        
        // 获取AI响应
        ChatResponse response = chatClient.call(prompt);
        String aiResponse = response.getResult().getOutput().getContent();
        
        // 添加AI响应到历史
        history.add(new AssistantMessage(aiResponse));
        
        return aiResponse;
    }
}

4. 高级功能实现

4.1 文件内容问答

通过文档解析实现基于上传文件的问答:

@PostMapping(value = "/ask-with-file", 
            consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public String askWithFile(@RequestParam MultipartFile file,
                         @RequestParam String question) throws IOException {
    
    // 解析文档内容
    String content = new String(file.getBytes(), StandardCharsets.UTF_8);
    
    // 构建提示词
    String prompt = """
        请根据以下文档内容回答问题:
        文档内容:
        {content}
        
        问题:{question}
        """.replace("{content}", content)
          .replace("{question}", question);
    
    return chatClient.call(new Prompt(prompt)).getResult().getOutput().getContent();
}

4.2 多模态处理(图片理解)

某些模型如llava支持图片理解:

@PostMapping("/analyze-image")
public String analyzeImage(@RequestParam MultipartFile image) throws IOException {
    byte[] imageData = image.getBytes();
    
    Media imageMedia = new Media(
        MediaType.IMAGE_PNG,  // 根据实际类型调整
        imageData
    );
    
    UserMessage userMessage = new UserMessage(
        "描述这张图片的内容",
        List.of(imageMedia)
    );
    
    Prompt prompt = new Prompt(List.of(userMessage));
    return chatClient.call(prompt).getResult().getOutput().getContent();
}

5. 性能优化与生产部署

5.1 模型参数调优

通过调整Ollama选项提升响应质量:

参数 推荐值 作用描述
temperature 0.5-0.8 控制生成随机性,值越高越有创意
top-p 0.9 核采样阈值,影响输出多样性
repeat-penalty 1.1 惩罚重复内容生成
spring:
  ai:
    ollama:
      chat:
        options:
          temperature: 0.7
          top-p: 0.9
          repeat-penalty: 1.1

5.2 生产环境配置建议

  1. 资源隔离:使用Docker部署Ollama服务

    FROM ollama/ollama
    EXPOSE 11434
    CMD ["ollama", "serve"]
    
  2. 负载管理:配置Spring Boot连接池

    spring:
      ai:
        ollama:
          client:
            connect-timeout: 30s
            read-timeout: 5m
    
  3. 日志监控:添加请求日志拦截器

    @Bean
    public OllamaApi ollamaApiWithLogging(Client client) {
        return new OllamaApiInterceptor(new OllamaApi(client));
    }
    

6. 常见问题解决方案

依赖下载失败

  • 检查是否配置了正确的Spring快照仓库
  • 尝试清理Maven本地仓库后重新构建

GPU未有效利用

  • 确认NVIDIA驱动和CUDA已安装
  • 添加Ollama GPU参数:
    spring:
      ai:
        ollama:
          chat:
            options:
              num-gpu: 1
    

中文输出质量不佳

  • 尝试调整提示词工程:
    String prompt = "你是一个专业的中文助手,请用流畅的中文回答:\n" + userQuestion;
    
  • 考虑使用专门优化中文的模型如qwen:14b-chat

实际开发中发现,合理设置temperature参数对中文输出的连贯性影响显著。在知识问答场景建议0.3-0.5,创意生成可提高到0.7-0.9。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐