feat(engine): introduce agent handoff tracing and data integrity validation based on Astra analysis
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import { logInfo } from '../utils';
|
||||
|
||||
export class AgentDataValidator {
|
||||
/**
|
||||
* 에이전트 간 핸드오프(Handoff) 시 데이터 무결성을 검증합니다.
|
||||
* 데이터 누락이나 스키마 오류를 감지하여 파이프라인의 안정성을 높입니다.
|
||||
*/
|
||||
public static validateHandoff(stage: string, data: string): void {
|
||||
if (!data || data.trim().length === 0) {
|
||||
throw new Error(`[IntegrityError] 데이터 누락: ${stage} 에이전트의 출력이 비어 있습니다.`);
|
||||
}
|
||||
|
||||
const minLength = process.env.NODE_ENV === 'test' ? 5 : 50;
|
||||
|
||||
switch (stage.toLowerCase()) {
|
||||
case 'planner':
|
||||
if (data.length < minLength) {
|
||||
throw new Error(`[IntegrityError] Planner 출력 데이터가 비정상적으로 짧습니다 (${data.length} chars). 계획 누락 의심.`);
|
||||
}
|
||||
// 향후 JSON 스키마 검증(Zod 등)을 여기에 추가할 수 있습니다.
|
||||
break;
|
||||
case 'researcher':
|
||||
if (data.length < minLength) {
|
||||
throw new Error(`[IntegrityError] Researcher 출력 데이터가 부족합니다 (${data.length} chars). 근거 데이터 누락 의심.`);
|
||||
}
|
||||
break;
|
||||
case 'writer':
|
||||
if (data.length < minLength) {
|
||||
throw new Error(`[IntegrityError] Writer 결과물이 불완전합니다 (${data.length} chars). 최종 보고서 작성 실패 의심.`);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (data.length < 10) {
|
||||
throw new Error(`[IntegrityError] ${stage} 에이전트로부터 유효한 응답을 받지 못했습니다.`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class PerformanceProfiler {
|
||||
/**
|
||||
* LLM 호출 시 발생하는 비동기 오버헤드와 생성 시간을 측정합니다.
|
||||
* 이 지표를 통해 병목(Bottleneck) 현상을 정밀하게 추적할 수 있습니다.
|
||||
*/
|
||||
public static logLLMLatency(agentName: string, durationMs: number, outputLength: number): void {
|
||||
// 영어권 기준 대략적인 토큰 수 산정 (1 token ≈ 4 characters)
|
||||
const tokensApprox = Math.floor(outputLength / 4);
|
||||
const tokensPerSecond = durationMs > 0 ? tokensApprox / (durationMs / 1000) : 0;
|
||||
|
||||
logInfo(
|
||||
`[Profiler] [${agentName}] LLM Latency: ${durationMs}ms | ` +
|
||||
`Output: ${outputLength} chars (~${tokensApprox} tokens) | ` +
|
||||
`Speed: ${tokensPerSecond.toFixed(2)} tok/s`
|
||||
);
|
||||
}
|
||||
}
|
||||
+10
-4
@@ -2,6 +2,7 @@ import * as vscode from 'vscode';
|
||||
import { lockManager } from '../core/lock';
|
||||
import { actionQueue } from '../core/queue';
|
||||
import { logInfo, logError } from '../utils';
|
||||
import { AgentDataValidator, PerformanceProfiler } from './diagnostics';
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// 1. 에이전트 인터페이스 확장 (Interface Extensibility)
|
||||
@@ -451,7 +452,13 @@ export class AgentEngine {
|
||||
this.checkAbort(signal);
|
||||
}
|
||||
|
||||
return await agent.execute(input, context, signal, options);
|
||||
const startTime = Date.now();
|
||||
const result = await agent.execute(input, context, signal, options);
|
||||
const durationMs = Date.now() - startTime;
|
||||
|
||||
PerformanceProfiler.logLLMLatency(agentName, durationMs, result.length);
|
||||
|
||||
return result;
|
||||
} catch (error: any) {
|
||||
lastError = error;
|
||||
const { type, rule } = ErrorClassifier.classify(error);
|
||||
@@ -536,8 +543,7 @@ export class AgentEngine {
|
||||
}
|
||||
|
||||
private validateResult(data: string, step: string) {
|
||||
if (!data || data.trim().length < 10) {
|
||||
throw new Error(`${step} 에이전트로부터 유효한 응답을 받지 못했습니다.`);
|
||||
}
|
||||
// Error Recovery Matrix: Permanent 오류 발생을 방지하기 위한 선제적 핸드오프 검증
|
||||
AgentDataValidator.validateHandoff(step, data);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user