切换主题
01. 项目边界与最小 MVP:先让复盘能闭环
产品一开始提的需求通常很轻:
“用户做完一笔训练交易,点一下复盘,系统能不能告诉他这笔交易主要问题是什么?”
这个需求听起来不难。我们拿到一个 tradeId,查交易记录,拼一段复盘文字返回就行。第一版甚至可以先不接大模型,用固定逻辑把业务闭环跑通。
但这里有一个坑:你不能一上来就把它做成“万能交易助手”。如果用户问“现在 BTC 能不能买”,系统也认真回答,那这就不是复盘教练了。它已经越过训练边界,变成实盘建议入口。
所以第一章只做一件事:定义项目边界,并跑通最小 MVP。
这一版先实现什么
我们先做一个接口:
http
POST /api/pa-review/reviews请求体很简单:
json
{
"tradeId": "T-1001",
"includeKline": true,
"question": "复盘这笔训练交易"
}返回结果也先不用追求花哨,只要能表达三个东西:
- 这是训练复盘,不是实盘建议。
- 这笔交易的主要问题是什么。
- 下一步训练任务是什么。
真实调用后,你会看到类似结果:
json
{
"status": "REVIEWED",
"tradeId": "T-1001",
"boundaryNotice": "这是训练复盘,不提供实盘买卖建议,也不预测未来涨跌。",
"riskReward": 2.0,
"realizedR": -0.8,
"executionScore": 62,
"primaryProblem": "没有等待回踩确认,入场动作和 plannedSetup 不一致",
"nextTrainingTask": "连续记录 20 笔突破后是否等待回踩确认的训练样本"
}注意这里的 boundaryNotice。它不是装饰字段,而是产品边界。后面不管我们加工具、记忆、RAG、搜索还是多智能体,这条边界都不能丢。
最小工程怎么搭
第一章对应这些文件:
text
api/
ReviewCoachController.java
ReviewRequestBody.java
ReviewReportResponse.java
coach/
ReviewCoachService.java
ReviewRequest.java
ReviewReport.java
ReviewStatus.javaController 只做转发:
java
@RestController
@RequestMapping("/api/pa-review")
public class ReviewCoachController {
private final ReviewCoachService reviewCoachService;
public ReviewCoachController(ReviewCoachService reviewCoachService) {
this.reviewCoachService = reviewCoachService;
}
@PostMapping("/reviews")
public ReviewReportResponse review(@RequestBody ReviewRequestBody request) {
return ReviewReportResponse.from(reviewCoachService.review(request.toCommand()));
}
}这里有一个工程习惯:Controller 不要塞复盘逻辑。它只把 HTTP 请求转成业务命令,再把业务结果转成响应对象。
ReviewRequestBody 是 HTTP 层 DTO:
java
public record ReviewRequestBody(
String tradeId,
boolean includeKline,
String question
) {
ReviewRequest toCommand() {
return new ReviewRequest(tradeId, includeKline, question);
}
}ReviewRequest 才是业务层命令。现在它们字段一样,但语义不一样。DTO 服务于接口,Command 服务于业务。
先跑起来
powershell
cd D:\idea_space\pa-review-coach-tutorial
mvn.cmd test
mvn.cmd spring-boot:run -Dspring-boot.run.jvmArguments=-Dfile.encoding=UTF-8再发请求:
powershell
Invoke-RestMethod `
-Uri "http://127.0.0.1:18091/api/pa-review/reviews" `
-Method Post `
-ContentType "application/json; charset=utf-8" `
-Body '{"tradeId":"T-1001","includeKline":true,"question":"复盘这笔训练交易"}'你先别急着问“这是不是 AI”。第一章的关键不是智能,而是闭环:请求能进来,报告能出去,边界能表达,下一步训练任务能落地。
这一章真正解决了什么
我们没有做一个完整教练。我们只是把系统的骨架立住了。
从现在开始,后面每加一个能力,都要回答同一个问题:它解决了哪一个真实业务追问?
如果回答不上来,就不要加。
练习题
- 如果用户的问题是“这笔交易亏了,下一笔我要不要马上做回来”,第一章的 MVP 应该直接复盘,还是先提示边界?
ReviewRequestBody和ReviewRequest字段一样,为什么还要拆成两个对象?- 你会把
boundaryNotice放在响应里,还是只放在日志里?为什么?