模块1(下):用Spring AI从0到1搭一个代码审查助手
上篇讲了4个核心技巧——角色约束、格式控制、Few-shot、思维链。今天用完整实战把它们串起来,再聊聊温度参数怎么选、以及我踩过的4个坑。
温度参数怎么选
这是另一个让我踩坑的点。
一开始我以为temperature=0最稳定,结果发现模型回答越来越"保守",稍微有点开放性的问题就直接说"这个问题我无法回答"。
后来才明白:temperature控制的是"随机性",不是"准确性"。
场景
Temperature
效果
代码审查、JSON输出
0.1 - 0.3
稳定、可复现
问答、总结、翻译
0.3 - 0.5
平衡稳定和自然
创意写作、头脑风暴
0.7 - 0.9
有创意、不重复
精确计算
0.0
最小随机性
Java代码里的设置:
java
// 精确场景:代码审查
var strictRequest = OpenAiChatOptions.builder()
.withTemperature(0.1)
.build();
// 平衡场景:日常问答
var balancedRequest = OpenAiChatOptions.builder()
.withTemperature(0.5)
.build();
// 创意场景:起名字、想创意
var creativeRequest = OpenAiChatOptions.builder()
.withTemperature(0.8)
.build();
所以:温度不是越高越好,也不是越低越稳定。选对场景就行。
完整实战:Spring AI代码审查助手
来一个能直接跑的完整例子。
Maven依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
application.yml配置
yaml
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
model: gpt-4o
完整Controller
java
@RestController
@RequestMapping("/api/review")
public class CodeReviewController {
private final ChatModel chatModel;
public CodeReviewController(ChatModel chatModel) {
this.chatModel = chatModel;
}
/**
* 代码审查主接口
* 结合了:角色约束 + Few-shot + CoT + 结构化输出
*/
@PostMapping("/java")
public Map<String, Object> reviewJavaCode(@RequestBody Map<String, String> request) {
String code = request.get("code");
String prompt = buildReviewPrompt(code);
var options = OpenAiChatOptions.builder()
.withModel("gpt-4o")
.withTemperature(0.2) // 低温保证格式稳定
.withResponseFormat(new ResponseFormat("json_object"))
.withMaxTokens(2000)
.build();
try {
String result = chatModel.call(new Prompt(prompt, options))
.getResult().getOutput().getText();
return Map.of(
"success", true,
"result", parseJson(result),
"raw", result
);
} catch (Exception e) {
return Map.of(
"success", false,
"error", e.getMessage()
);
}
}
private String buildReviewPrompt(String code) {
return """
你是一个拥有15年经验的Java架构师,精通Spring全家桶、并发编程、JVM调优。
请用思维链方式审查代码,先分析逻辑,再指出问题,最后给出评分和建议。
评分标准:
- 90-100:生产级代码,可直接上线
- 70-89:有优化空间,需要review
- 50-69:存在明显风险,需要重构
- 50以下:建议重写
审查代码:
%s
请返回JSON格式(不要添加任何解释性文字):
{
"score": 分数,
"grade": "等级描述",
"thinking": ["思考步骤1", "思考步骤2", "思考步骤3"],
"issues": [
{
"severity": "high|medium|low",
"type": "NPE|并发|性能|安全|规范",
"location": "代码位置",
"description": "问题描述",
"suggestion": "修改建议"
}
],
"summary": "整体评价"
}
""".formatted(code);
}
private Map<String, Object> parseJson(String json) {
// 实际项目中建议使用Jackson解析
// 这里简化处理
return Map.of("raw", json);
}
}
测试请求
bash
curl -X POST http://localhost:8080/api/review/java \
-H "Content-Type: application/json" \
-d '{
"code": "public String getUserName(Integer userId) { return userDao.findById(userId).getName(); }"
}'
返回示例:
json
{
"success": true,
"result": {
"score": 45,
"grade": "建议重写",
"thinking": [
"userId可能是null,直接传入会导致NPE",
"findById可能返回null,调用getName()会NPE",
"整体缺乏参数校验和异常处理"
],
"issues": [
{
"severity": "high",
"type": "NPE",
"location": "第1行",
"description": "Integer参数可能为null",
"suggestion": "添加 Objects.requireNonNull(userId) 或判空处理"
},
{
"severity": "high",
"type": "NPE",
"location": "第1行",
"description": "findById可能返回Optional.empty()",
"suggestion": "使用 Optional.ofNullable() 或 ifPresent()"
}
],
"summary": "存在严重的空指针风险,建议重构后上线"
}
}
常见坑,我帮你踩过了
坑1:Prompt越长越好?
不是。Prompt太长会导致:
-
模型"注意力分散",关键指令被稀释
-
token消耗增加,响应变慢
-
成本上涨
解法:删除所有"礼貌性废话",只留指令。模型不需要"请您帮我...",直接"帮我..."就行。
坑2:temperature=0就稳定?
不一定。温度控制的是token选择的随机性,但模型本身有"默认行为"。
想让输出稳定,温度+结构化输出要组合使用。
java
var options = OpenAiChatOptions.builder()
.withTemperature(0.1) // 低温
.withResponseFormat(new ResponseFormat("json_object")) // 强制JSON
.build();
坑3:示例越多越好?
不是。3个示例足够,再多反而会让模型"过度拟合"到示例的风格。
Few-shot的黄金规则:3个示例,覆盖正向、负向、边界情况。
坑4:直接问"你理解了吗?"
没用。模型会说"我理解了",但不代表它真的理解了。
解法:让模型复述任务或给出执行计划,通过输出来验证理解。
今天就能动手的任务
学再多不如动手练。今天给你三个任务,从简单到复杂:
任务1(5分钟):改造你现有的一个Prompt,加上角色约束。
把"帮我写代码"改成:
"你是一个Spring Boot专家,请帮我写一个用户注册接口,包含参数校验和异常处理"
看看回答质量有没有变化。
任务2(15分钟):让ChatGPT返回一个JSON结构化的自我介绍。
用这个Prompt:
"请以JSON格式返回你自己的介绍,包含name、experience(年数)、skills(数组)"
然后在代码里解析这个JSON,感受结构化输出的价值。
任务3(30分钟):用Spring AI写一个带Few-shot的翻译接口。
-
System Prompt定义角色(中英翻译专家)
-
Few-shot给出3个翻译示例
-
让用户输入中文,返回英文JSON
完整代码可以参考上面的Controller,改改Prompt就行。
总结
这一篇我们用Spring AI把四个技巧——角色约束、格式控制、Few-shot、CoT——串起来,实现了完整的代码审查助手。
关键点回顾:
-
温度参数要匹配场景,不是越低越好
-
结构化输出+低温是稳定JSON的黄金组合
-
Few-shot用3个示例覆盖正负向和边界情况
-
思维链能显著提升复杂任务的准确率
下一篇文章,我们聊模块2:RAG深度调优——怎么让你的AI真正"懂"你的业务数据。
(完整代码已上传到GitHub,文末有链接)
往期文章:
[Java转AI,我整理了8个模块的学习路线图](待发布后替换URL)
如果对你有帮助,点个赞再走~