向AI转型的程序员都关注公众号 机器学习AI算法工程

签合同前找律师审,一份合同报价 2000-5000 元,周期 2-4 小时起步。违约金不对等、管辖权单方约定这种坑,非法律专业的人很难一眼看出来。
我基于 Qwen3.8-Max 大模型 + Python Flask,搭建了一套 AI 合同条款精审助手。核心思路很直接:上传合同文件 → AI 自动提取全部条款 → 逐条六维度风险分析 → 生成评分报告与对比数据。整套系统 7 个核心源文件约 2000 行代码,实测 50 页(20,266 字符)技术开发与服务合同,295.5 秒完成全流程审查,安全评分 83/100,审查 62 条条款,发现 31 个问题。同等合同律师人工审查需 2-4 小时、花费 2000-5000 元,仅能覆盖 25 条条款、发现 9 个问题。
核心能力:
多格式文档解析:支持 PDF / Word / TXT / Markdown,自动提取合同全文
AI 逐条风险审查:六维度分析(霸王条款 / 模糊表述 / 缺失条款 / 条款矛盾 / 违法风险 / 违约金异常),四级风险标注
安全评分体系:加权算法计算整体安全评分,输出优秀 / 良好 / 一般 / 较差四档评级
可视化仪表盘:Chart.js 饼图 + 柱状图,风险等级分布与各条款评分一目了然
AI vs 人工对比:8 维度量化对比表,数据化展示 AI 审查优势
PDF 报告导出:一键生成包含封面、摘要、逐条分析、核心建议的完整审查报告
一、环境准备
1.1 Python 环境安装
步骤 1:确认 Python 版本 3.10+
python --version# Python 3.12.x
1.2 Qwen3.8 -Max API Key 获取
步骤 1:访问 阿里云百炼平台 并登录

步骤 2:进入「API-KEY 管理」,创建新的 API Key

步骤 3:复制 API Key 并妥善保管,后续配置到 .env 文件中

1.3 项目依赖安装
步骤 1:进入项目目录,安装全部依赖
cd contract-reviewerpip install -r requirements.txt
步骤 2:依赖清单
flask>=3.0.0 # Web 框架flask-cors>=4.0.0 # 跨域支持python-dotenv>=1.0.0 # 环境变量管理openai>=1.12.0 # Qwen API 调用(OpenAI 兼容格式)pdfplumber>=0.10.3 # PDF 文档解析python-docx>=1.1.0 # Word 文档解析fpdf2>=2.7.7 # PDF 报告生成
步骤 3:复制 .env.example 为 .env,填入 API Key
cp .env.example .env
# .env 配置文件DASHSCOPE_API_KEY=sk-your-api-key-hereDASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1MODEL_NAME=qwen3.8-maxPORT=5000
步骤 4:启动服务,访问 http://localhost:5000
python app.py
启动时会自动检测 API Key 是否已配置
二、项目搭建
2.1 项目架构总览
项目定位:AI 合同条款精审助手,Flask 后端对接 Qwen3.8-Max API 进行合同风险审查,原生前端提供上传、预览、结果展示、仪表盘、对比报告一站式交互
contract-reviewer/├── app.py # Flask 主应用(API 路由 + 演示数据 + 对比引擎)├── analyzer.py # AI 分析引擎(文档解析 + 条款提取 + 批量风险审查)├── config.py # 配置管理(环境变量 + 路径常量)├── reports.py # PDF 审查报告生成(封面 + 摘要 + 逐条分析 + 建议)├── requirements.txt # Python 依赖清单│├── templates/│ └── index.html # 前端主页面(上传 / 预览 / 加载 / 结果四区域)│├── static/│ ├── css/style.css # 完整样式表(CSS 变量主题 + 响应式布局)│ └── js/app.js # 前端交互逻辑(上传 / 分析 / 渲染 / 图表)│└── samples/└── sample_contract.txt # 示例合同(技术咨询服务合同,含已知风险条款)
2.2 技术选型
三、核心功能模块
3.1 文档上传与解析

