合同审查辅助
合同审查辅助用两档模型:主力模型抽取关键条款、给业务负责人写摘要,更强的模型对照公司的审查清单(playbook)逐条标出风险条款,并说明修改稿改了什么。结果是给法务和律师的参考,不构成法律意见,最终由律师判断。按每月 300 份合同、其中 100 份需要比对修改稿估算,用各模型最低价分组的实时价格计算,模型费用每月约 ¥40.72。
价格更新于 2026年11月13日 17:53
月成本估算
假设:每月审查 300 份合同,平均每份约 1.5 万 tokens(中文约 1.5 万字);条款抽取与摘要每份输入约 1.6 万 tokens、输出约 1,500 tokens;风险审查每份输入约 2 万 tokens(合同 1.5 万、审查清单 4,000、指令 1,000),输出约 2,000 tokens;其中 100 份有修改稿需要比对,每次输入约 6,000 tokens,输出约 1,000 tokens。
业务问题
销售、采购、合作合同越签越多,法务每份都要从头读一遍:付款条件、违约责任、责任上限、解约条款、争议解决。对方改一版发回来,还要逐段找改了哪里。业务部门等着签字,法务很容易成为瓶颈。
直接把合同丢给大模型问“有没有风险”,得到的往往是泛泛的提醒,和公司自己的底线对不上;模型还可能引用合同里根本没有的句子,或者漏掉关键的一条。
更可靠的做法是把公司的审查标准写成清单,让模型逐条对照、引用原文、说明理由,程序核对引用是否真的出自合同,最后由律师确认。模型负责先把需要关注的地方找出来,判断和决定仍然由律师作出。
推荐模型组合
推荐模型按实时目录自动选取,价格取各模型最低价分组,更新于 2026年11月13日 17:53。点模型名可查看全部分组价格。
条款抽取与业务摘要(主力模型)
qwen3.5-plus通义千问
输入 ¥1.12 / 输出 ¥6.72 每百万 tokens国产模型分组
每份合同都先过这一步:抽出主体、金额、期限、付款、违约、解约、争议解决等关键条款,按 JSON 返回,再写一段给业务负责人看的白话摘要。读长文、写短文,输入 tokens 占大头。
风险审查与版本比对(更强的模型)
Claude Sonnet 5.5Anthropic
输入 ¥3.2 / 输出 ¥16 每百万 tokensClaude 经济分组
对照审查清单逐条判断,要在长合同里准确找到对应条款并说明理由,是整个流程里最需要判断力的一步,用更强的模型。合同、清单和指令放在同一次请求里,输入常在 2 万 tokens 左右,单次请求能放多长,以所选模型官方公布的上下文长度为准。
参考架构
- 1
写审查清单
法务把公司的审查标准写成清单(playbook):每条有编号、主题、我方标准立场和不能接受的底线,比如“我方责任上限不超过合同金额”。清单是模型判断的依据,写得越具体,结果越稳定。
- 2
解析与切分
Word 和带文字层的 PDF 用程序提取文本,保留条款编号;扫描件先转成文字。特别长的合同按章节拆开分别审查,再合并结果。
- 3
条款抽取与摘要
主力模型按固定字段抽取关键条款并返回 JSON,再写一段给业务负责人的摘要:我们要付出什么、得到什么、主要风险在哪里。
- 4
对照清单审查
更强的模型拿合同全文和审查清单逐条比对,每条发现都给出清单编号、条款号、原文引用、风险等级和修改建议;清单里有、合同里缺的条款也列出来。程序再检查每条引用能否在原文里找到,找不到的标记出来请律师重点核对。
- 5
版本比对
对方发回修改稿时,先用程序做文本比对找出改动的段落,只把改动前后的内容交给模型,让它说明每处改动对哪一方有利、涉及清单里的哪一条。
- 6
律师确认
审查意见、修改建议和摘要都标明是模型辅助生成,由律师确认后再发给业务部门或对方;律师的修改意见可以反过来补进审查清单。
成本估算
假设:每月审查 300 份合同,平均每份约 1.5 万 tokens(中文约 1.5 万字);条款抽取与摘要每份输入约 1.6 万 tokens、输出约 1,500 tokens;风险审查每份输入约 2 万 tokens(合同 1.5 万、审查清单 4,000、指令 1,000),输出约 2,000 tokens;其中 100 份有修改稿需要比对,每次输入约 6,000 tokens,输出约 1,000 tokens。
| 项目 | 模型 | 用量假设 | 费用 |
|---|---|---|---|
| 条款抽取与业务摘要 | qwen3.5-plus | 300 次 × 输入 16,000 + 输出 1,500 tokens | ¥8.4 |
| 对照清单的风险审查 | Claude Sonnet 5.5 | 300 次 × 输入 20,000 + 输出 2,000 tokens | ¥28.8 |
| 修改稿比对 | Claude Sonnet 5.5 | 100 次 × 输入 6,000 + 输出 1,000 tokens | ¥3.52 |
| 合计(每月) | ¥40.72 | ||
按各模型最低价分组的实时价格计算,价格更新于 2026年11月13日 17:53。
只含模型调用费用,不含律师审核和文本解析成本。审查清单放在提示词开头、每次请求都不变,所选模型支持上下文缓存时,命中缓存的部分按更低的缓存读取价计费,实际费用会更低。表中按最低价分组计算;如果给合同审查单独选了官方来源的分组,按该分组的价格重新估算。合同越长、份数越多,费用大致按比例增加。
示例代码
审查清单写成结构化数据,模型按清单返回带原文引用的发现,程序核对引用是否出自合同;版本比对先用 difflib 找出改动的段落,只把改动交给模型解释。
import difflib
import json
import os
from openai import OpenAI
client = OpenAI(base_url="https://www.tutujin.com/v1", api_key=os.environ["TUTUJIN_API_KEY"])
# The company playbook, written by your legal team: one entry per rule.
PLAYBOOK = [
{"id": "LIAB-1", "topic": "limitation of liability", "standard": "Our total liability is capped at the contract value.", "red_line": "Unlimited liability for us."},
{"id": "PAY-1", "topic": "payment terms", "standard": "We pay within 30 days of a valid invoice.", "red_line": "Payment due in under 15 days or prepayment over 30%."},
{"id": "TERM-1", "topic": "termination", "standard": "Either party may terminate with 30 days of written notice.", "red_line": "Only the other party may terminate for convenience."},
]
RULES = "Playbook:\n" + json.dumps(PLAYBOOK, ensure_ascii=False)
def ask(system, user):
resp = client.chat.completions.create(
model="claude-sonnet-5-5",
messages=[{"role": "system", "content": system + "\n\n" + RULES}, {"role": "user", "content": user}],
temperature=0,
)
return resp.choices[0].message.content
def review(contract):
raw = ask(
"You help a company lawyer review contracts against the playbook. For every clause that departs from a rule "
"or crosses a red line, and for every playbook topic the contract does not cover, return one finding. "
'Reply with JSON only: {"findings": [{"rule_id": "", "clause": "clause number", "quote": "exact words copied '
'from the contract, empty if missing", "risk": "high|medium|low", "reason": "", "suggestion": ""}]}. '
"Do not give legal advice; the lawyer decides.",
contract,
)
findings = json.loads(raw[raw.find("{"): raw.rfind("}") + 1])["findings"]
for f in findings:
# a quote that cannot be found in the contract must be checked by the lawyer, never trusted
f["quote_found"] = f["quote"] == "" or f["quote"] in contract
return findings
def explain_changes(old, new):
"""Diff in code first, so the model only reads the paragraphs that changed."""
a, b = old.splitlines(), new.splitlines()
changes = [
"BEFORE:\n" + "\n".join(a[i1:i2]) + "\nAFTER:\n" + "\n".join(b[j1:j2])
for op, i1, i2, j1, j2 in difflib.SequenceMatcher(None, a, b).get_opcodes()
if op != "equal"
]
return ask(
"For each change, say in one or two sentences what changed, which party it favours "
"and which playbook rule it touches, if any.",
"\n\n".join(changes),
)
with open("contract_v1.txt", encoding="utf-8") as f1, open("contract_v2.txt", encoding="utf-8") as f2:
v1, v2 = f1.read(), f2.read()
for item in review(v2):
print(item["risk"], item["rule_id"], item["clause"], "" if item["quote_found"] else "QUOTE NOT FOUND - check by hand")
print(explain_changes(v1, v2))常见问题
每月审查 300 份合同,模型费用大概多少?
按每份约 1.5 万 tokens、每份都做条款抽取和风险审查、其中 100 份比对修改稿估算,用最低价分组计算约 ¥40.72。合同长度和审查份数对费用影响最大。
模型的审查结果能当作法律意见吗?
不能。模型的输出是给法务和律师的参考,帮你先把需要关注的条款找出来,整理好理由和原文引用。它可能漏掉风险、误解条款含义,也不了解交易背景,最终判断和对外意见必须由律师作出。
为什么要先写审查清单?
没有清单,模型只能给出泛泛的风险提示,和公司的实际底线对不上。清单把我们能接受什么、不能接受什么写清楚,模型逐条对照,结果才能比较、能复核;清单也可以随着律师的意见不断补充。
合同太长,一次放不下怎么办?
单次请求能放多少内容,以所选模型官方公布的上下文长度为准。超长合同按章节拆开分别审查,每段都带上审查清单,最后合并结果;也可以只把和清单主题相关的章节交给审查模型。
合同里的商业机密和个人信息怎么处理?
请求会经本站转发给模型服务处理。建议先隐去对方名称、身份证号、银行账号等不影响审查的信息再提交;对线路来源有要求的,可以给合同审查单独建一把 Key,选官方来源的分组,模型详情页列出了每个模型可用的分组。能否使用,请按你们自己的保密和数据合规要求评估。
扫描版合同能审吗?
可以,先把扫描件转成文字再审。识图模型读取扫描件的做法见文档解析与信息抽取方案;转出来的文字要核对一遍,数字和日期最容易出错。
