4月底时,知识星球里有个关于在 RAG 流程中,如何实现基于 Bad Cases(负面案例)的合同审查和合同生成(基于合同模板)的提问,算是一个很有代表性的进阶 RAG 应用方向,这篇针对其中的合同审查场景来做些介绍和演示。

注:“整体文档理解”(Bad Cases 分析)和“结构化对象检索”(模板匹配)
合同审查场景里,利用历史上的“坏案例”(Bad Cases,包含合同原文和审查结果)来辅助新合同的审查,而不仅仅依赖预设规则是个很实际的业务需求。但标准 RAG 主要召回与问题语义相似的片段,确实很难让 LLM 理解一个 Bad Cases 的整体情况和参考价值。直接将整个 Bad Cases 作为知识源,又面临上下文窗口限制和召回不精确(可能只匹配了表面相似性,而非关键问题点)的挑战。
结合我过去几个月一些相关项目中的实践经验,这篇基于 dify 工作流和设计的样例数据,向各位展示一个可快速上手的解决方案示例。

以下,enjoy:
1
正式开始介绍前,我们先来回顾下,在没有 LLM 和 RAG 技术普及之前,市场上常见合同审查工具以及其背后的规则引擎做法。

1.1
核心做法
知识库构建与规则编码:
传统规则引擎主要来自法律专业知识、行业惯例和公司自身的风险策略等方面,并且需要人工持续维护和更新。具体来说,通常来说包括:完整性检查、风险模式识别、一致性与准确性、合规性检查、量化指标监控等维度。

其次,需要将这些知识转化为一系列明确的、可执行的规则。例如:“合同必须包含‘争议解决’条款。” 、“‘责任限制’条款的上限不得低于合同总金额的 X%。”、“若合同类型为‘保密协议’,则保密期限不得少于 N 年。” 等。最后将这些规则用特定的语法(如正则表达式、关键词匹配、逻辑判断式)编码到规则引擎中。
自动化扫描与标记:
有了上述规则库之后,在实际使用时需要通过工具读取合同文本(通常使用 OCR 处理扫描件),规则引擎逐条或并行匹配合同内容与规则库中的规则,标记出违反规则、缺失条款、与标准范本不一致或存在预警关键词的地方。输出一般则是高亮显示问题条款、生成风险提示列表、给出初步的风险等级评分等。
来源:https://idp.jxdinfo.com/
1.2
局限性
语义理解的缺失:
规则引擎的主要实现逻辑是基于关键词、句式结构等表面特征进行匹配,很难理解语言的细微差别、上下文含义或真实意图。另外,对于规则库中没有预设到的措辞或条款变体,即使意思相同,也可能漏报或误报。 例如一个条款单独看可能没问题,但与其他条款结合起来就可能产生风险。
僵化与维护成本高:
其次,这种人工驱动的规则库需要持续、大量的更新和维护,成本高且容易滞后。尤其是为了覆盖更多场景,规则数量会急剧增加,导致规则间的冲突、管理复杂度会逐渐失控。
用户体验与解释性:
传统方法输出一般是一堆“规则违反”列表,缺乏对风险的深入解释和业务影响的分析,以及具体的、有针对性的修改建议,这点对于用户而言也是显然不够友好。
2
梳理了传统规则引擎的实现逻辑和局限性,这里接着介绍下这篇要展示的工作流编排逻辑。

