한신대 피드백 개선팩 반영

This commit is contained in:
Yun Chan 2026-07-03 19:53:14 +09:00
parent 5a9c110c11
commit 6b6241f468
25 changed files with 1247 additions and 94 deletions

View file

@ -0,0 +1,116 @@
# 한신대 개선 계획 대레드팀 검토
작성일: 2026-07-03
대상: `docs/ops/hanshin-feedback-improvement-plan-2026-07-03.md`, `docs/redteam/hanshin-feedback-plan-redteam-2026-07-03.md`
상태: 대레드팀 1차 완료 / 계획 균형 보정 반영
## 1. 판정
기존 레드팀은 실제 위험을 잘 잡았다. 다만 몇 조건이 “1차 개선을 안전하게 작게 낸다”가 아니라 “최종형을 한 번에 닫는다”로 비대해졌다.
본래 목적은 한신대 사용자가 실제로 겪은 반복 발화, 문맥 오해, 리뷰 UX 혼란, 교수자 설명 부족을 빠르게 줄이는 것이다. 그래서 레드팀 경고는 유지하되, 사용자 가치 기준으로 등급화해야 한다.
핵심 판정:
- P1 내부의 role mapping + history injection은 반드시 원자 패치다.
- P2/P3/P4는 P1과 같은 원자 배포 단위가 아니다. 독립적으로 빠르게 배포할 수 있다.
- privacy proof는 API·저장·export 계약이지, 리뷰 화면 자연어화를 막는 조건이 아니다.
- synthetic fallback은 fallback을 저장할 때 필요한 계약이다. 1차 품질 게이트는 fallback 저장 없이도 낼 수 있다.
- 교수자 설명은 임상 확정 표현을 피해야 하지만, 현재 구현과 한계를 설명하는 패널은 오히려 지금 필요하다.
## 2. 과잉 방어 지점
### C1. P2 fallback 경고가 품질 게이트 전체를 늦출 위험
레드팀의 “fallback을 실제 내담자 발화처럼 저장하면 안 된다”는 경고는 맞다. 하지만 이것이 “품질 게이트를 구현하지 말라”로 번지면 과잉이다.
1차에서는 fallback을 저장하지 않으면 된다. 역할 메타발화, 2턴 이후 재인사, 직전 내담자 발화와 거의 같은 응답처럼 명백한 결함은 먼저 감지하고 1회 재생성한다. 재생성 후에도 실패하면 client turn을 저장하지 않고 사용자에게 재시도 가능한 오류를 보여준다.
저장형 fallback, synthetic metadata, 평가 제외 규칙은 2차다.
### C2. P3 privacy proof가 UI 개선을 누르면 안 된다
API/저장/export에서 `[NAME]`, `[ORG]`, `[PHONE]` 같은 마스킹 토큰을 보존하는 건 맞다. 하지만 사람이 보는 리뷰 화면의 일반 transcript까지 반드시 토큰 그대로 보여야 하는 건 아니다.
1차에서는 API와 evidence quote는 마스킹을 유지하고, 일반 UI 렌더링에서만 자연어화한다. 이 방식이 privacy proof와 사용자 경험을 동시에 만족한다.
### C3. P4 임상 경고가 설명 패널을 늦추면 안 된다
교수자 질문은 제품 신뢰와 직결된다. “임상 확정 전이라 말할 수 없다”만 반복하면 한신대가 궁금해한 지점을 해결하지 못한다.
설명 패널은 현재 구현과 임상팀 검수 필요 범위를 분리하면 안전하게 먼저 낼 수 있다.
예시:
- DSM: 진단이 아니라 페르소나 행동 차원과 증상 차원을 구성하는 참고 축.
- CBT: 선택 이론 모드가 프롬프트/평가에 반영되는 수준.
- 개방도: LLM 감이 아니라 state machine 기반 시뮬레이션 상태값.
- 약물/검사: 처방·진단 도구가 아니므로 권유 기준은 임상팀 확정 전 자동화하지 않음.
### C4. 테스트 제안이 전체 회귀 게이트처럼 읽힌다
P1 차단 테스트는 다음으로 충분하다.
- persona role mapping
- gateway client-only history injection
- evaluator/structured output no-history
- 기존 gateway split 계약 갱신
voice, 전체 review, Playwright, stream buffering 장기 매트릭스는 통합 검증 또는 2차 안정화에 둔다.
## 3. 유지해야 하는 레드팀 경고
- P1 내부 원자성은 유지한다. role mapping 또는 gateway history injection 중 하나만 고치면 역효과가 날 수 있다.
- resident session은 1차에서 켜지 않는다. client/eval context 혼선 위험이 현실적이다.
- API/저장/export 마스킹 불변식은 유지한다.
- 저장되는 fallback은 실제 내담자 발화처럼 섞으면 안 된다.
- 임상 표현은 보수적으로 둔다. 설명 패널은 진단/처방 판단이 아니라 교육용 시뮬레이션의 현재 구현과 한계를 설명해야 한다.
## 4. 균형 잡힌 1차 MVP
### P1a. 컨텍스트
- `counselor -> user`, `client -> assistant` 매핑 수정.
- client 요청에서만 최근 대화 history를 라벨링해 마지막 user payload에 주입.
- evaluator/structured 요청에는 client history를 주입하지 않는 단위 테스트.
### P3a. 리뷰 UX
- API는 masked token 유지.
- 리뷰 화면 일반 transcript는 렌더링 단계 자연어화 허용.
- raw error는 학습자용 문구로 매핑.
- fast-loop/deep-loop 라벨 추가.
- `clientFeedback` 라벨을 “마지막 내담자 반응”처럼 사실에 맞게 수정.
### P2a. 출력 품질
- 역할 메타발화 차단.
- 2턴 이후 재인사 차단.
- 직전 내담자 발화와 거의 동일한 응답 차단.
- 1회 재생성 후 실패하면 client turn 미저장 + 재시도 가능 오류.
### P4a. 교수자 설명
- `SessionReview`에 “현재 구현 / 임상팀 확정 필요” 2열 또는 “현재 구현됨 / 제품 한계 / 임상팀 검수 필요” 3단 패널 추가.
- 임상 루브릭·약물 권유 기준·골든셋은 미확정으로 표시하되, 현재 제품이 실제로 하는 일은 명확히 답한다.
## 5. 2차로 미룰 것
- resident session namespace
- prompt caching 복구
- cleanup/restart recovery
- complete K-pair window 정교화
- synthetic fallback 저장 스키마와 모든 read-model exclusion
- stream 첫 문장 버퍼링 전면 도입
- fast-loop/deep-loop 충돌 reconciliation
- CBT chain/citation/rubric
- H2 골든셋
## 6. 계획 문서 반영 문장
- “레드팀 차단 조건은 사용자 가치 기준으로 등급화한다. P1 내부의 role mapping + history injection은 원자 패치로 유지하되, P2/P3/P4는 독립적으로 빠르게 배포 가능한 1차 개선으로 분리한다.”
- “P1 차단 테스트는 persona role mapping, gateway client-only history injection, evaluator no-history 계약으로 한정한다. voice/Playwright/전체 review 회귀는 P1 필수 차단이 아니라 통합 검증 단계로 둔다.”
- “마스킹 토큰 보존은 API·저장·export 계약이다. 리뷰 화면의 일반 transcript 표시에서는 동일 데이터를 렌더링 단계에서 자연어화할 수 있다.”
- “1차 품질 게이트는 fallback 저장을 목표로 하지 않는다. 재생성 후에도 역할 메타발화가 남으면 client turn을 저장하지 않고 사용자에게 재시도 가능한 오류로 표시한다.”
- “교수자 설명은 ‘못 한다’가 아니라 ‘현재 제품이 하는 것’과 ‘임상팀 확정이 필요한 것’을 분리해 답한다.”
- “resident session, synthetic fallback 저장, stream buffering, fast/deep reconciliation은 P1/P3 이후 2차 안정화 범위로 둔다.”

