接入文章优化LLM追踪

This commit is contained in:
czj
2026-07-16 12:19:16 +08:00
parent 90de3a698c
commit 8e50ecef77
9 changed files with 150 additions and 22 deletions
+46 -6
View File
@@ -7,6 +7,13 @@ import { getRepositoryFromRuntime } from "../../../../lib/db/repository";
import { optimizationFactCardSchema } from "../../../../lib/domain/validation";
import type { LlmAuditSummary } from "../../../../lib/llm/audit";
import { LlmValidationError } from "../../../../lib/llm/client";
import { getLlmTracePayloadStoreFromRuntime } from "../../../../lib/llm/trace-payload-store";
import {
createLlmTraceRecorder,
createNoopLlmTraceRecorder,
safeTraceError,
} from "../../../../lib/llm/trace-recorder";
import { getLlmTraceRepositoryFromRuntime } from "../../../../lib/llm/trace-repository";
import { getExportStoreFromRuntime } from "../../../../lib/workflow/export-store";
import { extractCandidateFactCard } from "../../../../lib/workflow/fact-extractor";
import {
@@ -61,6 +68,7 @@ export async function POST(request: Request) {
let jobId: string | undefined;
let caseId: string | undefined;
let stage: OptimizationStreamStage = "job";
let traceRecorder = createNoopLlmTraceRecorder();
const llmAuditSummary: LlmAuditSummary[] = [];
const processSummary: ProcessSummaryStep[] = [];
const requestStartedAt = Date.now();
@@ -104,6 +112,23 @@ export async function POST(request: Request) {
case: { id: optimizationCase.id, case_type: "article" },
});
try {
traceRecorder = await createLlmTraceRecorder({
jobId: job.id,
caseId: optimizationCase.id,
repository: getLlmTraceRepositoryFromRuntime(),
payloadStore: getLlmTracePayloadStoreFromRuntime(),
publish: (event) => send(event),
});
} catch (error) {
send({
type: "trace_warning",
job_id: job.id,
trace_completeness: "incomplete",
error_summary: safeTraceError(error),
});
}
stage = "fact_card";
const factCardStartedAt = Date.now();
const factCard = optimizationFactCardSchema.parse(
@@ -112,6 +137,7 @@ export async function POST(request: Request) {
onAuditSummary: (summary) => {
llmAuditSummary.push(summary);
},
onTraceEvent: traceRecorder.onLlmEvent,
})),
);
processSummary.push(
@@ -124,20 +150,24 @@ export async function POST(request: Request) {
}),
);
const savedFactCard = await repository.saveFactCard(job.id, factCard);
send({
const factCardReadyEvent: OptimizationStreamEvent = {
type: "fact_card_ready",
job_id: job.id,
fact_card: savedFactCard,
});
};
await traceRecorder.onWorkflowEvent(factCardReadyEvent);
send(factCardReadyEvent);
const result = await runStreamingOptimizationWorkflow({
jobId: job.id,
input: normalized.articleInput,
factCard: savedFactCard,
onEvent: (event) => {
onEvent: async (event) => {
stage = stageForEvent(event, stage);
await traceRecorder.onWorkflowEvent(event);
send(event);
},
onTraceEvent: traceRecorder.onLlmEvent,
onAuditSummary: (summary) => {
llmAuditSummary.push(summary);
},
@@ -180,7 +210,7 @@ export async function POST(request: Request) {
error_stage: null,
error_summary: null,
});
send({
const finalReadyEvent: OptimizationStreamEvent = {
type: "final_ready",
job_id: job.id,
case: { id: optimizationCase.id, case_type: "article" },
@@ -188,7 +218,10 @@ export async function POST(request: Request) {
optimized_article: optimizedArticle,
qa_report: qaReport,
export_paths: exportPaths,
});
};
await traceRecorder.onWorkflowEvent(finalReadyEvent);
await traceRecorder.finish({ status: "completed" });
send(finalReadyEvent);
} catch (error) {
const message = error instanceof Error ? error.message : "优化失败";
let failedVersion:
@@ -225,14 +258,21 @@ export async function POST(request: Request) {
failedVersion = undefined;
}
}
send({
const failedEvent: OptimizationStreamEvent = {
type: "failed",
job_id: jobId,
case: caseId ? { id: caseId, case_type: "article" } : undefined,
result_version: failedVersion,
stage,
error: message,
};
await traceRecorder.onWorkflowEvent(failedEvent);
await traceRecorder.finish({
status: "failed",
errorStage: stage,
errorSummary: message,
});
send(failedEvent);
} finally {
controller.close();
}