2.1
优势互补
首先需要说明的是,这两者在合同审查中都非常重要,但扮演着不同且互补的角色。 通用规则 (上文说的传统规则引擎)作用是基础框架与合规性检查,它更像一个“体检表”,用于快速判断合同在结构上是否完整,核心条款是否缺失,以及是否存在一些基础的、普遍适用的法律或商业实践要求未被满足。通用规则也是审查的基石和起点,保证了合同的“骨架”基本正确。
而上文一直提到的负面案例 (Bad Cases)主要作用则是审查的深度和经验的体现。或者换句话说,是具体风险场景的警示。在真实业务合同中的某些条款的缺失、模糊或不当设计是如何导致实际问题的(如争议、损失、败诉等)。Bad Cases 往往与特定的合同类型、行业背景或业务逻辑紧密相关,使得风险分析更具针对性。
总结来说, 通用规则更像是“静态的知识库”,告诉你“应该是什么样的”。 而 Bad Cases 是“动态的经验库”,告诉你“曾经发生过什么问题,为什么会发生,后果如何”。 在审查中,通常会先用通用规则进行一遍“扫描”,确保基础项没有问题。然后,针对合同的特定类型、交易背景以及在初步扫描中发现的潜在疑点,去 Bad Cases 库中寻找相似情境,以进行更深入、更具针对性的风险评估和条款优化。
两者哪个更重要? 它们都重要,缺一不可,是相辅相成的。如果只看通用规则,审查可能流于表面,无法预见复杂风险;如果只看 Bad Cases,可能会缺乏系统性,遗漏一些基础但关键的问题。
2.2
Bad Cases 召回策略
进一步来说,在 Dify(或类似)工作流汇总召回 Bad Cases 时,为了确保相关性和有效性,可以考虑以下优先级顺序:
问题条款相似性:
如果新合同中的某个条款的措辞、结构或潜在逻辑缺陷,与某个 Bad Case 中明确指出并导致问题的条款高度相似,那么这个 Bad Case 的参考价值是最大的。无论合同类型或行业是否完全一致,相似的问题条款往往意味着相似的风险逻辑。 例如: 新合同的验收条款约定“甲方收到乙方交付物后,如无书面异议,则视为验收合格”,这与某个 Bad Case 中因此类“默认合格”条款引发争议高度相关。
合同类型:
这点不言自明,相同类型的合同往往具有相似的交易结构、核心目标和常见的风险领域。例如,软件开发合同通常会关注知识产权、交付验收、维护责任等,而租赁合同则更关注租赁物状况、租金支付、违约责任等。因此,来自同一合同类型的 Bad Case 更可能触及与当前审查合同直接相关的议题。 例如: 审查一份新的“软件外包开发合同”时,来自历史“软件开发服务合同”的 Bad Case 通常比来自“房屋租赁合同”的 Bad Case 更具参考性。
业务场景相似性:
行业特性和具体的业务场景会显著影响合同条款的风险权重和解释。某些在某个行业是标准做法的条款,在另一个行业可能就是重大风险。业务场景决定了合同履行的具体环境和可能的矛盾点。 例如: 一份涉及处理大量个人敏感数据的市场推广合同,在召回 Bad Case 时,与数据合规、隐私保护相关的案例(即使合同类型略有差异,但如果行业同为互联网广告或涉及用户数据处理)可能比一个不涉及敏感数据的普通服务合同的 Bad Case 更重要。
总结来说,首先看“问题像不像”:条款本身是否存在已知的风险模式? 其次看“合同大类像不像”:是不是同一类型的法律关系和交易框架? 再看“具体环境像不像”:行业惯例、业务流程是否会让这个风险更加突出或具有不同的表现形式? 在理想情况下,工作流能够综合评估这些因素,并根据匹配度给出一个加权排序的 Bad Case 列表。例如,一个与当前新合同条款高度相似、合同类型一致且行业背景也相近的 Bad Case,这样参考价值无疑是最高的。
3
下文工作流演示中所采用的样例数据包括:3 份典型的待审查合同、5 份负面案例(Bad Cases),以及 1 套基础的审查规则。除了因为保密协议无法直接使用接触的商业项目资料外,通过模拟数据其实可以更有针对性地设计合同条款和潜在风险点,从而清晰地展示工作流在识别、分析和处理这些特定问题时的核心逻辑和能力。这比使用结构复杂、包含大量无关信息的真实合同更能突出重点。
3.1
合同类型的多样性:
NC001: 软件外包开发合同:这是常见的技术服务类合同,涉及项目范围、交付、验收、知识产权等多个关键点,能充分测试工作流对复杂业务逻辑的理解。

NC002: 单向保密协议 (接收方视角):这类合同专注于信息保密,条款相对聚焦,但对定义的准确性、义务的合理性要求很高。从“接收方视角”出发,可以测试工作流是否能识别出对单方不利的潜在风险。
NC003: 市场推广服务合同:这类合同通常包含效果承诺(KPI)、成果归属等,能测试工作流对服务效果衡量、知识产权转移等方面的审查能力。
三份合同里经过设计都预埋了些对应场景中一些典型风险点,这些新合同中的条款,很多都能直接或间接地与 Basic_rules.md 中的通用规则以及 Bade cases 文件夹中案例的风险点对应起来,便于工作流进行参照和匹配。

3.2
负面案例 (Bad Case 1-5) 的设计
覆盖常见的合同类型和风险领域
BC001: 软件开发服务合同 – 验收、违约责任、争议解决。

BC002: 保密协议 (NDA) – 保密范围、期限、违约责任。
BC003: 房屋租赁合同 – 交付标准、押金、提前终止、续租。
BC004: 产品采购合同 – 质量标准、验收期、责任限制。
BC005: 咨询服务合同 – 付款条件、成果交付、知识产权、终止条款。
这种多样性确保了工作流的知识库具有一定的广度。
结构化的风险总结
每个 Bad Case 都清晰地列出了 identified_risks, problematic_clauses_summary, 和 suggestion_or_lesson。这种结构化信息非常适合 LLM 进行学习和提取,能够让工作流更准确地理解历史风险的上下文和解决方案。

