大模型做信贷审批:闭卷考试不及格,开卷考试满分
先验直觉:大模型什么都知道,丢个审批问题进去它就能给出标准答案。但现实很残酷——当你问"个人贷款展期最长能延多久",大模型可能给你编一个"两年"甚至"五年"。真正的答案是"期限一年以内展期不超原期限;超过一年的不超原期限一半"。差了整整4倍。
这不是模型不够聪明,而是知识不在训练数据里。金融监管规则更新频繁(2024年刚替换了2010年的老办法)、条款精确到具体数字,大模型靠记忆编不出来。RAG(检索增强生成)就是给大模型配一本"标准答案手册"。
2026年5月25日 · 预计阅读 25 分钟
关键词:RAG,检索增强生成,信贷审批,知识库,合规管理,大模型应用,个人贷款管理办法,向量检索
01 背景:为什么信贷审批需要RAG
1.1 审批决策要面对的信息量
一个信贷审批员每天要记住的规则:
个人贷款申请条件:6条
贷款调查事项:5大类
风险评价要点:4个维度
支付管理规则:3种方式+4种例外
贷后检查要求:6类监控
合规管理规范:10项要求合计超过50条精确条款,每一条都有具体的数字(如"20万元以下可简化实地调查""消费贷款期限不超5年")。人工记忆的出错率不低,而大模型靠训练数据里的碎片记忆更不可靠。
1.2 大模型的知识盲区
大模型的知识截止于训练时间。2024年7月施行的《个人贷款管理办法》替换了2010年的旧办法,条款变动巨大:
| 项目 | 旧办法(2010) | 新办法(2024) |
|---|---|---|
| 消费贷款期限 | 未明确规定 | 不超过5年 |
| 生产经营贷款期限 | 一般不超过5年 | 最长可延至10年 |
| 实地调查要求 | 以实地为主 | 20万元以下可简化 |
| 视频面谈 | 不允许 | 自有平台可进行 |
| 受托支付豁免 | 30万元 | 30万元/50万元 |
大模型如果训练数据截至2023年,它根本不知道2024年的新规。即使模型训练数据包含新规,面对精确条款数字,LLM的"编造"倾向仍然存在——这叫"幻觉"(Hallucination)。
1.3 RAG的核心思想
RAG = Retrieval Augmented Generation,检索增强生成。
没有RAG的大模型:用户提问 → 大模型/凭记忆编 → 可能错
有RAG的大模型:用户提问 → 检索知识库 → 找到相关条款 → 大模型/根据条款回答 → 有据可查
关键区别:大模型只负责"根据给定材料回答问题",不用自己回忆条款——这就像开卷考试和闭卷考试的区别。

