技术探索与实践的一些经验
大家好,我是你们的老朋友,一个985毕业、在掘金写了三年入门教程的全栈工程师。今天这篇文章,我想聊聊我在技术探索与实践过程中积累的一些经验,并通过一个完整的项目案例,带大家把 Warp、Spring Boot、Qwen 这三个工具串起来,做一次真正有含金量的技术实践。
为什么要写这篇教程?
我当初学的时候,最大的痛点不是看不懂文档,而是不知道怎么把零散的工具组合起来解决一个真实问题。网上教程大多是"教你用A"、"教你用B",但很少有人告诉你"A+B+C 怎么一起用"。
所以今天这篇文章,我会用一个完整的项目案例,带大家体验一次从工具选型到落地交付的全过程。
先简单介绍一下今天的主角:
| 工具 | 定位 | 一句话说明 |
|---|---|---|
| Warp | AI 终端 | 用 AI 加持的现代命令行工具,写命令像聊天一样 |
| Spring Boot | Java 后端框架 | Java 生态里最主流的后端开发框架,没有之一 |
| Qwen | 大语言模型 | 阿里开源的大模型,支持 API 调用,中文能力很强 |
我们要做的事情是:用 Spring Boot 搭建一个后端服务,接入 Qwen 大模型,实现一个"智能代码助手"接口,全程使用 Warp 终端来提效。
环境准备
我当初学的时候,光配环境就配了两天。所以这部分我写得特别细,你跟着做就行。
1. 安装 Warp 终端
Warp 是一款基于 Rust 构建的现代终端,内置 AI 能力,支持命令补全、自然语言转命令等功能。
安装步骤:
- 访问官网
https://www.warp.dev - 根据你的操作系统下载对应版本(支持 macOS、Linux)
- 安装完成后打开,使用 GitHub 或 Google 账号登录
Windows 用户目前可以使用 WSL2 + Warp 的方式体验,或者直接等官方 Windows 版本。
2. 安装 JDK 17
Spring Boot 3.x 要求 JDK 17 及以上版本。
# macOS 使用 Homebrew 安装
brew install openjdk@17
# 配置环境变量(添加到 ~/.zshrc 或 ~/.bashrc)
export JAVA_HOME=$(/usr/libexec/java_home -v 17)
export PATH=$JAVA_HOME/bin:$PATH
验证安装:
java -version
# 输出: openjdk version "17.x.x"
3. 安装 Maven
brew install maven
mvn -version
# 输出: Apache Maven 3.x.x
4. 获取 Qwen API Key
- 访问阿里云百炼平台
https://bailian.console.aliyun.com - 注册并登录,进入"API Key 管理"
- 创建一个新的 API Key,妥善保存
核心概念
在动手之前,我先用大白话把三个核心概念讲清楚。
Warp 的 AI 能力到底能干嘛?
我当初学的时候,终端就是用来敲命令的。但 Warp 不一样,它内置了一个 AI Agent,你可以:
- 用自然语言描述需求,Warp 自动生成命令
- 自动补全复杂命令,比如
docker run的各种参数 - 解释报错信息,直接把错误丢给 AI 分析
举个例子,你在 Warp 里输入:
# 查找当前目录下所有大于100MB的文件
Warp 会自动生成:
find . -type f -size +100M -exec ls -lh {} \;
Spring Boot 的核心思想
Spring Boot 的核心就三个字:约定大于配置。
我当初学的时候,写一个 Spring MVC 项目要配一堆 XML。Spring Boot 直接帮你把这些都省了:
- 内嵌 Tomcat,不用单独部署
- 自动配置数据源、安全框架等
- 一个
application.yml搞定大部分配置
Qwen 模型调用方式
Qwen 的 API 兼容 OpenAI 的接口格式,这意味着你只需要:
- 发送一个 HTTP POST 请求
- 带上你的 API Key
- 传入 prompt 和参数
- 拿到模型返回的文本
本质上就是一次普通的 HTTP 调用,没有任何黑魔法。
实战项目:智能代码助手
接下来,我们一步步完成这个项目。
第一步:创建 Spring Boot 项目
打开 Warp 终端,用 Spring Initializr 快速生成项目骨架:
curl https://start.spring.io/starter.tgz \
-d type=maven-project \
-d language=java \
-d bootVersion=3.2.0 \
-d baseDir=qwen-assistant \
-d groupId=com.example \
-d artifactId=qwen-assistant \
-d name=qwen-assistant \
-d packageName=com.example.assistant \
-d javaVersion=17 \
-d dependencies=web,validation \
| tar -xzvf -
在 Warp 里,你甚至可以直接输入"帮我用 Spring Initializr 创建一个包含 web 和 validation 依赖的 Spring Boot 3.2 项目",它会自动帮你拼出上面的 curl 命令。
进入项目目录:
cd qwen-assistant
第二步:添加 Qwen SDK 依赖
打开 pom.xml,添加 HTTP 客户端依赖:
<dependencies>
<!-- 已有的依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- OkHttp 用于调用 Qwen API -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
<!-- JSON 处理 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.43</version>
</dependency>
</dependencies>
第三步:配置 application.yml
server:
port: 8080
qwen:
api-key: sk-xxxxxxxxxxxxxxxxxxxxxxxx
model: qwen-turbo
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
第四步:编写配置类
package com.example.assistant.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "qwen")
public class QwenConfig {
private String apiKey;
private String model;
private String baseUrl;
// getter 和 setter
public String getApiKey() { return apiKey; }
public void setApiKey(String apiKey) { this.apiKey = apiKey; }
public String getModel() { return model; }
public void setModel(String model) { this.model = model; }
public String getBaseUrl() { return baseUrl; }
public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl; }
}
第五步:编写 Qwen 调用服务
package com.example.assistant.service;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.example.assistant.config.QwenConfig;
import okhttp3.*;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class QwenService {
private final QwenConfig qwenConfig;
private final OkHttpClient httpClient;
public QwenService(QwenConfig qwenConfig) {
this.qwenConfig = qwenConfig;
this.httpClient = new OkHttpClient();
}
public String chat(String userMessage) throws IOException {
// 构建请求体
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("model", qwenConfig.getModel());
List<Map<String, String>> messages = new ArrayList<>();
// 系统提示词
Map<String, String> systemMsg = new HashMap<>();
systemMsg.put("role", "system");
systemMsg.put("content", "你是一个专业的编程助手,擅长解答Java、Spring Boot相关技术问题。回答要简洁准确。");
messages.add(systemMsg);
// 用户消息
Map<String, String> userMsg = new HashMap<>();
userMsg.put("role", "user");
userMsg.put("content", userMessage);
messages.add(userMsg);
requestBody.put("messages", messages);
// 发送请求
String jsonBody = JSON.toJSONString(requestBody);
RequestBody body = RequestBody.create(
jsonBody, MediaType.parse("application/json")
);
Request request = new Request.Builder()
.url(qwenConfig.getBaseUrl() + "/chat/completions")
.addHeader("Authorization", "Bearer " + qwenConfig.getApiKey())
.addHeader("Content-Type", "application/json")
.post(body)
.build();
try (Response response = httpClient.newCall(request).execute()) {
String responseBody = response.body().string();
JSONObject result = JSON.parseObject(responseBody);
return result.getJSONArray("choices")
.getJSONObject(0)
.getJSONObject("message")
.getString("content");
}
}
}
第六步:编写 Controller
package com.example.assistant.controller;
import com.example.assistant.service.QwenService;
import jakarta.validation.constraints.NotBlank;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api")
public class ChatController {
private final QwenService qwenService;
public ChatController(QwenService qwenService) {
this.qwenService = qwenService;
}
@PostMapping("/chat")
public Map<String, Object> chat(@RequestParam @NotBlank String message) {
Map<String, Object> result = new HashMap<>();
try {
String reply = qwenService.chat(message);
result.put("code", 200);
result.put("data", reply);
result.put("message", "success");
} catch (IOException e) {
result.put("code", 500);
result.put("data", null);
result.put("message", "调用失败: " + e.getMessage());
}
return result;
}
}
第七步:启动并测试
在 Warp 终端里启动项目:
mvn spring-boot:run
用 curl 测试接口:
curl -X POST "http://localhost:8080/api/chat?message=Spring Boot 如何配置多数据源?"
你会看到 Qwen 返回一段关于 Spring Boot 多数据源配置的专业回答。
项目流程总结
整个项目的流程可以用下面的步骤来描述:
用户输入问题
↓
Controller 接收请求
↓
QwenService 构建请求体(含系统提示词 + 用户消息)
↓
OkHttp 发送 POST 请求到 Qwen API
↓
解析 JSON 响应,提取模型回复
↓
返回给前端用户
常见问题
我当初学的时候踩过的坑,整理出来给大家避坑:
Q1:API 调用返回 401 怎么办?
检查你的 API Key 是否正确配置,注意不要有多余的空格。另外确认 Key 没有过期。
Q2:Warp 终端在 WSL2 里显示异常?
确保你的 WSL2 版本是最新的,可以在 PowerShell 里执行 wsl --update 来更新。
Q3:Qwen 返回的内容有乱码?
检查你的请求和响应编码是否统一为 UTF-8。在 OkHttp 里默认就是 UTF-8,一般不会有这个问题。
Q4:Spring Boot 启动报端口占用?
# 查找占用 8080 端口的进程
lsof -i :8080
# 杀掉对应进程
kill -9 <PID>
Q5:如何让 Qwen 的回答更稳定?
可以在请求体里加入 temperature 参数,值越低回答越确定:
requestBody.put("temperature", 0.3);
学习建议
完成这个项目之后,你可以沿着以下路径继续深入:
| 阶段 | 学习内容 | 目标 |
|---|---|---|
| 第一阶段 | Spring Boot 自动配置原理 | 理解框架底层机制 |
| 第二阶段 | Qwen 流式输出(SSE) | 实现打字机效果的对话 |
| 第三阶段 | 多轮对话上下文管理 | 让 AI 记住之前的对话 |
| 第四阶段 | Warp 高级用法(Warp Workflows) | 把常用命令封装成可复用流程 |
| 第五阶段 | 部署到云服务器 | 完整走一遍上线流程 |
最后说两句
我当初学的时候,总觉得技术探索是一件很高大上的事情,后来才发现,所谓探索,就是把一个个工具用熟,然后在真实场景里把它们组合起来。
Warp 让你写命令更快,Spring Boot 让你写后端更省心,Qwen 让你的应用拥有 AI 能力。三者结合,就是一个现代开发者该有的技术栈缩影。
不要怕犯错,不要怕折腾。打开 Warp,敲下第一行命令,你就已经走在探索的路上了。
我们下篇文章见。


评论 0