返回项目分享

Gym-Agent:把 Agent 和 RAG 塞进一个真实的预约系统

Spring Boot 3 + Vue3 的体育场馆预约平台,在常规预约链路之外接了 LangChain4j Agent 与 pgvector 知识库;Agent 只生成预约草稿,必须由用户点确认才真正落库。

维护中

为什么是体育场馆

我自己除了写代码,剩下的时间基本都在健身房和球场上,所以第一个从 0 到 1 的项目就想做这个。 业务本身不新,场馆预约系统满地都是,我想要的是一条足够完整的后端主链路: 用户、场馆、场地、时段、订单、公告、评论、收藏、通知,每一环都得自己接一遍。 链路跑通之后,再往上叠 Agent 和 RAG——这样 AI 部分是长在真实业务上的,不是一个悬浮的聊天框。

先说预约这条主链路

真正的难点不在增删改查,在时段:

  • 场地按日期 + 时间段开放,同一场地同一时段不能被约两次,冲突校验落在服务层,不依赖前端置灰;
  • 前端做了一张预约时段可视化表,可约、已占、已停用一个颜色说清楚,不用用户自己算时间;
  • 订单要能区分预约订单和商城订单,状态流转、取消、退款各自有流水记录(支付是模拟的,这点不装)。

外围接了 Redis(缓存、验证码、登录态)、MinIO(图片和文件)、Mail(预约/取消/退款通知)、 WebSocket、EasyExcel 导出,Maven 拆成 parent + admin / model / common 三个模块。 前端是 Vue3 + Element Plus + Vite,后台管理端和用户前台是两个工程, 本地跑起来分别是 3001 和 3002,后端在 9601。

Agent 只出草稿,确认权在人手里

这是整个项目里我最在意的一条设计。

用户说「帮我约明晚七点到九点的一个羽毛球场地」,Agent 会调工具去查场馆、查可预约时段, 然后生成一份预约草稿返回给前端;前端把它渲染成一张卡片,用户点确认按钮,才真正走预约接口。 中间那一步不能省——模型理解错了时间或者场地,代价是一次错误的真实预约。

配套还做了:

  • 「我的预约」这类高频意图走直达路由,不把所有问题都塞给模型,准确性和响应速度都更好;
  • 每次工具调用的名称、参数、结果都记进日志,带 traceId,后台能直接看到 Agent 到底干了什么—— 调试 AI 功能时,这一步比看代码有用得多。

RAG 用来回答「平台规则」这类问题

知识库走 PostgreSQL + pgvector:文档切片入库、向量化、检索、拼进提示词。 两个细节值得单独说:

  1. 命中来源展示:回答下面会列出标题、标签、知识范围、相似度和命中的文本片段。 没有来源的 RAG 回答,用户没法判断能不能信;
  2. 单条知识增量索引:后台改一条公告,不需要把整个知识库重跑一遍。

我知道哪里还不够

  • 支付是模拟的,没有真实资金链路;
  • 场馆别名(「奥体」到底指哪个馆)还没做解析,靠模型硬猜;
  • 多轮上下文的裁剪比较粗,长对话会丢信息;
  • 没有评测集。Agent 现在只能靠人工试,改一版提示词不知道是变好还是变坏—— 这也是我后来做 Job-Agent 时把 Eval 平台补上的原因。

怎么跑起来

需要 JDK 17、Maven 3.8+、MySQL 8、Redis 7、Node.js 16+。 先执行 db/gym.sql 初始化数据库,再把 Gym-admin/src/main/resources/application.yml 换成自己的环境, 敏感配置单独放在 application-local.yml(这个文件不进仓库),然后启动 AdminApplication 和两个前端工程。

对这个项目有问题或建议?讨论留在仓库里更容易被看到,欢迎 到仓库提 Issue