View file

@ -0,0 +1,130 @@
# 한신대 실사용 피드백 개선 계획 레드팀 검토
작성일: 2026-07-03
대상: `docs/ops/hanshin-feedback-improvement-plan-2026-07-03.md`
상태: 1차 적대 검토 완료 / 구현 전 차단 조건 반영 필요
## 1. 요약
계획의 방향은 맞다. 한신대 실사용 피드백을 단순 화면 문구 문제가 아니라 컨텍스트, 출력 품질, 리뷰 UX, 설명 가능성 문제로 나눈 판단은 타당하다.
다만 그대로 구현하면 위험한 지점이 있다. 특히 아래 네 가지는 구현 전 반드시 막아야 한다.
1. `persona.py` role mapping이 잘못된 상태에서 gateway history만 보존하면 품질이 악화될 수 있다.
2. `_split_messages()` 변경은 단순 보강이 아니라 gateway 계약 변경이다.
3. 리뷰 API의 마스킹 토큰을 자연어화하면 privacy proof와 기존 E2E 계약이 깨질 수 있다.
4. 품질 fallback을 실제 내담자 발화처럼 저장하면 평가·워크시트·carry-over가 오염된다.
## 2. BLOCKER
### B1. P1은 원자적으로 처리해야 한다
`persona.build_turn_messages()`의 recent turn role mapping 수정과 gateway `_split_messages()` history 소비 변경은 같은 패치에서 처리해야 한다. 현재 매핑이 잘못된 상태에서 history만 보존하면 상담자 발화를 내담자 과거 발화처럼 소비할 수 있다.
반영 문장:
> P1-1 role mapping 수정과 P1-2 gateway history 소비는 같은 패치에서 원자적으로 처리한다. history 보존만 먼저 배포하지 않는다.
### B2. Gateway history 보존은 계약 변경이다
현재 gateway 테스트는 “이전 assistant/user는 버리고 마지막 user만 보낸다”를 명시적으로 고정하고 있다. 따라서 `_split_messages()` 변경은 테스트 추가가 아니라 기존 계약과 골든 변경이다.
필수 조치:
- 기존 gateway split 테스트 기대값 갱신
- 호출부가 어떤 `ai_role`에서 history를 소비하는지 명시
- evaluator/structured output 요청에서 client history가 섞이지 않는지 회귀 테스트
### B3. Resident session은 1차 범위에서 꺼야 한다
gateway `_resolve_session()`은 같은 `session_id`가 살아 있으면 새 system prompt를 무시하고 재사용한다. evaluator도 같은 app session id를 보낼 수 있으므로 resident session을 성급히 켜면 client 컨텍스트와 evaluator 컨텍스트가 섞일 수 있다.
반영 문장:
> 이번 1차 구현은 stateless history injection으로 한정하며, resident session 재사용/prompt caching 복구는 별도 설계 없이는 켜지 않는다.
### B4. Fallback은 실제 임상 반응이 아니다
품질 게이트 실패 후 “말을 고르며 잠시 멈춘다” 같은 fallback을 실제 내담자 발화로 저장하면 deep-loop, 회기 요약, 다음 회기 carry-over, `clientFeedback`, worksheet evidence가 오염된다.
필수 조치:
- fallback 저장 시 `synthetic`/`fallback` 메타데이터 부여
- 평가·워크시트·carry-over 기본 입력에서 제외
- 학습자 UI에는 내부 reason 대신 안전한 표시 문구 제공
### B5. 리뷰 API 마스킹 토큰은 보존해야 한다
리뷰/상세 API는 privacy proof로 `[NAME]`, `[ORG]`, `[PHONE]` 같은 마스킹 토큰을 유지해야 한다. 사람용 UI에서 자연어화가 필요하더라도 API 축어록·근거 quote·worksheet evidence·export는 마스킹 불변식을 보존해야 한다.
반영 문장:
> 리뷰 API의 축어록·근거 quote는 privacy proof를 위해 `[NAME]` 등 마스킹 토큰을 보존한다. 자연어 치환은 UI 표시 전용 필드 또는 컴포넌트 렌더링에서만 적용한다.
### B6. 교수자 설명은 임상 확정처럼 쓰면 안 된다
DSM/CBT/약물·심리평가/루브릭/골든셋 설명은 “현재 구현됨”과 “임상팀 검수 필요”를 같은 톤으로 쓰면 안 된다. 특히 CBT는 현재 `theory_mode`와 evaluator prompt 연결 수준이지, 임상팀 확정 CBT 단계 chain/citation/rubric 구조가 아니다.
반영 문장:
> DSM/CBT/약물·검사/루브릭/골든셋 설명은 임상팀 검수 상태와 source/citation이 연결된 범위에서만 확정 표현을 쓴다.
## 3. MAJOR
- gateway history 직렬화는 `ai_role=client` 요청에만 적용해야 한다.
- `recent_turns(k=6)`은 레코드 수 기준이라 상담자/내담자 pair를 보장하지 않는다. 최근 완성 K쌍 기준으로 자른다.
- stream 버퍼링을 넣으면 사용자가 본 텍스트, 저장된 텍스트, 평가된 텍스트가 달라질 수 있다.
- voice 경로는 stream이 아니므로 generate 지연, TTS 시작, persistence 실패 시 learner-only 기록 방지를 따로 검증해야 한다.
- fast-loop 라벨만으로 “후속 해명을 반영하지 않았다”는 혼란이 닫히지 않을 수 있다. deep-loop/교수자 검토와 구분을 같이 보여줘야 한다.
- `clientFeedback`는 실제 피드백 산출물이 아니라 마지막 client turn이므로 라벨과 포함 조건을 재검토해야 한다.
- 오류 문구 개선은 단순 문자열 치환이 아니라 `errorKind`, role별 display copy, operator raw error 계약 분리여야 한다.
- 공유 payload에도 원문 축어록과 학습자 식별 정보가 들어가지 않는지 확인해야 한다.
## 4. MINOR
- 검증 명령은 Windows PowerShell 5.1 기준으로 `Push-Location ...; ...; Pop-Location` 또는 `py -3.11 -X utf8` 형태로 적는다.
- “컨텍스트 보존이 반복/문맥오해를 줄인다”는 표현은 필요조건으로 낮춘다. 출력 게이트와 평가 라벨까지 같이 닫아야 한다.
- 개방도는 “점수”보다 “시뮬레이션 상태값”으로 설명한다.
- seed persona 기준인지 DB catalog 기준인지 교수자 설명에서 구분한다.
- 학습자용 오류 문구는 “평가 AI 응답 형식이 맞지 않아”보다 “자동 평가를 완료하지 못했어”처럼 내부 구현을 덜 드러내는 표현이 낫다.
## 5. 구현 전 테스트 제안
Backend:
- `Push-Location apps/api; py -3.11 -X utf8 -m pytest -p no:cacheprovider engine_gateway/test_gateway_model.py app/test_orchestrator_masking.py app/test_session_turn_persistence.py app/test_evaluator_model_routing.py app/test_voice_ws.py -q; Pop-Location`
- 신규: `persona.build_turn_messages()``counselor -> user`, `client -> assistant`를 보장하는 단위 테스트.
- 신규: gateway `_split_messages()`가 client history를 라벨 포함 payload로 정확히 1회만 넣고 evaluator 요청에는 넣지 않는 테스트.
- 신규: REST/stream/voice fake engine 캡처 테스트에서 직전 상담자 질문과 내담자 답변이 실제 gateway user payload까지 도달하는지 검증.
- 신규: evaluator fast/deep이 client resident/history를 재사용하지 않는 회귀 테스트.
- 신규: quality fallback turn이 synthetic으로 표시되고 `clientFeedback`, worksheet evidence, deep eval에 무표시로 섞이지 않는지 검증.
Review/privacy:
- 신규: `/review` JSON은 raw PII 미포함 + masked token 보존, UI 표시만 humanized 되는지 검증.
- 신규: `no_structured_output`/`engine_error`/`parse_error`가 role별 display copy로 매핑되고 raw error는 learner UI에 안 나오는지 검증.
- 신규: 리뷰 API/detail/eval/export 경로에서 `[NAME]` 마스킹 불변식 보존.
- 신규: 공유 payload에 원문 축어록과 학습자 식별 정보가 실리지 않는지 검증.
Frontend:
- `Push-Location apps/web; npm run typecheck; Pop-Location`
- `Push-Location apps/web; npx playwright test e2e/session-review.spec.ts --project=chromium-desktop --workers=1; Pop-Location`
- DB/engine 가능 시 `Push-Location apps/web; npx playwright test e2e/session-persistence.spec.ts --project=chromium-single-run --workers=1 --grep "Korean PII|manual AI evaluation retry|case worksheet|selected CBT theory mode"; Pop-Location`
SSOT:
- `py -3.11 -X utf8 scripts\check-dev-dashboard-ssot.py --json`
## 6. 판정
계획은 진행 가능하다. 단, P1 내부는 표면 개선으로 쪼개면 위험하다. 대레드팀 검토 후 1차 구현 단위는 다음처럼 조정한다.
- P1: role mapping + client-only stateless history injection + evaluator 분리 focused test
- P2 1차: fallback 저장 없이 명백한 출력 결함 감지 + 1회 재생성 + 실패 시 client turn 미저장
- P3 1차: API 마스킹 불변식 + 리뷰 UI 렌더링 자연어화 + raw error display mapper + fast/deep 라벨
- P4 1차: 현재 구현과 임상팀 확정 필요 범위를 분리한 교수자 설명 패널
교수자 설명 패널은 제품 신뢰를 높일 수 있지만, 임상팀 확정 전 표현은 보수적으로 써야 한다.
후속 균형 검토: `docs/redteam/hanshin-feedback-plan-counter-redteam-2026-07-03.md`