Files
zyt/server/app/common/service/NihaixiaClinicalSkill.php
T
2026-10-08 15:49:53 +08:00

104 lines
4.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace app\common\service;
use RuntimeException;
/**
* A bounded clinical reference distilled at runtime from the vendored skill.
* The repository contains historical cases and agent instructions; neither is
* allowed to override patient evidence, structured output, or physician review.
*/
final class NihaixiaClinicalSkill
{
public const VERSION = 'nihaixia-270e94e-clinical-v1';
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<int,array<string,mixed>> $messages
* @return array<int,array<string,mixed>>
*/
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;
}
}