100 万房贷 30 年到底还多少?我用码道 Agent 写了个精算器,月供对拍银行算例误差 0.004 元

📅 发布时间:2026/10/7 15:33:33
100 万房贷 30 年到底还多少?我用码道 Agent 写了个精算器,月供对拍银行算例误差 0.004 元
100 万房贷 30 年到底还多少我用码道 Agent 写了个精算器月供对拍银行算例误差 0.004 元一键开通华为云码道 CodeArts 代码智能体https://developer.huaweicloud.com/codeartsco.html?sourcedmzntgwatomgit1sourceaddmzntgwatomgithd一、这玩意儿是干嘛的买房的人都有这个灵魂拷问贷 100 万、利率 4.9%、还 30 年我每个月到底要掏多少总共又要给银行白送多少利息等额本息和等额本金到底选哪个更划算银行 App 能算但你要对比不同方案、想提前还一笔看看省多少利息、想搞懂为什么第一个月利息占一大半就得来回切页面、还看不到逐月的账。我做了个网页填贷款额、利率、年限选还款方式它秒出月供、总利息、总还款画一条逐月的本金/利息堆叠曲线还能算提前还款后省多少。白底、干净、专业。代码是喂华为云码道 CodeArts Agent一轮轮建的仓库atomgit.com/wangleizi/mortgage-lens12 项测试全绿月供对拍公开银行算例误差0.0037 元。二、为什么做这个我自己去年看房销售甩过来一张月供测算表等额本息每月 5307、总利息 91 万。我盯着那个 91 万半天没看懂——100 万本金30 年怎么就多出 91 万利息销售只会说公式算的。回来我自己推了一遍年金公式发现这事儿其实清清楚楚就是一个等比数列求和。而且它跟前面潮汐、奶瓶那几篇一样有个确定的数学答案给定本金、利率、期数月供是唯一确定的没有模糊空间。既然销售那张表是公式算的那我就能自己实现这个公式再拿银行公开的算例去对看我对不对得上。我还特意把提前还款做进去了因为这是身边人问得最多的手头攒了二十万是提前还掉省利息还是留着理财这个只有把逐月表摆出来、把提前还之后重算一遍才能算清到底省多少。市面上很多计算器只给个初始月供不给这些我觉得不够用。选题三条铁律一秒看懂、有客观真值、别撞车。房贷精算切的是生活刚需 可精确验证这条线跟记账 App 不是一回事——记账是记录流水这是带闭式解对拍的贷款精算角度不撞。三、先跑起来看看零依赖纯 Node 20 ES Modulegitclone https://atomgit.com/wangleizi/mortgage-lens.gitcdmortgage-lensnode--test# 12 项测试全绿nodebin/dev.mjs# http://localhost:3000填 100 万 / 4.9% / 30 年等额本息月供 5307.27总利息 91.06 万。切到等额本金首月 6861、逐月递减到末月 2787总利息省了快 30 万——这俩方案的差距一张曲线图就讲明白了。我特别喜欢那条逐月堆叠曲线等额本息那条线前期红色利息占一大截、蓝色本金细细一条越往后蓝色越粗——这就是为什么还了十年感觉没还多少本金。销售嘴上说等额本息每月还得少但曲线不会骗人还得少是因为前期大部分钱都喂了利息。这张图比任何话术都直观。四、怎么钉码道 Agent老规矩提示词钉到函数级结尾挂铁律直接建文件并git add -A git commit git push不要只描述、不要贴代码正文只回复 git log 文件树 测试 pass/fail。第一轮提示词原样【R1 · 房贷计算器 mortgage-lens 核心精算层】 建 public 仓库 mortgage-lens。Node 20 ES Module零依赖node:test。 - src/annuity.mjs monthlyPayment({principal,monthlyRate,months}) M P·r·(1r)^n / ((1r)^n − 1)r0 退化为 P/n schedule 返回逐月 [{month,payment,principal_part,interest_part,remaining}] - src/linear.mjs 等额本金每月本金固定 P/n、利息剩余×r - test 硬断言: 100万/4.9%/30年 月供≈5307.37(±0.5)、Σ本金100万(误差1元) 直接建文件并 git commit git push只回复 git log 文件树 测试 pass/fail切 5 轮喂R1 核心公式、R2 真实算例锚定提前还款、R3 白底前端、R4 对拍报告一致性、R5 README。每轮本地 clone 复核。分轮这个习惯我是真踩出来的。房贷这种项目你要是一把梭丢给码道做个房贷计算器带图表和提前还款和对拍它大概率给你糊一个能跑但处处是坑的版本而且中途上下文一紧就开始偷工减料。拆成五轮、每轮一个能独立验收的东西每轮我都本地 clone 下来node --test跑一遍绿了再进下一轮——这样问题当场暴露不会攒到最后崩。五、架构公式 → 逐月表 → 对拍rate(年→月利率) → annuity/linear(月供公式) → schedule(逐月本金/利息) → prepay(提前还款) ↓ verify(对拍 6 组公开银行算例 内部一致性)方案原理特点等额本息年金现值公式每月还款额固定前期利息占比高总利息多等额本金每月本金固定利息随余额递减月供逐月降总利息少分层我是有意让算月供和列逐月表分开的。月供公式是一行闭式解但真正有用的是那张 360 行的逐月表——它才是回答我到底什么时候开始给银行打工变少提前还一笔能砍掉后面多少期利息这些东西的地方。所以核心不是那个公式是 schedule 这个把公式摊开成现金流的能力。verify 那层则完全独立于 UI命令行node bin/verify.mjs就能跑对拍方便 CI 里天天验。六、核心算法掰开揉碎等额本息的月供公式本质是让每月还款的现值之和等于本金解出来是这个公式我第一次推的时候是在一张餐巾纸上把每月还款按利率折回今天、令其和等于贷款额等比数列一求和就出来了。看着唬人其实就是M P·r·(1r)^n / ((1r)^n − 1)一行。难点不在记公式在于你信不信它——所以我才要拿银行公开算例去对。// src/annuity.mjsexportfunctionmonthlyPayment({principal,monthlyRate:r,months:n}){if(r0)returnprincipal/n;constpMath.pow(1r,n);returnprincipal*r*p/(p-1);}逐月表是关键——每月先扣利息剩余本金×月利率剩下的才是还的本金// src/annuity.mjsexportfunctionschedule({principal,monthlyRate:r,months:n}){constpaymonthlyPayment({principal,monthlyRate:r,months:n});letremainingprincipal;constrows[];for(letm1;mn;m){constinterestremaining*r;letprincipal_partpay-interest;if(mn)principal_partremaining;// 末期抹掉浮点尾差remaining-principal_part;rows.push({month:m,payment:pay,principal_part,interest,remaining});}returnrows;}等额本金更直白每月本金固定// src/linear.mjsexportfunctionschedule({principal,monthlyRate:r,months:n}){constbaseprincipal/n;letremainingprincipal;returnArray.from({length:n},(_,i){constinterestremaining*r;remaining-base;return{month:i1,payment:baseinterest,principal_part:base,interest,remaining};});}提前还款则是在已还若干期后用剩余本金重跑一遍公式// src/loan.mjsexportfunctionprepay({principal,monthlyRate,years,paidMonths,extra}){constrowsschedule({principal,monthlyRate,months:years*12});constremainingrows[paidMonths-1].remaining-extra;// 提前还一笔returnmonthlyPayment({principal:remaining,monthlyRate,months:years*12-paidMonths});}七、护城河光对拍银行算例还不够还得防自证我一开始的验证是拿 6 组公开的银行等额本息算例对月供。结果 max_abs_err 只有 0.0037 元看着很硬。但我做了前面几个项目学乖了——警惕自己算的参考值冒充外部权威。这 6 组算例的期望值如果是我自己用同一个公式算出来填进去的那又是自证。怎么破我加了一层跟公式无关的内部一致性校验// src/verify.mjs —— 对拍公开算例import{LOAN_SAMPLES}from./samples.mjs;import{monthlyPayment}from./annuity.mjs;exportfunctionverifyLoans(){letmaxErr0;for(constsofLOAN_SAMPLES){constoursmonthlyPayment({principal:s.principal,monthlyRate:s.annualPct/1200,months:s.years*12});maxErrMath.max(maxErr,Math.abs(ours-s.expectedMonthly));}return{n:LOAN_SAMPLES.length,max_abs_err_yuan:maxErr,all_within:maxErr1};}// src/consistency.mjsexportfunctioncheckConsistency(rows,principal){constsumPrincipalrows.reduce((s,r)sr.principal_part,0);return{principal_sum_ok:Math.abs(sumPrincipal-principal)1,// Σ本金必须贷款额last_balance_ok:Math.abs(rows.at(-1).remaining)1,// 末期余额归零monotonic_ok:rows.every((r,i)i0||r.interestrows[i-1].interest1e-6),};}这三条不依赖月供公式对不对它验的是账目结构本身成不成立360 个月还的本金加起来必须精确等于 100 万、最后余额必须归零、等额本息的每月利息必须单调递减。就算我月供公式写错了只要它产出的逐月表做不到Σ本金贷款额一致性测试立刻红。这跟上一篇 contrast-auditor 里拿独立库做差分测试是一个思路验证的参照物得离你写的那个公式足够远。银行算例是外部数值锚内部一致性是结构锚两条腿一起才敢说不是自嗨。说白了这两层验证管的是不同的错银行算例管我公式是不是记错了、系数是不是打错了内部一致性管就算公式没错我逐月累加的实现有没有把账算漏、浮点有没有炸。前者是数学层后者是工程层。只做前者你可能公式对了但代码实现有 bug 还测不出来只做后者你可能账平得挺好看但月供金额本身是错的。两个都上才算把我算对了这句话钉死。八、测试12 项// test/loan.test.mjsassert.ok(verifyLoans().all_within);// 6 组银行算例误差1元assert.ok(Math.abs(verifyLoans().max_abs_err_yuan)1);// test/consistency.test.mjsassert.deepStrictEqual(Object.values(checkConsistency(...)).every(Boolean),true);// test/annuity.test.mjsassert.ok(Math.abs(monthlyPayment({principal:1e6,monthlyRate:0.049/12,months:360})-5307.27)0.5);九、真实的坑坑 1仓库建成私有了。我 R1 提示词明明写了 public码道还是把 mortgage-lens 建成了 private——我本地 clone 直接弹要用户名密码。这是码道的老毛病默认私有我发了条 nudge 让它改 public 才匿名可访问。以后每条建仓提示词我都得把务必 public写三遍。坑 2浮点尾差。逐月表用浮点累加360 期下来末期余额不是精确 0而是 0.0000001 这种。第一版一致性测试last_balance_ok直接挂。修法很简单末期强制principal_part remaining把尾差吸收掉。这种数学上对、浮点上翻车的坑AI 不太会主动防。坑 3码道上下文又顶满 push 认证崩。R4 之后它 ag 的 git remote token 没了本地提交推不上去得点『选择仓库』重新绑定再 push。这个系列做到第五篇push 认证崩已经是保留节目了。我的应对是准备一条重新 clone 干净仓库 重做改动 push的兜底 nudge崩了就发一次。坑 4等额本金的末月到底多少。我一开始按每月本金固定 P/n算末月利息应该是(P/n)·r但浮点累到最后一个月余额不是精确的 P/n导致末月数字和理论值差几分钱。这种边界不处理一致性测试的末期归零就会挂。修法同样是末期强制把剩余本金一次性还掉。说到底房贷这种金额精确到分的场景浮点是绕不开的坑。我最后所有金额断言都放了 1 元以内的容差而不是要求分毫不差——因为银行系统是按分取整后再滚下一期的我用连续浮点末了几毛钱的差是正常的。这个该精确到哪一步的判断也是 AI 不会主动跟你说清楚的。你得自己决定这是对账工具1 元容差够不够严答案是不够但对验证公式实现有没有写错这个目的够了。十、提效数据环节码道 Agent我建仓库 写全部文件✅出题年金公式 逐月表✅一次对验收提前还款逻辑✅定方案加内部一致性防自证❌✅ 我修浮点尾差❌✅ 我改 public / 修 push❌✅ nudge码道把公式实现、逐月表、UI 飞快地搭出来一次就对上了银行算例。但这个验证会不会是自证“浮点尾差会不会翻车”“仓库是不是忘了设公开”——这些它不管得人盯着。十一、五维自检眼前一亮100 万 30 年到底还多少一秒想看答案。可验证护城河6 组公开银行算例 max_abs_err 0.0037 元 内部一致性Σ本金贷款额、末期归零、利息单调node bin/verify.mjs一键复现。原创度不是记账是带闭式解 结构锚定的贷款精算。工程质量12 测试、零依赖、白底规范。诚实度不含组合贷/LPR 重定价、浮点尾差处理全写明。这里我想多说一句已知不足。这个精算器是固定利率的但国内房贷很多是 LPR 浮动利率每年重定价一次、月供会变还有组合贷公积金商贷是两段利率拼的。这些我都没做因为一旦引入利率会变逐月表就要支持分段重算复杂度陡增还得接入 LPR 历史数据。我选择先把固定利率这个最基础、最能被公开算例验证的场景做扎实把浮动利率明确写成未覆盖。做小工具敢于承认边界比堆功能更重要——你至少知道它什么时候不准。十二、写在最后这项目最让我满意的一行代码不是那个对上了银行的月供公式是那条Σ本金必须等于贷款额的一致性断言。因为它跟公式本身无关——它逼着逐月表在账目结构层面自洽是我给自己上的一道防自证的保险。我见过太多人包括以前的我做这种计算工具验证方式就是我算出来 5307跟百度一样通过。可万一你公式抄错了、只是恰好这一组参数下结果撞对呢万一你逐月累加的时候把某期利息算重了、但月供总额看着还对、只有总利息悄悄多了几千呢这些光靠对一个最终数字根本发现不了。得从结构上卡——本金加总要等于贷款额、余额最后要归零、利息要单调——这些是不管公式怎么变都必须成立的硬约束才拦得住实现层的错。做到第五个会算 XX 的小工具我越来越形成一个肌肉记忆每写完一个看起来在自我验证的东西先别急着高兴问自己一句——如果我把这个结论扔掉还有什么离我更远的证据能撑起它银行算例是远一点的证据内部结构一致性是更远一点的证据。凑不齐就说明我还站在自己的闭环里。欢迎 clone 下来把你自己的房贷参数丢进去算算看看销售那张表和它算的一不一样https://atomgit.com/wangleizi/mortgage-lens整个项目二十来个文件、零依赖从建仓到能跑码道前后花了不到半小时而真正让它可信的那三个动作——加内部一致性防自证、修浮点尾差、把仓库改回 public——没一个是它主动做的。这个反差就是我这一整个系列想说的AI 把写出来变得廉价把写对、验对变得珍贵。