feat(scenarios): 支持场景配置加载与首页展示
This commit is contained in:
1
apps/__init__.py
Normal file
1
apps/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
apps/scenarios/__init__.py
Normal file
1
apps/scenarios/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
6
apps/scenarios/apps.py
Normal file
6
apps/scenarios/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ScenariosConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "apps.scenarios"
|
||||
64
apps/scenarios/services.py
Normal file
64
apps/scenarios/services.py
Normal file
@@ -0,0 +1,64 @@
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
REQUIRED_FIELDS = [
|
||||
("id",),
|
||||
("name",),
|
||||
("description",),
|
||||
("agent", "role"),
|
||||
("agent", "goal"),
|
||||
("agent", "instructions"),
|
||||
("rag", "enabled"),
|
||||
("tools",),
|
||||
("output", "type"),
|
||||
("audit", "enabled"),
|
||||
]
|
||||
|
||||
|
||||
class ScenarioNotFound(KeyError):
|
||||
pass
|
||||
|
||||
|
||||
class ScenarioValidationError(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
def _get_nested(config: dict, path: tuple[str, ...]):
|
||||
value = config
|
||||
for key in path:
|
||||
if not isinstance(value, dict) or key not in value:
|
||||
raise ScenarioValidationError("缺失必填字段: " + ".".join(path))
|
||||
value = value[key]
|
||||
return value
|
||||
|
||||
|
||||
def validate_scenario(config: dict) -> dict:
|
||||
for field_path in REQUIRED_FIELDS:
|
||||
_get_nested(config, field_path)
|
||||
return config
|
||||
|
||||
|
||||
def _scenario_files() -> list[Path]:
|
||||
config_dir = Path(settings.SCENARIO_CONFIG_DIR)
|
||||
if not config_dir.exists():
|
||||
return []
|
||||
return sorted([*config_dir.glob("*.yaml"), *config_dir.glob("*.yml")])
|
||||
|
||||
|
||||
def list_scenarios() -> list[dict]:
|
||||
scenarios = []
|
||||
for path in _scenario_files():
|
||||
with path.open("r", encoding="utf-8") as file:
|
||||
config = yaml.safe_load(file) or {}
|
||||
scenarios.append(validate_scenario(config))
|
||||
return scenarios
|
||||
|
||||
|
||||
def get_scenario(scenario_id: str) -> dict:
|
||||
for scenario in list_scenarios():
|
||||
if scenario["id"] == scenario_id:
|
||||
return scenario
|
||||
raise ScenarioNotFound(f"场景不存在: {scenario_id}")
|
||||
10
apps/scenarios/urls.py
Normal file
10
apps/scenarios/urls.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
|
||||
app_name = "scenarios"
|
||||
|
||||
urlpatterns = [
|
||||
path("", views.index, name="index"),
|
||||
]
|
||||
7
apps/scenarios/views.py
Normal file
7
apps/scenarios/views.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
from .services import list_scenarios
|
||||
|
||||
|
||||
def index(request):
|
||||
return render(request, "scenarios/index.html", {"scenarios": list_scenarios()})
|
||||
22
configs/document_review.yaml
Normal file
22
configs/document_review.yaml
Normal file
@@ -0,0 +1,22 @@
|
||||
id: document_review
|
||||
name: 文档审核助手
|
||||
description: 检查合同、制度或 SOP 中的风险点和缺失项
|
||||
applicable_questions:
|
||||
- 合同审核
|
||||
- 制度审核
|
||||
agent:
|
||||
role: 文档审核专家
|
||||
goal: 根据审核规则和知识库内容输出结构化审核意见
|
||||
instructions:
|
||||
- 不确定的问题必须标记为需人工复核
|
||||
- 输出必须包含风险等级和修改建议
|
||||
rag:
|
||||
enabled: true
|
||||
collection: document_review
|
||||
top_k: 5
|
||||
tools:
|
||||
- check_required_fields
|
||||
output:
|
||||
type: document_review_report
|
||||
audit:
|
||||
enabled: true
|
||||
22
configs/knowledge_qa.yaml
Normal file
22
configs/knowledge_qa.yaml
Normal file
@@ -0,0 +1,22 @@
|
||||
id: knowledge_qa
|
||||
name: 知识库问答助手
|
||||
description: 用于 SOP、制度、客服知识库和内部文档问答
|
||||
applicable_questions:
|
||||
- SOP 问答
|
||||
- 制度问答
|
||||
agent:
|
||||
role: 知识库问答专家
|
||||
goal: 基于知识库内容回答用户问题
|
||||
instructions:
|
||||
- 回答必须优先基于检索内容
|
||||
- 不确定时说明缺失信息
|
||||
rag:
|
||||
enabled: true
|
||||
collection: knowledge_qa
|
||||
top_k: 5
|
||||
tools:
|
||||
- generate_action_items
|
||||
output:
|
||||
type: general_answer
|
||||
audit:
|
||||
enabled: true
|
||||
23
configs/quality_analysis.yaml
Normal file
23
configs/quality_analysis.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
id: quality_analysis
|
||||
name: 质量异常分析助手
|
||||
description: 用于分析生产质量异常、检索 SOP、生成处理建议
|
||||
applicable_questions:
|
||||
- 质量异常分析
|
||||
- 缺陷原因定位
|
||||
agent:
|
||||
role: 质量管理专家
|
||||
goal: 根据用户问题、知识库和工具结果,输出可执行的质量分析报告
|
||||
instructions:
|
||||
- 回答必须基于知识库或工具结果
|
||||
- 涉及质量风险时给出风险等级
|
||||
rag:
|
||||
enabled: true
|
||||
collection: quality_analysis
|
||||
top_k: 5
|
||||
tools:
|
||||
- query_demo_records
|
||||
- calculate_rate
|
||||
output:
|
||||
type: quality_report
|
||||
audit:
|
||||
enabled: true
|
||||
24
configs/risk_audit.yaml
Normal file
24
configs/risk_audit.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
id: risk_audit
|
||||
name: 风险审核助手
|
||||
description: 用于财务、采购、报销和合同风险审核
|
||||
applicable_questions:
|
||||
- 财务审核
|
||||
- 采购审核
|
||||
- 合同风险分析
|
||||
agent:
|
||||
role: 风险审核专家
|
||||
goal: 识别业务材料中的风险点并给出审核建议
|
||||
instructions:
|
||||
- 风险点必须说明依据
|
||||
- 缺失材料要单独列出
|
||||
rag:
|
||||
enabled: true
|
||||
collection: risk_audit
|
||||
top_k: 5
|
||||
tools:
|
||||
- check_required_fields
|
||||
- calculate_rate
|
||||
output:
|
||||
type: risk_audit_report
|
||||
audit:
|
||||
enabled: true
|
||||
23
configs/ticket_assistant.yaml
Normal file
23
configs/ticket_assistant.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
id: ticket_assistant
|
||||
name: 工单处理助手
|
||||
description: 用于客服、售后和运维工单的分类与回复建议
|
||||
applicable_questions:
|
||||
- 客服工单
|
||||
- 售后工单
|
||||
agent:
|
||||
role: 工单处理专家
|
||||
goal: 判断工单类别、优先级并生成处理建议
|
||||
instructions:
|
||||
- 需要人工处理时明确标记
|
||||
- 回复建议要简洁可执行
|
||||
rag:
|
||||
enabled: true
|
||||
collection: ticket_assistant
|
||||
top_k: 5
|
||||
tools:
|
||||
- query_demo_records
|
||||
- generate_action_items
|
||||
output:
|
||||
type: ticket_response
|
||||
audit:
|
||||
enabled: true
|
||||
23
templates/scenarios/index.html
Normal file
23
templates/scenarios/index.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Universal Agent Demo Framework</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Universal Agent Demo Framework</h1>
|
||||
<p>用于复试展示的通用 AI Agent Demo 框架。</p>
|
||||
<main>
|
||||
{% for scenario in scenarios %}
|
||||
<section>
|
||||
<h2>{{ scenario.name }}</h2>
|
||||
<p>{{ scenario.description }}</p>
|
||||
<p>场景 ID:{{ scenario.id }}</p>
|
||||
<p><a href="{% url 'chat:index' scenario.id %}">进入对话</a></p>
|
||||
</section>
|
||||
{% empty %}
|
||||
<p>暂无可用场景,请检查 configs 目录。</p>
|
||||
{% endfor %}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
30
tests/test_scenarios.py
Normal file
30
tests/test_scenarios.py
Normal file
@@ -0,0 +1,30 @@
|
||||
import pytest
|
||||
|
||||
from apps.scenarios.services import (
|
||||
ScenarioNotFound,
|
||||
get_scenario,
|
||||
list_scenarios,
|
||||
)
|
||||
|
||||
|
||||
def test_list_scenarios_loads_five_configs():
|
||||
scenarios = list_scenarios()
|
||||
assert [scenario["id"] for scenario in scenarios] == [
|
||||
"document_review",
|
||||
"knowledge_qa",
|
||||
"quality_analysis",
|
||||
"risk_audit",
|
||||
"ticket_assistant",
|
||||
]
|
||||
|
||||
|
||||
def test_get_scenario_returns_full_agent_config():
|
||||
scenario = get_scenario("quality_analysis")
|
||||
assert scenario["agent"]["role"] == "质量管理专家"
|
||||
assert scenario["rag"]["enabled"] is True
|
||||
assert scenario["output"]["type"] == "quality_report"
|
||||
|
||||
|
||||
def test_get_scenario_raises_clear_error_for_missing_id():
|
||||
with pytest.raises(ScenarioNotFound, match="场景不存在"):
|
||||
get_scenario("missing")
|
||||
Reference in New Issue
Block a user