🧬 연구 허브

Skill

tnm-staging-extract 바로 실행

판독문에서 암 병기(TNM·AJCC)를 뽑는다. T·N·M을 정보추출과 분류로 나눠 근거와 함께 낸다.

언제 쓰나

병리 보고서·영상 판독문 → pT3N1bM0, Stage IIIB 같은 병기. 대장암(CRC)·폐암 구현이 있고, 다른 암종으로 확장할 때 이 구조를 그대로 쓴다.

정본 코드

~/Documents/IMOK/CRC-TNM-Agents/src/
  llm/tnm_agents/          에이전트 30여 개 (공통 + crc/ + lung/)
  llm/tnm_agent_factory.py AGENT_TYPE_MAP + 캐시 + 평가유형→에이전트 라우팅
  llm/prompt_composer.py   YAML 프롬프트 조립
  pipeline/                langgraph_tnm_workflow, orchestrator, retry_policy, result_merger
  config/workflows/        워크플로 정의 (YAML)
~/Documents/IMOK/NSCLC-ModularStageLLM/   폐암 모듈러 버전 (논문용, CITATION.cff 있음)
~/Documents/IMOK/LungCancerTNM/

같은 코드가 7벌 존재한다(CRC-TNM-Agents, _1, _crc, -251217, crc-tnm-app, crc-tnm-registry-closed-hotfix, @GMP/crc-tnm-registry-closed-main). 기능 전체는 IMOK/CRC-TNM-Agents(2026-03-12, 174 py)가 가장 넓고, LLM provider 계층만은 _crc(2026-07-14, 176 py)가 최신이다. 어느 쪽을 정본으로 삼을지는 아직 미정이다 — llm-provider-switch 참조.

바로 쓰는 코드

# 추출 결과에서 근거 없는 필드 찾기
python3 scripts/evidence.py --check-json result.json

scripts/evidence.pybase_evidence_agent.pyEvidenceField / EvidenceExtractionResult. 평면·중첩 형식 양방향 변환, <b> 하이라이트 검증(is_grounded), ungrounded() · low_confidence() 로 검수 대상 선별, defer() 로 판정 불가 표시.

핵심: 에이전트를 잘게 쪼갠다

한 프롬프트로 "이 판독문의 TNM을 말해줘"라고 하면 정확도가 안 나온다. T/N/M별로 나누고, 각각을 다시 정보추출 → 분류로 쪼갠다.

pathological_t_information_agent      판독문에서 T 관련 사실만 추출 (침윤 깊이, 장막 침범…)
pathological_t_characteristics_agent  종양 특성
pathological_t_margins_agent          절제연
      ↓
pathological_t_classification_agent   위 사실들로 pT 값만 판정

N·M도 같은 구조(pathological_n_informationpathological_n_classification, metastasis_informationmetastasis_classification). 마지막에 final_stage_agent가 T·N·M을 합쳐 AJCC stage를 낸다.

이렇게 나누는 이유: 사실 추출과 규칙 적용을 한 번에 시키면 LLM이 근거 없이 병기를 지어낸다. 나누면 어느 단계에서 틀렸는지 짚을 수 있고, 분류 단계는 AJCC 규칙만 보므로 프롬프트가 짧아진다.

암종별 차이는 crc/, lung/ 하위 디렉토리로 분리한다. 공통 골격은 최상위에 두고 암종 특이 에이전트만 추가한다(예: CRC의 lymph_node_count_agent, discrepancy_analyzer_agent).

근거를 반드시 같이 받는다

base_evidence_agent.pyEvidenceField가 모든 추출 필드에 강제하는 4종 세트:

value       추출값
evidence    출처 문장. 해당 부분을 <b>...</b>로 감쌈
reasoning   왜 그렇게 판단했는지
confidence  확신도

<b> 하이라이트가 중요하다 — 검수자가 원문 어디를 보고 판단했는지 바로 확인한다. 근거 없는 병기는 임상에서 못 쓴다. 출력은 평면(pT_evidence)과 중첩({"value":…, "evidence":…}) 둘 다 지원한다(to_dict / to_nested_dict).

규칙 기반 힌트 주입

llm/tnm_agents/rule_based_hints/registry_v2_hint_generator.py가 판독문에서 정규식·키워드로 확실한 것을 먼저 뽑아 프롬프트에 힌트로 넣는다. LLM이 처음부터 맨몸으로 읽는 것보다 정확하다. 규칙으로 확실한 건 규칙으로, 애매한 것만 LLM에게.

프롬프트는 YAML 조립

PromptComposer가 공통 모듈 + 에이전트별 프롬프트를 YAML에서 읽어 시스템 프롬프트를 조립한다(config/prompts/). 캐시하고 force_reload로 갱신. 30여 개 에이전트가 AJCC 정의 같은 공통 블록을 공유하므로, 프롬프트를 코드에 박으면 규칙 하나 고칠 때 30군데를 고쳐야 한다.

워크플로·재시도·보류

pipeline/이 LangGraph로 에이전트 실행 순서를 만든다. dependency_resolver가 의존 관계를 풀고 workflow_builder가 그래프를 세운다. 워크플로 정의는 config/workflows/ YAML — 코드 수정 없이 에이전트 조합을 바꾼다.

RetryPolicy(기본 max_retries=2)의 판단 기준이 중요하다:

  • has_llm_fallback() — 결과가 LLM 폴백으로 나왔는지 감지
  • should_retry() — 재시도할 가치가 있는지
  • should_abort() — 포기
  • DeferredOutputBuilder판정 불가를 "보류"로 명시 출력

마지막이 핵심이다. 억지로 병기를 내놓는 것보다 "이 케이스는 판정 불가"가 안전하다. 의료 추출에서 모른다고 말할 수 있는 경로를 반드시 만들어라.

함정

  • type_detector.py가 문서 종류(병리/영상/수술기록)를 먼저 판별한다. 이걸 건너뛰면 영상 판독문에 병리 에이전트를 돌리게 된다.
  • imaging_checker_agent는 영상 소견이 병리와 어긋날 때 잡아낸다. CRC의 discrepancy_analyzer_agent도 같은 역할.
  • 에이전트는 TNMAgentFactory{agent_type}_{id(llm_manager)} 키로 캐시한다. 테스트에서 매번 새 인스턴스가 필요하면 캐시를 인지해라.
  • isolate_context 옵션 — 에이전트 간 컨텍스트 오염을 막는다. 정확도가 흔들리면 여기부터 본다.

연관 skill

llm-provider-switch, pathology-llm-extract(같은 판독문 입력), excel-case-validator(케이스 정확도 검증)