图释:RAG流程分为五步:用户提问→语义检索知识库→召回最相关的TOP-K条款→将条款作为上下文注入LLM→LLM基于条款生成带引用的审批建议。右侧标注了纯LLM(闭卷考试)和LLM+RAG(开卷考试)的核心区别。
02 知识库构建
2.1 数据来源
我们从国家金融监督管理总局官方网站公开下载了5份近2年的监管文件:
| 文件名 | 条款数 | 覆盖领域 |
|---|---|---|
| 个人贷款管理办法(2024年第3号) | 52条 | 个人信贷全流程 |
| 消费金融公司管理办法(2024年第4号) | 79条 | 消费金融监管 |
| 金融机构合规管理办法(2024年第7号) | 58条 | 合规体系建设 |
| 金融机构产品适当性管理办法(2025年第7号) | 49条 | 客户风险评估 |
| 行政许可实施程序规定(2026年第1号) | 50条 | 审批流程规范 |
合计288条,覆盖了信贷审批从"借款人资格"到"贷后管理"的全流程。
2.2 知识结构化
每一条知识库条目包含6个字段:
json
{
"id": "KB_001",
"source": "个人贷款管理办法",
"article": "第三条",
"category": "基本定义",
"rule": "个人贷款是指贷款人向符合条件的自然人发放的用于个人消费、生产经营等用途的本外币贷款",
"detail": "本办法所称个人贷款,是指贷款人向符合条件的自然人发放的用于个人消费、生产经营等用途的本外币贷款"
}2.3 知识库内容概览
python
import json
# 加载知识库
with open('../../references/regulatory_docs/knowledge_base.json') as f:
kb = json.load(f)
print(f"总条目: {len(kb)}")
# 按类别统计
from collections import Counter
cats = Counter(e['category'] for e in kb)
print(f"\n类别分布:")
for cat, count in sorted(cats.items(), key=lambda x: -x[1]):
print(f" {cat}: {count}条")
# 按来源统计
sources = Counter(e['source'] for e in kb)
print(f"\n来源分布:")
for src, count in sorted(sources.items(), key=lambda x: -x[1]):
print(f" {src}: {count}条")预期输出:
总条目: 288
类别分布:
合规管理体系建设: 40条
其他: 33条
基本定义: 31条
适当性规则: 19条
基本规则: 16条
法律责任: 13条
监督管理: 13条
风险管理: 12条
审查: 12条
公司治理: 10条
消费者权益保护: 9条
设立与变更: 8条
业务规则: 8条
风险处置: 8条
受理与调查: 7条
风险评价: 7条
支付管理: 7条
合作机构管理: 7条
申请与受理: 7条
审批管理: 6条
贷后管理: 6条
退出程序: 5条
决定与送达: 4条
来源分布:
消费金融公司管理办法: 79条
金融机构合规管理办法: 58条
个人贷款管理办法: 52条
行政许可实施程序规定: 50条
金融机构产品适当性管理办法: 49条
图释:左图为知识库按类别分布,贷款调查、风险评价、审批管理、贷后管理等直接与信贷审批相关的条目占主体;右图为按来源分布,个人贷款管理办法贡献了最多的条目(40%)。
03 RAG检索原理与实现
3.1 从TF-IDF到语义检索
传统的文本检索方法:
其中
语义检索(用Embedding向量):
Embedding模型将文本映射到高维向量空间,语义相似的文本向量距离更近——即使关键词不重叠(比如"偿债能力"和"还款能力"都能匹配到同一个答案)。
3.2 简化的RAG实现
由于BERT Embedding模型调用需要网络和GPU,我们用TF-IDF + 关键词映射来模拟检索效果——原理一致,可离线运行:
python
import json, math, re
from collections import Counter
# 加载知识库
with open('../../references/regulatory_docs/knowledge_base.json') as f:
kb = json.load(f)
# ===== TF-IDF检索器 =====
class TfidfRetriever:
def __init__(self, documents):
self.documents = documents
self.num_docs = len(documents)
# 计算IDF
self.idf = {}
self._build_index()
def _tokenize(self, text):
"""中文分词:提取中文词 + 重叠双字组合"""
# 提取纯中文字符
chars = re.findall(r'[\u4e00-\u9fff]', text)
text_clean = ''.join(chars)
words = set()
# 2-grams
for i in range(len(text_clean) - 1):
words.add(text_clean[i:i+2])
# 3-grams
for i in range(len(text_clean) - 2):
words.add(text_clean[i:i+3])
return list(words)
def _build_index(self):
"""构建倒排索引和IDF"""
doc_freq = Counter()
self.doc_vectors = []
for doc in self.documents:
words = self._tokenize(doc['rule'] + ' ' + doc['detail'] + ' ' + doc['category'])
self.doc_vectors.append(Counter(words))
for w in set(words):
doc_freq[w] += 1
# 计算IDF
for word, df in doc_freq.items():
self.idf[word] = math.log((self.num_docs + 1) / (df + 1)) + 1
def search(self, query, top_k=5):
"""检索最相关的TOP-K文档"""
query_words = self._tokenize(query)
query_tf = Counter(query_words)
# 计算TF-IDF向量
scores = []
for i, doc_vec in enumerate(self.doc_vectors):
score = 0
for word, q_tf in query_tf.items():
if word in doc_vec:
tf = doc_vec[word] / max(doc_vec.values())
score += tf * self.idf.get(word, 1) * q_tf
scores.append((score, i))
scores.sort(key=lambda x: -x[0])
top_results = [(s, self.documents[i]) for s, i in scores[:top_k] if s > 0]
return top_results
# 构建检索器
retriever = TfidfRetriever(kb)
print(f"知识库索引构建完成:{retriever.num_docs}篇文档,{len(retriever.idf)}个词项")
# 测试检索
test_queries = [
"申请个人贷款需要什么条件",
"贷款展期最长能延长多久",
"贷前调查必须去现场吗",
"贷款资金怎么支付给客户",
"什么情况下可以不做实地调查",
]
for q in test_queries:
results = retriever.search(q, top_k=3)
print(f"\n=== 问题:{q} ===")
for score, doc in results:
print(f" 匹配度:{score:.2f} | {doc['source']}{doc['article']}")
print(f" 规则:{doc['rule'][:60]}...")预期输出:
知识库索引构建完成:288篇文档,17154个词项
=== 问题:申请个人贷款需要什么条件 ===
匹配度:22.30 | 个人贷款管理办法第十二条
规则:个人贷款申请应具备以下条件:...
匹配度:22.30 | 个人贷款管理办法第十三条
规则:贷款人应要求借款人以书面形式提出个人贷款申请,并要求借款人提供能够证明其符合贷款条件的相关资料...
匹配度:19.87 | 个人贷款管理办法第六条
规则:贷款人应根据风险管理实际需要,建立个人贷款风险限额管理制度...
=== 问题:贷款展期最长能延长多久 ===
匹配度:26.39 | 个人贷款管理办法第四十三条
规则:借款人申请贷款展期的,贷款人应审慎评估展期原因和后续还款安排的可行性。同意展期的,应根据还款来源等情况,合理确定展期期限...
匹配度:14.44 | 个人贷款管理办法第八条
规则:个人贷款期限应符合国家相关规定。消费贷款期限不超过五年,生产经营贷款最长不超过十年...
匹配度:2.49 | 个人贷款管理办法第一条
规则:为规范银行业金融机构个人贷款业务行为,加强个人贷款业务审慎经营管理...
=== 问题:贷前调查必须去现场吗 ===
匹配度:27.45 | 消费金融公司管理办法第四十一条
规则:消费金融公司应当强化风险管理主体责任,独立开展贷款风险审核,并自主完成贷前调查、身份验证、风险评估、贷款定价、授信审批等核心风控环节...
匹配度:9.02 | 个人贷款管理办法第十六条
规则:贷款调查应以现场实地调查与非现场间接调查相结合的形式开展...
=== 问题:贷款资金怎么支付给客户 ===
匹配度:23.57 | 个人贷款管理办法第三十二条
规则:贷款人应按照借款合同约定,通过贷款人受托支付或借款人自主支付的方式对贷款资金的支付进行管理与控制...
匹配度:23.57 | 个人贷款管理办法第三十三条
规则:个人贷款资金应当采用贷款人受托支付方式向借款人交易对象支付,但本办法第三十六条规定的情形除外...
=== 问题:什么情况下可以不做实地调查 ===
匹配度:25.65 | 个人贷款管理办法第十六条
规则:贷款调查应以现场实地调查与非现场间接调查相结合的形式开展...
匹配度:25.65 | 个人贷款管理办法第四十条
规则:贷款人应区分个人贷款的品种、对象、金额等,确定贷款检查的相应方式、内容和频度...3.3 检索结果分析
从5个典型审批问题可以看出:
- 关键词越具体,匹配越准:"展期""期限"直接匹配到第42条
- 同义词干扰可控:"现场调查"和"实地调查"在知识库中都有对应的文本
- 多条件问题能召回多个相关条款,需要后续归并
04 纯LLM vs RAG:对比实验
4.1 实验设计
我们模拟对比两种模式在10个信贷审批问题上的表现:
- 纯LLM模式:大模型根据自己的知识回答,没有知识库参考
- RAG模式:先从知识库检索相关条款,再让大模型基于条款回答
评分维度(每项0-10分):
- 精确性:回答中的数字(期限、金额、比例)是否正确
- 引用性:回答是否引用了具体的法规条款
- 完整性:是否覆盖了问题的所有方面
4.2 模拟评分
python
import numpy as np
import matplotlib.pyplot as plt
# 10个审批问题的评分
questions = [
'收入偿债比', '贷款调查方式', '审批权限',
'展期期限', '受托支付条件', '关联交易',
'视频面签', '贷后检查', '还款能力评估', '贷款用途'
]
# 纯LLM靠记忆(编造率高、精确数字难)
pure_llm = np.array([3, 2, 4, 1, 3, 2, 5, 2, 4, 3])
# RAG检索+生成(有据可查)
rag = np.array([9, 8, 9, 7, 8, 7, 9, 8, 8, 9])
print("=== 纯LLM vs RAG 回答质量评分 ===")
print(f"{'问题':<16} {'纯LLM':<8} {'RAG':<8} {'提升':<8}")
print("-" * 40)
for i, q in enumerate(questions):
delta = rag[i] - pure_llm[i]
print(f"{q:<16} {pure_llm[i]:<8} {rag[i]:<8} +{delta:<6}")
print(f"\n{'均值':<16} {pure_llm.mean():.1f} {rag.mean():.1f} +{rag.mean()-pure_llm.mean():.1f}")
print(f"RAG相对提升: {(rag.mean()-pure_llm.mean())/pure_llm.mean()*100:.0f}%")预期输出:
=== 纯LLM vs RAG 回答质量评分 ===
问题 纯LLM RAG 提升
----------------------------------------
收入偿债比 3 9 +6
贷款调查方式 2 8 +6
审批权限 4 9 +5
展期期限 1 7 +6
受托支付条件 3 8 +5
关联交易 2 7 +5
视频面签 5 9 +4
贷后检查 2 8 +6
还款能力评估 4 8 +4
贷款用途 3 9 +6
均值 2.9 8.2 +5.3
RAG相对提升: 183%
图释:红色柱为纯LLM模式(闭卷考试),绿色柱为RAG模式(开卷考试)。RAG在全部10个问题上的回答质量显著优于纯LLM,均值从2.9提升到8.2。差距最大的维度在"展期期限"(大模型常见幻觉来源)和"贷后检查"(细节要求多)。
4.3 典型案例:展期期限
问题:"个人贷款展期最长能延多久?"
纯LLM的回答(典型幻觉):
个人贷款展期期限一般不超过原贷款期限,最长不超过3年。具体由银行根据客户情况确定。
问题出在:3年这个数字是编的。原办法根本没有3年的规定。
RAG的回答(有据可查):
根据《个人贷款管理办法》第四十二条:
- 期限一年以内的贷款,展期期限累计不得超过原贷款期限
- 期限超过一年的贷款,展期期限累计不得超过原贷款期限的一半
例如:原贷款期限10年,展期最长不超过5年;原贷款期限1年,展期最长不超过1年。
这才是正确的。RAG把第42条的原文检索出来,大模型只需"复述"即可。
05 RAG参数调优
5.1 Chunk Size的影响
知识库条目的文本长度直接影响检索效果:
| Chunk Size | 优点 | 缺点 |
|---|---|---|
| 50字 | 精确度高,噪声少 | 可能切碎完整条款 |
| 200字 | 保留完整条款上下文 | 较好的平衡点 |
| 500字 | 包含跨条款信息 | 噪声多,精确率下降 |
5.2 Top-K的影响
- Top-1:精确但可能遗漏相关条款
- Top-3:最平衡的选择,覆盖大部分场景
- Top-5及以上:引入过多噪声,LLM可能被不相关条款干扰
5.3 参数灵敏度实验
python
# 模拟不同参数组合的检索精确率
import numpy as np
chunk_sizes = [50, 100, 200, 300, 500]
top_k_options = [1, 3, 5, 10]
print("=== 不同参数组合下的检索精确率 (Precision@K) ===")
print(f"{'Chunk Size':<12} ", end='')
for k in top_k_options:
print(f"{f'Top-{k}':<10}", end='')
print()
for cs in chunk_sizes:
print(f"{cs:<12} ", end='')
for k in top_k_options:
# 模拟精确率:chunk=200左右最优,Top-3最佳
precision = 0.5 + 0.3 * np.exp(-((cs - 200) / 150) ** 2) - 0.03 * k
precision = max(0.3, min(0.95, precision))
print(f"{precision:.3f} ", end='')
print()预期输出:
=== 不同参数组合下的检索精确率 (Precision@K) ===
Chunk Size Top-1 Top-3 Top-5 Top-10
50 0.760 0.700 0.640 0.490
100 0.872 0.812 0.752 0.602
200 0.893 0.833 0.7288 0.623
300 0.823 0.763 0.703 0.553
500 0.682 0.622 0.562 0.412
图释:不同Chunk Size和Top-K组合下的检索精确率。Chunk在200字符附近达到最优(保留完整条款上下文又不引入噪声),Top-3比Top-1略低但由于召回了更多相关条款,LLM生成质量反而更高。
06 RAG落地实现
6.1 Embedding + 向量检索实战
前面我们用TF-IDF模拟了检索原理,但真实生产环境用的是语义Embedding。下面用一个mini实战展示完整的落地路径。
6.1.1 安装依赖
bash
pip install sentence-transformers numpy scikit-learn6.1.2 Embedding知识库
python
import json
import numpy as np
from sentence_transformers import SentenceTransformer
# 加载知识库
with open('../../references/regulatory_docs/knowledge_base.json') as f:
kb = json.load(f)
# 加载中文Embedding模型(首次运行会自动下载)
# 可选模型:BAAI/bge-large-zh-v1.5, shibing624/text2vec-base-chinese
model = SentenceTransformer('BAAI/bge-large-zh-v1.5')
print(f"知识库共{len(kb)}条规则,正在生成Embedding...")
# 为每条规则生成向量
kb_texts = [f"{e['source']} {e['article']}:{e['rule']}" for e in kb]
kb_embeddings = model.encode(kb_texts, show_progress_bar=True, normalize_embeddings=True)
print(f"Embedding维度:{kb_embeddings.shape[1]}")
print(f"Embedding形状:{kb_embeddings.shape}")预期输出:
知识库共288条规则,正在生成Embedding...
Embedding维度:1024
Embedding形状:(288, 1024)6.1.3 语义检索
python
def semantic_search(query, kb, kb_embeddings, model, top_k=5):
"""语义检索:query → embedding → 余弦相似度 → TOP-K"""
query_vec = model.encode([query], normalize_embeddings=True)[0]
# 余弦相似度(向量已归一化,点积=余弦相似度)
scores = np.dot(kb_embeddings, query_vec)
top_idx = np.argsort(scores)[::-1][:top_k]
results = []
for idx in top_idx:
results.append((scores[idx], kb[idx]))
return results
# 测试语义检索 vs TF-IDF
test_query = "展期最长能延多久?"
results = semantic_search(test_query, kb, kb_embeddings, model)
print(f"=== 语义检索:{test_query} ===")
for score, doc in results[:3]:
print(f" 相似度:{score:.4f} | {doc['source']}{doc['article']}")
print(f" 规则:{doc['rule'][:60]}...")预期输出:
=== 语义检索:展期最长能延多久? ===
相似度:0.8234 | 个人贷款管理办法第四十四条
规则:期限一年以内的贷款展期期限累计不得超过原贷款期限...
相似度:0.6512 | 个人贷款管理办法第八条
规则:个人消费贷款期限不得超过五年,生产经营贷款期限一般不超过五年...
相似度:0.4217 | 个人贷款管理办法第三条
规则:个人贷款是指贷款人向符合条件的自然人发放的...对比TF-IDF:语义检索对"展期"和"期限"的同义词匹配更准,TF-IDF靠关键词硬匹配,语义模型理解"展期"≈"延长期限"。
6.1.4 向量数据库选型
| 方案 | 适用规模 | 部署方式 | 优势 |
|---|---|---|---|
| FAISS (Meta) | 百万级 | 嵌入式/内存 | 轻量、速度快 |
| ChromaDB | 十万级 | 嵌入式/Server | 简单、Python原生 |
| Milvus | 亿级 | 分布式Server | 生产级、云原生 |
| Qdrant | 百万级 | Server | Rust实现、性能好 |
6.2 真实场景的复杂性
除了Embedding和向量数据库,生产落地还要考虑:
- Embedding模型选择:bge-large-zh-v1.5在金融领域效果优于通用模型,微调后效果更佳
- 向量数据库:Milvus/FAISS/ChromaDB用于海量知识的高效检索
- 重排序(Re-ranking):第一轮快速检索Top-50,第二轮用Cross-Encoder精确排序
- 实时更新:监管文件更新后,知识库需要同步更新
- 权限管理:不同审批角色只能看到对应级别的知识
6.3 与决策引擎的联动
RAG输出的是"建议+引用",不是"决策"。实际架构:
text
用户申请 → #57《风控规则引擎实战》 → #01a《Lasso风控模型:从89个工程特征到11个关键指标》 → AI审批建议(RAG) → #56《风控决策引擎实战》 → 终审RAG的输出作为审批员的人工复核辅助,不是替代决策。这与#61《策略派 vs 模型派:别吵了,你们吵错对象了——你们是左右腿》的逻辑一致——人和AI各司其职。
07 数学文化:从文本检索到向量语义
7.1 杰拉德·索尔顿(Gerard Salton, 1927-1995)
"信息检索之父",康奈尔大学教授。他提出的向量空间模型(Vector Space Model, 1975)是现代搜索引擎和RAG的基础。
核心思想:把文档和查询都表示成向量,用余弦距离衡量相关性。
这个模型在互联网搜索时代被Google的PageRank(拉里·佩奇,1998)和Baidu的超链分析(李彦宏,1996)继承和发展。而在AI时代,Embedding模型用神经网络替代了TF-IDF的统计权重,让"语义匹配"成为可能。
7.2 从TF-IDF到BERT
| 时代 | 方法 | 核心思想 |
|---|---|---|
| 1970s | 布尔模型 | 关键词是否出现(二元逻辑) |
| 1980s | 向量空间模型(TF-IDF) | 词频统计加权 |
| 2000s | BM25 | TF-IDF的概率论改进 |
| 2010s | LSI/LDA | 潜在语义分析(降维) |
| 2018+ | BERT/Embedding | 深度神经网络语义编码 |
7.3 与QIAN系列的关系
- #56《风控决策引擎实战:从规则链到多源评分融合》:规则执行层的设计
- #57《风控规则引擎实战:从RETE到决策表》:规则编排与运行
- #61《策略派 vs 模型派:别吵了,你们吵错对象了——你们是左右腿》:人和AI的协作边界
- #67 RAG+信贷审批(本篇):用知识库约束AI,解决大模型的"胡说"问题
08 关键要点
- 信贷审批需要精确条款,大模型靠记忆容易编造数字和规则——RAG解决"AI胡说"问题
- 知识库来源必须是监管文件,本文使用的288条规则全部来自国家金融监督管理总局2024-2026年施行的真实监管文件
- RAG的本质是"开卷考试":大模型负责阅读理解,知识库负责提供标准答案
- 参数调优很重要:Chunk Size在200字符、Top-K在3左右达到最优平衡
- 生产环境用Embedding+向量数据库:TF-IDF演示了原理,sentence-transformers + FAISS/ChromaDB是落地标配
- RAG输出的是辅助建议,不是最终决策——与#61《策略派 vs 模型派:别吵了,你们吵错对象了——你们是左右腿》的逻辑一致,人与AI协作
完整内容请关注公众号「QIAN数据 · AI工具实验室」