资讯动态

CTRAG实战:用RAG+大模型实现可追溯的自动化合规检查

发布时间:2026/8/28 17:38:20 来源:尧图企业网站定制
在许多工程与业务场景中“合规检查”Compliance Checking都是一项高频率、高成本、高责任的工作。比如建筑项目中检查设计图纸是否满足消防规范制造企业中核对设备维护记录是否符合安全标准金融场景中审核合同条款是否违反监管要求。传统做法依赖人工逐条比对效率低且容易遗漏而直接让大语言模型LLM读文档、给结论又常常出现“幻觉”、格式不稳定、条款引用错误等问题。本文要讨论的CTRAGIn-Context Retrieval-based Framework for Automated Compliance Checking using LLMs正是为了解决这一矛盾而提出的框架思路。它将检索增强生成RAG、上下文学习In-Context Learning与合规检查任务结合起来用“先检索、再推理、后判断”的方式让 LLM 在回答合规结论时能追溯规则来源并输出相对稳定的结构化结果。下面我会从概念原理讲起再到代码级实现逐步拆解这套框架的完整链路。无论你是算法工程师、后端开发还是正在做文档智能化的技术选型都能从中获得可落地的参考。1. 背景与核心概念1.1 合规检查到底难在哪里合规检查的核心目标是判断一条事实记录或一份文档是否满足一组规则或标准。这里的“规则”可以是法定条文、企业制度、行业规范、合同条款等。传统做法可以抽象成两条路规则引擎路线把合规规则翻译为 if-else 逻辑、决策表或 Drools 等规则表达式由程序自动执行。优点是结果可控缺点是规则经常变化维护成本极高。人工审核路线由业务专家逐条比对。优点是理解能力强能处理模糊语义缺点是速度慢、人员培训周期长、标准不统一。LLM 出现后很多人尝试直接用大模型做合规判断。比如把规则和待检查文本一起放进 Prompt让模型回答“是否合规”。这种方式简单粗暴但存在三个致命问题规则文本过长合规条款往往很多全部塞进 Prompt 会超出上下文窗口或导致模型注意力分散。知识过时合规规则会修订模型训练数据中的旧规则可能产生误导。幻觉与不可追溯模型可能给出一个看似合理但没有依据的结论用户无法核验它对在哪、错在哪。这些痛点正是 CTRAG 框架要解决的。1.2 什么是 CTRAGCTRAG 的全称是Contextual/In-Context Retrieval-Augmented Generation直译过来是“基于上下文检索增强生成”或“上下文检索增强框架”。它属于 RAGRetrieval-Augmented Generation检索增强生成在特定垂直任务上的改进变体。可以把 CTRAG 理解为在调用大模型进行合规判断之前先从规则知识库中检索出与当前待检文本最相关的若干条规则再将这些规则作为上下文注入 Prompt让 LLM 在“知道该引用哪几条规则”的前提下给出结论。与通用 RAG 相比CTRAG 更强调In-Context的作用——即检索出来的内容不是简单地拼在 Prompt 后面而是经过结构化组织让模型能够把“待检查项”与“规则条款”一一对应并明确输出推理过程。1.3 CTRAG 的典型应用场景建筑工程合规判断施工方案、设计图纸说明是否满足消防、结构安全等规范。企业制度审计比对新发布的内部管理制度与国家法规、行业标准。合同风险审查检查合同中的付款条件、违约责任条款是否符合公司模板要求。数据安全合规判断数据处理流程描述是否满足《数据安全法》《个人信息保护法》等要求。供应链合规审核供应商提交的资质文件是否满足准入规则。凡是“事实记录 规则文本 人工判断”重复性高的场景CTRAG 都有落地空间。2. 相关技术原理拆解2.1 从 RAG 到 CTRAG两种思维的区别RAG 的核心流程是user query → retrieve → augment → generate。它把检索到的文档片段作为参考信息帮助生成更准确的答案。CTRAG 在这个基础上把目标从“生成答案”调整为“进行合规判断”因此需要在 Prompt 设计和结果约束上做几层改造。维度通用 RAGCTRAG检索目标最大相似度的文档片段与合规判断相关的规则条款上下文组织通常是“问题 文档片段”“待检对象 规则集 判断要求 输出格式”输出结果自由文本答案结构化合规结论通过/不通过/待确认核心指标答案准确率、相关性精确率、召回率、条款引用正确率可解释性弱强需要返回引用条款编号2.2 In-Context Learning 为什么重要In-Context Learning上下文学习指不更新模型参数仅通过 Prompt 中的示例和提示文本让大模型快速适应新任务的能力。CTRAG 利用这一点把合规判断任务转换成一种“少样本分类推理”问题。举个例子在 Prompt 中给出一个示例规则建筑高度大于 27m 的住宅建筑属于高层民用建筑应设置消防电梯。 待检信息某住宅楼建筑高度 35m设计文件中未设置消防电梯。 结论不通过违反规则编号 GB-2023-015。模型看到这样的示例后会模仿这种推理链路处理后续输入。这么做的好处是不需要为每类合规规则重新训练模型只要调整 Prompt 示例就能适配新业务。CTRAG 把“检索”当作启动上下文学习的触发条件——先检索出相关规则再放入上下文让示例和真实规则能对应起来。2.3 合规检查的核心流程抽象无论具体业务如何自动化合规检查都可以抽象成下面五步输入解析把待检文档转成结构化或半结构化文本段落。规则匹配从规则库中检索候选规则。上下文构造将候选规则与输入文本组织成 Prompt。推理判断由 LLM 输出判定结论和依据。结果校验检查输出格式解析出结构化结果必要时做人工复核。CTRAG 就是对这个流程的系统化实现。3. 环境准备与实验设计3.1 运行环境CTRAG 本身不是一个需要安装的第三方包而是一种实现方法。实际开发时建议环境如下操作系统Linux / macOS / Windows 均可生产环境推荐 Linux。Python3.9 及以上。LLM APIOpenAI 兼容接口、国内大模型 API或通过 Ollama、vLLM 等部署的开源模型。向量数据库Chroma、FAISS、Milvus、Elasticsearch 均可。嵌入模型如 text-embedding-3-small、bge-large-zh、m3e-base 等。需要强调的是版本必须根据你的项目实际情况调整。本文示例采用常见的 OpenAI 兼容接口和 Chroma 作为向量库重点演示框架思路不绑定某一家的商业产品。3.2 数据准备为了让示例可以运行需要准备两类数据规则库一组带编号的合规条款每条记录包含“条款编号”“条款内容”“适用范围”。待检数据若干条业务描述例如“某住宅楼设计高度 35m未设置消防电梯”。在真实项目中规则库往往以 Excel、Word、PDF、数据库表等形式存在。建议先统一清洗为 JSON 格式再写入向量库。3.3 评测指标合规检查的结果不要只看“准确率”建议至少关注以下指标指标含义精确率Precision被判为不合规的样本中真正不合规的比例召回率Recall实际不合规的样本中被模型找出的比例条款引用正确率模型引用的规则编号与人工标注一致的比例结构化解析成功率LLM 输出能被程序稳定解析为 JSON 的比例延迟单条检查的平均耗时4. CTRAG 框架设计与核心实现4.1 框架整体流程CTRAG 的整体流程可以画成如下阶段待检文本 │ ▼ 【输入解析】 → 如果文档是 PDF/Word先转成纯文本再切段 │ ▼ 【向量化】 → 将待检段落转成向量 │ ▼ 【规则检索】 → 在规则向量库中查询 Top-K 相似条款 │ ▼ 【上下文构造】 → 组装 Prompt任务描述 Few-shot 示例 检索到的规则 待检文本 │ ▼ 【LLM 推理】 → 输出 JSON 格式判定结果 │ ▼ 【结果解析】 → 提取判定结果、引用条款、风险说明这个流程的意义在于每一步都是可插拔的。检索可以换向量库LLM 可以换模型结果解析可以换规则表达式。4.2 知识库构建规则库构建要考虑两个层次存储层原始规则以结构化 JSON 保存方便人工维护。向量层将规则内容切分后向量化存入向量库供相似度检索。规则切分是重点。不要把一条规则拆得太碎也不要把多条规则混在一起。建议以“一条完整约束”为一个最小检索单元。4.3 检索模块检索模块负责从规则库中找出与待检文本最相关的规则。常用方法是把待检文本 embedding 成向量。在向量库中执行相似度检索。返回 Top-K 条规则K 一般取 38。这里有个容易犯的错误直接对整个大文档做向量检索效果往往不好。更好的做法是检索时使用“段落级”文本。如果规则存在版本差异把版本号也作为过滤条件。4.4 提示词构建CTRAG 的 Prompt 是整个框架的灵魂可以分成四层系统角色你是一名合规审核专家... 任务描述请根据给定规则判断待检信息是否合规。 检索到的规则以 JSON 数组形式列出。 Few-shot 示例一个完整的“规则待检信息结论”示例。 待检输入当前需要判断的文本。注意Few-shot 示例一定要和真实检索出来的规则“共格式”——示例中的规则编号、结论格式要和被检索规则的输出格式一致否则模型可能模仿出错误格式。4.5 合规判断与结果解析LLM 输出不能直接入库必须经过解析。建议强制模型输出 JSON{ is_compliant: false, violated_rules: [GB-2023-015], reason: 建筑高度35m超过27m应设置消防电梯但未设置, suggestions: 补充消防电梯设计 }后端再用json.loads解析。如果担心模型输出不规范可以在 Prompt 中要求“只输出 JSON不要其他内容”并对异常输出做重试。5. 完整 Python 示例下面以一个最小可运行的 CTRAG 示例为例演示从规则入库到合规判断的完整过程。5.1 创建项目结构项目结构如下ctrag-demo/ ├── data/ │ └── rules.json # 规则库 ├── src/ │ ├── __init__.py │ ├── vector_store.py # 向量库操作 │ ├── retriever.py # 检索模块 │ ├── prompt_builder.py # Prompt 构造 │ ├── llm_client.py # LLM 调用 │ └── compliance_checker.py # 主流程 └── main.py # 入口5.2 准备规则数据文件路径data/rules.json。这里只列两条示例规则实际项目中可以扩展到上千条。[ { rule_id: GB-2023-015, rule_text: 建筑高度大于27m的住宅建筑属于高层民用建筑应设置消防电梯。, scope: 住宅建筑 }, { rule_id: GB-2023-018, rule_text: 高层民用建筑应设置火灾自动报警系统且系统应具备远程启动功能。, scope: 高层民用建筑 }, { rule_id: GB-2023-021, rule_text: 消防车道净宽度和净空高度均不应小于4m。, scope: 民用建筑 } ]5.3 向量库操作文件路径src/vector_store.py。这里使用 Chroma 作为向量库embedding 函数可以通过 OpenAI 兼容接口实现也可以替换为本地模型。import json from typing import List, Dict class RuleVectorStore: def __init__(self, collection_name: str rules): try: import chromadb except ImportError: raise ImportError(请先安装 chromadb: pip install chromadb) self.client chromadb.Client() self.collection self.client.get_or_create_collection(collection_name) def load_rules_from_json(self, json_path: str, embed_func): with open(json_path, r, encodingutf-8) as f: rules: List[Dict] json.load(f) ids [rule[rule_id] for rule in rules] documents [rule[rule_text] for rule in rules] metadatas [{scope: rule.get(scope, ), rule_id: rule[rule_id]} for rule in rules] embeddings [embed_func(doc) for doc in documents] self.collection.upsert( idsids, documentsdocuments, metadatasmetadatas, embeddingsembeddings ) return len(rules)需要说明的是embed_func是外部传入的向量化函数这样可以灵活切换不同 embedding 模型。5.4 检索模块文件路径src/retriever.py。检索模块根据待检文本返回 Top-K 条规则。from typing import List, Dict class RuleRetriever: def __init__(self, store): self.store store def retrieve(self, query: str, embed_func, top_k: int 3) - List[Dict]: query_embedding embed_func(query) result self.store.collection.query( query_embeddings[query_embedding], n_resultstop_k ) rules [] # 遍历检索结果 for i in range(len(result[ids][0])): rule_id result[ids][0][i] rule_text result[documents][0][i] metadata result[metadatas][0][i] distance result[distances][0][i] if distances in result else None rules.append({ rule_id: rule_id, rule_text: rule_text, scope: metadata.get(scope, ), score: 1 - distance if distance is not None else 0.0 }) return rules5.5 Prompt 构造模块文件路径src/prompt_builder.py。这里实现 CTRAG 最核心的 Prompt 组装逻辑。from typing import List, Dict SYSTEM_PROMPT 你是一名专业的合规审核专家擅长根据给定规则对业务文本进行合规判断。 FEW_SHOT_EXAMPLE 规则 编号GB-2023-015 内容建筑高度大于27m的住宅建筑属于高层民用建筑应设置消防电梯。 待检信息某住宅楼建筑高度35m设计文件中未设置消防电梯。 输出 { is_compliant: false, violated_rules: [GB-2023-015], reason: 建筑高度35m超过27m属于高层住宅建筑应设置消防电梯但未设置。, suggestions: 补充消防电梯设计并复核建筑平面布局。 } class PromptBuilder: def build_prompt(self, text: str, rules: List[Dict]) - str: rules_block \n.join( [f编号{r[rule_id]}\n内容{r[rule_text]} for r in rules] ) prompt f 请根据下列规则对待检信息进行合规判断。 ### 检索到的规则 ### {rules_block} ### 判断要求 ### 1. 如果待检信息违反一条或多条规则is_compliant 为 false。 2. violated_rules 中列出所有被违反的规则编号。 3. reason 必须说明推理过程并引用具体规则内容。 4. 只输出 JSON不要输出其他文字。 ### 示例 ### {FEW_SHOT_EXAMPLE} ### 待检信息 ### {text} return prompt5.6 LLM 调用模块文件路径src/llm_client.py。这里封装了大模型调用兼容 OpenAI 接口也可以替换成其他厂商的 SDK。import json from typing import Dict import openai class LLMClient: def __init__(self, api_key: str, base_url: str, model: str gpt-4o-mini): self.client openai.OpenAI(api_keyapi_key, base_urlbase_url) self.model model def complete_json(self, system_prompt: str, user_prompt: str, max_retries: int 2) - Dict: for attempt in range(max_retries): try: response self.client.chat.completions.create( modelself.model, messages[ {role: system, content: system_prompt}, {role: user, content: user_prompt} ], temperature0.1, response_format{type: json_object} # 如果模型支持 ) content response.choices[0].message.content return json.loads(content) except json.JSONDecodeError: if attempt max_retries - 1: raise raise RuntimeError(LLM 输出不是合法 JSON)注意response_format{type: json_object}并不是所有模型都支持。如果不支持可以去掉该参数并在 Prompt 中反复强调 JSON 输出。5.7 主流程文件路径src/compliance_checker.py负责串联整个 CTRAG 流程。import os from .vector_store import RuleVectorStore from .retriever import RuleRetriever from .prompt_builder import PromptBuilder, SYSTEM_PROMPT from .llm_client import LLMClient class ComplianceChecker: def __init__(self, rules_json_path: str, embed_func, api_key: str, base_url: str, model: str): self.store RuleVectorStore() self.store.load_rules_from_json(rules_json_path, embed_func) self.retriever RuleRetriever(self.store) self.prompt_builder PromptBuilder() self.llm_client LLMClient(api_keyapi_key, base_urlbase_url, modelmodel) self.embed_func embed_func def check(self, text: str, top_k: int 3) - dict: rules self.retriever.retrieve(text, self.embed_func, top_ktop_k) user_prompt self.prompt_builder.build_prompt(text, rules) result self.llm_client.complete_json(SYSTEM_PROMPT, user_prompt) return { input_text: text, retrieved_rules: rules, result: result }5.8 入口与运行文件路径main.py。import os from src.compliance_checker import ComplianceChecker # 将文本向量化这里以 OpenAI 兼容接口为例 def embed_func(text: str): import openai client openai.OpenAI(api_keyos.getenv(OPENAI_API_KEY), base_urlos.getenv(OPENAI_BASE_URL)) resp client.embeddings.create( modeltext-embedding-3-small, inputtext ) return resp.data[0].embedding if __name__ __main__: checker ComplianceChecker( rules_json_pathdata/rules.json, embed_funcembed_func, api_keyos.getenv(OPENAI_API_KEY), base_urlos.getenv(OPENAI_BASE_URL), modelgpt-4o-mini ) text 某住宅楼建筑高度35m设计文件中未设置消防电梯。 output checker.check(text) print(output[result])运行命令export OPENAI_API_KEY你的密钥 export OPENAI_BASE_URLhttps://api.openai.com/v1 python main.py5.9 预期输出如果一切正常控制台会输出类似下面的 JSON{ is_compliant: false, violated_rules: [GB-2023-015], reason: 建筑高度35m超过27m属于高层住宅建筑应设置消防电梯但未设置。, suggestions: 补充消防电梯设计并复核建筑平面布局。 }同时output[retrieved_rules]中可以看到检索命中了哪些规则方便排查问题。6. 实验与对比分析6.1 对比基线设置要验证 CTRAG 的效果建议设置三组对比Baseline 1直接让 LLM 回答不提供任何外部规则只看模型内部知识。Baseline 2把全部规则拼进 Prompt 的标准 RAG 方式不做检索适合规则库很小的情况。CTRAG本文框架先检索 Top-K 规则再注入 Prompt。在规则库较大、单条 Prompt 无法容纳全部规则时Baseline 2 会直接失效而 CTRAG 可以稳定工作。6.2 对比维度建议从以下维度记录结果对比项直接 LLM全量规则注入CTRAG能否处理大规模规则库否否受上下文限制是结论是否可追溯否是是条款引用正确率低中高推理延迟低高输入过长中对规则更新的适应性差中好6.3 实验注意事项在实验时需要确保所有对比使用相同的测试集和相同的 LLM 模型否则结果不可比。另外建议把测试集按照“是否违反规则”分层抽样保证正负样本均衡否则精确率和召回率会出现虚高。7. 常见问题与排查思路7.1 检索不到相关规则现象待检文本明明违反了某条规则但检索返回的 Top-K 中没有这条规则。可能原因规则文本与待检文本用词差异太大比如规则写“消防电梯”业务描述写“疏散用梯”。Embedding 模型对专业术语理解不足。规则切分过碎导致语义不完整。解决思路检查规则库质量补充同义词和近义改写。换用领域相关的 embedding 模型。增大 top_k 值从 3 调整到 5 或 8。增加“关键词召回”作为 BM25 融合检索与向量检索双路召回。7.2 LLM 输出格式不稳定现象模型偶尔输出 JSON 以外的内容导致json.loads失败。解决思路在 Prompt 中明确“只输出 JSON不要输出 markdown 代码块”。开启模型的 JSON mode。增加重试机制解析失败后让模型重新输出。用正则提取第一个{到最后一个}之间的内容作为兜底。7.3 规则之间存在冲突现象两条规则都命中待检文本但结论相反。解决思路在规则维护时增加规则优先级字段。在 Retriever 返回结果时按优先级排序。在 Prompt 中说明“如果规则冲突以优先级高的规则为准”。7.4 LLM 幻觉导致引用不存在的规则现象violated_rules中出现规则库中不存在的编号。解决思路在结果解析阶段对规则编号做白名单校验。如果发现规则编号不在当前规则库内标记为“疑似幻觉”转入人工复核。7.5 常见问题速查表问题现象常见原因解决思路检索结果相关度低embedding 模型不匹配更换模型或融合关键词检索LLM 输出解析失败Prompt 约束不足或模型不支持 JSON mode增加重试、正则兜底违规结论不一致规则冲突或 top_k 过大设定优先级、调整 top_kPrompt 超过上下文窗口规则检索太多或待检文本太长缩小 top_k、对待检文本切段线上效果与测试不一致测试集和真实数据分布不同扩大真实样本验证集8. 工程化最佳实践8.1 规则库要版本化管理合规规则一定会变化。建议在规则表中增加version和effective_date字段每次修订都新增一条记录而不是覆盖原记录。这样既能实现“按时间点回放”也能支持不同版本的合规判断需求。例如{ rule_id: GB-2023-015, version: 2024-06, effective_date: 2024-06-01, rule_text: ..., scope: 住宅建筑 }在检索时可以根据待检文本对应的时间点过滤启用版本避免“拿新规则审旧项目”的乌龙。8.2 重视人工复核闭环LLM 合规判断不能 100% 自动化至少要在初次上线阶段保留人工复核环节。建议在结果中标记置信度检索到的规则数量为 0 → 低置信度。LLM 引用了白名单外的规则 → 低置信度。规则冲突且无法消解 → 低置信度。低置信度结果进入人工复核队列。8.3 日志与审计合规检查是强审计场景必须记录输入文本。检索返回的规则列表。完整 Prompt。LLM 输出原始内容。解析后的结构化结果。人工复核结果。记录完整 Prompt 很重要否则后期无法复现模型当时为什么会给出这个结论。8.4 安全与权限边界如果合规数据涉及业务敏感信息需要注意三点最小权限原则只有授权人员能查看完整 Prompt 与原始文本。数据脱敏进入向量库和 LLM 请求前对敏感字段做脱敏。API 密钥管理不要硬编码在代码中使用环境变量或 Secrets Manager。8.5 性能优化方向缓存如果多条待检文本的内容高度相似可以启用检索结果缓存避免多次调用向量库。批处理LLM 调用支持 batch可以把合规判断任务批量下发。模型分层简单规则用轻量模型判断复杂模糊场景才调用大模型控制成本。9. 总结与进一步学习CTRAG 是一个把 LLM 与检索增强、上下文学习结合起来的合规检查框架。它的核心价值在于让大模型不是凭空“想”出一个合规结论而是在给定规则上下文中“推理”出可追溯的合规结论。从实现角度你需要掌握五样东西规则知识库的结构化建模。向量检索的基本用法。Prompt 中 Few-shot 与规则上下文的组织方式。LLM 结构化输出的解析与容错。人工复核与审计日志的闭环设计。如果你准备在真实项目中落地 CTRAG我建议按下面的路线继续深入先做一个小规模 PoC比如 2050 条规则、100 条测试样本验证框架可行。再扩展规则库引入版本管理和检索过滤。接着做评测集把精确率、召回率和条款引用正确率跑出来。最后再接人工复核流程和监控告警。合规检查本质上是一项责任重大的工作任何时候都不要把模型的输出直接当作最终裁决。让 LLM 做“初筛者”让人工做“复核者”这套框架才能发挥最大价值。如果你对 RAG 的工程落地、向量数据库选型或 Prompt 调优有兴趣可以在下一篇文章中继续深入。希望这篇 CTRAG 的拆解能帮你在自动化合规方向上少走一些弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价