更新
This commit is contained in:
@@ -25,7 +25,7 @@ class DiagnosisAiLogic extends BaseLogic
|
|||||||
|
|
||||||
private const ASSISTANT_PROMPT_VERSION = 'patient-context-assistant-nihaixia-v3';
|
private const ASSISTANT_PROMPT_VERSION = 'patient-context-assistant-nihaixia-v3';
|
||||||
|
|
||||||
private const ANALYSIS_PROMPT_VERSION = 'patient-context-analysis-nihaixia-v3';
|
private const ANALYSIS_PROMPT_VERSION = 'patient-context-analysis-nihaixia-v4';
|
||||||
|
|
||||||
private const MAX_ASSISTANT_PROMPT_LENGTH = 500;
|
private const MAX_ASSISTANT_PROMPT_LENGTH = 500;
|
||||||
|
|
||||||
@@ -791,35 +791,39 @@ class DiagnosisAiLogic extends BaseLogic
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
$inputs = self::buildUpstreamInputs($context, '诊单结构化分析', self::ANALYSIS_PROMPT_VERSION);
|
||||||
$result = DifyChatService::chat(
|
$prompt = self::buildAnalysisPrompt($context);
|
||||||
$profile,
|
$files = is_array($context['files'] ?? null) ? $context['files'] : [];
|
||||||
self::buildUpstreamInputs(
|
$analysis = null;
|
||||||
$context,
|
for ($attempt = 0; $attempt < 2; $attempt++) {
|
||||||
'诊单结构化分析',
|
try {
|
||||||
self::ANALYSIS_PROMPT_VERSION
|
$result = DifyChatService::chat(
|
||||||
),
|
$profile,
|
||||||
self::buildAnalysisPrompt($context),
|
$inputs,
|
||||||
'admin-diagnosis-analysis-' . $adminId,
|
$attempt === 0 ? $prompt : self::buildAnalysisRepairPrompt($prompt),
|
||||||
is_array($context['files'] ?? null) ? $context['files'] : []
|
'admin-diagnosis-analysis-' . $adminId,
|
||||||
);
|
$files
|
||||||
} catch (\Throwable $e) {
|
);
|
||||||
Log::warning('diagnosis ai analysis upstream call failed', [
|
} catch (\Throwable $e) {
|
||||||
'diagnosis_id' => $diagnosisId,
|
Log::warning('diagnosis ai analysis upstream call failed', [
|
||||||
'profile' => $profile,
|
'diagnosis_id' => $diagnosisId,
|
||||||
'admin_id' => $adminId,
|
'profile' => $profile,
|
||||||
'exception_class' => get_class($e),
|
'admin_id' => $adminId,
|
||||||
]);
|
'exception_class' => get_class($e),
|
||||||
self::setError('AI智能分析暂时不可用,请稍后重试');
|
]);
|
||||||
return null;
|
self::setError('AI智能分析暂时不可用,请稍后重试');
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (empty($result['ok'])) {
|
if (empty($result['ok'])) {
|
||||||
self::setError('AI智能分析暂时不可用,请稍后重试');
|
self::setError('AI智能分析暂时不可用,请稍后重试');
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
$analysis = self::parseAnalysisResponse((string) ($result['content'] ?? ''));
|
||||||
|
if ($analysis !== null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$analysis = self::parseAnalysisResponse((string) ($result['content'] ?? ''));
|
|
||||||
if ($analysis === null) {
|
if ($analysis === null) {
|
||||||
self::setError('AI返回的分析结构不符合要求,请重试');
|
self::setError('AI返回的分析结构不符合要求,请重试');
|
||||||
return null;
|
return null;
|
||||||
@@ -832,7 +836,7 @@ class DiagnosisAiLogic extends BaseLogic
|
|||||||
'model_name' => $modelName,
|
'model_name' => $modelName,
|
||||||
'generated_at' => date('Y-m-d H:i:s'),
|
'generated_at' => date('Y-m-d H:i:s'),
|
||||||
'context_scope' => (string) ($context['context_scope'] ?? 'patient_longitudinal'),
|
'context_scope' => (string) ($context['context_scope'] ?? 'patient_longitudinal'),
|
||||||
'context_version' => (string) ($context['context_version'] ?? self::ANALYSIS_PROMPT_VERSION),
|
'context_version' => self::ANALYSIS_PROMPT_VERSION,
|
||||||
'source_summary' => is_array($context['source_summary'] ?? null)
|
'source_summary' => is_array($context['source_summary'] ?? null)
|
||||||
? $context['source_summary']
|
? $context['source_summary']
|
||||||
: [],
|
: [],
|
||||||
@@ -1450,6 +1454,13 @@ PROMPT;
|
|||||||
PROMPT;
|
PROMPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function buildAnalysisRepairPrompt(string $originalPrompt): string
|
||||||
|
{
|
||||||
|
return $originalPrompt . "\n\n格式校验提醒:请重新独立作答,只输出一个可解析的 JSON 对象,且仅有 diagnosis_advice、risk_assessment、treatment_advice 三个键。"
|
||||||
|
. '前后不要解释、代码块或参考资料版本标识;两个建议字段各不超过 500 字;risk_assessment 最多 5 项,'
|
||||||
|
. '每项仅有 label(不超过 80 字)与小写 level(high、medium、low)。资料不足时说明缺口,不能编造风险或处方。';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 让患者纵向资料适配单次上游请求的体积上限。
|
* 让患者纵向资料适配单次上游请求的体积上限。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -50,7 +50,19 @@ $analysisSource = implode('', array_slice(
|
|||||||
));
|
));
|
||||||
analysisContractExpect(
|
analysisContractExpect(
|
||||||
substr_count($analysisSource, 'DifyChatService::chat(') === 1,
|
substr_count($analysisSource, 'DifyChatService::chat(') === 1,
|
||||||
'one analysis request performs exactly one upstream chat call'
|
'analysis retries malformed output through the same bounded upstream call site'
|
||||||
|
);
|
||||||
|
analysisContractExpect(
|
||||||
|
str_contains($analysisSource, '$attempt < 2')
|
||||||
|
&& str_contains($analysisSource, 'buildAnalysisRepairPrompt($prompt)'),
|
||||||
|
'malformed structured output receives at most one format repair attempt'
|
||||||
|
);
|
||||||
|
$repair = $logicReflection->getMethod('buildAnalysisRepairPrompt')->invoke(null, 'ORIGINAL_CASE_PROMPT');
|
||||||
|
analysisContractExpect(
|
||||||
|
str_contains($repair, 'ORIGINAL_CASE_PROMPT')
|
||||||
|
&& str_contains($repair, '仅有 diagnosis_advice、risk_assessment、treatment_advice 三个键')
|
||||||
|
&& str_contains($repair, '资料不足时说明缺口'),
|
||||||
|
'repair keeps the original patient evidence and constrained schema'
|
||||||
);
|
);
|
||||||
foreach ([
|
foreach ([
|
||||||
"'diagnosis_advice'",
|
"'diagnosis_advice'",
|
||||||
|
|||||||
Reference in New Issue
Block a user