此外,这些案例中暴露的问题,如定义模糊、权利义务不对等、缺少关键保护、责任限制不合理等,都是合同审查中非常经典和常见的风险类型,具有很好的代表性。
通过这种设计,当新的待审查合同进入工作流时,通用规则(Basic_rules.md)提供了普适性的检查清单。新合同中的潜在风险点,可以通过与 Bad Cases 中的 keywords_for_retrieval 和 identified_risks 进行匹配,快速找到相似的历史案例。Bad Cases 中的 suggestion_or_lesson 可以为新合同的审查报告提供具体的修改方向和风险警示。
4
这个工作流实现了一个多阶段的合同审查流程,具体来说分为以下四个部分:

4.1
输入收集与预处理
收集用户提供的合同文件、特定关注点、合同类型和通用审查规则,提取并转换合同文本。



工作流触发的输入页面

注:“合同文本提取”节点输出的是包含单个字符串的列表’合同内容’,而后续 LLM 或 Template 节点可能期望的是纯字符串合同内容。最初我忽略了这种细微的类型差异,导致 Prompt 渲染异常或 LLM 理解偏差,后来增加 Template 节点进行显式数据类型转换。
4.2
初步风险识别
使用 LLM 对合同文本进行初步分析,快速识别潜在风险点。

4.3
相似案例检索与分析
根据初步风险和合同类型,从知识库中检索相关的历史风险案例 (bad cases),并由另一个 LLM 提取这些案例的关键风险点。


4.4
综合审查与报告生成
将新合同文本、初步风险分析、相关历史案例风险、通用审查规则以及用户特定关注点整合起来,形成一个详细的提示,交由一个强大的 LLM 进行深度审查,并生成结构化的合同审查报告。


注:即便所有输入信息都正确传递给了最终的审查 LLM,它也可能因为 Prompt 不够优化而无法产出高质量的、有针对性的报告。解决方案是优先使用大参数的高阶 LLM,其次是尽可能设计结构化、任务明确、信息聚焦的最终 Prompt。
5


6
感兴趣的推荐从输入信息质量深化(Bad Case 处理)、输出结果行动性增强(修改建议)和系统整体智能与用户体验提升(迭代与反馈)三点着手。
6.1
通过 Loop 节点对召回的 Bad Cases 进行逐一分析
当前的 Bad Case 风险点总结是将所有召回的 Bad Cases 结果作为一个整体交由单个 LLM 调用进行处理,要求其“对于输入文本中明确存在的每一个案例”进行总结。 可以考虑换成引入一个 Loop(循环)节点。 循环的输入是召回的 Bad Case 列表,每次迭代处理一个 Bad Case,进行更细致的关联性分析。
6.2
引入“条款级风险定位与具体修改建议生成”能力
当前工作流的输出是一份“合同审查报告”,其中包含修改建议,但工作流本身不能直接生成可用的、具体的条款修改文本。 可以考虑调整“新合同的审核”节点的 LLM 提示词,明确要求其不仅识别风险,还要定位到新合同中的具体问题条款编号和原文,进而针对识别出的每一个主要风险点,尝试生成 1-2 个具体的、可操作的条款修改建议文本。
6.3
建立迭代式审查与用户反馈机制
当前工作流是一个单向的处理流程,用户输入合同,得到一份审查报告。在输出审查报告后,如果能允许用户选择报告中的某个风险点,然后触发一个新的、更聚焦的 LLM 调用,针对该点进行更深入的解释、提供更多替代修改方案、或分析特定修改方案的利弊,会更助于得到一个更加理想的结果。(这点类似 OpenAI、Gemini 的 Deep Research 的交互逻辑。)
7
RAG 的进阶应用,不仅仅是简单的信息检索和问答,是利用 RAG 作为核心能力之一,结合更复杂的逻辑、多步骤处理、外部工具调用、模型间的协作,来完成更复杂的任务或驱动更智能的交互。
24 年对于 Agent 爆发的预期越来越高,在多个细分场景 RAG(特别是能够处理企业内部各种静态文档、数据库,并能连接外部工具和信息的进阶 RAG)将不再是“锦上添花”,而是会成为构建企业级大模型应用落地的基础要求和核心组件。它解决了 LLM 的幻觉问题、知识更新问题,并为 Agent 提供了行动和决策的“事实依据”。这篇介绍的合同审查工作流也是这个理念的实践,合同生成的案例预计 6 月初发出,欢迎蹲一蹲。
Anyway,充分实践才是硬道理。
(项目工程文件与样例数据有需要请移步至知识星球)
