AI辅助开发库存管理系统:Flask+SQLite并发安全与成本核算 库存管理系统这个东西几乎是每个做业务系统的开发者都绕不开的一道坎需求看起来简单到一句话就能说清真动手做的时候才发现坑全在细节里。这次我把整套系统重做了一遍思路是AI辅助开发——用WorkBuddy这类AI编程助手承担样板代码、接口骨架、前端表格渲染这些重复劳动Python负责把业务逻辑和并发安全的硬骨头啃下来。整套系统覆盖商品档案、多仓库存、出入库流水、加权平均成本、盘点调整、低库存预警和报表导出代码量不大但每一行都经得起真实仓库的日常折腾。这篇内容适合三类人看一是手上有Excel库存表、想做成系统的中小团队开发者二是想搞清楚AI写的代码到底能不能用、怎么改才能用的工程同学三是接了内部工具需求、预算和时间都紧的独立开发者。下面我把选型理由、表结构、核心事务逻辑、AI协作的具体姿势和踩过的坑一条条摊开讲。1. 需求拆解与技术选型为什么是这套组合1.1 从一张共享表格说起库存管理的真实痛点绝大多数库存系统都是从一张共享表格演化来的几个仓管各存一份每天下班前对一次对不上的时候谁也说不清是哪一笔出的问题。这种模式的根本毛病不在于表格不好用而在于它只记录了当前是多少没有记录为什么变成这个数。库存管理的核心资产其实是流水当前数量只是流水的一个聚合结果。所以我在做需求拆解的时候第一件事就是把当前库存和库存流水拆成两个概念。当前库存是为了查询快流水是为了追责和对账。这两个东西必须同时存在任何只做其中一个的方案半年内一定会被业务方骂。第二个痛点是多仓。哪怕公司只有一个物理仓库也建议预留仓库维度因为很快就会出现待检区退货区样品区这类逻辑仓事后加字段的成本远高于一开始就留好。第三个痛点是成本核算。很多自研系统只记数量不记成本等到财务要算毛利的时候才发现数据全废了。入库单价的记录方式直接决定后面能不能算出加权平均成本这个决策在表设计阶段就要定死中途改几乎等于重构。想清楚这三点需求边界基本就清晰了商品档案、多仓库存、出入库单据、成本核算、盘点调整、预警和报表。剩下的功能都是锦上添花。提示如果你的业务存在同一个SKU不同批次成本差异很大的情况比如生鲜、电子元器件加权平均就不够用了需要上批次管理。这个决策一定要在表设计前和业务方确认不要自己拍脑袋。1.2 技术栈取舍Flask加SQLite够用且好维护技术选型上我给自己的约束是单机能跑、零外部依赖、部署成本接近零。库存系统的并发量通常不高——一个中型仓库一天几百到几千笔单据峰值集中在早晚两个时段这种量级上MySQL和SQLite的差距可以忽略但运维复杂度差了一个数量级。后端选Flask理由很实际路由和蓝图机制简单团队里随便谁接手都能两天内看懂生态成熟导出Excel、生成报表这些都有现成库。前端不引框架就用原生HTML加少量JS表格渲染直接用服务端模板理由是这个系统的用户是仓管和财务他们在意的是打开快、字大、能打印不是单页应用的丝滑。用React反而会增加构建链路出问题时排查成本陡增。数据库用SQLite但要开WAL模式。很多人对SQLite的印象停留在玩具数据库实际上在单机读多写少的场景里它非常能打而且备份就是拷一个文件对小团队极其友好。这里有个前提所有写操作必须走事务且事务粒度要小。后面第3节会展开讲并发处理的具体做法。方案部署复杂度适合规模主要风险SQLite Flask极低单文件单仓/多仓日均千级单据写并发高时锁等待MySQL Flask中等需运维多组织、日均万级运维与备份成本云数据库 前后端分离较高多端协同成本与调试链路长1.3 AI辅助开发的正确姿势让AI做脚手架你做决策WorkBuddy在这个项目里的定位我一开始就想清楚了它不是帮你写完整个系统的魔法棒而是把重复劳动压缩到几分钟的加速器。我实际让它承担的工作有三类生成CRUD接口的样板代码、生成前端表格和表单的HTML结构、根据报错信息给出排查方向。反过来有三类工作我坚决不让它做表结构的最终决策、事务与并发逻辑、成本计算规则。原因是AI生成的代码有一个共性特征——它在平均值场景下非常靠谱在边界场景下容易想当然。比如让它写一个出库接口它会给你先查库存、判断够不够、再更新这样的顺序逻辑这段代码在单用户测试时百分百通过一到两个人同时出库同一SKU就会超卖。它不是不会写原子更新而是它默认你的场景是理想的。所以我的协作方式是先自己把数据模型和关键状态机想清楚写成一段明确的约束说明丢给AI让它按约束生成生成之后逐行读重点看三处——有没有事务、有没有边界判断、有没有把浮点数用来存钱。这三处只要有一处不对整段重写比打补丁更省事。2. 数据模型设计库存系统的地基2.1 五张核心表与字段取舍逻辑表结构这块我改了三个版本才定稿。最终是五张表商品表、仓库表、库存表、流水表、单据表。商品表存SKU、名称、分类、单位、参考售价、安全库存仓库表存仓库编码和名称库存表是商品与仓库的多对多关系加上数量流水表记录每一笔变动单据表记录一次操作的头部信息操作人、时间、备注、单据号。字段取舍上有几个决策值得说明。第一金额全部用整数存分不用浮点。浮点数在累加几百次之后会出现0.30000000000000004这种经典误差库存成本一旦有分位误差财务对账会非常痛苦。第二时间统一存UTC的ISO字符串展示层再转本地时区避免服务器迁移后数据错乱。第三库存表上给(product_id, warehouse_id)建唯一索引这是防止重复行的最后一道保险——业务层写错了也不会产生两行库存。流水表里我特意加了balance_after字段记录这笔变动之后的结存数量。这个字段是冗余的理论上可以聚合算出来但它对排查问题的价值极高当客户说我这儿显示的数量不对你只要看最后一条流水的balance_after和库存表的qty是否一致就能立刻定位是流水漏记还是库存被脏写。多存一个整数换来的排查效率非常值。2.2 为什么流水表一分都不能省我见过不止一个自研系统为了省事只更新库存不记流水理由是反正能查到单据。这个想法在有单据的情况下勉强成立但现实是单据会被删、会被改、会有线下调整、会有历史数据迁移一旦某个环节绕过了单据库存就成了一个无法解释的数字。流水表的设计原则是只增不改不删。任何导致库存变化的操作都必须写一条流水包括入库、出库、盘盈、盘亏、调拨、退货、初始化。流水上记录操作类型、关联单据号、变动数量、变动后结存、操作人和时间。有了这个任何时候出现数量争议你把某个SKU的流水按时间排一遍加起来等于当前库存账就平了不等的话缺口在哪个时间点、哪一笔一目了然。还有个容易被忽略的点初始化库存也要走流水。很多系统在导入期初数据时图快直接塞进库存表结果后面所有对账都少一个基准点。我的做法是给每一条期初数据生成一条类型为INIT的流水成本和数量都照常记这样从第一天起账就是平的。2.3 建表脚本与初始化配置下面是核心建表语句直接在SQLite里跑就行。注意开头那几行PRAGMA尤其是外键开关SQLite默认是关的很多人不知道这一点结果外键写了等于没写。PRAGMA journal_mode WAL; PRAGMA foreign_keys ON; PRAGMA busy_timeout 5000; CREATE TABLE products ( id INTEGER PRIMARY KEY AUTOINCREMENT, sku TEXT NOT NULL UNIQUE, name TEXT NOT NULL, category TEXT, unit TEXT NOT NULL DEFAULT 件, price_cent INTEGER NOT NULL DEFAULT 0, cost_cent INTEGER NOT NULL DEFAULT 0, safety_stock INTEGER NOT NULL DEFAULT 0, is_active INTEGER NOT NULL DEFAULT 1, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); CREATE TABLE warehouses ( id INTEGER PRIMARY KEY AUTOINCREMENT, code TEXT NOT NULL UNIQUE, name TEXT NOT NULL, is_active INTEGER NOT NULL DEFAULT 1 ); CREATE TABLE stock ( id INTEGER PRIMARY KEY AUTOINCREMENT, product_id INTEGER NOT NULL REFERENCES products(id), warehouse_id INTEGER NOT NULL REFERENCES warehouses(id), qty INTEGER NOT NULL DEFAULT 0, updated_at TEXT NOT NULL, UNIQUE (product_id, warehouse_id) ); CREATE TABLE stock_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, product_id INTEGER NOT NULL REFERENCES products(id), warehouse_id INTEGER NOT NULL REFERENCES warehouses(id), biz_type TEXT NOT NULL, biz_no TEXT, change_qty INTEGER NOT NULL, unit_cost_cent INTEGER NOT NULL DEFAULT 0, balance_after INTEGER NOT NULL, operator TEXT, remark TEXT, created_at TEXT NOT NULL ); CREATE INDEX idx_logs_product ON stock_logs(product_id, created_at); CREATE INDEX idx_logs_bizno ON stock_logs(biz_no); CREATE INDEX idx_logs_time ON stock_logs(created_at);这里有个细节值得单独说stock表用(product_id, warehouse_id)做唯一约束同时我给它加了一个id主键。为什么不直接用联合主键因为后面做分页和按行更新的时候单列主键写起来更省事ORM映射也更直观。这是纯粹工程便利性的取舍不影响正确性。3. 核心业务逻辑入库、出库与并发安全3.1 入库逻辑与加权平均成本的算法入库要做三件事加库存、写流水、更新加权平均成本。前两件是显而易见的第三件决定这个系统能不能算账。加权平均成本的公式是新成本 (原库存量 × 原成本 本次入库量 × 本次单价) ÷ (原库存量 本次入库量)注意分母是新总量如果原库存是0直接取本次单价不要出现除零。这个公式看起来简单但有两个坑必须提前躲开。第一个坑是负数库存如果历史数据里存在负库存这在管理松散的公司很常见加权平均算出来的成本会跑飞出现负数成本或者天文数字。我的处理是入库时对原库存量做max(qty, 0)保护同时在后台报表里单独标记负库存行交给业务方清理。第二个坑是精度成本用分做整数除法必然产生余数我的做法是四舍五入到分并把舍入损失记录在流水上方便财务追溯。还有一个业务细节调拨入库不应该更新平均成本。因为调拨只是货从一个仓移到另一个仓公司层面的成本没变。如果调拨也走加权平均成本会在仓库之间来回漂移最后算不出真实毛利。所以我在biz_type里区分了PURCHASE_IN和TRANSFER_IN只有前者触发成本重算。3.2 出库逻辑一次原子更新胜过十次查询出库是整个系统最容易出问题的地方。新手写法是先查库存、判断够不够、再更新这三步之间有窗口期两个人同时出库就会超卖。正确做法是把判断和更新合成一条SQL让数据库来保证原子性def outbound(conn, product_id, warehouse_id, qty, biz_no, operator, allow_negativeFalse): now utc_now_iso() with conn: # 自动提交或回滚 cur conn.execute( UPDATE stock SET qty qty - ?, updated_at ? WHERE product_id ? AND warehouse_id ? AND qty ?, (qty, now, product_id, warehouse_id, qty) ) if cur.rowcount ! 1: if not allow_negative: raise StockNotEnough(f商品{product_id}库存不足需要{qty}) conn.execute( UPDATE stock SET qty qty - ?, updated_at ? WHERE product_id ? AND warehouse_id ?, (qty, now, product_id, warehouse_id) ) row conn.execute( SELECT qty FROM stock WHERE product_id? AND warehouse_id?, (product_id, warehouse_id) ).fetchone() balance row[qty] conn.execute( INSERT INTO stock_logs (product_id, warehouse_id, biz_type, biz_no, change_qty, unit_cost_cent, balance_after, operator, created_at) VALUES (?,?,?,?,?,?,?,?,?), (product_id, warehouse_id, SALE_OUT, biz_no, -qty, 0, balance, operator, now) ) return balance关键在那句AND qty ?。它把库存够不够的判断交给了数据库引擎在行锁的保护下完成rowcount返回0就说明条件不满足。这一招在SQLite和MySQL上写法略有差别但思路通用是我做库存类系统十几年最舍不得换的一个模式。allow_negative参数是给特定场景留的口子。有些公司允许先出库后补货比如预售这种情况下负库存是合法业务状态不能一刀切拒绝。但一定要把它做成显式开关而不是默认放开同时流水里要能看出来哪些是负库存出库。3.3 事务边界与并发把锁等待时间压到毫秒级用了原子更新不等于线程安全就万事大吉事务粒度才是决定并发表现的关键。我踩过的一个坑是把更新库存 写流水 更新单据状态 写操作日志全部包在一个大事务里然后里面还夹了一次网络请求调用外部接口校验结果高峰期出现大量database is locked。解决思路有三条。第一条事务里只允许数据库操作任何可能超时的外部调用必须挪到事务外面。第二条保持加锁顺序一致多个表都要更新时先更新库存再写流水再更新单据所有入口按同一个顺序走避免死锁。第三条SQLite上开启WAL并把busy_timeout设到5000毫秒让写冲突自动重试而不是立刻报错。批量操作还要额外处理。比如批量出库100个SKU如果每条都开一个事务SQLite的写锁开销会非常明显。我的做法是整个批次一个事务但单条失败时记录错误并继续最后汇总成功和失败明细返回给前端。这样既保证了吞吐又不会因为一条数据有问题导致整批回滚——仓管最烦的就是提交了50条全部失败还得重新填。注意批量操作里千万不要用executemany去更新带条件的库存因为rowcount会变成总数你无法知道具体哪一条失败。逐条执行虽然慢一点但可追溯性重要得多。3.4 盘点与库存调整让差异有理有据盘点是库存系统里最容易被轻视的模块。很多系统只提供一个修改库存数量的按钮这等于开了一个后门谁都能改改完没痕迹。正确做法是盘点单机制——盘点时录入实盘数系统算差异审核通过后生成盘盈或盘亏流水库存随之调整。盘盈盘亏的流水必须记录调整原因常见的原因是漏记、错发、破损、计量误差。我在流水表上加了remark字段并做了枚举提示让操作人从下拉里选而不是自由输入。这个小小的约束让后面的差异分析变得可能按月统计一下破损和漏记的比例就知道仓库管理该往哪个方向改。还有一个实操细节盘点期间要冻结该仓库的出库。实现上不需要真的锁表只要在出库接口里检查该仓库是否存在进行中的盘点单有就拒绝并提示。这个检查成本很低但能避免盘着盘着又来一车货的经典混乱。4. 接口设计与AI协作把生成的代码改到能用4.1 接口分层与返回结构统一接口这块我采用最朴素的三层路由层负责参数解析和权限校验服务层负责业务逻辑和事务数据层负责SQL。这么分不是为了好看是为了让AI生成的代码有明确的落位。当我对WorkBuddy说给我写一个商品查询接口返回结构统一为 code/message/data它产出的代码就会自然落在路由层我只需要检查它有没有越界写SQL。返回结构一定要在第一天就统一否则后期前端要写十种不同的解析逻辑。我的约定是成功返回{code: 0, message: ok, data: {...}}业务异常返回code为非零的业务码加可读的中文提示系统异常统一返回500并记录trace id。分页统一返回data: {list: [], total: 0, page: 1, size: 20}。参数校验我用了一个轻量的装饰器方案而不是引重型校验库。原因是这个系统的字段不多手动校验反而更直观而且AI生成的校验代码经常遗漏空字符串和None不是一回事这种细节自己写一遍更放心。4.2 AI生成代码的三类典型毛病与修正用WorkBuddy写了大概两周我总结出它生成的代码有三类高频问题几乎每次都要人工修。第一类是相信入参。它生成的函数默认前端传来的数量和单价都是合法正整数不会做负数校验。而实际业务里用户复制粘贴带空格、带千分位逗号、甚至是负数都会稳定复现。所以我的习惯是在服务层入口加一道标准化去空格、去逗号、转整数、判正负。第二类是忽略事务。生成的多表写入代码往往是连续几条execute没有包在事务里。只要中间报错数据就半截。修正方式很简单在服务层入口用with conn:包起来但要注意把上下文管理器套在正确的位置上别套到只读查询里。第三类是返回结构漂移。同一个项目里AI生成的接口一会儿返回{data: [...]}一会儿返回{items: [...]}一会儿直接返回数组。这个必须靠调用方统一约定来治我在提示词里固定带上返回结构的模板命中率就会高很多。4.3 提示词模板怎么问才拿到能用的代码这个是我觉得最值得分享的部分。同样的工具问法不同产出质量差三倍。我摸索出的模板结构是四段背景约束、数据结构、明确要求、禁止事项。举个例子写报表接口时我这样问背景Flask SQLite 库存系统已有表 stock_logs(product_id, warehouse_id, biz_type, change_qty, unit_cost_cent, balance_after, created_at)。 约束金额单位是分时间是UTC ISO字符串所有查询必须走索引。 需求写一个函数 stats_by_product(product_ids, start, end)返回每个商品的 出库总量、出库金额分、退货总量。必须一次SQL聚合不要循环查询。 禁止不要用 f-string 拼SQL不要返回浮点数金额不要省略空结果的处理。这段提示词的产出基本可以直接用。核心经验是把禁止事项写清楚比把需求写清楚更重要因为AI的默认习惯就是最省事的写法你不明确禁止它一定用字符串拼SQL、一定用浮点数、一定在循环里查数据库。5. 完整实操从零把系统跑起来5.1 目录结构与依赖安装目录结构保持扁平一眼能看到全部文件。这样做的原因是这类内部工具的维护者经常换人层级太深会增加理解成本。inventory/ app.py # 入口与蓝图注册 db.py # 连接管理、PRAGMA设置 services/ inbound.py outbound.py stocktake.py report.py templates/ index.html product.html static/app.js data/inventory.db requirements.txt依赖只有四个Flask、openpyxl导出Excel、python-dateutil时区处理、pytest测试。安装一行搞定python -m venv venv source venv/bin/activate pip install flask openpyxl python-dateutil pytestdb.py里最重要的一段是连接初始化每个连接都要把PRAGMA重新设一遍因为SQLite的PRAGMA是连接级别的不是库级别的——这点很多人搞错以为在初始化脚本里设一次就全局生效了。import sqlite3 def get_conn(db_path): conn sqlite3.connect(db_path, timeout5.0, isolation_levelNone) conn.row_factory sqlite3.Row conn.execute(PRAGMA journal_modeWAL) conn.execute(PRAGMA foreign_keysON) conn.execute(PRAGMA busy_timeout5000) conn.execute(PRAGMA synchronousNORMAL) return connisolation_levelNone是关掉Python的隐式事务管理改成手动控制用with conn:显式开启事务。这样事务边界完全由业务代码决定不会出现以为提交了其实没提交的诡异情况。5.2 期初数据导入与第一次对账系统上线前必须做一次期初导入。我的做法是让财务提供一份Excel包含SKU、仓库、数量、单价四个字段然后用一个一次性脚本导入每条都生成INIT类型的流水。导入脚本要注意三件事一是全量校验先行把所有行先过一遍发现SKU重复、数量为负、单价为空的直接报出来不要边导边报那样导到一半失败很难恢复二是导入前清空环境避免重复导入导致库存翻倍三是导入完成后立刻跑一次对账校验stock.qty与SUM(stock_logs.change_qty)是否全部相等。对账SQL很简单但建议做成一个定时任务每天凌晨跑一次有差异就发通知SELECT s.product_id, s.warehouse_id, s.qty, COALESCE(SUM(l.change_qty), 0) AS log_sum FROM stock s LEFT JOIN stock_logs l ON l.product_id s.product_id AND l.warehouse_id s.warehouse_id GROUP BY s.product_id, s.warehouse_id HAVING s.qty COALESCE(SUM(l.change_qty), 0);这条查询在流水上百万行时会慢所以我在stock_logs上建了(product_id, created_at)的联合索引。如果还是慢可以改成增量对账——只核对最近7天有变动的商品历史数据按月核一次。这个折中方案在我们日均两千单的场景下完全够用。5.3 低库存预警与报表导出低库存预警是最容易做出价值的小功能。规则很简单qty safety_stock就算预警但要注意两个细节。第一安全库存应该支持按仓设置因为中心仓和前置仓的补货节奏完全不同。我在products表上放了一个全局默认值如果后续需要细粒度控制再加一张stock_policy表不需要现在就把表结构复杂化。第二预警要做去重和抑制。如果每天推一次某商品库存不足推一个月之后就没有人看了。我的做法是分级低于安全库存推送一次低于安全库存的30%再推送一次并且同一个商品7天内不重复推送。实现上就是查询流水表里最近一次该商品的预警记录简单有效。报表导出用openpyxl流式写入不要一次性把所有行读进内存。这个系统单据量不大但导出一年流水也有几十万行一次性加载会让内存飙到几百兆。做法是分页查询每1000行写一批最后save。实测导出十万行在普通笔记本上大概三秒完全可以接受。6. 常见问题与排查技巧实录6.1 高频问题速查表下面这些问题都是我在实际项目中真实遇到并解决过的按出现频率排序现象可能原因排查动作解决办法库存数出现超卖先查后改非原子更新看是否存在并发压测改为条件更新qty ?判断 rowcount报 database is locked事务过大或长事务占用写锁检查事务内是否有外部调用缩小事务、开WAL、设busy_timeout成本出现负数或异常大负库存参与加权平均查该商品历史流水对原库存做 max(qty,0) 保护金额有分位误差用浮点存金额全局搜索 FLOAT/REAL统一改整数分展示层除100外键约束不生效PRAGMA 未开或连接级失效执行PRAGMA foreign_keys每个新连接都要设置一次导出Excel内存爆一次性加载全表看导出时内存曲线分页流式写入中文导出乱码编码未指定检查写入时的 encoding统一用 utf-8-sig时间显示差8小时直接存本地时间看库里时间字符串存UTC展示层转换表格里成本出现负数那条我印象最深。当时是一家客户的期初数据里有二十多个SKU是负库存加权平均一算成本直接变成负数报表上出现了负毛利。定位花了半小时修复只花了十分钟——加一行max(qty, 0)就行。但教训是脏数据不会因为你写了保护代码就消失必须在导入阶段做强校验。6.2 三个不容易想到的避坑技巧第一个技巧关于备份。SQLite的备份不要用文件拷贝因为WAL模式下还有-wal和-shm两个附属文件直接拷主文件可能拿到不一致的数据。正确做法是用VACUUM INTO一条命令生成一个干净快照VACUUM INTO /backup/inventory_20240101.db;这个命令是原子操作执行期间读不受影响生成的备份文件可以直接拿去用。我把它写进每日定时任务保留最近30天成本几乎为零。第二个技巧关于索引陷阱。AI生成查询时特别喜欢在字符串字段上用LIKE %关键字%这种前导通配符用不上索引数据量一大就全表扫。我的处理是把搜索拆成两类SKU和单据号这种精确或前缀匹配的走索引商品名称这种模糊搜索如果数据量在几万行以内就接受全扫多了就上FTS5全文索引。这个判断要提前做不要等到卡了才补。第三个技巧关于测试。库存系统的测试重点不是正常流程能不能跑通而是并发下会不会错。我写了一个简易的并发测试脚本开10个线程同时对同一个SKU出库每个线程出1件初始库存50件最后校验库存必须是40流水总数必须是10条且SUM(change_qty)等于 -10。这个测试跑起来只要两秒但抓出过两次我自认为没问题的代码里的并发漏洞。7. 上线之后的几点真实体会系统跑了三个月之后我回头看这个项目有几件事和最初的预判不太一样值得写下来。第一件是AI辅助开发的实际收益比预期低但方向是对的。我原以为能省掉70%的编码时间实际大概省了40%。省下来的主要是样板代码和前端表格而真正耗时的部分——事务设计、并发验证、数据清洗、业务方沟通——AI帮不上忙。但它确实把我的注意力从怎么写转移到了怎么设计这个转变本身价值很大。第二件是业务方的关注点和开发者完全不同。我花了大量时间做加权平均成本、流水对账、并发安全业务方最满意的功能是按SKU搜索时能直接看到在哪个仓、还剩多少和一键导出当月出入库明细。这提醒我内部的工具型系统第一优先级永远是看得清、查得快、导得出账务精确是底线但不产生惊喜。第三件关于数据治理。系统上线后最大的问题不是代码bug而是SKU重复创建。同一个商品A仓管建了一个螺丝M6B仓管建了一个螺丝 m6中间带个空格系统认成两个商品库存就分裂了。后来我做了一个简单的相似度检测在新建商品时提示库里已存在相似名称情况马上好转。这类问题在Excel时代永远发现不了只有系统化之后才会暴露也算是一种副作用。如果再给一次机会有几件事我会做得更早一是把对账脚本从第一天就挂成定时任务而不是等出问题才写二是给所有金额字段统一加单元测试杜绝浮点混入三是把提示词模板沉淀成一个文档给团队共用让每个人都用同一种方式跟AI协作产出的一致性会高很多。最后分享一个我一直在用的习惯。每次让AI生成一段关键业务代码我都会问它一句这段代码在什么情况下会出错它给出的答案有一半是废话但另一半往往能点出我忽略的边界。这比让它直接写代码有用得多。工具的价值不在于替你思考而在于逼你把思考写清楚。