Skip to content

02. 第一个 ReviewCoachAgent:让回答像教练,而不是像闲聊

上一章练习参考答案

第一题,应该先提示边界。用户已经从复盘训练跳到了“下一笔要不要做回来”,这很容易变成实盘决策建议。系统可以引导他改写问题,比如“这笔交易有没有遵守原计划”,但不能顺着回答下一笔怎么做。

第二题,HTTP DTO 和业务 Command 字段一样也建议拆开。接口会变,业务命令也会变,拆开之后你可以在 Controller 做校验、默认值、兼容旧字段,而不污染业务层。

第三题,boundaryNotice 应该放在响应里。因为边界不是内部日志,它要被用户看见,也要被前端、审计和测试稳定拿到。

MVP 的第一个问题

上一章的 MVP 能返回结果了,但它还不像教练。

如果系统只是说:

“这笔交易亏损,建议下次注意风险。”

这种话没有训练价值。用户听完不会知道自己下一次该练什么。真正的教练要能固定住几个动作:

  • 先声明边界:只复盘训练样本。
  • 再看计划:这笔交易原本想练什么。
  • 再看执行:入场、止损、止盈和退出有没有偏离计划。
  • 最后给训练任务:下一组样本要怎么练。

所以第二章引入 ReviewCoachService,它就是本地版的 ReviewCoachAgent。等接入 Spring AI Alibaba 时,这个角色可以映射为一个带系统提示词、工具、记忆和保护栏的 Agent。

先看它的职责

ReviewCoachService 不是“会写一段话”的类,而是复盘编排器:

java
public class ReviewCoachService {

    public ReviewReport review(ReviewRequest request) {
        if (guardrailService.isLiveAdviceRequest(request.question())) {
            return blocked(request);
        }

        TradeRecord trade = tradeRepository.findById(request.tradeId())
                .orElseThrow(() -> new IllegalArgumentException("trade not found"));

        if (!trade.hasRiskPlan()) {
            return needsMoreContext(trade);
        }

        RiskMetrics risk = riskCalculator.calculate(trade);
        // 组装结构化复盘报告
    }
}

这段逻辑故意写得很直白。你以后接大模型,也不要把所有判断都交给模型。像越界拦截、交易读取、风险计算、信息缺失判断,这些都应该是稳定代码先做。

为什么叫 Agent

在教程里我们先用 ReviewCoachService 承载 Agent 职责,因为它能本地跑通。但你要理解真正的 Agent 边界:

  • 它有角色:PA 训练复盘教练。
  • 它有任务:复盘已发生的训练交易。
  • 它有工具:读交易、读 K 线、算风险。
  • 它有记忆:训练者长期问题。
  • 它有保护栏:不回答实盘买卖方向。

如果以后换成 Spring AI Alibaba,可以把这部分抽成类似:

java
ChatClient reviewCoachClient = chatClientBuilder
        .defaultSystem("你是 PA 训练复盘教练,只复盘已经发生的训练交易。")
        .defaultTools(tradeTools, riskTools, klineTools)
        .build();

本章重点不是 API 长什么样,而是 Agent 的职责边界不能乱。

这一章怎么验证

继续调用同一个接口:

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":"复盘这笔训练交易"}'

这次你重点看这些字段:

json
{
  "status": "REVIEWED",
  "primaryProblem": "没有等待回踩确认,入场动作和 plannedSetup 不一致",
  "nextTrainingTask": "连续记录 20 笔突破后是否等待回踩确认的训练样本",
  "sections": {
    "coachSummary": "这是一笔突破后追多训练失败样本,重点不是预测行情,而是复盘执行动作。"
  }
}

它不是泛泛地说“注意风险”,而是把问题落到“入场动作和计划不一致”。

这一章真正解决了什么

第一章解决的是能不能闭环。第二章解决的是:闭环之后,输出有没有训练味。

一个复盘教练不能只安慰用户,也不能只吐槽用户。它要把一笔交易变成下一次训练动作。

练习题

  1. 如果用户写了很长一段情绪化描述,ReviewCoachAgent 应该先共情,还是先抽取交易事实?
  2. 哪些判断适合放在稳定代码里,哪些部分适合交给大模型生成?
  3. 如果后面要接 Spring AI Alibaba,你会把 Agent 的系统提示词写在哪里?

Built with VitePress. Deployed on Cloudflare Pages.