从 0 到 1 搭建智合 AI 商业风控平台:技术实现、踩坑记录与项目收获

📅 2026/7/7 7:48:55
从 0 到 1 搭建智合 AI 商业风控平台:技术实现、踩坑记录与项目收获
前言这次项目我做的是一个面向合同与商业风险识别的 AI 风控平台项目名称是“智合 AI 商业风控平台”。它不是一个单纯的上传文件小工具而是围绕“合同上传、AI 分析、报告生成、风险检索、实时通知、支付计费、报告分享”构建的一整套 Web 应用。项目做完以后我最大的感受是真正难的不是某一个接口怎么写而是如何把多个系统能力稳定地串起来。AI、文件存储、消息队列、WebSocket、搜索、支付、短信、前端状态管理每一个单独看都不复杂但它们组合在一起就会暴露很多工程化问题。这篇博客主要从三个方面复盘这个项目项目实现了什么功能项目中用到了哪些关键技术点开发过程中遇到了哪些报错和问题以及我从中学到了什么一、项目简介智合 AI 商业风控平台的核心目标是帮助用户上传 PDF 或 Word 格式的合同文件然后由 AI 自动提取合同文本、识别风险条款、生成风险报告并支持后续追问、检索、分享和支付。项目的核心业务链路可以概括为用户上传合同 - 后端保存文件 - 创建分析任务 - RabbitMQ 投递任务 - AI Worker 提取文本并调用大模型 - 写入分析报告 - Redis Pub/Sub 推送通知 - WebSocket 通知前端 - ES Worker 建立搜索索引从用户角度看它主要包含这些功能手机号、验证码、OAuth 登录合同文件上传与批量分析AI 风险识别与报告生成报告详情查看、AI 追问、合同改写合同对比、模板市场、行业知识库风险洞察图表与历史分析统计Elasticsearch 全文检索WebSocket 实时通知支付宝充值与余额扣费报告分享与 PDF / TXT 导出二、整体技术架构项目采用前后端分离架构。后端使用FastAPI提供 REST API 和 WebSocket 接口SQLAlchemy操作 MySQL 数据库MySQL存储用户、文件、订单、报告等核心数据Redis缓存 Token、验证码以及作为 WebSocket 通知通道RabbitMQ处理 AI 分析、邮件通知、ES 同步等异步任务Elasticsearch支持报告全文检索MinIO对象存储失败时回退到本地 uploadsPyPDF2、python-docx提取 PDF / DOCX 文本httpx调用 Dify / OpenAI 兼容接口前端使用Vue 3 TypeScript ViteElement Plus 作为 UI 组件库Pinia 管理登录态和用户状态Axios 封装统一请求ECharts 实现风险图表和分析动画html2canvas jsPDF 实现报告导出 PDF我把后端拆成了几个层次app/ routers/ API 路由层 services/ 业务逻辑层 utils/ 工具能力层 models/ ORM 数据模型 workers/ 后台任务消费者前端也按职责拆分frontend/src/ views/ 页面 components/ 公共组件 api/ 接口封装 stores/ Pinia 状态管理 composables/ 可复用逻辑这个分层对后期维护很重要。项目功能越来越多时如果没有清晰边界登录、文件、分析、支付、搜索这些逻辑很容易混在一起改一个功能就可能影响另一个模块。三、核心技术点1. FastAPI 分层接口设计后端使用 FastAPI 作为主框架。FastAPI 的优势是开发效率高类型提示清晰也方便通过依赖注入管理数据库会话和用户鉴权。例如文件上传接口中后端使用UploadFile接收文件用Depends(get_current_user)获取当前用户用Depends(get_db)获取数据库连接。这样路由层只负责接收参数和返回响应真正的文件保存、扣费、任务投递交给服务层或工具层处理。这种写法让代码职责更清楚routers/files.py负责文件相关接口utils/file_storage.py负责文件存储services/analyzer.py负责 AI 分析workers/ai_worker.py负责异步分析任务2. 文件上传与双存储模式项目支持 PDF 和 DOCX 文件上传。前端使用 Element Plus 的el-upload组件关闭自动上传通过FormData手动提交文件。后端接收文件后会先校验 MIME 类型然后调用统一的save_file()方法保存文件。文件存储采用“双模式”优先保存到 MinIO如果 MinIO 不可用则回退到本地uploads/这样做的好处是开发环境也能正常跑不会因为对象存储没有启动就导致上传功能完全不可用。同时文件 ID 统一设计为minio/xxx local/xxx后续读取文件时只要根据前缀判断文件来源即可。3. RabbitMQ 异步任务解耦AI 分析通常比较耗时如果用户上传合同后直接在 HTTP 请求里等待模型返回体验会很差也容易造成接口超时。所以我把分析流程设计成异步任务用户提交分析请求后端创建analysis_reports记录状态为pending将任务投递到 RabbitMQ 的ai_task_queueAI Worker 消费任务并执行分析分析完成后更新报告状态推送 WebSocket 通知前端项目中一共设计了三个队列ai_task_queue AI 分析任务 search_sync_queue ES 索引同步任务 email_notify_queue 邮件通知任务消息队列的价值在这里体现得很明显它让耗时任务从主请求链路中拆出来用户不需要一直等待接口阻塞系统也更容易扩展 Worker 数量。4. AI 分析与 JSON 容错AI 分析模块是项目的核心。系统会从 PDF / DOCX 中提取文本再调用 Dify 或 OpenAI 兼容接口让模型返回结构化风险报告。但是大模型返回内容有一个很典型的问题它不一定严格按照 JSON 返回。有时会多输出解释文字有时会包一层 Markdown 代码块有时甚至会出现尾随逗号。因此我在服务端做了兜底处理prompt 中明确要求返回 JSON服务端先尝试json.loads如果失败再截取第一个{到最后一个}之间的内容如果仍然失败则降级为 mock 结果保证流程不断这个设计让我意识到AI 能力接入业务系统时不能把模型输出当作完全可靠的数据源。模型输出必须经过校验、修复、兜底和标记。5. WebSocket 实时通知分析任务是异步执行的所以前端需要知道任务什么时候完成。项目中使用 FastAPI WebSocket Redis Pub/Sub 实现通知。流程如下AI Worker 分析完成 - Redis 发布 ws_notify 消息 - 后端 WebSocket 订阅线程收到消息 - 根据 user_id 找到对应连接 - 推送 analysis_done 给前端前端封装了useNotify()composable负责自动连接/ws/notify携带 token 鉴权30 秒心跳断线后自动重连页面卸载时清理连接这个功能让用户不需要一直手动刷新页面报告生成后可以自动收到提醒。6. Elasticsearch 搜索与 MySQL 兜底报告生成后系统会把报告摘要、风险等级、风险标签、文件名等信息同步到 Elasticsearch便于用户做全文检索。搜索功能采用 ES 优先、MySQL 兜底的策略ES 可用时从 ES 查询并分页ES 不可用时回退到 MySQL 查询用户文件和报告这样即使 ES 出问题用户也不至于完全无法搜索只是搜索能力会降级。7. 前端图表与数据可视化前端使用 ECharts 做了多个图表Dashboard 中展示风险等级分布饼图Dashboard 中展示最近 6 个月分析趋势折线图Insights 页面展示风险类型分布、高频风险条款 TOP5、月度趋势Analysis 页面使用 ECharts graph 做分析过程动画这些图表的数据都来自后端统计接口而不是前端硬编码。例如GET /api/stats/overview GET /api/stats/trend GET /api/stats/insights实现图表时我也注意了 Vue 生命周期问题必须等 DOM 渲染完成后再初始化 ECharts所以用到了nextTick()页面卸载时也要调用dispose()否则多次切换页面可能造成内存泄漏。8. 支付与余额扣费项目中加入了支付模块支持支付宝预下单、二维码支付、订单查询、支付回调和余额充值。分析计费逻辑采用优先级订阅会员 - 免费次数 - 余额扣费如果用户余额不足接口返回 402。支付成功后后端更新订单状态并增加用户余额同时通过 WebSocket 通知前端刷新余额。开发环境中还保留了模拟支付模式这样即使支付宝沙箱环境不可用也能继续调试完整业务流程。四、开发中遇到的报错与解决1. RabbitMQ 连接断开Worker 不消费任务问题表现是任务已经进入队列但 Worker 偶尔不消费或者 RabbitMQ 重启后 Worker 一直报连接错误。原因是 RabbitMQ 消费是长连接网络抖动、容器重启都会影响连接。如果多个 Worker 都固定 5 秒重连就可能在服务刚恢复时一起重连形成“重连风暴”。解决思路Worker 捕获连接异常断开后延迟重试队列和消息都设置持久化后续可以把固定重试改成指数退避2. AI 返回内容不是标准 JSON这是项目里最常见的问题之一。模型有时会返回以下是分析结果 json { ... } 或者在 JSON 后面加解释文字导致后端解析失败。解决思路prompt 中强调只返回 JSON后端做 JSON 提取和容错解析解析失败时降级为 mock 结果后续优化方向是在结果中明确标记_source: mock避免用户误以为是 AI 真实结果3. Token 过期后前端直接跳登录页项目早期的 Axios 拦截器遇到 401 会直接清空 localStorage 并跳转登录页。问题是用户可能正在看报告或填写表单突然被踢出去体验很差。更合理的处理方式是401 时先尝试调用/api/auth/refresh刷新成功后重试原请求刷新失败再跳转登录多 Tab 场景下可以用 BroadcastChannel 同步 token这个问题让我意识到鉴权不是只要能登录就结束了登录态续期也是用户体验的一部分。4. MinIO 不可用导致存储模式混乱项目支持 MinIO 和本地存储回退。问题在于如果应用启动时 MinIO 不可用文件会回退到本地等 MinIO 恢复后部分文件在 MinIO部分文件在本地后续管理会变复杂。解决思路文件 ID 中记录存储前缀上传失败时明确写日志后续可以增加 MinIO 健康检查和自动重连部署时确保本地 uploads 也有 volume 持久化5. Elasticsearch 静默失败ES 不可用时如果接口只是返回空数组用户会误以为“没有搜索结果”而不是搜索服务异常。解决思路ES 查询失败时回退 MySQL返回结果中增加 fallback 标识ES Worker 连续失败时增加告警这类问题的关键是降级可以做但不能静默。用户和开发者都应该知道当前处于降级状态。6. WebSocket 连接泄漏WebSocket 是长连接用户断网、刷新页面、重复登录都会造成复杂的断开场景。如果只依赖正常 close 流程很容易残留旧连接。解决思路连接建立和关闭都放在try/finally发送失败时主动移除连接定期扫描过期连接对连接字典加锁避免并发写入问题7. 数据库连接池吃紧当多个 Worker、WebSocket、审计日志同时使用数据库时连接池可能被打满。解决思路根据 Worker 数量调整pool_size和max_overflow加入pool_pre_pingTrue检测失效连接高频审计日志可以改成 MQ 异步批量写入后续接入连接池监控指标五、项目收获1. 先分层再扩展这个项目功能很多如果一开始没有拆分routers / services / utils / workers / models后期一定会很难维护。分层之后排查问题会更快。例如上传失败就先看文件路由再看文件存储工具分析失败就看 AI Worker 和 analyzer通知失败就看 Redis Pub/Sub 和 WebSocket。2. 外部依赖一定要有兜底项目依赖了很多外部服务AI 接口RabbitMQRedisElasticsearchMinIO支付宝阿里云短信这些服务任何一个出问题都可能影响用户流程。所以系统不能假设外部服务永远可用必须设计重试、降级、超时、告警和恢复机制。3. 异步任务能显著提升体验AI 分析、邮件通知、ES 同步都不适合放在主请求里同步完成。通过 RabbitMQ 拆成后台任务后接口响应更快系统也更容易扩容。但异步任务也带来了新的问题比如任务重试、失败回滚、任务状态同步、用户通知等。这些都需要在设计阶段考虑。4. AI 接入业务要重视结构化输出大模型很强但它不是传统接口。传统接口会稳定返回固定 JSON而模型可能多说一句话就导致解析失败。所以 AI 接入业务系统时需要额外关注prompt 约束输出格式校验JSON 修复失败重试mock 标记用户可感知的降级提示5. 前端状态比想象中重要项目页面很多有上传中、分析中、已完成、失败、空列表、搜索无结果、登录过期等各种状态。如果前端没有统一处理 loading、empty、error用户很容易觉得“页面坏了”。好的前端不仅要把数据展示出来还要让用户知道系统正在做什么、失败在哪里、下一步能做什么。6. 工程化比单点功能更重要这个项目让我体会最深的是真正的项目不是把某个 demo 跑通而是让它在各种异常情况下还能尽量稳定运行。比如MQ 断了怎么办ES 不可用了怎么办AI 超时怎么办Token 过期怎么办文件存储失败怎么办用户支付回调延迟怎么办这些问题都不是“功能点”但它们决定了系统是否可靠。六、总结智合 AI 商业风控平台最终完成的不只是一个合同分析页面而是一条完整的工程化链路文件上传 - AI 分析 - 异步任务 - 实时通知 - 报告展示 - 全文检索 - 支付计费 - 数据统计 - 分享导出通过这个项目我对前后端分离、异步任务、AI 工程化、WebSocket 通知、搜索系统、支付链路和容错设计都有了更完整的理解。如果要继续优化这个项目我会优先做三件事增加统一监控和告警例如 Worker 状态、MQ 堆积、ES 可用性、数据库连接池指标。完善 AI 输出结构化能力例如使用 JSON mode、解析失败重试、明确标记 mock 来源。优化登录态和前端体验例如自动刷新 Token、统一错误提示、增强加载状态和空状态。这次项目最大的收获可以用一句话总结功能跑通只是第一步让系统在异常情况下仍然可用才是真正的工程能力。