十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从RAG到CTRAG:构建自动化合规检查的检索增强生成框架

从RAG到CTRAG:构建自动化合规检查的检索增强生成框架 1. 核心能力速览CTRAG 的全称是Compliance Testing with Retrieval-Augmented Generation它并不是单一模型而是一套面向自动化合规检查的In-Context Retrieval-based Framework。简单理解当 LLM 处理合规问题时不是直接凭训练记忆作答而是先从外部文档库中检索相关条款再把检索结果作为上下文注入模型让模型基于“真实条款 当前待检内容”完成判断。这套流程正好对应了 RAG 的经典三段式索引构建 → 语义召回 → 上下文增强生成但 CTRAG 更强调In-Context设计也就是“把合规标准放进上下文里再让模型作答”。能力项说明项目类型In-Context RAG 框架面向合规检查Compliance Checking核心技术检索增强生成RAG、LLM 推理、向量检索、上下文注入解决问题的方向自动化检查文本/文档是否符合特定规范、条例或合同条款主要输入合规标准文档规范、法规、合同条款 待检查文本/图片描述主要输出合规/不合规判断、异常条款定位、解释说明、引用来源推荐硬件取决于所选 LLM 与向量库规模云端 API 模式下 CPU 即可本地模型需要按显存评估显存占用不确定需按实际模型版本与推理参数测试支持平台常规 Python 环境、云服务器、本地 GPU 工作站均可启动方式建议通过 Python 脚本或 API 服务启动流程分为知识库构建、检索接口、LLM 推理三部分是否支持 API框架层面可封装为标准 HTTP 服务需按项目自行实现是否支持批量任务支持需要设计批量读入、批量推理、结果落盘与失败重试适合场景建筑规范审查、招投标合规、合同条款比对、法律条文初筛、金融监管文本核对、企业内部制度审查技术要求Python、向量数据库/索引、Embedding 模型、LLM API 或本地模型本文不会涉及具体的现成仓库路径或一键包因为 CTRAG 属于研究型框架更侧重“自己搭建一套合规检查链路”。我会从零给出可落地的框架搭建思路、检索链路代码模板、合规检查测试方法和排查清单你拿到之后可以替换自己的文档库和待检数据直接跑通一条最小可用的合规检查流程。2. 适用场景与使用边界合规检查是一项依赖“标准答案”的任务和普通拔高文本生成不一样。普通问答可以灵活发挥但合规检查必须落到具体条款上。CTRAG 的价值正在于把标准文档变成召回源让 LLM 不再是“随口说”而是“看着条款说”。2.1 适合什么场景合同条款比对把标准合同模板加入知识库让模型检查新合同里是否出现缺少条款、赔偿金额异常、义务描述被删改等问题。建筑规范审查检查设计说明、施工方案中的技术参数是否违反对应规范例如消防间距、材料等级、结构荷载等。法律法规初筛面对新发布的法规或监管文件快速检索企业制度中可能存在冲突的条款。金融与审计合规检查产品宣传文案、业务协议中是否包含被监管禁止的表述。企业内部制度审核将公司制度导入知识库审核新发布的内部通知是否与上位制度冲突。这类场景有一个共同点存在明确的标准文档并且判断需要引用具体条号。这正是 RAG 的舒适区。2.2 不适合什么场景开放式合规咨询比如“我们公司合规体系应该怎么建设”这类问题没有唯一标准答案不适合做条款匹配。强多模态规范很多规范的判断依据是图纸、照片、现场情况框架需要先接入视觉模型才能处理单纯文本 RAG 无法覆盖。超大规模实时审查如果每分钟要审查数万份文档需要考虑任务队列和计算资源RAG 链路本身不是瓶颈但 Embedding 和 LLM 推理的吞吐是瓶颈。需要人工强判断的场景LLM 只能做初步筛查最终判断必须由具备资质的人员完成。2.3 合规与使用边界这一点必须强调。合规检查涉及法规、合同、企业内部敏感信息使用框架时要注意四件事数据授权知识库里的法规、标准、合同必须确保来源合法不能把未授权内部资料直接丢进公开云服务。隐私保护待检查文档可能包含个人隐私或商业机密优先选择私有化部署或本地模型。结果复核LLM 存在幻觉合规判断不能直接替代人工审核尤其不能用于出具正式审计意见。版权合规导入 PDF、扫描件、网页内容时要确认是否有复制和再分发的权利。3. CTRAG 工作原理与框架组成CTRAG 的核心是“先检索、后判断”。整个框架可以拆成五个模块3.1 知识库索引模块把合规标准文档拆分成适合检索的片段这项工作直接决定召回质量。如果文档是 PDF文字层可能缺失需要先做 OCR。拆分时不能机械按页切也不能直接按字符数切。最稳妥的做法是按章节和条款边界切分再控制每个片段长度。对于建筑规范来说可以按“节 - 条 - 款”切分对于合同可以按“条款主题”切分。每个片段建议控制在 300 到 800 个 token 内。切得太短会丢失上下文切得太长会增加后续 LLM 的上下文负担也会降低检索精度。3.2 向量检索模块将每个片段向量化存入向量数据库或索引。查询时对待检查文本做同样的向量化然后召回 Top-K 个最相关的条款片段。选型上有两种路线轻量路线使用chromadb或faiss适合单机、千级到十万级片段的场景。服务化路线使用elasticsearch、milvus、qdrant适合百万级片段和线上服务场景。Embedding 模型的选择直接决定语义召回上限。可以考虑通用中文 Embedding比如bge-large-zh、bge-m3等如果领域术语很多需要考虑领域微调或做同义词扩展。更稳妥的判断是先拿一批典型问题测试 Top-5 召回率再决定是否需要换模型。3.3 上下文组装模块召回结果不是直接把 Top-K 片段全部塞给 LLM。CTRAG 强调 In-Context 设计所以上下文组装要解决一个问题如何让模型在有限上下文窗口里尽量看到完整的合规判断依据。推荐做法是先召回 Top-10 候选片断。用轻量重排模型或规则对候选片断进行精排。再把精排后的 Top-3 到 Top-5 片段拼接进提示词。要求 LLM 输出时标注“依据第 X 条”。通过这种方式既解决了“上下文窗口塞不下全部知识库”的问题也解决了“召回了但没用对片段”的问题。3.4 LLM 推理模块LLM 负责最终的合规判断。判断部分可以有两种设计抽取式让模型从待检文本中寻找与条款冲突的内容输出“违反/不违反/无法判断”和对应条款。生成式让模型输出完整的核查意见包括问题描述、违反条款、严重程度、修改建议。从工程稳定性角度看建议先做抽取式再补充生成式说明。因为抽取式可以配合结构化输出方便后续自动处理和二次核验。3.5 输出与证据回溯模块合规检查最怕“模型说违规但不知道依据在哪”。CTRAG 框架里输出必须携带证据。建议输出结构化 JSON{ check_result: 不通过, violated_clauses: [ { clause_id: GB 50016-2014 第5.2.2条, evidence: 待检文档第3.1节明确写出疏散门宽度为0.8m小于规范要求的1.4m } ], risk_level: 高, suggestion: 门宽度应不小于1.4m }有了这个结构后续可以做自动统计分析哪些条款是最容易违反的待检文档风险集中在哪个章节这些信息对合规审查业务非常有价值。4. 本地部署环境准备与前置条件CTRAG 的部署不是“双击运行”这么简单你至少需要准备三类依赖基础运行环境、知识库与向量检索组件、LLM 推理环境。4.1 基础环境清单下面是一个通用检查清单实际路径和版本需要根据项目调整项目建议操作系统Windows 10/11、Ubuntu 20.04、CentOS 7Python3.9 到 3.11避免过高版本导致依赖不兼容包管理工具pip、conda文档解析库pypdf、pdfplumber、fitzPyMuPDF、PaddleOCR文本处理库langchain、llama-index可选向量库chromadb、faiss、qdrant、milvus 按需求选一LLMOpenAI 兼容 API 或本地推理框架vLLM、Ollama、XinferenceGPU可选本地模型需要显存按模型定API 模式不需要 GPU4.2 LLM 与 Embedding 的选型思路因为没有指定具体模型我给一套保守选型建议Embedding 模型优先选中文语义检索效果稳定的开源模型比如BAAI/bge-large-zh-v1.5。显存不够时考虑 API 形式的 Embedding 服务。LLM 推理如果你有 16G 以上显存可以部署 7B 到 14B 的开源 Chat 模型如果只有 API Key直接调用线上模型更省事。本地部署 vs APIAPI 模式开发快、效果稳定但数据会送到外部服务本地模式部署麻烦但数据不出内网。合规检查业务涉及敏感数据更推荐本地化方案但如果只是内部测试可以先接 API 验证链路。4.3 数据准备你需要准备两类数据标准文档合规规范、合同模板、法律法规。待检文档需要被判定是否合规的文本。建议建立两个独立目录并且在文件名中包含版本日期data/ ├── standard_docs/ # 标准知识库 │ ├── 建筑防火规范_2022.pdf │ └── 劳动合同模板_v3.docx └── to_check/ # 待检文档 ├── 项目A设计方案_0320.docx └── 合同草案_客户B.docx5. CTRAG 检索链路搭建与启动方式下面给出一套最小可运行的代码框架。注意这是通用模板不是某个特定项目的官方代码你需要根据自己的文档格式和向量库类型调整。5.1 安装依赖pip install fastapi chromadb sentence-transformers pypdf langchain openai5.2 构建知识库索引import chromadb from chromadb.utils import embedding_functions from pypdf import PdfReader import hashlib # 1. 初始化客户端 client chromadb.PersistentClient(path./ctrag_db) embedding_fn embedding_functions.SentenceTransformerEmbeddingFunction( model_nameBAAI/bge-large-zh-v1.5 ) collection client.get_or_create_collection( namecompliance_standard, embedding_functionembedding_fn ) # 2. 切分文档 def split_pdf_by_clause(pdf_path, max_chars500): 按页和段落切分PDF实际需要按规范条款边界优化 reader PdfReader(pdf_path) chunks [] for page_no, page in enumerate(reader.pages): text page.extract_text() if not text or len(text.strip()) 10: continue # 简单切分通用场景建议按章节和条款切分 for i in range(0, len(text), max_chars): chunk text[i:i max_chars] chunks.append((fpage_{page_no}_chunk_{i}, chunk)) return chunks standard_path data/standard_docs/建筑防火规范_2022.pdf chunks split_pdf_by_clause(standard_path) # 3. 写入向量库 ids [hashlib.md5(chunk[0].encode()).hexdigest() for chunk in chunks] docs [chunk[1] for chunk in chunks] metadatas [ {source: standard_path, chunk_id: chunk[0]} for chunk in chunks ] collection.upsert( idsids, documentsdocs, metadatasmetadatas ) print(f已将 {len(docs)} 个文本片段写入向量库)5.3 检索候选条款def retrieve_clauses(question, top_k5): 从合规知识库中检索与问题最相关的条款 results collection.query( query_texts[question], n_resultstop_k, include[documents, metadatas, distances] ) return results这一步就可以先验证召回了。比如问题是“疏散门的宽度不应小于多少米”返回的 Top-5 片段应包含相关规范条款而不是无关的勘误说明。5.4 组装上下文并调用 LLM这里使用 OpenAI 兼容接口的通用调用方式实际地址和 Key 需要替换为你的服务配置。import json import requests # 调用 OpenAI 兼容 API 或本地 vLLM 服务 LLM_API_URL http://127.0.0.1:8000/v1/chat/completions LLM_API_KEY EMPTY def compliance_check(document_text, retrieved_clauses): context for rank, r in enumerate(retrieved_clauses): context f[条款 {rank 1}]\n{r}\n\n prompt f你是一个严谨的合规检查助手。请根据给定的合规条款判断待检文本是否存在违反条款的情况。 ## 合规条款 {context} ## 待检文本 {document_text} ## 输出要求 只输出JSON字段如下 {{ check_result: 通过/不通过/无法判断, violated_clauses: [ {{ clause_id: 条款编号或来源, evidence: 待检文本中的冲突内容 }} ], risk_level: 低/中/高, suggestion: 修改建议 }} response requests.post( LLM_API_URL, headers{Authorization: fBearer {LLM_API_KEY}}, json{ model: your-model-name, messages: [ {role: system, content: 你是合规审查助手必须严格按照条款输出。}, {role: user, content: prompt} ], temperature: 0.1, max_tokens: 1000 }, timeout120 ) result response.json() return result[choices][0][message][content]5.5 启动一个最简单的 API 服务在生产中做批量任务时建议把上面流程封装成 FastAPI 服务。from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class CheckRequest(BaseModel): document_id: str document_text: str class CheckResponse(BaseModel): document_id: str result: str app.post(/api/v1/compliance_check, response_modelCheckResponse) def run_check(req: CheckRequest): clauses retrieve_clauses(req.document_text) result compliance_check(req.document_text, clauses) return CheckResponse( document_idreq.document_id, resultresult ) if __name__ __main__: import uvicorn uvicorn.run(app, host127.0.0.1, port8000)启动命令python app.py启动后访问地址为http://127.0.0.1:8000/docs这里可以看到 FastAPI 自动生成的 Swagger 文档页面可以直接调试接口。如果启动时提示端口被占用换成其他端口即可uvicorn app:app --host 127.0.0.1 --port 80016. 功能测试与效果验证如何判断 CTRAG 是否可用框架搭起来之后最核心的问题是效果到底行不行6.1 测试数据准备不要拿整个标准文档去测试。准备 Three 组数据标准问题集30 到 50 个典型合规问题覆盖“哪些情况属于违规”。正例文本明确合规的文本片段预期结果为通过。反例文本明确违规的文本片段预期结果为不通过并指出违规条款。每组数据都应在标准文档中有明确依据。6.2 测试维度测试项测试方法通过标准检索召回准确率对每个问题检查 Top-5 中是否包含相关条款建议大于 80%否则需调整切分或 Embedding合规判断准确率对比 LLM 输出与人工标注结果建议大于 85%否则需优化提示词或重排条款定位能力检查输出中的 clause_id 是否真实存在且相关100% 相关不允许凭空编造证据可信度检查 evidence 是否能在待检文本中找到原句100% 可溯源边界判断能力测试“无法判断”的场景模型不应硬猜应返回无法判断批量稳定性连续检查 100 份文档无内存持续增长、无接口超时、无输出截断6.3 常用评估脚本示例def evaluate_precision(questions, min_recall0.8): hit_count 0 for q in questions: results retrieve_clauses(q[question], top_k5) hits [doc for doc in results[documents][0] if q[expected_clause] in doc] if hits: hit_count 1 precision hit_count / len(questions) print(fTop-5 召回命中率: {precision:.2%}) return precision min_recall6.4 失败时怎么定位如果召回效果不好按顺序排查标准文档切分是否合理如果条款被切成两半召回率必然下降。Embedding 模型是否匹配领域通用模型对专业术语理解有限考虑领域微调或添加同义词。查询提问方式是否合理如果问题描述与条款原文差异太大需要先做查询改写。待检文本质量如果待检文本本身是从 OCR 得到的存在错字和版面混乱需要先做文本清洗。7. 接口 API 调用与批量任务设计CTRAG 框架作为自动化合规检查系统不可能只做单条检查。实际业务里每天可能要检查几十份到几千份文档。7.1 单文档检查 API接口请求示例{ document_id: project_A_design_0320, document_text: 本项目首层疏散门净宽度为0.8m安装于建筑东侧开启方向为向内开启。 }返回结果{ document_id: project_A_design_0320, result: { check_result: 不通过, violated_clauses: [ { clause_id: 建筑防火规范 第3.7.5条, evidence: 疏散门净宽度0.8m, risk_level: 高 } ] } }7.2 批量任务处理批量任务不建议循环调用同步 API因为容易堆积和超时。更好的做法是设计一个简单的任务队列客户端把待检文档上传服务端生成task_id。后端异步处理解析文档 → 分块 → 检索 → LLM 检查。处理完成后结果写入outputs/{task_id}.json。客户端通过GET /api/v1/task/{task_id}查询状态。import uuid from pathlib import Path tasks {} def create_batch_task(doc_paths): task_id str(uuid.uuid4()) tasks[task_id] { status: pending, total: len(doc_paths), done: 0, results: [] } # 实际项目中用后台任务队列这里只保存任务状态 for doc_path in doc_paths: text extract_text(doc_path) clauses retrieve_clauses(text) result compliance_check(text, clauses) tasks[task_id][results].append({ doc: doc_path, result: result }) tasks[task_id][status] completed return task_id7.3 失败重试建议批量任务中LLM 接口可能因为网络、负载、超时等原因失败。建议使用指数退避重试import time import random def call_with_retry(func, max_retries3): for attempt in range(max_retries): try: return func() except Exception as e: if attempt max_retries - 1: raise e wait_time 2 ** attempt random.uniform(0, 1) time.sleep(wait_time)8. 资源占用与性能观察CTRAG 框架的资源占用涉及两个关键部分Embedding 与向量检索、LLM 推理。8.1 指标观察方式启动服务后可以用nvidia-smi监控 GPU 显存nvidia-smi -l 2如果使用容器部署可以用docker stats观察内存和 CPU 使用docker stats8.2 影响性能的主要因素文本切分长度切分越长向量库中片段越少检索和索引速度越快但单条上下文越长。Top-K 参数召回片段越多LLM 上下文越长推理耗时越长显存占用也可能增加。Embedding 批大小建立索引时大 batch 吞吐更高但占用更多内存。LLM 并发数并发请求数越高吞吐越高但显存和 API 配额压力也越大。8.3 降低资源占用的思路如果本地 GPU 紧张可以按顺序尝试改用 API 模式LLM 部分不占本地显存。量化模型7B 模型用 4-bit 量化后显存占用大幅降低。控制上下文长度精排后只保留 Top-3 片段减少输入 token 数。Embedding 复用标准文档索引只需构建一次不要每次启动都重复构建。9. 常见问题与排查方法问题现象可能原因排查方式解决方案知识库索引构建很慢Embedding 模型较大或文档切分粒度过细观察 CPU/GPU 占用调大切分长度、增加批量大小、升级硬件检索召回结果与问题无关切分不合理、Embedding 模型不适合领域打印 Top-5 片段查看内容按条款边界切分、更换领域 Embedding、加查询改写LLM 输出不合理的条款编号提示词约束不足或召回片段缺失检查召回片段中是否包含该条款调整 Top-K、增加重排、在提示词中强调只能引用给定条款待检文档无法提取文字PDF 是扫描件或缺少文字层打开 PDF 检查是否可选文字接入 OCR 工具如 PaddleOCR批量任务中途失败单份文档超长、LLM 接口超时查看任务日志和堆栈设置单文档最大长度、加超时重试、按段落分块处理接口返回 500代码异常或 LLM 服务不可用查看后端日志检查 LLM 服务是否启动、请求参数格式是否正确显存不足本地模型参数量过大使用nvidia-smi查看显存换更小模型、开启量化、采用 API 模式判断结果不能接受提示词设计不合理或模板不完整人工复核失败样本增加结构化输出约束、加入少样本示例10. 最佳实践与使用建议CTRAG 框架工程化落地如果要把 CTRAG 从实验代码变成可用的合规检查系统建议遵守以下八条10.1 先小规模验证再全量投入第一批测试不要接几百份文档到系统里。先用 20 份文档、50 个问题人工核对召回和判断结果。确认准确率达标后再扩大到全量。10.2 保留一套“最小可运行配置”把以下内容固定下来标准文档目录和版本。Embedding 模型名称。Top-K 参数。LLM 模型和温度参数。输出 JSON 结构。每次变更环境时先用最小配置跑通再继续调整其他参数。10.3 文档和结果分目录管理建议目录结构data/ ├── standards/ # 标准知识库 ├── inputs/ # 待检文档 ├── outputs/ # 检查结果 │ ├── json/ │ └── reports/ └── logs/ # 运行日志批量任务必须输出日志。每份文档记录开始时间、结束时间、耗时、召回片段数、LLM 输出、是否重试。10.4 利用重排优化召回单纯依赖向量检索Top-5 召回中可能只有两个相关。建议增加一个交叉编码器重排模型对候选片段重新打分。这是 RAG 框架提升精度的最常见手段。10.5 对输出做格式校验LLM 输出 JSON 经常不稳定。建议用pydantic或jsonschema做在线校验解析失败就重试一次。10.6 建立“未召回到”反馈通道如果模型判断“无法判断”很可能是知识库没有正确的条款。把这类问题记录下来定期分析有可能是相关知识缺失也有可能是切分不匹配。10.7 限定接口访问范围合规检查接口涉及内部敏感文档不要直接暴露到公网。建议在服务端限制 IP 白名单加 API Key 鉴权。10.8 人工复核是最后一道防线CTRAG 能做的是提高初筛效率把人工从“全文阅读”变成“只复核风险片段”。在合规、法务、审计这些高风险场景中AI 结论必须经过具备资质的人员确认不能直接用于出具正式报告。11. 下一步可以扩展的方向CTRAG 框架本身的可玩性很高落地之后可以继续往四个方向扩展多模态合规检查接入视觉模型把图纸、现场照片接入图像理解模型让框架可以同时比较文本条款和图像证据。构建领域知识库增量更新机制规范更新后自动替换旧条款并做版本对比让合规检查始终基于最新标准。引入规则引擎做硬校验对于“数值上下限”“时间期限”这类硬指标不依赖 LLM用正则和规则引擎先判定再让 LLM 处理语义层面的问题。开发长期记忆与反馈学习模块把人工复核结果回流到框架中作为少样本示例持续改善提示词输出质量。落地合规检查最关键的并不是“选一个更强的大模型”而是把知识库切分、检索召回、上下文注入、结构化输出这四个环节打磨稳定。CTRAG 这类 In-Context 检索框架最大的价值就是让 LLM 的每一次判断都有据可查。建议你拿到代码后先挑一份你最熟悉的标准文档做知识库写 10 个确定能判断的问题把召回和判断跑通再逐步扩大测试范围。整个过程并不复杂但每一步都值得认真验证。
返回列表