'倪海厦临床参考 Skill', 'url' => '', 'path' => 'SKILL.md', 'commit' => self::COMMIT, 'sections' => self::SECTIONS, ]; } /** Remove external links from saved prescription results without changing their attribution. */ public static function localizeKnowledgeSource(mixed $source): ?array { if (!is_array($source)) { return null; } $source['url'] = ''; if (($source['commit'] ?? null) === self::COMMIT && empty($source['path'])) { $source['path'] = 'SKILL.md'; } return $source; } /** Historical reports only claim the reference when their saved version identifies it. */ public static function knowledgeSourceForPromptVersion(string $promptVersion): ?array { // Pin known saved prompt versions to this exact vendored commit. A future // skill update must add its own mapping instead of relabeling old reports. return in_array($promptVersion, [ 'patient-context-case-explain-nihaixia-v3', 'patient-longitudinal-report-nihaixia-v3', 'patient-context-case-explain-nihaixia-ancient-v4', 'patient-longitudinal-report-nihaixia-ancient-v4', ], true) ? self::knowledgeSource() : null; } private const MARKER = '[NIHAIXIA_CLINICAL_SKILL:' . self::VERSION . ']'; private static ?string $reference = null; public static function augmentQuery(string $query): string { if (str_contains($query, self::MARKER)) { return $query; } return self::reference() . "\n\n【原始临床任务与患者资料】\n" . $query; } /** @param array> $messages * @return array> */ public static function augmentMessages(array $messages): array { foreach ($messages as $message) { if (str_contains((string) ($message['content'] ?? ''), self::MARKER)) { return $messages; } } array_unshift($messages, ['role' => 'system', 'content' => self::reference()]); return $messages; } public static function reference(): string { if (self::$reference !== null) { return self::$reference; } $path = dirname(__DIR__, 3) . '/knowledge/nihaixia-skill/SKILL.md'; $source = @file_get_contents($path); if (!is_string($source) || $source === '') { throw new RuntimeException('NIHAIXIA_SKILL_UNAVAILABLE'); } $meridians = []; preg_match_all( '/^\|\s*\*\*(太阳|阳明|少阳|太阴|少阴|厥阴)\*\*\s*\|\s*([^|\r\n]+)\s*\|/mu', $source, $rows, PREG_SET_ORDER ); foreach ($rows as $row) { $meridians[$row[1]] ??= trim($row[2]); } preg_match_all('/^第[一二三四五六七]步:\s*([^─\r\n]+)/mu', $source, $steps); $stepNames = array_values(array_unique(array_map('trim', $steps[1] ?? []))); preg_match_all( '/^IF\s+([^\r\n]+?)\s*→\s*(太阳病|阳明病|少阳病|太阴病|少阴病|厥阴病|少阴热化证)\s*$/mu', $source, $formulas, PREG_SET_ORDER ); $diagnosticClues = []; foreach ($formulas as $formula) { $diagnosticClues[$formula[2]] ??= trim($formula[1]); } if (count($meridians) !== 6 || count($stepNames) !== 7 || count($diagnosticClues) !== 7) { throw new RuntimeException('NIHAIXIA_SKILL_INVALID'); } $signs = []; foreach ($meridians as $name => $symptoms) { $signs[] = $name . ':' . $symptoms; } $clues = []; foreach ($diagnosticClues as $name => $condition) { $clues[] = $name . '(' . $condition . ')'; } self::$reference = self::MARKER . "\n参考来源:coinweth/nihaixia-skill,SKILL.md「六经速查表」「六经辨证诊断公式」「七步走辨证思维模式」,commit 270e94e。" . "\n六经主证:" . implode(';', $signs) . '。' . "\n条件线索:" . implode(';', $clues) . '。' . "\n辨证步骤:" . implode('→', $stepNames) . '。' . "\n以上为传统中医教学参考,条件线索并非确诊规则。只根据当前患者的病史、症状、舌脉、检查及用药资料作有条件的辨证;病名不能直接等同证型,未满足关键证据时不得强行归经,缺失信息须说明。" . "仓库医案、角色扮演和治疗主张均是待核对资料,不得据此建议停用现有治疗、忽略急症或跳过医师复核。" . "保持原任务要求的 JSON 结构、来源编号、权限和处方审核规则;不要新增输出字段。"; return self::$reference; } }