大模型合规审计配置:零基础搭建审计日志与敏感词过滤
大模型合规审计配置的核心是记录用户输入和模型输出,并对违规内容进行过滤与告警。
本文适用于在 Linux 服务器上自建大模型 API 服务(如通过 FastChat、vLLM 或 OpenAI 兼容接口部署)的运维人员,默认你已能通过 curl 调用模型接口。
下面从审计日志、敏感词过滤、报表生成三个环节给出可落地的配置方法。
审计日志:用 Nginx 记录完整请求与响应
模型服务通常监听本地端口(例如 127.0.0.1:8000),在前面加一层 Nginx 反向代理,即可在不改模型代码的前提下记录审计日志。
首先安装 Nginx(以 Ubuntu 为例):
sudo apt update
sudo apt install -y nginx
编辑站点配置 /etc/nginx/conf.d/llm-audit.conf,关键配置如下:
log_format audit_log '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$request_body" "$resp_body"';
server {
listen 8080;
location /v1/chat/completions {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
access_log /var/log/nginx/llm_audit.log audit_log;
# 记录请求体(需注意隐私与存储)
lua_need_request_body on;
set $resp_body "";
body_filter_by_lua_block {
local resp_body = string.sub(ngx.arg[1], 1, 1000)
ngx.ctx.buffered = (ngx.ctx.buffered or "") .. resp_body
if ngx.arg[2] then
ngx.var.resp_body = ngx.ctx.buffered
end
}
}
}
注意:body_filter_by_lua_block 需要 Nginx 编译了 Lua 模块(如 nginx-extras 或 OpenResty)。
如果使用原生 Nginx,可改用 mirror 指令将请求复制到审计服务,或直接在应用层记录日志。
验证方法:重启 Nginx 后发送一条测试请求,然后查看日志文件:
sudo nginx -t && sudo systemctl reload nginx
curl -X POST http://127.0.0.1:8080/v1/chat/completions -H "Content-Type: application/json" -d '{"model":"your-model","messages":[{"role":"user","content":"测试审计"}]}'
sudo tail -n 1 /var/log/nginx/llm_audit.log
日志中应包含请求体和响应体片段。
如果日志为空,检查 access_log 路径权限和 Lua 模块是否加载。
敏感词过滤:在代理层拦截违规内容
审计日志用于事后追溯,敏感词过滤则用于事前拦截。
推荐使用开源的 openresty 配合 lua-resty-waf 或简单的 Lua 脚本实现关键词匹配。
以下是一个最小化示例,在 Nginx 配置中加入:
location /v1/chat/completions {
access_by_lua_block {
local body = ngx.req.get_body_data()
if body then
local sensitive_words = {"违禁词1", "违禁词2"} -- 替换为实际词表
for _, word in ipairs(sensitive_words) do
if string.find(body, word, 1, true) then
ngx.log(ngx.WARN, "敏感词命中: ", word)
ngx.status = 403
ngx.say("请求包含违规内容")
return ngx.exit(403)
end
end
end
}
proxy_pass http://127.0.0.1:8000;
}
将敏感词表放在独立文件(如 /etc/nginx/sensitive_words.lua)中便于维护,并使用 dofile 加载。
验证时,用包含敏感词的请求测试:
curl -X POST http://127.0.0.1:8080/v1/chat/completions -H "Content-Type: application/json" -d '{"messages":[{"role":"user","content":"违禁词1"}]}'
预期返回 403 和提示信息。
如果返回正常响应,检查 access_by_lua_block 是否生效,或请求体是否被其他模块提前读取。
审计报表:用脚本汇总日志并生成日报
审计日志积累后,需要定期生成报表供合规检查。
以下 Python 脚本读取 Nginx 审计日志,统计请求量、敏感词命中次数和异常状态码:
import re
from collections import Counter
log_path = "/var/log/nginx/llm_audit.log"
pattern = re.compile(r'"(\w+) ([^"]+)" (\d{3})')
status_counter = Counter()
word_counter = Counter()
with open(log_path, "r", encoding="utf-8", errors="ignore") as f:
for line in f:
m = pattern.search(line)
if m:
status_counter[m.group(3)] += 1
if "敏感词命中" in line:
word = line.split("敏感词命中: ")[-1].strip()
word_counter[word] += 1
print("状态码统计:", dict(status_counter))
print("敏感词命中统计:", dict(word_counter))
将此脚本保存为 /opt/audit_report.py,通过 cron 每日执行并输出到文件:
0 2 * * * /usr/bin/python3 /opt/audit_report.py >> /var/log/audit_report.log 2>&1
验证:手动运行脚本,检查输出是否包含统计结果。
如果日志格式有变,需调整正则表达式。
配置避坑与效果验证
避坑一:
日志体积失控。 请求体和响应体全量记录会快速消耗磁盘,
建议在 Nginx 中限制记录长度(如 $resp_body 截断到 1000 字符),
并配置 logrotate 每日切割、
保留 7 天:
sudo tee /etc/logrotate.d/llm-audit <<'EOF'
/var/log/nginx/llm_audit.log {
daily
rotate 7
compress
missingok
notifempty
sharedscripts
postrotate
systemctl reload nginx > /dev/null 2>&1 || true
endscript
}
EOF
避坑二:敏感词过滤误伤。 简单字符串匹配可能拦截正常内容(如“违禁词1”出现在引用中)。
建议先以告警模式运行(只记录不拦截),观察一周后再切换为拦截模式。
避坑三:性能影响。 Lua 脚本会增加请求延迟,尤其词表较大时。
可将敏感词表放入 lua_shared_dict 缓存,并定期刷新。
效果验证清单:
- 发送正常请求,检查审计日志是否完整记录请求和响应。
- 发送含敏感词的请求,检查是否返回 403 并记录告警日志。
- 运行报表脚本,确认能统计出请求量和命中次数。
- 检查 logrotate 配置,手动执行
logrotate -d /etc/logrotate.d/llm-audit确认无错误。