六页扫描合同里,有这样一句话:
合同签订后五个工作日内,甲方支付合同总价的百分之六十作为预付款。
它出现在第二页。
qwen3.7-plus 把这条约定识别为高风险,理由也不复杂:60% 的预付款明显偏高,一旦供应方延迟履行或失去履约能力,采购方可能面对大额资金难以追回的问题。模型给出的建议是把比例降到 30% 以内,或者要求供应方提供等额银行保函、履约保证金。
如果故事停在这里,这只是一次看起来不错的模型回答。
真正的问题还在后面:审查人能不能从这条风险直接回到合同第二页,逐字核对原文?能不能把它标成"已复核",补一条自己的意见?这份结果离开当前浏览器后,还能不能交给下一位经办人?
为了让一条风险走完这段路,我做了一个采购合同风险审查助手。它调用蓝耘 MaaS 的 qwen3.7-plus 分析合同,但没有把终点设在"模型回答完成",而是继续往前走:结构化、定位、复核、导出。
本文中的五份合同均为自拟或脱敏测试材料。工具只做风险初筛,不构成法律意见。
一、为什么先把蓝耘 MaaS 引进来
合同审查助手对模型的要求有些特殊。
它既要读长文本,也要看扫描页面;既要理解付款、验收、违约等条款之间的关系,又要按固定字段返回 JSON。能力之外,接入方式还得足够简单,否则大量时间会耗在 SDK 适配和接口改造上,而不是合同工作流本身。
蓝耘 MaaS 恰好把这些问题放在了同一个入口里。模型广场可以直接查看模型类型、能力标签、上下文长度和价格,选定模型后再通过统一 API 接入应用。对于已经使用 OpenAI Python SDK 的项目,主要调整集中在 Base URL、API Key 和模型名,文件解析、页面交互和报告导出代码不需要围绕另一套专用 SDK 重写。
这次我选择 qwen3.7-plus,不是只因为它能生成文本。蓝耘控制台将其标为高性价比 Plus 模型,并标注视觉理解和 1024k 上下文。文字合同需要长文本理解,扫描合同需要视觉能力,结构化风险清单则依赖稳定的指令遵循。它的能力组合正好覆盖了这三个环节。
蓝耘在这里承担的也不只是"提供一个模型地址"。它把模型选型、接口接入和 API Key 管理连在一起,让我可以把更多精力放在风险如何定位、如何复核、如何导出这些真正决定工具是否可用的问题上。
二、三个办法,都能"看合同",但不是同一件事
在写代码之前,我先把三种常见路径摆在了一起。
| 路径 | 能解决什么 | 主要问题 | 适合的位置 |
|---|---|---|---|
| 人工逐页通读 | 能结合交易背景作专业判断 | 重复劳动多,长合同容易遗漏,整理报告耗时 | 最终复核与决策 |
| 把合同直接发给模型 | 很快得到风险摘要和建议 | 回答难筛选,页码和原文不稳定,结果不便继续处理 | 临时咨询、快速找思路 |
| 结构化审查助手 | 把模型输出变成风险条目,保留原文、定位和复核状态 | 仍依赖模型输出质量,必须人工确认 | 首轮筛查与意见整理 |
这张表里没有谁要取代谁。
人工判断依然负责最后一道门。qwen3.7-plus 负责从大量合同内容中提取候选风险,程序则负责让这些风险变成可以筛选、定位和流转的工作对象。
工具的价值,恰好出现在三者交接的地方。
三、第一步:把"一段回答"变成"一组工作对象"
直接让模型审查合同,最容易得到一篇长回答。它能读,却很难继续用。
我需要的不是一段语言流,而是一组字段稳定的数据:风险等级、风险类别、页码、章节、原文摘录、风险分析和修改建议。页码无法确认时必须返回 null,原文必须逐字引用,不允许改写或编造。
因此,后端要求模型输出固定 JSON:
json
{
"overall_risk_level": "高",
"risks": [
{
"level": "高",
"category": "价格与付款",
"page": 2,
"section": "第二部分 价格、付款与发票",
"quote": "合同签订后五个工作日内,甲方支付合同总价的百分之六十作为预付款",
"risk_point": "预付款比例过高,资金风险极大",
"analysis": "......",
"suggestion": "......"
}
]
}
模型输出并不总是天然规整。程序会先直接解析,再清理 Markdown 围栏、提取最外层 JSON、处理尾逗号;仍然失败时,才额外发起一次 JSON 修复调用。修复后依旧无法解析,接口才返回失败,而不是拿一段残缺文本冒充成功结果。
解析成功后,程序还会统一风险等级、页码和列表字段。到了这一步,模型回答才第一次变成了可以被页面继续处理的数据。
TXT 样例验证了这件事。工业传感器采购合同共 1527 字符,页面得到 11 个风险条目:高风险 6 项、中风险 4 项、低风险 1 项。它们可以按等级、类别和关键词筛选。 
DOCX 表格合同也进入了同一条链路。办公设备采购合同共 1087 字符,输出 10 项风险:高风险 4 项、中风险 5 项、低风险 1 项。 
这一轮实测中,DOCX 文件解析耗时 0.46 秒,模型耗时 29.09 秒,接口返回 HTTP 200。

