feat: add trusted ticket intake backend

This commit is contained in:
hailin
2026-07-16 19:37:32 +08:00
parent b592dc219d
commit bcd6de4609
28 changed files with 1966 additions and 42 deletions

View File

@@ -0,0 +1,159 @@
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from django.utils import timezone
from apps.agents.models import AgentDefinition, AgentStepBinding, AgentVersion
from apps.modelhub.models import ModelDeployment
from apps.skills.models import SkillDefinition, SkillVersion
TICKET_FIELDS = {
"type": "object",
"properties": {
"title": {"type": "string"},
"description": {"type": "string"},
"category_code": {"type": "string"},
"priority": {"type": "string", "enum": ["low", "medium", "high", "urgent"]},
"problem_performance": {"type": "string"},
"problem_object": {"type": "string"},
"submitter_name": {"type": "string"},
"submitter_org": {"type": "string"},
"impact_scope": {"type": "string"},
"environment": {"type": "string"},
"related_system": {"type": "string"},
},
"required": [
"title",
"description",
"category_code",
"priority",
"problem_performance",
"problem_object",
"submitter_name",
"submitter_org",
"impact_scope",
"environment",
"related_system",
],
"additionalProperties": False,
}
AGENT_INPUT_SCHEMA = {
"type": "object",
"properties": {
"source_text": {"type": "string"},
"current_fields": {"type": "object"},
"messages": {"type": "array", "items": {"type": "object"}},
"image_refs": {"type": "array", "items": {"type": "object"}},
},
"required": ["source_text", "current_fields", "messages", "image_refs"],
}
OUTPUT_SCHEMA = {
"type": "object",
"properties": {
"fields": TICKET_FIELDS,
"missing_fields": {"type": "array", "items": {"type": "string"}},
"questions": {"type": "array", "items": {"type": "string"}},
},
"required": ["fields", "missing_fields", "questions"],
"additionalProperties": False,
}
class Command(BaseCommand):
help = "Create and publish the single-step ticket intake Agent and Skill."
def add_arguments(self, parser):
parser.add_argument("--deployment-id", type=int)
@transaction.atomic
def handle(self, *args, **options):
deployments = ModelDeployment.objects.filter(enabled=True, provider__enabled=True)
deployment_id = options.get("deployment_id")
deployment = (
deployments.filter(id=deployment_id).first() if deployment_id else deployments.first()
)
if deployment is None:
raise CommandError("请先配置并启用模型渠道和模型配置")
skill, _ = SkillDefinition.objects.get_or_create(
code="ticket-draft",
defaults={"name": "可信建单草稿", "description": "从描述与追问答案生成工单草稿。"},
)
skill_version = skill.versions.filter(status="published").order_by("-version").first()
if skill_version is None:
next_version = (
skill.versions.order_by("-version").values_list("version", flat=True).first() or 0
) + 1
skill_version = SkillVersion.objects.create(
definition=skill,
version=next_version,
status="published",
prompt_template=(
"根据用户原始描述 {{ input.source_text }}、"
"当前字段 {{ input.current_fields }}、"
"逐问记录 {{ input.messages }} 以及随消息提供的可选图片,生成完整工单草稿。"
"分类代码只能使用 business_issue、operation_issue、"
"data_issue、technical_issue。"
"无法可靠判断的值使用空字符串并列入 missing_fields,同时为缺失项生成简洁问题。"
"只输出符合 Schema 的 JSON。"
),
input_schema=AGENT_INPUT_SCHEMA,
output_schema=OUTPUT_SCHEMA,
example_input={
"source_text": "生产环境采集任务两小时没有更新",
"current_fields": {},
"messages": [],
"image_refs": [],
},
published_at=timezone.now(),
)
skill.active_version = skill_version
skill.save(update_fields=["active_version", "updated_at"])
agent, _ = AgentDefinition.objects.get_or_create(
code="ticket-intake",
defaults={"name": "可信建单 Agent", "description": "单步生成可审核的结构化工单草稿。"},
)
version = agent.versions.filter(status="published").order_by("-version").first()
if version is None:
next_version = (
agent.versions.order_by("-version").values_list("version", flat=True).first() or 0
) + 1
version = AgentVersion.objects.create(
definition=agent,
version=next_version,
status="published",
model_deployment=deployment,
system_prompt=(
"你是企业技术支持建单助手。不得创建工单,只生成待用户审核的 JSON 草稿;"
"不得臆造机构、联系人、环境或影响范围。"
),
input_schema=AGENT_INPUT_SCHEMA,
example_input={
"source_text": "生产环境采集任务两小时没有更新",
"current_fields": {},
"messages": [],
"image_refs": [],
},
published_at=timezone.now(),
)
AgentStepBinding.objects.create(
agent_version=version,
code="draft",
order=1,
skill_version=skill_version,
input_mapping={
"source_text": "$input.source_text",
"current_fields": "$input.current_fields",
"messages": "$input.messages",
"image_refs": "$input.image_refs",
},
)
agent.active_version = version
agent.save(update_fields=["active_version", "updated_at"])
self.stdout.write(
self.style.SUCCESS(
f"Published ticket-intake v{version.version} with deployment {deployment.id}."
)
)