给推理接口加一层AI透明度配置,让每次输出可追溯
AI透明度配置不是给模型加个说明文档,而是让每次推理输出都能回答三个问题:调用了哪个模型、依据了哪些输入、经过了哪些处理步骤。
如果你的服务已经有推理接口,不需要重构模型,可以在接口前加一层记录中间件,把透明度信息写进结构化日志。
适用条件是你能拿到推理请求和响应,并且有地方存日志;
如果模型是闭源第三方 API,记录范围会受对方返回字段限制,这一点先确认再动手。
先定记录字段,再写代码
透明度记录不需要记录所有内容,先定最小字段集。
一个可用的起点是:请求 ID、模型名称和版本、输入内容的摘要哈希、输出内容摘要、调用耗时、是否命中缓存、返回状态。
输入原文是否落盘要单独决策,默认只记哈希和长度,避免把用户敏感内容直接写进日志。
在项目里新建 transparency.py,把字段定义成常量,后续改字段只改一处。
TRANSPARENCY_FIELDS = [
"request_id",
"model_name",
"model_version",
"input_hash",
"input_length",
"output_hash",
"output_length",
"latency_ms",
"cache_hit",
"status",
]
模型版本不要手写死,能从模型配置或加载信息里读取就读取,否则版本字段会随时间失真。
在推理接口前挂记录中间件
以常见的 Python Web 服务为例,在请求进入推理函数前生成请求 ID,推理返回后补齐输出字段,再统一写日志。
下面是一个最小中间件示例,按你实际框架调整装饰器写法即可。
import hashlib, time, uuid, json, logging
logger = logging.getLogger("transparency")
def transparency_record(payload, model_name, model_version):
raw = json.dumps(payload, ensure_ascii=False, sort_keys=True)
return {
"request_id": str(uuid.uuid4()),
"model_name": model_name,
"model_version": model_version,
"input_hash": hashlib.sha256(raw.encode()).hexdigest(),
"input_length": len(raw),
"cache_hit": False,
"status": "received",
}
async def infer_with_record(payload, infer_func):
record = transparency_record(payload, "your-model", "2025-01")
start = time.time()
try:
output = await infer_func(payload)
record["status"] = "success"
out_raw = json.dumps(output, ensure_ascii=False, sort_keys=True)
record["output_hash"] = hashlib.sha256(out_raw.encode()).hexdigest()
record["output_length"] = len(out_raw)
return output
except Exception:
record["status"] = "error"
raise
finally:
record["latency_ms"] = int((time.time() - start) * 1000)
logger.info(json.dumps(record, ensure_ascii=False))
这段代码只负责记录,不改变推理结果。
如果接口有缓存层,把 cache_hit 在命中缓存的分支里置为 True,否则透明度记录会误导排查。
避坑:日志脱敏和保留周期先定好
透明度和隐私是两件事,但很容易在日志里混在一起。
输入哈希不能反推原文,这是默认安全的原因;
一旦为了排查方便把原文也写进日志,就需要单独的脱敏规则和访问控制。
保留周期也要提前定。
日志保留太久会增加泄露面,保留太短又无法回溯问题。
一个折中做法是按天分文件,保留最近 30 天,超出后自动清理,具体天数按你的合规要求调整,不要照搬。
另外,模型名称和版本要来自配置文件或加载信息,不要依赖注释或人工记忆,否则记录字段会变成摆设。
验证记录是否真的完整
改完后不要只看日志有没有输出,要抽查三条链路:正常请求、异常请求、缓存命中。
正常请求的 status 应为 success,异常请求应为 error 且保留原异常,缓存命中时 cache_hit 为 True。
可以用一段小脚本按 request_id 检索日志,确认字段齐全:
grep '"request_id"' /var/log/transparency/app.log | tail -n 5
如果日志里缺少 output_hash,先检查推理函数是否抛出了未被捕获的异常,再检查 finally 块是否执行。
记录层本身不应该吞掉异常,否则排查会更难。
什么时候需要扩展记录范围
如果业务涉及多步处理,比如检索增强或规则过滤,只记录输入输出哈希不够,需要把中间步骤的版本或标识也加进字段。
反过来,如果只是单模型短文本分类,最小字段集通常已经够用。
透明度配置的目标是让每次输出可追溯,不是记录越多越好。
最后提醒一点:透明度记录不能替代模型评估或审计,它只解决“这次输出是怎么来的”这个问题。
先按上面的字段和中间件落地,再根据实际排查需求增删字段,比一开始就设计大而全的方案更容易维护。