到这里,长回答已经变成了一组可以操作的风险卡片。
但这条路径藏着一个前提:文件里得有文字。
四、第二步:文本链路走不通,多模态才真正登场
很多合同 PDF 看上去有字,底层却只有一页页图片。程序从中抽取不到正文,传统文本调用在这里会直接断掉。
工具因此保留了两条 PDF 处理路径:
text
文字 PDF -> 逐页抽取文字并注入【第N页】标记 -> 文本分析
扫描 PDF -> 逐页渲染为 PNG -> 多模态分析
程序会根据提取文本的总量和平均每页字符数判断应该走哪条路径。扫描页按照真实页序发送给模型,超过每批上限时继续分批;单批失败会被记录,不会悄悄丢掉。
也正是在这里,前面对蓝耘 MaaS 和 qwen3.7-plus 的选择不再是一段参数介绍,而是对扫描合同这道具体难题的回答。
在蓝耘 MaaS 模型广场里,能力、上下文和价格信息可以在选型时一起查看。合同正文使用 qwen3.7-plus 的文本理解能力,扫描页使用视觉理解能力;同一个模型覆盖两条输入路径,也让后续的 JSON 字段和页面处理保持一致。 
蓝耘提供 OpenAI 兼容端点。API Key 在 MaaS 平台的"API KEY 管理"中创建,真实密钥只保存在本地 .env,不进入代码仓库,也不出现在文章和截图里:
dotenv
BLUEYUN_API_KEY=你的蓝耘API密钥
BLUEYUN_BASE_URL=https://maas-api.lanyun.net/v1
BLUEYUN_MODEL=qwen3.7-plus
后端最终请求 https://maas-api.lanyun.net/v1/chat/completions:
python
client = OpenAI(
api_key=cfg["api_key"],
base_url=cfg["base_url"],
timeout=300.0,
)
response = client.chat.completions.create(
model=cfg["model"],
messages=messages,
response_format={"type": "json_object"},
temperature=0.2,
)
这段代码没有平台专用的复杂封装。调用层越薄,工具其余部分就越容易保持独立:以后调整模型时,合同解析、风险复核和报告导出仍然可以沿用。对我来说,这正是 MaaS 平台在开发阶段最直接的价值。
为了验证两条路径,我把同一类云服务合同分别做成文字 PDF 和扫描 PDF。
文字 PDF 共 1 页,程序直接抽取文本,模型耗时 23.76 秒,输出 6 项风险:高风险 4 项、中风险 2 项。 
扫描 PDF 同样是 1 页,但运行日志明确进入了"扫描件分支":1 页、1 批,文件解析耗时 23.72 秒,模型耗时 23.46 秒,也输出 6 项风险。 

