Skip to content

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.java

Controller 只做转发:

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”。第一章的关键不是智能,而是闭环:请求能进来,报告能出去,边界能表达,下一步训练任务能落地。

这一章真正解决了什么

我们没有做一个完整教练。我们只是把系统的骨架立住了。

从现在开始,后面每加一个能力,都要回答同一个问题:它解决了哪一个真实业务追问?

如果回答不上来,就不要加。

练习题

  1. 如果用户的问题是“这笔交易亏了,下一笔我要不要马上做回来”,第一章的 MVP 应该直接复盘,还是先提示边界?
  2. ReviewRequestBodyReviewRequest 字段一样,为什么还要拆成两个对象?
  3. 你会把 boundaryNotice 放在响应里,还是只放在日志里?为什么?

Built with VitePress. Deployed on Cloudflare Pages.