from agent_core.results import AgentResult from .models import AgentAuditLog def create_audit_log( scenario_id: str, scenario_name: str, user_input: str, agent_result: AgentResult, ) -> AgentAuditLog: """ 将一次 Agent 执行结果落库为审计日志。 设计原则: - 成功与失败都必须记录,方便复盘整条执行链路 - 敏感信息在写库前先脱敏,避免误存 API Key - 对前端和 Django Model 统一输出稳定字段 """ return AgentAuditLog.objects.create( scenario_id=scenario_id, scenario_name=scenario_name, user_input=user_input, retrieved_chunks=agent_result.references, tool_calls=agent_result.tool_calls, structured_output=agent_result.structured_output, final_answer=agent_result.answer, raw_output=agent_result.raw_output, model_name=agent_result.model_name, latency_ms=max(agent_result.latency_ms, 0), status=agent_result.status, error_message=mask_sensitive_text(agent_result.error), ) def mask_sensitive_text(value: str) -> str: """ 对错误文本中的敏感配置进行脱敏。 当前至少处理: - `LLM_API_KEY=...` - `EMBEDDING_API_KEY=...` """ masked = value for marker in ("LLM_API_KEY=", "EMBEDDING_API_KEY="): masked = _mask_token_after_marker(masked, marker) return masked def _mask_token_after_marker(value: str, marker: str) -> str: """将 marker 后紧跟的 token 替换为脱敏占位符。""" if marker not in value: return value prefix, _, suffix = value.partition(marker) secret, separator, rest = suffix.partition(" ") masked_secret = "sk-***" if secret.startswith("sk-") else "***" return f"{prefix}{marker}{masked_secret}{separator}{rest}"