两次恰好都得到 6 项风险,不能据此推导两个格式永远产生相同结果。能确认的是:没有文本层的 PDF 不再是流程终点,工具确实把它转入了多模态分析链路。
扫描件终于能读了。
可"读出来"仍然不等于"可以复核"。如果风险与原页脱节,审查人还是得重新翻完整份合同。
五、第三步:让风险一直带着原文和页码
于是,故事回到了开头那份六页扫描合同。
程序把 6 页渲染为图片,作为 1 批交给蓝耘 MaaS。qwen3.7-plus 返回 12 项风险:高风险 6 项、中风险 4 项、低风险 2 项。文件解析耗时 47.23 秒,模型耗时 45.61 秒,本次没有触发 JSON 修复调用。 
但风险数量不是这里最重要的数字。
更关键的是那条 60% 预付款风险始终带着自己的证据:风险类别是"价格与付款",章节指向"第二部分 价格、付款与发票",页码是第二页,下面保留了逐字原文。
点击"第2页",右侧合同预览会跳到对应页面。审查人不必相信卡片本身,可以马上核对合同语境。核对完成后,还能把状态从"待复核"改为"已复核",并补充备注。 
这条链路可以写得很短:
text
模型发现风险
-> 保留逐字原文与实际页码
-> 点击风险跳回合同页面
-> 人工核对并记录状态、备注
可它改变了工具的性质。
在这之前,页面展示的是模型结论;从这一刻开始,页面承载的是人与模型共同处理的一项工作。
六、第四步:不能离开浏览器的结果,还不算交付
如果复核状态和备注只存在于当前页面,换一台电脑、交给另一位同事,前面的工作又会断掉。
所以导出不是最后临时添上的一个按钮,而是这条链路的出口。导出时,程序把页面传回的复核状态和备注合并进风险数据,再生成 Markdown、HTML 或 PDF。
HTML 报告保留合同名称、审查模型、处理耗时、风险统计、原文摘录、分析、建议和复核状态,适合在浏览器中查看与归档。 
PDF 报告共 3 页,可以离线打开和转交。 
至此,第二页那条 60% 预付款风险才真正走完一圈:从扫描图像中被发现,变成结构化条目,带着原文回到第二页,等待人作出判断,最后进入一份可以转交的报告。
七、用五份材料横向检查整条链路
前面的叙事只抓住了一条风险。为了确认工具不是只在一个画面里"看起来能用",我又用五种输入形态检查了整条链路。
| 样例 | 主要验证目标 | 文件解析耗时 | 模型耗时 | 本次结果 |
|---|---|---|---|---|
| 工业传感器采购合同(TXT) | 结构化输出、筛选 | 0.04 秒 | 42.99 秒 | 11 项:高 6 / 中 4 / 低 1 |
| 办公设备采购合同(DOCX) | 表格内容读取 | 0.46 秒 | 29.09 秒 | 10 项:高 4 / 中 5 / 低 1 |
| 云服务采购合同(文字 PDF) | 文本抽取、页码保留 | 0.64 秒 | 23.76 秒 | 6 项:高 4 / 中 2 |
| 云服务采购合同(扫描 PDF) | 单页多模态识别 | 23.72 秒 | 23.46 秒 | 6 项:高 4 / 中 2 |
| 设备采购、安装与维保合同(六页扫描 PDF) | 多页识别、定位、复核、导出 | 47.23 秒 | 45.61 秒 | 12 项:高 6 / 中 4 / 低 2 |
这些数字只属于本次样例和当时的接口环境。它们证明五条实际请求完成了,不证明固定速度,也不能替代准确率测试。
这轮横向检查反而让我看清一件事:不同格式的差别主要发生在"模型调用之前"。TXT、DOCX、文字 PDF 和扫描 PDF 需要不同的读取策略;一旦被整理成带页码的文字或有序页面图像,后面的结构化、筛选、复核和导出就能回到同一条流程。
八、纵向走完,再回头看四层分工
把一条风险从输入看到交付,四层分工的边界也清楚了。
蓝耘 MaaS 的价值,是把模型选择、调用接口和密钥管理组织在同一个平台里,让模型能力能够进入应用,而不必让业务代码跟某一套专用 SDK 紧紧绑定。
qwen3.7-plus 的价值,是从合同文字或扫描页面中提取候选风险,并按约束生成结构化字段。
程序的价值,是处理格式差异,保留页码和原文,对 JSON 做容错解析与归一化,把风险送进筛选、定位、复核和导出流程。
人的价值,是核对上下文,结合真实交易背景判断风险是否成立、建议是否可行,并为最终意见负责。
模型很强,也不能越过人的责任。程序写得再完整,也不能替代专业判断。真正可用的工作流,不是让平台、模型、程序和人互相冒充,而是让每一方只承担自己擅长的那一段。
这也是我对"AI 合同审查工具"的判断:它的核心不是自动给出多少条结论,而是把一次模型回答转化为可定位、可复核、可交付的工作对象。
结语
回到第二页那条 60% 预付款约定。
蓝耘 MaaS 让合适的模型以熟悉的方式进入工具,qwen3.7-plus 再从扫描页面里把这条约定识别出来;程序让它始终带着原文和页码;人核对语境,决定是否接受修改建议,并留下最终意见。
一条风险穿过整条链路,最后才成为报告中的一项内容。
这次实操让我看到,蓝耘 MaaS 的价值并不止于"调通一次模型"。模型广场降低了选型成本,OpenAI 兼容接口缩短了接入路径,统一的 API Key 管理让凭证与业务代码分开;真正进入工具之后,模型能力又能和本地的解析、定位、复核、导出流程各司其职。
合同审查助手不需要扮演律师。蓝耘也不是替人完成最后判断的黑盒。更合适的位置,是借助蓝耘把散落在不同格式、不同页面里的问题先整理好,把证据送到人面前,让人的判断有一个更清楚的起点。
这比让模型再写一段更长的回答,难得多,也有用得多。