docs: AIcoding.md 提炼为通用方法论,去除具体项目信息

This commit is contained in:
freedakgmail
2026-06-14 11:37:56 +08:00
parent 87e0a931ba
commit eb4c8e8ba3
+83 -93
View File
@@ -1,143 +1,133 @@
# AI Coding 方法与技巧总结 — 外包项目风险评估系统
# AI Coding 通用方法与技巧
> 本文复盘本项目(`outsourcing-risk-assessment`)在 AI 辅助编码(AI Coding)下沉淀的方法论、协作技巧与工程实践,并附优化建议,供后续项目复用
> 一套可迁移到任意项目的 AI 辅助编码(AI Coding)方法论:如何与 AI 高效协作、如何约束 AI 产出质量、如何让系统保持可回归与可审计
---
## 一、项目概览
- **业务**:外包项目风险评估 AI 系统。销售录入项目 → AI 解析分类 → 确定性引擎评分/分级/红线/盈利测算 → 风控/管理层分级审批 → 归档与审计。
- **技术栈**
- 后端:TypeScript(严格模式)+ Hono + PostgreSQL`node-pg-migrate`,29 个迁移)+ 通义千问 qwen-plus
- 前端:React 18 + Vite + Zustand + Recharts + 自建 Design System
- 测试:Vitest + fast-check(属性测试)+ Testing Library + axe(可访问性)+ PlaywrightE2E
- 部署:`deploy.sh` 一键部署(PM2 + nginx + Let's Encrypt),生产 https://pm.hr8ai.top
- **规模**:113 个测试文件、40+ 属性测试文件、规格文档 2387 行(requirements/design/tasks)。
---
## 二、核心方法论
## 一、核心方法论
### 1. 规格驱动开发(Spec-Driven Development
项目以 `.kiro/specs/` 下的三份文档为"地面真值",先规格后代码
先规格、后代码。把"需求 → 设计 → 任务"作为地面真值,再让 AI 据此实现
| 文档 | 作用 |
|------|------|
| `requirements.md` | EARS 格式需求(WHEN/IF/WHERE/SHALL),可测试、可追溯 |
| `design.md` | 架构、数据模型、模块边界、**正确性属性Correctness Properties** |
| `tasks.md` | 可执行任务清单,逐项实现并验证 |
| 阶段 | 产出 | 要点 |
|------|------|------|
| 需求 | 可测试、可追溯的需求描述 | 用结构化句式(如 WHEN/IF/WHERE/SHALL),每条需求都能映射到验收标准 |
| 设计 | 架构、数据模型、模块边界、**正确性属性** | 明确不变量(invariants),它们将成为测试依据 |
| 任务 | 可执行任务清单 | 拆到可独立实现并验证的粒度 |
**要点**每个需求都映射到验收标准;每条正确性属性都对应一个属性测试(如 `computeRiskScore.property18.test.ts`)。代码改动先回到规格确认,避免"凭感觉写"
**收益**AI 有明确的"做什么"与"对错标准",避免凭感觉发挥;改动先回到规格确认,减少返工与漂移
### 2. 确定性引擎 + LLM 语言层 的分层(最关键的架构决策
### 2. 确定性核心 + AI 语言层 的分层(最关键的架构原则
这是本项目最重要、最值得复用的原则:
> **凡涉及金额、评分、判定、裁决等关乎正确性与合规的逻辑,一律用确定性纯函数实现,绝不交给大模型;大模型只承担语言理解(解析、抽取、归类、摘要、预填)。**
> **凡是涉及金额、评分、分级、红线、裁决的逻辑,一律是确定性纯函数,绝不交给 LLM;LLM 只做语言理解(分类、指标预填、岗位抽取、综合研判)。**
- **确定性核心**:无副作用、可复算、相同输入恒得相同输出,便于测试与审计。
- **AI 边界层**:负责把自然语言/非结构化输入转成结构化数据;调用失败或超时时**自动降级**到确定性兜底,不阻塞主流程。
- **收益**:把大模型的不确定性隔离在"翻译层",不污染决策;系统结果稳定、可解释、可回归——这是合规与高可靠系统的硬要求。
- **纯函数核心**`src/scoring``src/cost/profitability.ts``src/strategy` 等均为无副作用、可复算、可属性化测试的纯函数。相同输入永远得到相同输出。
- **LLM 边界**`src/llm``src/adapters` 负责把自然语言转成结构化输入;失败/超时自动降级到确定性兜底(`fallback.ts`),不阻塞主流程。
- **收益**:可审计、可回归、结果稳定、合规可解释——金融/风控类系统的硬要求。LLM 的不确定性被隔离在"翻译层",不污染决策。
### 3. 属性化测试(Property-Based Testing
### 3. 属性化测试(Property-Based Testing, PBT
对核心逻辑写"属性",而不仅是样例用例。属性描述对**任意**合法输入都应成立的不变量,例如:
用 fast-check 对核心引擎做属性测试,而非只写样例用例。例如:
- 输出值恒落在合法值域内;
- 派生结果与其定义函数恒等(如等级恒等于按分值分级的结果);
- 幂等性:重复执行结果不变;
- 往返一致:序列化后再反序列化与原值等价;
- 局部不变:修改 A 不应影响与之无关的 B。
- 风险总分恒在 [0,100],且分级恒等于 `classifyGrade(score)`
- 编辑重评时未改动的维度评分必须保持不变(preserve 属性);
- 持久化往返(save → load)必须等价(roundtrip 属性)。
**收益**:用随机输入覆盖边界,暴露样例测试漏掉的缺陷;属性即"活的规格",重构时是安全网。
**收益**:用随机输入覆盖人想不到的边界;属性即"活的规格",是重构时的安全网。
---
## 三、AI 协作中验证过的有效技巧
## 二、与 AI 协作的有效技巧
### 1. 小步快跑 + 每批验证
长任务拆成小批,每批改完立刻跑验证三件套
```bash
npx tsc --build # 后端类型检查(改后必须重启 dist 进程)
npx tsc -p web/tsconfig.json --noEmit # 前端类型检查
npx vitest run # 全量测试(456 用例)
```
**绝不在未验证的情况下连续堆改动**。类型检查 + 测试通过才进入下一批。
长任务拆成小批,每批改完立刻跑验证三件套(类型检查 / 静态检查 / 测试),全绿才进入下一批。**绝不在未验证的情况下连续堆叠改动**——否则错误会层叠,难以定位。
### 2. 严格的 TypeScript 配置
开启 `exactOptionalPropertyTypes``noUncheckedIndexedAccess` 等最严选项。编译器把大量运行期 bug 前移到编码期——AI 生成的代码尤其受益于强类型护栏。
### 2. 用强类型/静态检查做护栏
开启语言可用的最严格静态检查选项。编译器/类型系统把大量运行期 bug 前移到编码期AI 生成的代码尤其受益于强约束护栏。
### 3. 每个改动独立 commit
每完成一个可工作的改动就 commit,信息写清"根因 + 改法 + 验证"。便于回滚便于审计 AI 的每一步。
### 3. 每个可工作的改动独立提交
一个改动完成并验证后立即提交,提交信息写清"根因 + 改法 + 验证方式"。便于回滚,也便于审计 AI 的每一步决策
### 4. 根因优先,打补丁
遇到问题(如"盈利收入为 0"、"校准重复提示"先定位**根因**再动手:
- 收入为 0 → 根因是报价口径录入缺失,不是计算 bug → 加录入校验而非改公式
- 校准重复提示 → 根因是偏差来自历史数据 + 公式累加 → 改为基于未校准基准的幂等计算,并暴露"已校准"状态
### 4. 根因优先,拒绝表面打补丁
遇到问题先定位**根因**再动手:
- 区分"数据/输入缺失"与"逻辑 bug"——前者加校验与提示,后者改逻辑
- 区分"展示问题"与"计算问题"——不要用改公式来掩盖录入或展示缺陷
- 同一方法连续失败两次就停下来分析根因,换思路,而不是继续微调。
### 5. 生产环境的真实验证
改完不止单测,还在生产上端到端验证(登录拿 token → 调接口 → 查数据库确认副作用)。例如验证"登出留痕":
```bash
TOKEN=$(curl ... /api/auth/login ...)
curl -X POST .../api/auth/logout -H "Authorization: Bearer $TOKEN"
# 再查 system_logs 确认出现"登出"记录
```
### 5. 端到端真实验证
单元测试之外,在接近真实的环境做端到端验证:触发操作 → 检查副作用(数据库记录、文件产出、外部状态),确认改动真的生效,而不仅是"代码看起来对"。
### 6. 复用既有组件与模式
新功能优先沿用既有约定(如统一 `Table` 组件、`Icon` 图标集、复合键分隔符 `\u0000`、用户 ID 关联),而非另起炉灶。一处修复(如给 `Table` 加横向滚动容器)让全站受益
### 6. 复用既有约定,一处修复全局受益
新功能优先沿用项目既有组件、约定与模式,而非另起炉灶。把修复做在共享组件/工具层,让所有调用方一起受益,而不是到处贴补丁
### 7. 规避工具/环境陷阱(踩坑沉淀)
- 多字节中文 `curl` 输出常被 shell 截断 → 用 `printf` / 写临时文件 + python 读取。
- bash 命令不用全角括号;复杂逻辑放 `node -e` / `python3 -c`
- 后端改完必须 `tsc --build` 再重启 `dist` 进程,否则跑的是旧代码。
- JSONB 不能存裸 `\u0000` → 入库前编码(`\u0000``\uE000`)、读出时解码。
### 7. 明确给 AI 的协作偏好
开工前把稳定偏好讲清楚,例如:
- 回复与文档使用的语言;
- "简单改动直接改、复杂设计先给方案确认";
- 哪些逻辑禁止交给大模型;
- 命名/格式/金额展示等约定;
- 测试数据必须清理、长任务分批推进等流程要求。
AI 在明确边界内自主推进效率最高。
### 8. 规避工具与环境陷阱
- 命令行处理多字节文本(如中文)易被截断/乱码时,改用写临时文件 + 脚本读取等稳健方式。
- 复杂逻辑放进脚本(`node -e` / `python3 -c` 等),避免在 shell 里拼脆弱的一行命令。
- 编译型/需构建的后端,改完务必重新构建再重启进程,否则跑的是旧产物。
- 注意存储层对特殊字符的限制(如某些数据库不接受特定控制字符),入库前编码、读出时解码。
---
## 、工程实践沉淀
## 、工程实践沉淀
- **数据库迁移化**:所有 schema 变更走 `migrations/*.cjs`,可重放、可回滚,生产与本地一致。
- **配置惰性读取**`AUTH_SECRET` 等密钥惰性读取(避免模块导入时固化导致 RBAC 失效;密钥放 gitignore 的 `deploy.env`
- **全局审计中间件**一个 `app.use('/api/*')` 中间件统一记录所有写操作 + 登录/登出 + 关键只读(导出/查看),自动解析操作人/角色/目标项目/决策/IP/耗时,跳过高频轮询端点避免噪音。
- **数据隔离与 ID 关联**:全部人员用稳定用户 ID 关联记录,界面实时解析成姓名;销售只见本人发起的评估(行级隔离
- **可访问性内建**用 axe 在测试中校验对比度、焦点、ARIA 角色,UI 一致性由 Design System 保证
- **数据库变更迁移化**:所有 schema 变更走可重放、可回滚的迁移脚本,保证各环境一致。
- **配置与密钥惰性读取**运行期再读取密钥/配置,避免模块加载时固化导致开关失效;密钥不入库,放进被忽略的本地配置
- **统一审计中间件**用一处中间件集中记录写操作与关键读操作(操作人角色、对象、动作、结果、耗时、来源),跳过高频轮询端点避免日志噪音。
- **稳定 ID 关联 + 数据隔离**:记录之间用稳定 ID 关联界面实时解析为可读名称;按角色/归属做行级数据隔离。
- **质量内建**把可访问性、对比度、一致性等检查纳入自动化测试,由统一的设计体系保证 UI 一致
- **一键部署**:把构建、上传、迁移、重启、健康检查封装成一条命令,降低发布风险与心智负担。
---
## 、优化建议(我的视角
## 、优化建议(通用清单
### 工程与质量
1. **补 E2E 回归**:已装 Playwright,但回归仍靠手测。建议补一条主链路 E2E(登录→新建→申报→风控→管理层→归档→审计),纳入 CI,防止"改 A 坏 B"。
2. **CI 门禁**`.github/workflows/ci.yml` 应强制 `typecheck + lint + vitest` 全绿才可合并/部署;`deploy.sh` 前置一次测试闸门。
3. **前端测试拆分**:详情页改动频繁,按功能区拆 snapshot/交互测试,降低脆性
4. **大数据量性能**:列表服务端分页,建议补关键查询索引(如 `system_logs(ts)``assessments(assessor_id,status)`);前端列表上虚拟滚动。
1. **端到端回归纳入 CI**:补一条主链路 E2E,作为"改 A 坏 B"的防线
2. **CI 门禁**类型检查 + 静态检查 + 测试全绿才可合并/部署;发布脚本前置测试闸门。
3. **测试分层与解耦**:高频变动模块按功能区拆分测试,降低脆性;区分单元/集成/E2E 各司其职
4. **性能前置**:列表服务端分页 + 关键查询索引;大数据量时前端虚拟滚动。
### 架构与可维护性
5. **拆分 `src/server/index.ts`**:单文件已超 2500 行,建议按资源域拆成路由模块(assessments / users / calibration / logs …),降低认知负担与合并冲突。
6. **审计中间件的请求体重复读取**:登录/审批分支在 `next()` 后再次 `c.req.json()`,依赖框架缓存。建议显式缓存一次请求体,避免框架升级后行为变化
7. **校准语义文档化**把"目标净利率基准 / 历史偏差 / 幂等校准"的语义写进 design.md,避免未来再次误解为可累加
5. **及时拆分巨型文件**:单文件过大时按职责/资源域拆分,降低认知负担与合并冲突。
6. **减少隐式依赖**:避免依赖框架的隐式缓存/副作用,关键数据显式获取一次并复用
7. **关键语义文档化**易被误解的业务语义(如可累加 vs 幂等、历史值 vs 当前值)写入设计文档,防止重复踩坑
### LLM
8. **LLM 输出校验与可观测**:对分类/预填的 LLM 结果做 schema 校验 + 置信度阈值(部分已做),并把 LLM 调用耗时/降级率纳入系统日志,便于评估模型稳定性与成本
9. **提示词与模型版本治理** prompt 模板与模型名集中管理、版本化,便于灰度与回滚。
10. **经验库闭环**`experience_library` 已具雏形,可把"预测 vs 实际"偏差与驳回原因反哺到 LLM 预填的 few-shot,形成数据飞轮
### AI
8. **AI 输出做 schema 校验 + 置信度阈值**:结构化校验大模型产出,低置信走兜底;把调用耗时/降级率纳入监控
9. **提示词与模型版本治理**集中管理、版本化 prompt 与模型名,便于灰度与回滚。
10. **数据飞轮**:把"预测 vs 实际"偏差、人工修正反哺给 AI 的少样本示例,持续提升质量
### 安全与合规
11. **JWT 增强**:当前为自实现 HMAC,建议迁移到 `jose`,支持密钥轮换与更短有效期 + 刷新令牌。
12. **密钥与备份**:确认 `.env`/`deploy.env` 不入库(已 gitignore;定期演练数据库备份恢复(已有 `baidu-backup.sh`,建议加恢复演练)
13. **登出令牌失效**:当前登出仅前端丢弃 token,服务端无状态。若需"立即失效"引入短期 token + 服务端黑名单/版本号。
11. **认证用成熟方案**:优先用成熟库而非自实现,支持密钥轮换、较短有效期 + 刷新令牌。
12. **密钥治理与备份演练**:确认密钥不入库;定期演练备份恢复,而不仅是备份
13. **会话失效策略**:无状态令牌如需"立即失效",引入短期令牌 + 服务端黑名单/版本号。
---
## 、可复用的"黄金法则"清单
## 、可复用的"黄金法则"清单
1. 决策逻辑确定性纯函数化,LLM 只做语言层,二者严格隔离。
2. 先规格(需求/设计/正确性属性)后代码,规格是地面真值。
1. 决策逻辑确定性纯函数化,AI 只做语言层,二者严格隔离。
2. 先规格(需求 / 设计 / 正确性属性)后代码,规格是地面真值。
3. 核心逻辑写属性测试,而不仅是样例测试。
4. 小步改动 + 每批 `typecheck + test` 验证 + 独立 commit
4. 小步改动 + 每批"类型检查 + 测试"验证 + 独立提交
5. 根因优先,拒绝表面打补丁。
6. 改完在生产做端到端真实验证(含数据库副作用)。
7. 严格 TS + 迁移化 schema + 全局审计,让系统可回归、可审计、可解释。
6. 改完在接近真实的环境做端到端验证(含副作用)。
7. 强类型 + 迁移化 schema + 统一审计,让系统可回归、可审计、可解释。
8. 开工前对齐协作偏好与边界,让 AI 在明确约束内自主推进。
---
*本文由项目实践复盘整理,可随项目演进持续更新*
*本文为通用方法论,可随团队实践持续补充*