一个工程合同 AI 审查助手,是怎么从 0 搭到能演示、能导出的?
做 AI 项目,最容易出现的一种情况是:
想法很完整,规划很宏大,但系统始终停留在“差一点就能跑”的状态。
一开始想做审批流,想做多租户,想接大模型,想做知识库,想把页面做漂亮,想把权限体系一次性设计完整。结果到了最后,真正能给用户演示的,往往只有几张页面,或者几个还没真正串起来的接口。
这次做“工程合同 AI 审查助手”时,我们刻意反着来。
我们没有先追求最复杂的能力,而是先盯着一条最朴素、也最关键的链路:
登录 -> 上传 PDF 合同 -> 提取文本 -> 提取关键信息 -> 识别风险 -> 生成摘要 -> 导出报告
这篇文章,不讲空泛概念,只讲一件事:
我们是怎样把一个“工程合同 AI 审查助手”从 0 搭成一个真正能启动、能登录、能上传、能分析、能导出的 MVP。
一、为什么要做这个项目?
工程合同审查,本身就是一个高频、繁琐、又非常依赖经验的工作。
一份合同拿到手之后,商务经理、合约人员、法务、项目经理往往都要重点关注这些内容:
-
合同基本信息是否完整 -
合同编号、签订日期、金额、工期是否清晰 -
付款条款是否合理 -
结算条款是否存在风险 -
违约责任是否对等 -
质保金条款是否过重 -
发票和税务要求是否合理 -
争议解决条款是否存在明显倾向 -
变更签证、解除条款是否缺失
问题在于,这类工作并不是每次都必须完全从零开始人工通读。
很多时候,业务真正需要的是一个“第一轮预审助手”:
-
先把 PDF 文本提出来 -
先把基础信息整理出来 -
先把明显风险点标出来 -
先生成一版审查摘要 -
再由人工做进一步判断和复核
所以,这个项目从一开始就没有把自己定义成“替代法务”的系统,而是明确定位为:
一个面向工程行业的合同 AI 预审助手。
二、为什么我们没有一开始就做“大而全”?
做业务 AI 项目时,一个很常见的问题就是:
什么都想做,结果什么都还没真正跑通。
比如一开始就把这些都放进范围:
-
审批流 -
多租户 -
权限矩阵 -
电子签 -
OCR -
大模型问答 -
法规知识库 -
模板中心 -
完整财务结算联动
这些方向当然都很有价值,但如果一开始全部纳入,项目很容易进入一种状态:
需求看起来很完整,系统却始终没有形成一个真正的闭环。
所以这次我们从第一天就给自己定了一个非常明确的原则:
先做 MVP,只做最小可用版。
具体来说,就是坚持下面这些规则:
-
先把链路跑通,不做复杂审批流 -
所有实现优先保证“能跑通、可维护、易理解” -
不过度设计 -
后端逻辑必须分层 -
前端页面必须拆组件 -
每个阶段都必须有验证方法 -
如果验证失败,先修复,再进入下一阶段
这套原则看起来很普通,但它决定了整个项目不会跑偏。
因为它逼着我们不断回答一个问题:
这一阶段做完之后,用户到底能不能真实地往前走一步?
三、我们是怎么拆里程碑的?
为了避免一边做一边散,我们没有“想到哪做哪”,而是按里程碑推进。
整个项目被拆成了 6 个阶段:
Milestone 1:项目骨架
Milestone 2:数据库与认证
Milestone 3:合同上传与文本提取
Milestone 4:合同信息提取与风险识别
Milestone 5:前端联调
Milestone 6:报告导出与交付收尾
这个拆法的核心意义在于:
每个阶段都只解决当前最关键的问题。
而且每完成一个阶段,都必须回答清楚四件事:
-
启动命令是什么 -
测试命令是什么 -
怎么验证 -
失败时怎么排查
这样做的结果就是,项目不会在某个阶段堆一大堆“看起来快做完”的功能,而是始终保持每一步都有真实结果。
四、Milestone 1:先把项目“站起来”
第一阶段我们没有急着做业务功能,而是先搭项目骨架。
这一阶段完成的事情包括:
-
创建前后端目录结构 -
创建 Docker 基础文件 -
创建 README 初稿 -
后端增加 /health 健康检查接口 -
前端增加一个最基础的首页占位页
很多人会觉得这一步“没业务价值”。
但实际上,任何项目如果骨架没搭好,后面都会越来越乱。
因为没有骨架,就会出现这些问题:
-
前后端目录边界混乱 -
启动方式不统一 -
新人接手困难 -
验证路径不明确 -
甚至连系统“是不是活着”都不好判断
所以第一阶段真正的目标不是“做功能”,而是:
让整个项目先站起来。
当后端能启动、GET /health 返回 200、前端能打开时,这个项目才算真正有了继续开发的基础。
五、Milestone 2:让它成为一个“真系统”
第二阶段,我们开始把这个项目从“有页面、有接口的骨架”推进成一个“有真实用户体系的系统”。
这一阶段完成了:
-
PostgreSQL 连接配置 -
SQLAlchemy 模型基础 -
Alembic 数据库迁移 - users 表
-
JWT 登录 -
默认管理员初始化
这一步为什么必须尽早做?
因为后面所有能力都依赖数据库:
-
合同记录 -
文件元数据 -
文本提取结果 -
风险项 -
审查报告 -
用户和鉴权
同时,登录又是整个系统的基本入口。
我们不想做一个“前端看起来有登录,实际上后端并没有真正用户体系”的演示壳子,所以这一阶段我们坚持把登录做成真的:
-
数据库里有真实用户 -
后端真做账号密码校验 -
后端真签发 JWT - /auth/me
可以获取当前用户信息
同时,为了让整个系统更容易启动和演示,我们固定了默认管理员账号:
-
用户名:admin -
密码:Admin123456
这一步完成后,系统第一次真正具备了“业务系统”的基础形态。
六、Milestone 3:让合同文件真正进入系统
第三阶段开始进入合同业务本身。
这一阶段我们解决的是:
一份 PDF 合同,怎么才能真正进入系统,并成为后续分析可用的数据。
这里看起来只是“上传”,但实际上做了四件关键事。
1. 只允许上传 PDF
系统明确限制:非 PDF 一律拒绝。
这件事看似简单,但其实非常重要。
因为如果输入不受控,后面所有解析、提取、识别都会变得脆弱。
所以我们要求:
-
非 PDF 必须拒绝 -
上传失败必须返回明确报错
2. 文件真实落盘
上传成功之后,文件会保存到 uploads 目录,而不是只是经过一次接口处理。
这样,合同就真正进入了系统的文件存储。
3. 文件元数据入库
我们把文件名、路径、大小、类型等信息写进数据库,确保后面:
-
可以追踪 -
可以查询 -
可以导出 -
可以审计
4. 提取 PDF 原始文本
这是这一阶段最关键的地方。
因为后面无论是字段提取、风险识别还是摘要生成,本质上都依赖一件事:
先拿到可分析的合同文本。
所以我们把 PDF 中提取出的原始文本保存到 contract_parse_results 表中。
到这里,合同就从“一个上传成功的文件”正式变成了“一个可分析对象”。
七、Milestone 4:让系统具备“合同审查能力”
如果说前面 3 个阶段主要解决的是:
-
项目能不能启动 -
用户能不能登录 -
合同能不能进入系统
那么第四阶段解决的就是:
系统到底能分析出什么。
这一阶段,我们重点完成了三块能力:
1. 合同基础信息提取
至少提取这些字段:
-
合同名称 -
合同编号 -
项目名称 -
甲方 -
乙方 -
合同类型 -
签订日期 -
合同金额 -
工期 -
付款条款 -
质保期 -
争议解决 -
违约责任
2. 风险识别
至少覆盖这 10 类风险:
-
付款条款风险 -
结算条款风险 -
工期责任风险 -
违约责任不对等 -
质保金风险 -
发票税务风险 -
争议解决风险 -
工作范围不清 -
变更签证条款缺失 -
合同解除条款风险
3. 审查摘要
系统根据提取结果和风险结果,输出一版总体审查结论和风险等级。
这里我们特别强调了一条架构原则:
service 层必须独立,不要把规则写死在路由里。
因为如果把规则直接塞进路由,后面一定会遇到这些问题:
-
路由越来越胖 -
测试越来越难写 -
逻辑难复用 -
将来接真实大模型时不好替换
所以我们把提取、风险识别、摘要生成都拆成独立 service。
另外,考虑到当前版本还没有接入真实 LLM,我们采用的是:
规则版 + mock fallback
也就是说:
-
先用规则跑通字段提取和风险识别 -
如果部分字段不完整,用 fallback 做兜底 -
保证整条分析流程始终能跑完
这一步很务实,也很关键。
因为对于 MVP 来说,最重要的不是“一开始就最聪明”,而是:
先保证整个流程可跑通。
八、Milestone 5:把前后端真正打通
后端能力基本完整之后,第五阶段开始做真正的前后端联调。
这一阶段完成了:
-
登录页 -
合同列表页 -
合同上传页 -
合同详情页 -
风险展示区 -
审查摘要展示 -
前后端打通
这一步最重要的一条原则是:
如果接口字段不一致,优先统一接口,不要前端硬拼。
这一点非常关键。
因为很多项目联调时,为了让页面先显示出来,前端会开始:
-
自己猜字段 -
到处兼容结构 -
每个页面都写一套映射逻辑
短期看起来快,长期一定会非常痛苦。
所以我们的做法是:
-
先统一后端返回结构 -
再让前端按统一模型接数据 -
页面尽量保持清晰简单
在视觉上,这一阶段也坚持“实用优先”,没有刻意追求复杂风格,而是使用:
-
Vue 3 -
Vite -
Element Plus -
Pinia -
Axios
这套组合非常适合快速搭建后台型业务系统。
到这一阶段完成时,用户第一次可以真正走完一条完整页面链路:
登录 -> 列表 -> 上传 -> 详情 -> 分析 -> 查看结果
这也是一个 MVP 是否成立的关键标志。
九、Milestone 6:把“能开发”变成“能交付”
很多项目做到前后端打通就结束了,但真正交付时最难的往往是最后一步。
因为真正的使用者关心的是:
-
系统怎么启动 -
登录账号是什么 -
上传后怎么演示 -
结果怎么导出 -
我不懂代码,能不能按文档跑起来
所以第六阶段我们重点完成了三件事。
1. 审查报告导出
分析结果不能只停留在页面里,还要能输出成文件。
所以我们补了:
-
导出接口 -
导出按钮 -
报告记录表 -
导出文件保存
当前版本先导出 Markdown 报告。
为什么是 Markdown?
因为在 MVP 阶段,它有几个非常明显的好处:
-
简单 -
稳定 -
易验证 -
易扩展
也就是说,我们先解决“导得出来”,再去追求“导得更漂亮”。
2. Docker Compose 完整化
我们不满足于“理论上能启动”,而是希望用户可以尽量做到:
一条命令拉起前端、后端和数据库。
所以我们完整补齐了 Docker Compose,并让后端容器启动时自动执行:
-
数据库迁移 -
管理员初始化
这样项目的最短启动方式就变成了:
docker compose up --build
3. README 和部署文档收尾
这一阶段,我们重写了 README 和部署文档。
并且要求非常明确:
README 必须让不懂代码的人也能看懂。
这意味着文档里不能只是堆技术术语,而是要真正告诉使用者:
-
第一步做什么 -
第二步做什么 -
登录账号是什么 -
怎么验证系统正常 -
怎么完成一次完整演示 -
失败时怎么排查
到这里,项目才真正具备了“交付属性”。
十、交付前,我们还专门做了一轮检查
在所有里程碑都完成之后,我们没有直接宣布结束,而是又做了一轮“交付前检查”。
这一步非常必要。
因为很多问题在开发阶段不明显,但在交付阶段会变成明显风险。
最后我们补掉了两个非常关键的问题:
1. 合同相关接口统一加 JWT 鉴权
避免出现“前端看起来需要登录,后端合同接口却实际不校验身份”的问题。
2. 重写 API 文档
把 docs/api-spec.md 同步成当前真实接口、真实测试账号和真实请求方式,避免文档和代码脱节。
这轮检查让项目从“功能完成”真正走向“可以放心交付”。
十一、这版系统现在是什么状态?
如果用一句话概括当前这个项目,我会说:
它已经不是一个概念验证,而是一个完整流程已跑通的工程合同 AI 审查 MVP。
它已经具备:
-
真正登录 -
真正上传 -
真正存文件 -
真正提取文本 -
真正做字段提取 -
真正做风险识别 -
真正生成摘要 -
真正导出报告 -
真正支持 Docker 一键启动 -
真正有可用的 README 和部署文档
当然,它也很清楚自己的边界:
-
当前还是规则版,不是真实 LLM 版 -
扫描件 PDF 支持还不够强 -
导出目前是 Markdown,不是正式模板报告 -
更适合演示、试运行和 MVP 验收
但这恰恰说明它是一个健康的 MVP:
能跑通,也知道下一步该往哪走。
十二、如果继续往下做,最值得优先增强什么?
如果这个项目继续迭代,我认为最值得优先投入的是这几件事:
1. 接入真实大模型
把当前规则版字段提取和风险识别逐步升级为“LLM 优先 + 规则兜底”。
2. 增强 OCR
支持扫描件 PDF,让系统适用面更广。
3. 升级导出能力
从 Markdown 升级到正式 Word / PDF 模板版报告。
4. 增强合同台账能力
补筛选、搜索、状态管理、分页等后台常见能力。
换句话说:
当前版本已经把主体搭起来了,下一阶段要做的是智能增强和交付增强。
十三、这次项目最值得复用的方法论
如果让我把整个过程浓缩成一句话,我会说:
做 AI 项目,最重要的不是先把能力想得多复杂,而是先把真实流程跑通。
这次“工程合同 AI 审查助手”的搭建过程,本质上验证了一件很重要的事:
-
不需要一开始就最复杂 -
不需要一开始就最智能 -
不需要一开始就最漂亮
你只需要先做到一件事:
让用户真的能从头到尾走完一遍完整流程。
只有这样,后面的大模型、OCR、模板导出、知识库、审批流,才真正有落脚点。
结尾
如果你也在做 AI 业务系统,我真心建议你把目标先从“做一个完美平台”改成:
先做一个别人能启动、能登录、能上传、能看到结果、能导出的系统。
这看起来不宏大,但非常有力量。
因为只有当一个系统真的能跑通,后面的所有增强才有意义。
而这次“工程合同 AI 审查助手”的搭建过程,最想证明的也正是这一点:
先做能跑通的最小闭环,再做更聪明的增强版。
夜雨聆风