给博客加了四个占卜应用,记录一下搭建过程
起因
博客搭好之后一直想加点有意思的东西。我对传统术数有点兴趣,就想着能不能用 AI 做个在线解卦的工具。一开始只做了六爻,后来发现架构挺通用的,就顺手把大六壬、奇门遁甲、太乙神数也一起做了。
最终效果在 https://bai-blog.cc.cd/app/ ,四个应用都能用。
---
技术选型
前端没什么好说的,四个应用本身就是现成的 HTML 页面,直接丢到 Next.js 的 public/ 目录下就能访问,不需要走框架路由。
后端主要解决一个问题:怎么把用户的卦象信息扔给大模型,再把结果流式返回来。
最终方案:
---
前端结构
四个应用放在 public/ 下面,各自独立:
每个目录里都有 index.html 和 mapping_page/。主页面负责输入和展示,排盘逻辑在子页面里通过 iframe 通信。
用纯 HTML 的原因很简单:这些页面本身就有复杂的排盘逻辑,和 Next.js 混在一起反而麻烦。而且纯 HTML 加载快,维护也方便,改一个文件就行。
---
AI 解读怎么做的
核心思路是任务队列 + SSE 流式输出。
用户点"AI解读"的时候,前端先发一个 POST 请求创建任务,后端把任务信息存到 Supabase,返回一个 taskId。然后前端用这个 taskId 建立 SSE 连接,后端调用大模型,边生成边推送给前端。
为什么要用任务队列?因为 AI 解读可能要几十秒,用户可能中途断线。有了 taskId,断线重连还能拿到之前的结果。而且历史解读都存在数据库里,方便复盘。
AI 调用封装在 src/lib/deepseek.ts(名字是历史原因,其实现在接的是 MGTV 的接口)。核心就是调 /chat/completions 接口,开 stream,解析 SSE 数据。
---
Prompt 设计
四个应用共用一套调用框架,但各有各的 prompt。
以六爻为例,prompt 大概分这几块:
其他三个应用也是类似的结构,只是知识体系不同。六壬侧重天地盘和四课三传,奇门看重格局和用神落宫,太乙关注积年和局数。
Prompt 调了不少次,主要是让 AI 别太发散,按框架来分析,同时又不能太死板。这个平衡不好把握。
---
Supabase 搭建
选 Supabase 主要是省事,不用自己搭后端,直接用它的 PostgreSQL 加 REST API。
创建项目
去 supabase.com 注册账号,新建一个项目。选区域的时候离你近的就行,我选的新加坡。项目创建完会给你两个 key:
这两个 key 加上项目 URL 就是 .env.local 里那三个变量。
建表
项目创建完,在 SQL Editor 里直接跑建表语句。
**ai_tasks 表**(占卜任务):
create table ai_tasks (
task_id uuid primary key,
biz_type text not null, -- liuyao / liuren / qimen / taiyi
status text default 'pending', -- pending / processing / completed / failed
request_payload jsonb, -- 原始请求数据
result_analysis text, -- AI 解读结果
reasoning_process text, -- 推理过程(目前没用到,留着备用)
created_at timestamptz default now(),
updated_at timestamptz default now()
);**messages 表**(留言板):
create table messages (
id bigint generated always as identity primary key,
nickname text default '匿名',
content text not null,
is_approved boolean default false, -- 需要审核才显示
created_at timestamptz default now()
);建完表之后,记得在 Supabase 后台的 Table Editor 里看看字段对不对。也可以在那边直接加 RLS 策略,不过我图省事先没加。
Next.js 里怎么连
服务端用 service role key,这样能读写所有数据:
import { createClient } from "@supabase/supabase-js";
export const supabaseServer = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);前端用 anon key,只能访问开了权限的表:
export const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);实际用下来,前端基本不直接碰数据库,都是通过 API Routes 中转。只有留言板的读取是前端直接查的。
---
部署
本地开发就 npm run dev,四个应用在 /liuyao/、/liuren/ 这些路径下直接访问。
推到 GitHub 之后 Vercel 自动部署,基本不用管。但环境变量需要手动在 Vercel 后台配,主要是 Supabase 的连接信息和 AI 接口的 key。
域名用的 bai-blog.cc.cd,在 Vercel 后台加了自定义域名,DNS 指过去就行。
---
踩的坑
**环境变量不生效**:改了 .env.local 之后必须重启 dev server,热更新不读环境变量。这个坑踩了好几次。
**API 额度问题**:一开始用的 DeepSeek 的模型,后来切换到 MGTV 的接口。切换的时候忘了改 Vercel 后台的环境变量,线上一直报错。排查了半天才发现是额度用完了,不是代码问题。
**模型选择**:试过几个模型,效果差别挺大的。有些模型在术数领域基本是胡说八道,有些还行。最后选了 glm-5.1,性价比和效果都能接受。
---
写在最后
四个应用搭下来,最大的感受是 Prompt 工程比写代码花的时间多得多。代码层面其实不复杂,就是标准的 API 调用加流式输出。但怎么让 AI 按照术数的逻辑去分析,而不是一本正经地胡说,这个真的需要反复调试。
另外就是前端页面的适配问题,四个应用的排盘逻辑各不相同,好在都是现成的,主要是做整合和调优。
整体架构挺简洁的,后续想加新的占卜类型也很方便,写个新 HTML 加个新 prompt 就行。