diff --git a/packages/services/conversation-service/src/infrastructure/agents/coordinator/coordinator-agent.service.ts b/packages/services/conversation-service/src/infrastructure/agents/coordinator/coordinator-agent.service.ts index 8aa291d..a824e01 100644 --- a/packages/services/conversation-service/src/infrastructure/agents/coordinator/coordinator-agent.service.ts +++ b/packages/services/conversation-service/src/infrastructure/agents/coordinator/coordinator-agent.service.ts @@ -219,8 +219,9 @@ export class CoordinatorAgentService implements OnModuleInit { turnCount: number, agentsUsedInLoop: string[], ) => { - return this.evaluationGate.evaluate(null, { - stage: context.consultingState?.currentStageId || null, + const stage = context.consultingState?.currentStageId || null; + const gateResult = await this.evaluationGate.evaluate(null, { + stage, collectedInfo: context.consultingState?.collectedInfo || null, assessmentResult: context.consultingState?.assessmentResult || null, responseText, @@ -229,6 +230,22 @@ export class CoordinatorAgentService implements OnModuleInit { hasConverted: false, agentsUsed: agentsUsedInLoop, }); + + // Gate 失败时,将失败教训异步保存为系统经验(fire-and-forget) + if ( + !gateResult.passed && + (gateResult.action === 'RETRY' || gateResult.action === 'SUPPLEMENT') + ) { + this.persistGateFailureAsExperience( + gateResult, + stage, + context.conversationId, + ).catch(err => + this.logger.warn(`Failed to persist gate failure experience: ${err}`), + ); + } + + return gateResult; }; // 6. Build agent loop params @@ -501,6 +518,44 @@ export class CoordinatorAgentService implements OnModuleInit { } } + // ============================================================ + // Gate Failure → System Experience + // ============================================================ + + /** + * 将评估门控失败沉淀为系统经验 + * 经验写入 knowledge-service,状态为 PENDING,需 admin 审核后激活 + * 激活后,未来对话中 Context Injector 的 searchExperiences() 会检索到并注入 prompt + * 从而让 AI 在第一次生成回复时就遵循人工经验,避免重复犯错 + */ + private async persistGateFailureAsExperience( + gateResult: import('./evaluation-gate.service').GateResult, + stage: string | null, + conversationId: string, + ): Promise { + const failedRules = gateResult.results.filter(r => !r.passed); + if (failedRules.length === 0) return; + + const stageLabel = stage || '通用'; + + for (const rule of failedRules) { + const scenario = `${stageLabel}阶段 — ${rule.ruleName}`; + const content = `在${stageLabel}阶段,${rule.message || rule.ruleName + '检查未通过'}。AI 回复前应确保满足此要求,避免生成不合格内容后重试。`; + + await this.knowledgeClient.saveExperience({ + experienceType: 'KNOWLEDGE_GAP', + scenario, + content, + sourceConversationId: conversationId, + confidence: 45, + }); + + this.logger.debug( + `Persisted gate failure as experience: [${rule.ruleType}] ${scenario}`, + ); + } + } + // ============================================================ // Event Mapping // ============================================================ diff --git a/packages/services/conversation-service/src/infrastructure/knowledge/knowledge-client.service.ts b/packages/services/conversation-service/src/infrastructure/knowledge/knowledge-client.service.ts index 65c942a..91f73cc 100644 --- a/packages/services/conversation-service/src/infrastructure/knowledge/knowledge-client.service.ts +++ b/packages/services/conversation-service/src/infrastructure/knowledge/knowledge-client.service.ts @@ -287,6 +287,38 @@ export class KnowledgeClientService implements OnModuleInit { } } + /** + * 保存系统经验 + * 用于将评估门控的失败教训沉淀为全局经验,影响未来所有对话 + */ + async saveExperience(params: { + experienceType: string; + content: string; + scenario: string; + sourceConversationId: string; + confidence?: number; + relatedCategory?: string; + }): Promise { + try { + const response = await fetch(`${this.baseUrl}/api/v1/memory/experience`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(params), + }); + + if (!response.ok) { + console.error(`[KnowledgeClient] saveExperience failed: ${response.status}`); + return null; + } + + const data = (await response.json()) as ApiResponse; + return data.success ? data.data : null; + } catch (error) { + console.error('[KnowledgeClient] saveExperience error:', error); + return null; + } + } + // ============================================================ // Convenience Methods (for Specialist Agents) // ============================================================