Files
RiskAgent/AIcoding.md
T

144 lines
9.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AI Coding 方法与技巧总结 — 外包项目风险评估系统
> 本文复盘本项目(`outsourcing-risk-assessment`)在 AI 辅助编码(AI Coding)下沉淀的方法论、协作技巧与工程实践,并附优化建议,供后续项目复用。
---
## 一、项目概览
- **业务**:外包项目风险评估 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/` 下的三份文档为"地面真值",先规格后代码:
| 文档 | 作用 |
|------|------|
| `requirements.md` | EARS 格式需求(WHEN/IF/WHERE/SHALL),可测试、可追溯 |
| `design.md` | 架构、数据模型、模块边界、**正确性属性(Correctness Properties** |
| `tasks.md` | 可执行任务清单,逐项实现并验证 |
**要点**:每个需求都映射到验收标准;每条正确性属性都对应一个属性测试(如 `computeRiskScore.property18.test.ts`)。代码改动先回到规格确认,避免"凭感觉写"。
### 2. 确定性引擎 + LLM 语言层 的分层(最关键的架构决策)
这是本项目最重要、最值得复用的原则:
> **凡是涉及金额、评分、分级、红线、裁决的逻辑,一律是确定性纯函数,绝不交给 LLM;LLM 只做语言理解(分类、指标预填、岗位抽取、综合研判)。**
- **纯函数核心**`src/scoring``src/cost/profitability.ts``src/strategy` 等均为无副作用、可复算、可属性化测试的纯函数。相同输入永远得到相同输出。
- **LLM 边界**`src/llm``src/adapters` 负责把自然语言转成结构化输入;失败/超时自动降级到确定性兜底(`fallback.ts`),不阻塞主流程。
- **收益**:可审计、可回归、结果稳定、合规可解释——金融/风控类系统的硬要求。LLM 的不确定性被隔离在"翻译层",不污染决策。
### 3. 属性化测试(Property-Based Testing, PBT
用 fast-check 对核心引擎做属性测试,而非只写样例用例。例如:
- 风险总分恒在 [0,100],且分级恒等于 `classifyGrade(score)`
- 编辑重评时未改动的维度评分必须保持不变(preserve 属性);
- 持久化往返(save → load)必须等价(roundtrip 属性)。
**收益**:用随机输入覆盖边界,暴露样例测试漏掉的缺陷;属性即"活的规格",重构时是安全网。
---
## 三、AI 协作中验证过的有效技巧
### 1. 小步快跑 + 每批验证
长任务拆成小批,每批改完立刻跑验证三件套:
```bash
npx tsc --build # 后端类型检查(改后必须重启 dist 进程)
npx tsc -p web/tsconfig.json --noEmit # 前端类型检查
npx vitest run # 全量测试(456 用例)
```
**绝不在未验证的情况下连续堆改动**。类型检查 + 测试通过才进入下一批。
### 2. 严格的 TypeScript 配置
开启 `exactOptionalPropertyTypes``noUncheckedIndexedAccess` 等最严选项。编译器把大量运行期 bug 前移到编码期——AI 生成的代码尤其受益于强类型护栏。
### 3. 每个改动独立 commit
每完成一个可工作的改动就 commit,信息写清"根因 + 改法 + 验证"。便于回滚、便于审计 AI 的每一步。
### 4. 根因优先,不打补丁
遇到问题(如"盈利收入为 0"、"校准重复提示")先定位**根因**再动手:
- 收入为 0 → 根因是报价口径录入缺失,不是计算 bug → 加录入校验而非改公式。
- 校准重复提示 → 根因是偏差来自历史数据 + 公式累加 → 改为基于未校准基准的幂等计算,并暴露"已校准"状态。
### 5. 生产环境的真实验证
改完不止单测,还在生产上端到端验证(登录拿 token → 调接口 → 查数据库确认副作用)。例如验证"登出留痕":
```bash
TOKEN=$(curl ... /api/auth/login ...)
curl -X POST .../api/auth/logout -H "Authorization: Bearer $TOKEN"
# 再查 system_logs 确认出现"登出"记录
```
### 6. 复用既有组件与模式
新功能优先沿用既有约定(如统一 `Table` 组件、`Icon` 图标集、复合键分隔符 `\u0000`、用户 ID 关联),而非另起炉灶。一处修复(如给 `Table` 加横向滚动容器)让全站受益。
### 7. 规避工具/环境陷阱(踩坑沉淀)
- 多字节中文 `curl` 输出常被 shell 截断 → 用 `printf` / 写临时文件 + python 读取。
- bash 命令不用全角括号;复杂逻辑放 `node -e` / `python3 -c`
- 后端改完必须 `tsc --build` 再重启 `dist` 进程,否则跑的是旧代码。
- JSONB 不能存裸 `\u0000` → 入库前编码(`\u0000``\uE000`)、读出时解码。
---
## 四、工程实践沉淀
- **数据库迁移化**:所有 schema 变更走 `migrations/*.cjs`,可重放、可回滚,生产与本地一致。
- **配置惰性读取**`AUTH_SECRET` 等密钥惰性读取(避免模块导入时固化导致 RBAC 失效);密钥放 gitignore 的 `deploy.env`
- **全局审计中间件**:一个 `app.use('/api/*')` 中间件统一记录所有写操作 + 登录/登出 + 关键只读(导出/查看),自动解析操作人/角色/目标项目/决策/IP/耗时,跳过高频轮询端点避免噪音。
- **数据隔离与 ID 关联**:全部人员用稳定用户 ID 关联记录,界面实时解析成姓名;销售只见本人发起的评估(行级隔离)。
- **可访问性内建**:用 axe 在测试中校验对比度、焦点、ARIA 角色,UI 一致性由 Design System 保证。
---
## 五、优化建议(我的视角)
### 工程与质量
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)`);前端列表上虚拟滚动。
### 架构与可维护性
5. **拆分 `src/server/index.ts`**:单文件已超 2500 行,建议按资源域拆成路由模块(assessments / users / calibration / logs …),降低认知负担与合并冲突。
6. **审计中间件的请求体重复读取**:登录/审批分支在 `next()` 后再次 `c.req.json()`,依赖框架缓存。建议显式缓存一次请求体,避免框架升级后行为变化。
7. **校准语义文档化**:把"目标净利率基准 / 历史偏差 / 幂等校准"的语义写进 design.md,避免未来再次误解为可累加。
### LLM 层
8. **LLM 输出校验与可观测**:对分类/预填的 LLM 结果做 schema 校验 + 置信度阈值(部分已做),并把 LLM 调用耗时/降级率纳入系统日志,便于评估模型稳定性与成本。
9. **提示词与模型版本治理**:把 prompt 模板与模型名集中管理、版本化,便于灰度与回滚。
10. **经验库闭环**`experience_library` 已具雏形,可把"预测 vs 实际"偏差与驳回原因反哺到 LLM 预填的 few-shot,形成数据飞轮。
### 安全与合规
11. **JWT 增强**:当前为自实现 HMAC,建议迁移到 `jose`,支持密钥轮换与更短有效期 + 刷新令牌。
12. **密钥与备份**:确认 `.env`/`deploy.env` 不入库(已 gitignore);定期演练数据库备份恢复(已有 `baidu-backup.sh`,建议加恢复演练)。
13. **登出令牌失效**:当前登出仅前端丢弃 token,服务端无状态。若需"立即失效",可引入短期 token + 服务端黑名单/版本号。
---
## 六、可复用的"黄金法则"清单
1. 决策逻辑确定性纯函数化,LLM 只做语言层,二者严格隔离。
2. 先规格(需求/设计/正确性属性)后代码,规格是地面真值。
3. 核心逻辑写属性测试,而不仅是样例测试。
4. 小步改动 + 每批 `typecheck + test` 验证 + 独立 commit。
5. 根因优先,拒绝表面打补丁。
6. 改完在生产做端到端真实验证(含数据库副作用)。
7. 严格 TS + 迁移化 schema + 全局审计,让系统可回归、可审计、可解释。
---
*本文由项目实践复盘整理,可随项目演进持续更新。*