refactor: 下沉会话执行编排到 chat 服务层

This commit is contained in:
2026-06-04 04:31:55 +08:00
parent de2bd2956f
commit 1b6c54fe78
3 changed files with 159 additions and 87 deletions

View File

@@ -1,3 +1,12 @@
from collections.abc import Callable
from django.utils import timezone
from agent_core.orchestrator import run_agent
from agent_core.results import AgentResult
from apps.audit.services import create_audit_log, create_notification_record
from apps.scenarios.services import get_scenario
from .models import Conversation
@@ -19,6 +28,48 @@ def create_conversation_for_batch(batch_id: str, product_name: str) -> Conversat
return conversation
def execute_conversation_agent(
*,
conversation: Conversation,
message: str,
document_ids: list[int],
detail_url_builder: Callable[[int], str] | None = None,
) -> tuple[AgentResult, object]:
"""
在服务层串起会话执行、审计留痕与通知落库。
View 只负责收集请求参数和渲染结果,不直接承载 Agent Core 编排。
"""
scenario = get_scenario("document_review")
try:
result = run_agent(
scenario,
message,
options={
"conversation_id": conversation.conversation_id,
"batch_id": conversation.batch_id,
"product_name": conversation.product_name,
"document_ids": document_ids,
},
)
except Exception as exc:
result = AgentResult(status="failed", error=str(exc), answer="")
audit_log = create_audit_log(
"document_review",
"注册审核智能体",
message,
result,
batch_id=conversation.batch_id,
conversation_id=conversation.conversation_id,
product_name=conversation.product_name,
)
_apply_agent_result_to_conversation(conversation, result)
detail_url = detail_url_builder(audit_log.id) if detail_url_builder else ""
_persist_notification_records(result, web_detail_url=detail_url)
return result, audit_log
def _generate_conversation_id() -> str:
return f"conv-{Conversation.objects.count() + 1:03d}"
@@ -34,3 +85,51 @@ def _build_initial_node_results() -> list[dict]:
{"code": "word_export", "label": "Word 回填导出", "status": "待处理"},
{"code": "feishu_notify", "label": "飞书通知", "status": "待处理"},
]
def _persist_notification_records(result: AgentResult, *, web_detail_url: str = "") -> None:
payload = result.notification_payload or {}
owners = payload.get("owners") or []
if not owners:
return
resolved_detail_url = payload.get("web_detail_url") or web_detail_url
resolved_message_status = payload.get("message_status") or (
"sent" if result.status == "success" else "failed"
)
resolved_receipt = payload.get("receipt") or {"status": result.status}
for owner in owners:
create_notification_record(
batch_id=payload.get("batch_id", ""),
conversation_id=payload.get("conversation_id", ""),
product_name=payload.get("product_name", ""),
trigger_source="agent_execution",
notify_reason=payload.get("notify_reason", "task_completed"),
owner_role=owner.get("owner_role", ""),
feishu_user_id=owner.get("feishu_user_id", ""),
message_status=resolved_message_status,
web_detail_url=resolved_detail_url,
receipt=resolved_receipt,
)
def _apply_agent_result_to_conversation(conversation: Conversation, result: AgentResult) -> None:
conversation.task_status = result.status
if result.node_results:
conversation.node_results = result.node_results
conversation.latest_summary = {
"answer": result.answer,
"status": result.status,
"error": result.error,
"structured_output": result.structured_output,
"notification_payload": result.notification_payload,
}
conversation.last_run_at = timezone.now()
conversation.save(
update_fields=[
"task_status",
"node_results",
"latest_summary",
"last_run_at",
"updated_at",
]
)

View File

@@ -1,19 +1,17 @@
from django.contrib import messages
from django.utils import timezone
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.views.decorators.http import require_POST
from agent_core.orchestrator import run_agent
from agent_core.results import AgentResult
from apps.audit.services import create_audit_log, create_notification_record
from apps.audit.services import create_audit_log
from apps.documents.models import SubmissionBatch, UploadedDocument
from apps.documents.services import append_documents_to_batch
from apps.scenarios.services import get_scenario
from .export_service import generate_registration_export, update_conversation_with_export_report
from .forms import ChatForm, ConversationUploadForm
from .models import Conversation
from .services import execute_conversation_agent
RISK_LEVEL_DISPLAY = {
"high": "",
@@ -86,34 +84,12 @@ def detail(request, conversation_id: str):
{"name": "综合风险报告", "description": "形成高优先级问题、建议动作和责任人通知。"},
]
if request.method == "POST" and form.is_valid():
scenario = get_scenario("document_review")
message = form.cleaned_data["message"]
try:
result = run_agent(
scenario,
message,
options={
"conversation_id": conversation.conversation_id,
"batch_id": conversation.batch_id,
"product_name": conversation.product_name,
"document_ids": form.cleaned_data["document_ids"],
},
)
except Exception as exc:
result = AgentResult(status="failed", error=str(exc), answer="")
audit_log = create_audit_log(
"document_review",
"注册审核智能体",
message,
result,
batch_id=conversation.batch_id,
conversation_id=conversation.conversation_id,
product_name=conversation.product_name,
)
_apply_agent_result_to_conversation(conversation, result)
_persist_notification_records(
result,
web_detail_url=reverse("audit:detail", args=[audit_log.id]),
result, audit_log = execute_conversation_agent(
conversation=conversation,
message=message,
document_ids=form.cleaned_data["document_ids"],
detail_url_builder=lambda log_id: reverse("audit:detail", args=[log_id]),
)
active_node = "risk"
conversation.refresh_from_db()
@@ -233,32 +209,6 @@ def export_word(request, conversation_id: str):
messages.error(request, f"Word 导出失败:{exc}")
return redirect("chat:detail", conversation_id=conversation.conversation_id)
def _persist_notification_records(result: AgentResult, *, web_detail_url: str = "") -> None:
payload = result.notification_payload or {}
owners = payload.get("owners") or []
if not owners:
return
resolved_detail_url = payload.get("web_detail_url") or web_detail_url
resolved_message_status = payload.get("message_status") or (
"sent" if result.status == "success" else "failed"
)
resolved_receipt = payload.get("receipt") or {"status": result.status}
for owner in owners:
create_notification_record(
batch_id=payload.get("batch_id", ""),
conversation_id=payload.get("conversation_id", ""),
product_name=payload.get("product_name", ""),
trigger_source="agent_execution",
notify_reason=payload.get("notify_reason", "task_completed"),
owner_role=owner.get("owner_role", ""),
feishu_user_id=owner.get("feishu_user_id", ""),
message_status=resolved_message_status,
web_detail_url=resolved_detail_url,
receipt=resolved_receipt,
)
def _build_workspace_summary(
conversation: Conversation,
batch: SubmissionBatch | None,
@@ -495,26 +445,3 @@ def _get_export_status_display_text(status: str) -> str:
def _get_notify_message_status_display_text(status: str) -> str:
return NOTIFY_MESSAGE_STATUS_DISPLAY.get(status, status)
def _apply_agent_result_to_conversation(conversation: Conversation, result: AgentResult) -> None:
conversation.task_status = result.status
if result.node_results:
conversation.node_results = result.node_results
conversation.latest_summary = {
"answer": result.answer,
"status": result.status,
"error": result.error,
"structured_output": result.structured_output,
"notification_payload": result.notification_payload,
}
conversation.last_run_at = timezone.now()
conversation.save(
update_fields=[
"task_status",
"node_results",
"latest_summary",
"last_run_at",
"updated_at",
]
)