合规检查在不少行业里仍然是“人肉 表格 会议评审”的活。一个稍微复杂一点的项目可能要同时核对几十份法规、几百个条款还要跨文档确认引用关系。传统规则引擎只能处理写死的“如果-那么”逻辑遇到语义模糊的合规要求就完全失灵。大模型出现后很多人尝试直接把法规文档丢给 LLM 做判断结果很快发现两个问题一是模型会一本正经地编造不存在的条款二是无法向审查方证明“这个结论到底依据的是哪一条”。CTRAG 这个名字代表的框架正是冲着这两个问题去的。它的核心思路不是让 LLM 自由发挥而是先用检索把相关条款找出来再让模型基于检索到的上下文做合规判断。这篇博客会拆开讲清楚几个问题自动化合规检查到底难在哪LLM 用于合规判断为什么不能“裸奔”CTRAG 这种 In-Context Retrieval 的框架如何工作如果自己想在项目里搭一个类似的系统应该怎么做、需要注意哪些坑。需要先说明的是由于手头只有论文标题和关键词没有完整的论文正文本文会基于框架命名、以及检索增强生成在合规场景下的通用工程实践来做拆解。这不会影响你理解 CTRAG 的思路因为它的关键技术点——In-Context Retrieval、基于 LLM 的合规判断、引用溯源——都是可以落到代码里的。1. 这篇文章真正要解决的问题先回答一个最关键的问题自动化合规检查Automated Compliance CheckingACC为什么直到现在才被 AI 领域认真对待因为过去的大部分自动化方案都太“脆”了。早期做法是基于规则引擎把法规要求翻译成结构化的条件表达式。比如“建筑高度不得超过 30 米”翻译成代码里的if height 30: fail。这种方式对数值型条款有效但法规里大量存在“合理的”“充分的”“不得损害公共利益”这类模糊表达规则引擎无法建模。后来也有基于逻辑推理的方案比如用描述逻辑对规范进行形式化建模但建模成本极高维护一套适用于多行业的规则库会变成另一个无底洞。LLM 的出现改变了一个关键点语义理解能力。模型能读懂“如果项目位于饮用水水源保护区则不得建设排放污染物的设施”这种自然语言条款也能判断一个项目描述是否命中该条款。但直接让 LLM 做判断有两大硬伤。第一是幻觉模型可能引用一条不存在的法规条款来支撑结论。第二是审计不通过合规结论必须能够被追溯审查方要看到模型依据的是哪一版法规的哪一条而不是一句“大模型认为合规”。CTRAG 要解决的就是这两个问题。它用“检索相关条款 → 放入上下文 → 让 LLM 基于条款判断”的流程把 LLM 的自由生成限制在检索到的法规上下文之内同时把检索到的条款作为引用来源输出。这种方式在工程上意味着三件事你不需要重新训练模型你可以在不修改模型的情况下更新法规库你输出的结论天然带引用可以直接放到审计报告里。这篇文章适合哪类读者如果你在做合规科技、建筑信息模型审查、金融合规、数据安全合规、医疗合规等方向的系统设计或者你想在项目里引入 LLM 但不想接受“模型自由发挥”带来的风险那么这篇博客会给你一个可参考的框架。看完之后你能理解 CTRAG 的模块划分、能搭出一个最小可运行的检索增强合规检查原型、也能知道它在生产落地时要面对哪些真实问题。2. 基础概念与核心原理2.1 什么是 Automated Compliance Checking自动化合规检查是建筑工程、金融、数据保护、环境评估等领域的传统研究课题。它的定义很简单用计算机系统自动判断“某个待审查对象是否符合一组规范要求”。输出通常是一个合规结论、风险等级、不合规原因列表以及对应的依据条款。传统 ACC 系统高度依赖专家知识的形式化表达。瑞士、挪威、新加坡等国家在建筑规范审查上有不少研究积累很多系统把规范条文转成逻辑规则再与设计模型做匹配。这类系统的优点是结果可解释、可复现缺点是规则库建设成本高、规则之间可能冲突、新法规发布后需要人工更新规则。另一个缺点是它只能做“条款命中”式检查很难处理开放式的、需要语义推理的合规问题。例如“该数据存储方案是否满足最小化收集原则”这类判断需要理解业务场景和法规意图传统规则系统无能为力。这是 LLM 和检索增强框架能够切入的空白地带。LLM 能做的不是替代传统规则引擎而是把那些无法形式化、依赖语义理解的合规判断自动化。2.2 LLM 做合规检查的两种路线从工程角度看用 LLM 做合规检查有两种路线。第一种是“长上下文直接判断”。把整部法规文档塞进 LLM 的上下文窗口然后让模型回答问题。优点是简单直接调用 API 即可缺点是上下文窗口有限法规文档动辄几十上百页超过窗口后只能截断截断就可能丢掉关键条款。更麻烦的是模型对长文本后段内容的注意力会下降检索准确率和引用准确性都不可控。另一个隐性成本是每增加一个待审查项目都要把整份法规重新拼进 prompttoken 成本非常高。第二种是“检索增强判断”。先根据待审查内容检索出最相关的法规条款只把这几条放进上下文。这就是 RAG 的基本思路。它的优势在于法规库再大每次参与判断的只是小部分条款模型不需要背下所有法规只需要基于给定的条款做推理条款来源可以被记录和验证。CTRAG 属于这一路线的演进版本它的重点是在“检索”和“上下文组织”层面做了更针对合规场景的强化。2.3 In-Context Retrieval 与普通 RAG 的差异RAG 的通用流程是文档切块 → 向量化 → 存入向量库 → 根据用户问题检索 Top-K 块 → 拼接 prompt → LLM 生成回答。这个流程在很多问答场景已经够用但在合规检查场景有明显不足。普通 RAG 检索的是“文本块”但法规条款经常是嵌套的一个条款里面包含多个子项某个子项又引用了另一章的定义条款。如果只检索一块文本模型可能只看到结论看不到上下文。In-Context Retrieval 的思路是在检索阶段就为每个条款保存更丰富的上下文信息包括条款编号、所属章节、生效版本、关联条款引用等并将其一起送入 LLM。这样模型判断时看到的不仅仅是孤立的一句话而是一个“可引用的条款单元”。另外合规场景对召回要求苛刻。漏检一条关键条款可能导致严重的合规风险。普通 RAG 用单次向量检索Top-K 可能漏掉语义不相似但法规上相关的条款。In-Context Retrieval 通常会在向量检索之外叠加关键词检索、同义词扩展、同义条款匹配、甚至多轮检索让检索结果覆盖更完整。这也是 CTRAG 这类框架与通用 RAG 的核心差异检索不追求“看起来相关”而是追求“不能漏”。2.4 CTRAG 的定位从标题可以判断CTRAG 全称至少包含 Context、Retrieval、LLM、Compliance 这些关键词。更稳妥的理解是Compliance-oriented Contextual Retrieval-Augmented Generation即面向合规场景的上下文检索增强生成框架。它与通用 RAG 的差异可以总结为四点对比维度通用 RAGCTRAG 类合规框架检索对象任意文本块结构化法规条款及关联信息上下文要求语义相关即可必须包含条款编号、版本、引用链判断要求生成自然语言回答输出合规结论、风险等级、引用条款审计要求无强制追溯结论必须可追溯到具体条款更新频率文档更新较少法规频繁修订知识库需持续维护这张表是理解 CTRAG 的核心。它本质上不是一个新的通用模型而是一种把信息检索、上下文工程和 LLM 推理组合起来的系统方案。3. CTRAG 框架的核心模块与架构拆解将 CTRAG 抽象成一个可实现的系统至少需要五个核心模块。3.1 法规知识库层这是整个框架的地基。知识库中存储的不只是法规 PDF 原始文本而是被处理成“条款单元”的结构化数据。普通 RAG 的文档库是“文本块的集合”而合规知识库应该是“条款的集合”。每个条款单元至少包含条款编号、正文内容、所属法规、发布机构、生效日期、版本号、关联条文引用。有了这些元数据后续的引用溯源才能成立。做这一层最容易踩的坑是直接把 PDF 全文本塞进向量库。这样会导致检索时返回的是大段无结构文本LLM 无法判断这些文字来自哪一条法规。因此在构建知识库时必须预留元数据字段并把文档切分与“条款切分”结合起来。比如根据“第X条”或“Article X”做结构化切分而不是按固定字符数硬切。3.2 检索层检索层负责根据待审查内容召回相关的法规条款。工程上通常采用混合检索策略。向量检索负责语义匹配解决“含义相近但用词不同”的问题。关键词检索负责精确匹配解决条款编号、专业术语、专有名词的匹配问题。二者结果做去重和合并再按相关性排序。对于法律合规领域还需要做查询改写把项目描述中的口语化表达改写为法规中常见的规范术语。例如“收集用户的手机定位”可以改写为“收集个人信息中的行踪轨迹”才能在法规库中检索到对应条款。3.3 上下文组装层检索到条款之后不能直接把 Top-K 个文本块拼起来还要组装出 LLM 可以高效利用的上下文。组装规则包括按法规优先级排序对存在引用关系的条款进行递归展开在每条条款前标注来源、效力等级、版本号控制总 token 数量在模型窗口安全范围内。这个层是 In-Context Retrieval 的关键。如果只是把条款简单拼接模型很可能忽略掉重要的限定条件。比如某项目符合 A 条款的表面要求但 A 条款的例外条款规定“以下情形除外”此时如果检索结果里没有例外条款模型就会判断错误。因此上下文组装不仅要管“放什么”还要管“放全没有”。3.4 推理与验证层推理层调用 LLM 对组装好的上下文做合规判断。理想输出不是自由文本而是结构化 JSON包含是否合规、风险等级、理由列表、引用条款列表。验证层则对 LLM 的输出做二次校验检查引用的条款 ID 是否真实存在于知识库中检查引用条是否真的被包含在送给模型的上下文里检查模型是否试图引用上下文之外的条款。发现异常时可以触发重新检索或标记“无法判断”。这一层在合规审计场景中不可或缺它能拦住一大部分幻觉输出。4. 环境准备与前置条件要动手搭建一个最小 CTRAG 原型需要一个 Python 环境、一个向量数据库、一个 LLM API。本文示例代码采用以下环境实际版本请以项目实际情况为准操作系统Windows / macOS / Linux 均可Python 3.9 以上包管理pip 或 poetry向量库Chroma本地轻量适合原型验证嵌入模型OpenAI text-embedding-3-small大模型OpenAI gpt-4o-mini 或同级别模型文档解析pypdf框架LangChain 社区版本安装依赖pip install openai langchain langchain-community langchain-openai chromadb pypdf tiktoken如果使用 OpenAI 接口需要配置环境变量export OPENAI_API_KEYyour-api-keyWindows 下使用set OPENAI_API_KEYyour-api-key原型阶段建议先用小规模法规文件测试比如选一个只有几十页的规范作为知识库。不要一开始就导入整个法律体系否则检索效果和调试成本都会失控。5. 核心流程拆解一个完整的 CTRAG 合规检查流程可以拆成以下步骤。5.1 知识库数据准备准备好法规 PDF 或 Markdown 文件放在统一目录中。对于 PDF 文件需要先解析文本注意扫描版 PDF 需要 OCR本文不展开。把法规文件按“条款”切分而不是按固定长度切分。这一步很关键直接决定后续检索粒度和引用准确性。如果法规是 Markdown 格式可以直接按“第X条”标题切。5.2 文档切分与向量化对每个条款单元做切分后保留元数据来源文件名、条款编号、页码、生效版本。然后将条款文本通过嵌入模型转换成向量写入向量库。这里的要点是不要只存文本一定要把条款编号和来源写入 metadata。5.3 检索与上下文构建输入一个待审查的项目描述先做查询改写然后分别在向量库和倒排索引中检索相关条款。将两路结果合并、去重按照相关度排序取 Top-K。再根据条款之间的引用关系把被引用的关联条款补充进来。最终形成一个有结构的上下文文本。5.4 LLM 推理与结构化输出把上下文和项目描述一起放入 prompt要求模型输出符合规定格式的 JSON。系统提示词需要明确角色、判断依据边界、输出字段、以及“只能引用给定条款不得编造条款”的红线。温度设置为 0减少随机性。5.5 结果验证与报告解析模型输出校验引用字段。如果引用了知识库中不存在的条款就判定为幻觉输出重新检索或返回“无法判断”。最后将合规结论、风险等级、依据条款、判断理由汇总为报告。6. 完整示例代码实现下面给出一个最小可运行的 CTRAG 原型代码用于演示从法规知识库构建到合规判断的完整链路。6.1 示例 1构建法规知识库索引# build_index.py import os from langchain_community.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings from langchain_community.vectorstores import Chroma DOC_DIR ./regulations DB_DIR ./compliance_db embeddings OpenAIEmbeddings(modeltext-embedding-3-small) text_splitter RecursiveCharacterTextSplitter( chunk_size800, chunk_overlap120, separators[\n\n, \n, 。, , , ] ) docs [] for file in os.listdir(DOC_DIR): if not file.endswith(.pdf): continue loader PyPDFLoader(os.path.join(DOC_DIR, file)) pages loader.load() chunks text_splitter.split_documents(pages) for chunk in chunks: chunk.metadata[source_file] file docs.extend(chunks) vectorstore Chroma.from_documents( documentsdocs, embeddingembeddings, persist_directoryDB_DIR ) print(findexed chunks: {len(docs)})这段代码的核心作用是完成“文档 → 切片 → 向量 → 入库”。chunk_size800是经验值法规条款如果较长建议按条款粒度切分而不是等长切分。chunk_overlap在这里用于减少条款边界被切断的损失但它不能替代基于章节的切分。6.2 示例 2检索与上下文组装# retrieve.py from langchain_openai import OpenAIEmbeddings from langchain_community.vectorstores import Chroma DB_DIR ./compliance_db embeddings OpenAIEmbeddings(modeltext-embedding-3-small) vectorstore Chroma( persist_directoryDB_DIR, embedding_functionembeddings ) retriever vectorstore.as_retriever( search_typesimilarity, search_kwargs{k: 5} ) def build_context(query: str) - str: docs retriever.invoke(query) parts [] for i, doc in enumerate(docs, 1): source doc.metadata.get(source_file, unknown) page doc.metadata.get(page, unknown) parts.append( f[条款 {i}]\n f来源: {source}\n f页号: {page}\n f内容: {doc.page_content} ) return \n\n.join(parts) if __name__ __main__: context build_context(平台采集用户地理定位数据用于个性化推荐) print(context)这个示例展示的是“检索结果如何变成可追溯上下文”。每个条款都带上来源文件和页码目的就是让后续 LLM 输出的引用能够回到原始文件。这里的检索方式还是最基础的相似度检索。生产系统里建议叠加 BM25 关键词检索再用Reciprocal Rank Fusion合并结果。6.3 示例 3LLM 合规判断与结果解析# check.py import json from openai import OpenAI client OpenAI() SYSTEM_PROMPT 你是一名合规审查专家。请基于给定的法规条款判断项目描述是否合规。 规则 1. 只能引用用户提供的条款不得编造或引用外部条款。 2. 输出必须是 JSON包含以下字段 - is_compliant: boolean - risk_level: LOW | MEDIUM | HIGH - reasons: string[] - citations: string[] 3. 如果给定条款不足以下结论将 is_compliant 设为 false并在 reasons 中说明原因。 def compliance_check(project_desc: str, context: str) - dict: user_prompt f项目描述 {project_desc} 当前检索到的相关法规条款 {context} 请结合上述条款分析该项目是否合规并给出依据。 resp client.chat.completions.create( modelgpt-4o-mini, temperature0, response_format{type: json_object}, messages[ {role: system, content: SYSTEM_PROMPT}, {role: user, content: user_prompt}, ], ) return json.loads(resp.choices[0].message.content)这段代码把 LLM 的输出限制成了 JSON 格式。response_format{type: json_object}是为了提高格式稳定性。temperature0是为了让每次判断尽量一致。系统提示词里强调“只能引用给定条款”这是控制幻觉的最直接手段但要注意它不是万能的后续还需要验证层。6.4 示例 4主流程串联# main.py import json from retrieve import build_context from check import compliance_check if __name__ __main__: query 平台采集用户地理定位数据用于个性化推荐是否合规 context build_context(query) result compliance_check(query, context) print(json.dumps(result, ensure_asciiFalse, indent2))运行python main.py7. 运行结果与效果验证如果知识库中有相关法规模型应输出类似这样的结构化结果{ is_compliant: false, risk_level: MEDIUM, reasons: [ 平台收集用户地理定位数据属于处理个人信息中的行踪轨迹信息属于敏感个人信息。, 收集前未说明是否存在单独同意机制因此存在合规风险。 ], citations: [ 个人信息保护法-第二十八条, 个人信息保护法-第二十九条 ] }注意这个输出是示例性质实际输出取决于知识库中加载的法规内容和项目描述。验证一个 CTRAG 系统不能只靠“看起来对不对”至少要看三个维度第一检索质量。审查查询对应的真实相关条款是否出现在 Top-K 中。可以人工标注一批测试查询统计召回率。第二判断准确率。拿一批人工标注过合规结论的项目描述对比系统判断与人工判断的一致性。第三引用准确率。检查模型输出的 citations 是否真实存在于知识库、是否真的被检索进入上下文。如果 outputs 中的条款 ID 没有出现在上下文里那基本可以判定为幻觉。如果运行失败第一步看错误位置如果是 API 调用报错看是否配置了环境变量如果是向量库加载失败看持久化目录和嵌入模型是否一致不同嵌入模型生成的向量不能混用如果输出不是合法 JSON看模型是否支持json_object输出格式或者系统提示词是否够明确。8. 常见问题与排查思路问题现象可能原因排查方式解决方案检索不到相关条款嵌入模型对专业术语理解不足或法规文档未正确切分打印检索 Top-K 文本人工检查相似度分数改为混合检索加入 BM25 关键词匹配优化切分粒度按条款切分模型引用不存在的条款模型在生成时编造引用校验 citations 字段是否都在上下文中在提示词中强调禁止外部引用增加结果验证层过滤幻觉引用输出 JSON 格式不稳定模型变体不支持结构化输出或提示词约束不够检查返回原始文本使用支持 JSON mode 的模型增加输出格式示例上下文超出模型窗口检索结果和关联条款过多统计每次请求的 token 消耗控制 Top-K 数量对关联条款做摘要优先选择上下文更长的模型不同法规对同一事项要求冲突知识库中法规之间冲突检索同时返回人工核对冲突条款建立法规优先级和版本规则在上下文中标注优先适用关系向量库版本升级后无法加载Chroma 持久化格式变更查看错误日志重建索引或固定向量库版本同一问题多次判断结果不同模型温度过高或上下文顺序不稳定将 temperature 设为 0固定条款排序规则统一 prompt 模板和条款排序方式9. 最佳实践与工程建议从原型走向生产CTRAG 系统还需要考虑很多工程问题。第一个建议是建立法规知识库的版本管理。法规会更新条款会废止判断结果会随着法规版本变化而变化。生产系统必须记录每条判断使用的法规版本否则审计时无法回答“当时为什么判定合规”。建议用一个简单的regulations_version字段记录版本号或者用单独的元数据表维护。第二个建议是认真设计切分策略。法规条文有内在结构按字符数硬切会破坏条款完整性导致检索片段残缺。更推荐的做法是先解析文档的标题层级识别“第X条”边界再按条款切分。如果条款过长再在条款内部做二次切分但每个分块必须保留条款编号。第三个建议是引入验证层不要完全信任 LLM 输出。验证层不只是检查 JSON 是否合法还要检查引用是否存在、引用是否在当前上下文、风险等级是否与理由一致。这一步是审计合规系统的生命线。第四个建议是控制成本。合规审查通常不是单次问答而是成批审查。可以对检索结果做缓存同一份法规如果已经向量化不需要每次重新切分。对 LLM 调用可以考虑使用缓存命中完全相同的项目描述和上下文直接返回历史结果。还要注意 token 消耗一次检索上下文里放入 10 条长条款可能消耗几千 token批量场景下成本会线性上升。第五个建议是建设小规模标注评估集。随便写几个测试用例只能证明“能跑通”不能证明“测得好”。建议挑 50 到 100 个真实项目描述人工标注合规结论和应命中的条款作为回归测试集。每次修改切分策略、prompt 模板或检索参数都跑一遍回归测试防止效果回退。第六个建议是明确系统的辅助定位。在合规场景中LLM 判断应该作为“预审”或“辅助审查”而不是最终决策。系统输出高风险项目时应由专业合规人员复核。这一点不仅是工程建议也是责任边界的判断。10. 总结与后续学习方向CTRAG 这类框架的价值不在于用了多强的模型而在于把一个高风险场景中的 LLM 应用从“不可控的自由生成”变成了“可检索、可引用、可追溯的辅助判断”。它的核心是三个动作把法规加工成结构化条款库通过上下文检索把相关条款送到模型面前用结构化输出和验证层把模型的回答限制在可审计范围内。这套思路可以迁移到任何“判断结果必须给依据”的领域比如安全审计、招聘合规、信贷审核、技术标准符合性检查。如果你要继续深入建议按这个顺序学习先熟悉 RAG 的基本流程和向量检索原理然后研究混合检索和重排序算法比如 BM25、Cross-Encoder Rerank再深入法律文本的结构化解析包括条款切分、引用关系抽取最后关注 LLM 输出可靠性包括结构化输出、幻觉检测和评估集建设。这些方向组合起来才是 CTRAG 能在生产环境中真正落地的基础。