
同一个出生时间,问三个 AI 内容产品,得到三个不同的干支编码结果------这不是 AI 不够聪明,是工具选型错误:该用确定性代码的地方,用了概率模型硬扛。
本文复盘我花 13 天做的开源历法引擎:干支编码为什么是确定性计算、节气边界怎么处理、1000 条带出处的断语库怎么建,附完整源码。
一、干支编码:规则是死的,答案只有一个
把公历时间转换为干支纪年(年柱/月柱/日柱/时柱),规则全部确定:
- 年界看立春时刻,不看春节;
- 月界看节气交节时刻(精确到分钟);
- 23 点后为晚子时,时柱按次日干支;
- 中国 1986-1991 年夏令时需回拨一小时;
- 真太阳时按出生地经度校正。
每个边界答案唯一、可复现------这正是"该计算而非生成"的典型问题。
二、为什么大模型会算错
大模型是概率模型,本质在猜"下一个词最可能是什么"。让它处理历法边界:
- 偶尔对:训练数据里见过类似案例;
- 经常错:历法边界是低频细节,覆盖不足;
- 无法一致:同一输入、不同推理路径,输出不同。
用户问出三个答案,等于没问。

三、确定性实现:206 年节气表 + 精确切分
工程上采用预验证数据表方案,节气时刻不靠公式现算:
js
// 节气表(1895-2100 共 206 年,预验证数据)
const JIEQI = {
range: [1895, 2100],
data: {
"2026": ["02-04 04:02", "03-05 21:59", "04-05 02:40", /* 立春/惊蛰/清明... */],
// ...
}
};
// 年柱:立春时刻为界,精确到分钟
function yearGZ(y, m, d, hh, mm) {
const lichun = parseJieqi(JIEQI.data[y][0]); // 立春时刻
const born = toMinutes(y, m, d, hh, mm);
const yy = born >= lichun ? y : y - 1;
return ganZhiFromYear(yy);
}
核心排盘调用(101 个 API 之一):
js
const ctx = BaziEngine.paipan("测试", "男", 1990, 5, 15, 23, 30, "广州市", "no");
// ctx.yg=庚午 ctx.mg=辛巳 ctx.dg=庚辰 ctx.hg=戊子
// 23:30 属晚子时:日柱仍为当天庚辰,时柱已按次日日干遁为戊子
四、断语库:1000 条,每条带古籍出处
解读不是让 AI 现场编,而是规则匹配 + 出处可追溯:
json
{
"id": "char_jia",
"category": "性格",
"condition": { "日主": "甲木" },
"conclusion": "如参天大树,仁德有担当,有领导气质;喜火通明、水木相滋,忌金重土埋。",
"source": "《滴天髓》甲木参天 / 《穷通宝鉴》甲木",
"confidence": "高",
"suggestion": "发挥领导才能,注意人际柔性,寒木需火暖局"
}
每条断语都标注书名篇名,不搞"祖传秘方"。审计脚本专门扫描两类问题规则:
- "永远成立"的废话规则 → 删;
- "永远不命中"的死规则 → 删;
- 1000 个真实盘批量跑,检查断语矛盾。
五、工程质量:13 套测试 + CI 门禁
- 13 套回归测试(排盘 28 项 / 农历 27 项 / E2E 验收等);
- CI 门禁:不绿不让合并;
- 单文件 438KB、零外部依赖,浏览器/Node 双端可用。
六、开源与在线体验
- GitHub :https://github.com/ruanxiaoer888/bazi-engine(MIT 协议)
- 平台:SkillHub、ClawHub 双平台上架,13 套回归测试 + CI 门禁
- 在线产品 :「本初」------它不预言什么,只把你出生的那一刻,翻译成一份可以读的「出厂说明书」。从出生之初,认识本来的你。
- 在线体验 :https://benchu.xiaoerpro.com/
历法计算是确定性的,该算的不能靠猜。欢迎 ⭐ star 仓库、提 issue/PR,或评论区聊聊你的实现思路。
免责声明:本文内容仅供历法技术研究与传统文化参考,不构成任何专业建议。