diff --git a/apps/audit/models.py b/apps/audit/models.py index 5a2dc7d..48edd01 100644 --- a/apps/audit/models.py +++ b/apps/audit/models.py @@ -2,6 +2,7 @@ from django.db import models class AgentAuditLog(models.Model): + # 审计状态需要同时服务数据库检索和前端展示。 STATUS_SUCCESS = "success" STATUS_FAILED = "failed" @@ -25,6 +26,19 @@ class AgentAuditLog(models.Model): def __str__(self) -> str: return f"{self.scenario_name or self.scenario_id} #{self.pk}" + def get_status_display_text(self) -> str: + """返回更适合页面展示的中文状态。""" + return { + self.STATUS_SUCCESS: "执行成功", + self.STATUS_FAILED: "执行失败", + }.get(self.status, self.status) + + def get_user_input_summary(self, max_length: int = 28) -> str: + """在列表页展示用户输入摘要,避免长文本撑破表格。""" + if len(self.user_input) <= max_length: + return self.user_input + return f"{self.user_input[:max_length]}..." + class DemoBusinessRecord(models.Model): scenario_id = models.CharField(max_length=100, db_index=True) diff --git a/apps/audit/views.py b/apps/audit/views.py index 11484fd..594c3d2 100644 --- a/apps/audit/views.py +++ b/apps/audit/views.py @@ -4,8 +4,19 @@ from .models import AgentAuditLog def log_list(request): + # 列表页支持按场景筛选,方便演示时快速定位同一类场景的执行记录。 + scenario_id = (request.GET.get("scenario_id") or "").strip() logs = AgentAuditLog.objects.all() - return render(request, "audit/log_list.html", {"logs": logs}) + if scenario_id: + logs = logs.filter(scenario_id=scenario_id) + return render( + request, + "audit/log_list.html", + { + "logs": logs, + "selected_scenario_id": scenario_id, + }, + ) def log_detail(request, log_id: int): diff --git a/templates/audit/log_list.html b/templates/audit/log_list.html index 94f6ffc..cca078b 100644 --- a/templates/audit/log_list.html +++ b/templates/audit/log_list.html @@ -7,6 +7,12 @@ 执行留痕

审计日志

每次 Agent 执行都会记录模型、检索片段、工具调用和最终结果,方便演示链路可解释性。

+ {% if selected_scenario_id %} +

+ 当前筛选场景:{{ selected_scenario_id }} + 清空筛选 +

+ {% endif %}
@@ -15,9 +21,11 @@ ID 场景 + 输入摘要 状态 模型 耗时 + 创建时间 详情 @@ -26,13 +34,15 @@ {{ log.id }} {{ log.scenario_name }} - {{ log.status }} + {{ log.get_user_input_summary }} + {{ log.get_status_display_text }} {{ log.model_name }} {{ log.latency_ms }} ms + {{ log.created_at|date:"Y-m-d H:i" }} 查看详情 {% empty %} - 暂无审计日志,先去执行一次对话吧。 + 暂无审计日志,先去执行一次对话吧。 {% endfor %} diff --git a/tests/test_audit.py b/tests/test_audit.py index 6a7d43b..4ac7b31 100644 --- a/tests/test_audit.py +++ b/tests/test_audit.py @@ -27,6 +27,41 @@ def test_audit_list_page_shows_log(client, db): assert "知识库问答助手" in response.content.decode("utf-8") +def test_audit_list_can_filter_by_scenario(client, db): + create_audit_log( + "knowledge_qa", + "知识库问答助手", + "制度问题", + AgentResult(answer="回答一", status="success"), + ) + create_audit_log( + "quality_analysis", + "质量异常分析助手", + "质量问题", + AgentResult(answer="回答二", status="success"), + ) + + response = client.get(reverse("audit:list"), {"scenario_id": "knowledge_qa"}) + + content = response.content.decode("utf-8") + assert response.status_code == 200 + assert "知识库问答助手" in content + assert "质量异常分析助手" not in content + + +def test_audit_list_page_shows_user_input_summary(client, db): + create_audit_log( + "knowledge_qa", + "知识库问答助手", + "这是一个比较长的用户输入,用于确认列表页会展示输入摘要。", + AgentResult(answer="回答", status="success"), + ) + + response = client.get(reverse("audit:list")) + + assert "这是一个比较长的用户输入" in response.content.decode("utf-8") + + def test_create_audit_log_masks_api_keys_from_error_message(db): result = AgentResult( answer="",