feat(agent): 增加 LLM 路由与诊断日志

This commit is contained in:
2026-06-06 17:56:41 +08:00
parent 47b5ad1054
commit fa77c68d77
21 changed files with 832 additions and 17 deletions

View File

@@ -1,5 +1,6 @@
from __future__ import annotations
import logging
from threading import Thread
from uuid import uuid4
@@ -36,6 +37,9 @@ NODE_DEFINITIONS = [
]
logger = logging.getLogger("review_agent.file_summary.workflow")
def default_skill_registry() -> SkillRegistry:
registry = SkillRegistry()
registry.register(ArchiveExtractSkill())
@@ -65,6 +69,14 @@ def create_file_summary_batch(
)
if not active_attachments:
raise ValueError("当前对话没有可用附件。")
logger.info(
"File summary batch creation started",
extra={
"conversation_id": conversation.pk,
"user_id": user.pk,
"attachment_ids": [attachment.pk for attachment in active_attachments],
},
)
batch = FileSummaryBatch.objects.create(
conversation=conversation,
@@ -82,6 +94,10 @@ def create_file_summary_batch(
WorkflowNodeRun.objects.create(batch=batch, node_code=code, node_name=name)
record_event(batch, "workflow_created", {"batch_id": batch.pk, "batch_no": batch.batch_no})
logger.info(
"File summary batch created",
extra={"batch_id": batch.pk, "batch_no": batch.batch_no},
)
return batch
@@ -91,6 +107,7 @@ class WorkflowExecutor:
self.registry = registry or default_skill_registry()
def run(self) -> None:
logger.info("Workflow run started", extra={"batch_id": self.batch.pk})
self.batch.status = FileSummaryBatch.Status.RUNNING
self.batch.started_at = timezone.now()
self.batch.save(update_fields=["status", "started_at"])
@@ -100,6 +117,10 @@ class WorkflowExecutor:
for node in self.batch.node_runs.order_by("id"):
self._run_node(node)
except Exception as exc:
logger.exception(
"Workflow run failed",
extra={"batch_id": self.batch.pk, "error": str(exc)},
)
self.batch.status = FileSummaryBatch.Status.FAILED
self.batch.error_message = str(exc)
self.batch.finished_at = timezone.now()
@@ -111,8 +132,17 @@ class WorkflowExecutor:
self.batch.finished_at = timezone.now()
self.batch.save(update_fields=["status", "finished_at"])
record_event(self.batch, "workflow_completed", {"batch_id": self.batch.pk})
logger.info("Workflow run completed", extra={"batch_id": self.batch.pk})
def _run_node(self, node: WorkflowNodeRun) -> None:
logger.info(
"Workflow node started",
extra={
"batch_id": self.batch.pk,
"node_code": node.node_code,
"node_name": node.node_name,
},
)
now = timezone.now()
node.status = WorkflowNodeRun.Status.RUNNING
node.progress = 10
@@ -132,6 +162,15 @@ class WorkflowExecutor:
if skill_name:
result = self.registry.execute(skill_name, WorkflowContext(batch=self.batch))
if not result.success:
logger.warning(
"Workflow node skill failed",
extra={
"batch_id": self.batch.pk,
"node_code": node.node_code,
"skill_name": skill_name,
"result_message": result.message,
},
)
raise RuntimeError(result.message or f"{node.node_name}执行失败")
node.status = WorkflowNodeRun.Status.SUCCESS
@@ -144,11 +183,17 @@ class WorkflowExecutor:
"node_progress",
{"node_code": node.node_code, "status": node.status, "progress": node.progress},
)
logger.info(
"Workflow node finished",
extra={"batch_id": self.batch.pk, "node_code": node.node_code},
)
def start_file_summary_workflow(batch: FileSummaryBatch, *, async_run: bool = True) -> None:
executor = WorkflowExecutor(batch)
if not async_run:
logger.info("Workflow starting synchronously", extra={"batch_id": batch.pk})
executor.run()
return
logger.info("Workflow starting asynchronously", extra={"batch_id": batch.pk})
Thread(target=executor.run, daemon=True).start()