多格式文档解析:支持 PDF / Word / TXT / Markdown,自动提取全文,最大 20MB。
def parse_document(self, file_path: str) -> dict:ext = os.path.splitext(file_path)[1].lower()parsers = {".pdf": self._parse_pdf, # pdfplumber 逐页提取".docx": self._parse_docx, # python-docx 段落合并".doc": self._parse_docx,".txt": self._parse_txt, # 多编码尝试 utf-8/gbk/gb2312".md": self._parse_txt,}parser = parsers.get(ext)if not parser:raise ValueError(f"不支持的文件格式: {ext}")text = parser(file_path)if not text.strip():raise ValueError("文档内容为空,请检查文件")return {"text": text, "char_count": len(text), "filename": os.path.basename(file_path)}
前端拖拽上传:支持拖拽 + 点击选择,上传后展示文件预览(全文展示),提供「返回首页」和「重新上传」两个导航入口。
uploadArea.addEventListener('drop', (e) => {e.preventDefault();uploadArea.classList.remove('dragover');if (e.dataTransfer.files.length) handleFileUpload(e.dataTransfer.files[0]);});
3.2 AI 分析引擎(三步 Pipeline)

三步 Pipeline 编排:提取条款 → 批量风险分析 → 整体评估,非单次调用,而是链式处理 + 自动回退。
上传文档 → 解析文本 → AI 提取条款 → AI 批量风险分析 → AI 整体评估 → 加权评分 → 渲染结果↓ (批量失败时)回退到逐条分析(每条单独调 API)
第一步:AI 提取合同条款

prompt = """你是一位专业的中国合同审查律师。请仔细阅读以下合同文本,提取所有独立条款。要求:1. 保留原始条款编号2. 完整保留条款原文内容3. 每个条款独立编号4. 包括合同的基本信息条款(如当事方、签署日期等)5. 包括所有附件和补充条款请以JSON数组格式返回:[{"id": "条款编号", "text": "条款完整原文", "title": "条款标题/主题"}]"""
第二步:批量风险分析(核心 Prompt)
将所有条款一次性丢给 AI,六维度逐条分析风险:
prompt = f"""c。请对以下合同的所有条款逐条进行风险分析。分析维度:1. 霸王条款:单方面加重对方义务或限制对方权利2. 模糊表述:可能导致争议的模糊用语3. 缺失条款:缺少必要的限定条件或例外情形4. 条款矛盾:与其他条款存在逻辑矛盾5. 违法风险:可能违反《民法典》《消费者权益保护法》《劳动法》等6. 违约金异常:违约金比例过高或过低风险等级标准:- critical:严重风险,可能导致重大经济损失或法律纠纷- high:高风险,需要立即修改- medium:中风险,建议优化- low:低风险,基本可接受请以JSON数组格式返回每个条款的分析结果:[{{"clause_index": 0,"risk_level": "critical/high/medium/low","risk_types": ["具体风险类型"],"analysis": "详细风险分析说明(100-200字)","suggestion": "具体修改建议,给出修改后的条款文本","risk_score": 1到10的整数,"legal_basis": "相关法律条文引用"}}]"""
第三步:生成整体评估
prompt = f"""你是一位资深的合同审查律师。请基于以下信息对合同进行整体评估。合同原文摘要(前1000字):{{text[:1000]}}高风险条款摘要:{{risk_summary}}共审查 {{len(clauses)}} 条条款。请以JSON格式返回整体评估:{{"summary": "合同整体评估概述(200字以内)","overall_risk": "critical/high/medium/low","strengths": ["合同优点1", "合同优点2"],"critical_issues": ["关键问题1", "关键问题2"],"key_suggestions": ["核心建议1", "核心建议2", "核心建议3"],"contract_type": "合同类型(如劳动合同/买卖合同/租赁合同等)"}}"""
API 调用封装:显式关闭 thinking 模式加速 JSON 输出,180 秒超时兜底。
def _call_ai(self, prompt: str, max_tokens: int = 4096) -> str:"""调用 Qwen3.8-Max API(显式关闭 thinking 以加速 JSON 输出)"""try:response = self.client.chat.completions.create(model=self.model,messages=[{"role": "system", "content": "你是一位拥有15年经验的中国合同审查律师,""擅长发现合同中的风险条款、霸王条款和模糊表述。""请始终以有效的JSON格式返回分析结果,不要包含任何非JSON内容。"},{"role": "user", "content": prompt},],temperature=0.1,max_tokens=max_tokens,extra_body={"enable_thinking": False}, # 关键:关闭 thinking 加速 JSON 输出)content = response.choices[0].message.contentif content is None:return "{}"return content.strip()except Exception as e:print(f"[AI调用错误] {e}")return "{}"
3.3 审查结果展示

安全评分计算:加权算法,critical=10 / high=7 / medium=4 / low=1,结合 AI 给出的具体评分归一化到 0-100。
def _calculate_score(self, clauses: list) -> int:if not clauses:return 50RISK_WEIGHTS = {"critical": 10, "high": 7, "medium": 4, "low": 1}total_penalty = 0for clause in clauses:level = clause.get("risk_level", "low")weight = self.RISK_WEIGHTS.get(level, 1)risk_score = clause.get("risk_score", 5)total_penalty += weight * (risk_score / 10.0)max_penalty = len(clauses) * 10return max(0, min(100, round(100 - (total_penalty / max_penalty * 100))))
条款卡片渲染:每条条款展示风险等级标签、风险类型标签、原文引用、风险分析、修改建议、法律依据、风险评分进度条,支持按等级筛选。
function renderClauses(clauses) {const riskLabels = { critical: '严重', high: '高危', medium: '中等', low: '低危' };clauses.forEach(clause => {const level = clause.risk_level || 'low';const types = (clause.risk_types || []).map(t => `<span class="type-tag">${escapeHtml(t)}</span>`).join('');const scorePercent = (clause.risk_score || 0) * 10;card.innerHTML = `<div class="clause-header"><span class="clause-title">条款 ${escapeHtml(clause.original_id || '?')}:${escapeHtml(clause.title || '')}</span><span class="risk-badge ${level}">${riskLabels[level] || level}</span></div>${types ? `<div class="clause-types">${types}</div>` : ''}<div class="clause-text">${escapeHtml(clause.original_text || '')}</div><div class="clause-section-label">🔍 风险分析</div><div class="clause-analysis">${escapeHtml(clause.analysis || '无分析')}</div><div class="clause-section-label">✏️ 修改建议</div><div class="clause-suggestion">${escapeHtml(clause.suggestion || '无建议')}</div>${clause.legal_basis ? `<div class="clause-legal">📖 ${escapeHtml(clause.legal_basis)}</div>` : ''}<div class="risk-score-bar"><div class="risk-score-fill" style="width:${scorePercent}%"></div></div>`;});}
3.4 风险仪表盘

Chart.js 可视化:环形饼图展示风险等级分布,柱状图展示各条款风险评分,统计卡片汇总关键指标。
// 环形饼图 - 风险等级分布const pieCtx = document.getElementById('riskPieChart');pieCtx._chart = new Chart(pieCtx, {type: 'doughnut',data: {labels: ['严重', '高危', '中等', '低危'],datasets: [{ data: values, backgroundColor: ['#dc2626', '#ea580c', '#ca8a04', '#16a34a'] }],},});// 柱状图 - 各条款风险评分const barCtx = document.getElementById('riskBarChart');barCtx._chart = new Chart(barCtx, {type: 'bar',data: {labels: clauseLabels,datasets: [{ label: '风险评分', data: clauseScores, backgroundColor: clauseColors }],},options: { scales: { y: { beginAtZero: true, max: 10 } } },});
3.5 AI vs 人工对比报告

8 维度对比表:安全评分、审查时间、审查成本、条款数、严重风险发现、高风险发现、结果一致性、全量覆盖。
def _build_comparison_table(ai_analysis: dict, human: dict) -> list:ai_risk = ai_analysis.get("risk_counts", {})human_risk = human.get("risk_counts", {})def get_risk(d, key, cn_key):return d.get(key, d.get(cn_key, 0)) # 兼容中英文 keyreturn [{"dimension": "安全评分", "ai": f"{ai_analysis.get('overall_score', 0)}/100","human": f"{human['score']}/100", "winner": "ai" if ... else "human"},{"dimension": "审查时间", "ai": ai_analysis.get("analysis_duration", "?"),"human": human["duration"], "winner": "ai"},{"dimension": "审查成本", "ai": "≈ ¥0.5","human": human["cost"], "winner": "ai"},{"dimension": "严重风险发现", "ai": str(ai_critical),"human": str(human_critical), "winner": "ai" if ai_critical >= human_critical else "human"},...]
人工审查基准数据:基于行业平均,评分 78/100、审查 2-4 小时、成本 ¥2,000-5,000、发现 9 个问题。
代码路径:app.py → _get_human_benchmark() 第 193-208 行
def _get_human_benchmark() -> dict:return {"score": 78, "total_clauses": 25,"risk_counts": {"critical": 2, "high": 3, "medium": 4, "low": 16},"duration": "约 2-4 小时", "cost": "¥2,000 - ¥5,000", "issues_found": 9,"notes": ["人工审查受疲劳影响,可能遗漏低风险条款","不同律师审查标准不一致","审查周期长,影响业务进度","按时/按份计费,成本较高",],}
3.6 演示模式

无需 API Key 即可体验:内置 12 条示例条款分析数据,覆盖严重 / 高 / 中 / 低四级风险,包含完整的审查结果、仪表盘和对比报告。
def analyze_demo(task_id):if task_id not in analysis_store:analysis_store[task_id] = {"filename": "示例合同 - 技术咨询服务合同.txt","text": "","created_at": datetime.now().isoformat(),}demo_result = _get_demo_analysis() # 内置 12 条示例分析数据analysis_store[task_id]["analysis"] = demo_resultreturn jsonify(demo_result)
五、技术选型与踩坑记录
5.1 开发工具链
整个项目用 Qoder 作为 IDE,接入 Qwen3.8-Max 模型做 AI 辅助编程,从项目搭建、代码编写到调试修复,全程在 Qoder 里完成。
用 Qoder + Qwen3.8-Max 开发的最大感受是:代码生成 和上下文理解能力很强,7 个核心文件约 2000 行代码,大部分是 Qoder 里对话生成的。但运行时的问题,AI 不一定能提前想到,得自己跑起来才知道。下面 6 个坑,调了 6 轮才从“能跑”变成“稳定可用”。
5.2 坑 1:Thinking 模式导致 API 卡死 10 分钟
这是最大的坑。API 调用一直超时,简单测试 2.4 秒能返回,但合同分析的大 Prompt 直接卡死。
排查过程:
先用简单 Prompt 测试 → 2.4 秒返回,正常
加上 enable_thinking=False → 0.5 秒返回
才发现:自定义端点默认开启了 thinking 模式,模型会先做一大段“内心独白”再输出结果
简单 Prompt 的 thinking 很短,但批量分析 36 条条款的 Prompt,thinking 内容巨长,直接超时
# 解决:显式关闭 thinkingextra_body={"enable_thinking": False}# 效果:从超时 10 分钟 → 101 秒完成全流程
5.3 坑 2:50 页大合同分析完跳回预览页
用户上传 50 页测试合同,分析一段时间后莫名其妙跳回预览页。
排查过程:
写测试脚本直接调 analyzer → AI 连通性正常(回复 OK)
但条款提取返回 0 条,抓取 AI 原始返回发现 JSON 在 7638 字符处被截断
根因:max_tokens=4096 太小,大合同的条款提取需要输出大量 JSON,4096 token 根本不够
# 解决:三管齐下# 1. 默认 max_tokens 4096 → 8192# 2. 条款提取专用 max_tokens=16384# 3. 新增 _repair_truncated_json() 截断修复:JSON 数组被截断时,# 自动找最后一个完整对象并闭合数组,避免全部丢失
5.4 坑 3:openai SDK 版本冲突
TypeError: Client.__init__() got an unexpected keyword argument 'proxies'
环境里 openai==1.12.0 和 httpx 版本不兼容,pip install --upgrade openai 升级到 2.53.0 后恢复。
5.5 坑 4:演示模式 404 + 中英文 Key 不一致
两个问题一起爆发:
前端 JS 设置 currentTaskId = ‘demo’,但 analysis_store 字典里没有 ‘demo’ 这个 key → 404
演示数据 risk_counts 用英文 key(critical/high/medium),summary.risk_counts 用中文 key(严重风险/高风险/中风险),对比表取不到值,统计全是 0
# 解决 1:analyze_demo 端点自动创建 task 条目# 解决 2:兼容函数,两种 key 都尝试def _count_issues(risk_counts: dict) -> int:en_total = sum(risk_counts.get(k, 0) for k in ["critical", "high", "medium"])cn_total = sum(risk_counts.get(k, 0) for k in ["严重风险", "高风险", "中风险"])return max(en_total, cn_total)
5.6 坑 5:XSS 注入 + 事件冒泡
两个前端问题:
innerHTML 直接插入 AI 返回内容,有 XSS 风险 → 新增 escapeHtml() 全局转义
“选择文件”按钮在拖拽区域内,点击时同时触发 uploadArea 的 click 事件,文件选择对话框弹出两次 → stopPropagation() 修复
function escapeHtml(str) {if (!str) return '';const div = document.createElement('div');div.textContent = str;return div.innerHTML;}selectFileBtn.addEventListener('click', (e) => {e.stopPropagation();fileInput.click();});
6 轮调试,从“能跑”到“稳定可用”。Qoder 的代码生成和上下文理解能力确实强,2000 行代码大部分是对话生成的。但运行时的问题(超时、截断、版本冲突、事件冒泡)只有实际跑起来才会暴露,AI 不一定能提前想到。建议开发流程:Qoder 生成代码 → 立即跑起来测试 → 发现问题再让 Qoder 修,比一次性生成大段代码再统一调试效率高得多。
六、效果对比

以下数据来自实测:50 页(20,266 字符)技术开发与服务合同,AI 全流程审查 295.5 秒完成,与同等规模律师人工审查结果对比。
AI 审查结果
律师人工审查
8 维度对比



七、总结
实测 50 页(20,266 字符)技术开发与服务合同,AI 审查 295.5 秒完成,成本约 0.5 元,审查 62 条条款发现 31 个问题;律师人工审查需 2-4 小时、花费 2000-5000 元,仅覆盖 25 条条款发现 9 个问题。AI 在安全评分(83 vs 78)、审查条款数(62 vs 25)、高风险发现(5 vs 3)三个关键维度全面领先,且结果 100% 可复现,不受疲劳和主观判断影响。
整套系统 7 个核心文件约 2000 行代码,实现了从文档解析、条款提取、批量风险审查、安全评分、可视化仪表盘、AI vs 人工对比报告到 PDF 导出的完整链路。对于中小企业日常合同初审场景,AI 不是替代律师,而是让你在找律师之前,就已经知道合同里有哪些坑。
机器学习算法AI大数据技术
搜索公众号添加: datanlp
长按图片,识别二维码
阅读过本文的人还看了以下文章:
【模型高效部署】tensorrtx 深度解读,yolov11高性能推理实战案例
实时语义分割ENet算法,提取书本/票据边缘
整理开源的中文大语言模型,以规模较小、可私有化部署、训练成本较低的模型为主
《大语言模型》PDF下载
动手学深度学习-(李沐)PyTorch版本
基于40万表格数据集TableBank,用MaskRCNN做表格检测
《基于深度学习的自然语言处理》中/英PDF
Deep Learning 中文版初版-周志华团队
【全套视频课】最全的目标检测算法系列讲解,通俗易懂!
《深度学习入门:基于Python的理论与实现》高清中文PDF+源码
python就业班学习视频,从入门到实战项目
2019最新《PyTorch自然语言处理》英、中文版PDF+源码
《21个项目玩转深度学习:基于TensorFlow的实践详解》完整版PDF+附书代码
《深度学习之pytorch》pdf+附书源码
《Python数据分析与挖掘实战》PDF+完整源码
不断更新资源
深度学习、机器学习、数据分析、python
搜索公众号添加: datayx

