From 68e548e97cf28ec7ff5f83699373883d14e98392 Mon Sep 17 00:00:00 2001 From: tkv00 Date: Tue, 15 Sep 2026 18:11:18 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[HSC-426]=20docs:=20=EB=B9=84=EA=B5=90=20?= =?UTF-8?q?=EC=8B=A4=ED=97=98=20=EC=A7=91=EA=B3=84=EC=99=80=20=EC=9B=90?= =?UTF-8?q?=EB=B3=B8=20=ED=95=B4=EC=8B=9C=20=EB=B3=B4=EA=B4=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../docs/evidence/catalog-replay-summary.json | 31 +++++ .../docs/evidence/human-keyword-scores.json | 106 ++++++++++++++++++ .../docs/evidence/human-run-summary.json | 95 ++++++++++++++++ .../evidence/operational-before-after.json | 26 +++++ .../docs/evidence/provenance.json | 26 +++++ 5 files changed, 284 insertions(+) create mode 100644 experiments/consultation-agent/docs/evidence/catalog-replay-summary.json create mode 100644 experiments/consultation-agent/docs/evidence/human-keyword-scores.json create mode 100644 experiments/consultation-agent/docs/evidence/human-run-summary.json create mode 100644 experiments/consultation-agent/docs/evidence/operational-before-after.json create mode 100644 experiments/consultation-agent/docs/evidence/provenance.json diff --git a/experiments/consultation-agent/docs/evidence/catalog-replay-summary.json b/experiments/consultation-agent/docs/evidence/catalog-replay-summary.json new file mode 100644 index 0000000..a208c5a --- /dev/null +++ b/experiments/consultation-agent/docs/evidence/catalog-replay-summary.json @@ -0,0 +1,31 @@ +{ + "cases": 50, + "before": { + "structural_valid": 50, + "review_required": 0, + "model_calls": 82, + "tool_calls": 16, + "estimated_usd": 0.0571458, + "uncached_usd": 0.0703266 + }, + "after": { + "structural_valid": 50, + "review_required": 2, + "model_calls": 67, + "tool_calls": 1, + "estimated_usd": 0.0482058, + "uncached_usd": 0.0559338 + }, + "labels_changed": 2, + "human_gold": 0, + "incremental_new_success_calls": 17, + "incremental_new_estimated_usd": 0.013293749999999998, + "imported_base_calls": 50, + "same_initial_responses": true, + "semantic_quality_change": "unknown", + "limitations": [ + "Previously used development data", + "One replay per intervention; review-generation stochasticity not separated", + "No semantic accuracy or 2000-case gate pass" + ] +} diff --git a/experiments/consultation-agent/docs/evidence/human-keyword-scores.json b/experiments/consultation-agent/docs/evidence/human-keyword-scores.json new file mode 100644 index 0000000..1a25127 --- /dev/null +++ b/experiments/consultation-agent/docs/evidence/human-keyword-scores.json @@ -0,0 +1,106 @@ +{ + "label_source": "user-attested human labels, original unmodified", + "cases": 50, + "delivered_keywords_primary": { + "single": { + "cases": 50, + "tp": 100, + "fp": 35, + "fn": 27, + "micro_precision": 0.7407407407407407, + "micro_recall": 0.7874015748031497, + "micro_f1": 0.7633587786259542, + "exact_matches": 12, + "review_required": 1 + }, + "fixed": { + "cases": 50, + "tp": 95, + "fp": 33, + "fn": 32, + "micro_precision": 0.7421875, + "micro_recall": 0.7480314960629921, + "micro_f1": 0.7450980392156863, + "exact_matches": 12, + "review_required": 3 + }, + "budget_review": { + "cases": 50, + "tp": 95, + "fp": 33, + "fn": 32, + "micro_precision": 0.7421875, + "micro_recall": 0.7480314960629921, + "micro_f1": 0.7450980392156863, + "exact_matches": 12, + "review_required": 3 + }, + "adaptive": { + "cases": 50, + "tp": 95, + "fp": 33, + "fn": 32, + "micro_precision": 0.7421875, + "micro_recall": 0.7480314960629921, + "micro_f1": 0.7450980392156863, + "exact_matches": 12, + "review_required": 3 + } + }, + "raw_keywords_secondary": { + "single": { + "cases": 50, + "tp": 101, + "fp": 37, + "fn": 26, + "micro_precision": 0.7318840579710145, + "micro_recall": 0.7952755905511811, + "micro_f1": 0.7622641509433963, + "exact_matches": 12, + "review_required": 0 + }, + "fixed": { + "cases": 50, + "tp": 101, + "fp": 37, + "fn": 26, + "micro_precision": 0.7318840579710145, + "micro_recall": 0.7952755905511811, + "micro_f1": 0.7622641509433963, + "exact_matches": 12, + "review_required": 0 + }, + "budget_review": { + "cases": 50, + "tp": 101, + "fp": 37, + "fn": 26, + "micro_precision": 0.7318840579710145, + "micro_recall": 0.7952755905511811, + "micro_f1": 0.7622641509433963, + "exact_matches": 12, + "review_required": 0 + }, + "adaptive": { + "cases": 50, + "tp": 101, + "fp": 37, + "fn": 26, + "micro_precision": 0.7318840579710145, + "micro_recall": 0.7952755905511811, + "micro_f1": 0.7622641509433963, + "exact_matches": 12, + "review_required": 0 + } + }, + "sentiment_accuracy": null, + "sentiment_reason": "original labels conflict with user-confirmed definition; AI proposals not approved gold", + "usefulness_gate": false, + "limitations": [ + "50 designed cases, no proven population representativeness", + "prior tuning exposure and complete keyword annotation rubric unverified", + "shared initial completion; one stochastic follow-up run", + "held cases deliver no labels in primary metric; raw keyword scores also shown", + "known-success API cost excludes uncertain archived sandbox attempt" + ] +} diff --git a/experiments/consultation-agent/docs/evidence/human-run-summary.json b/experiments/consultation-agent/docs/evidence/human-run-summary.json new file mode 100644 index 0000000..b9affaf --- /dev/null +++ b/experiments/consultation-agent/docs/evidence/human-run-summary.json @@ -0,0 +1,95 @@ +{ + "cases": 50, + "arms": { + "single": { + "structural_valid": 50, + "validated_status": 49, + "review_required": 1, + "estimated_usd": 0.0174957, + "uncached_usd": 0.0285837, + "logical_model_calls": 50, + "tool_calls": 0, + "tool_errors": 0, + "mean_logical_request_seconds": 0.9998336233012378, + "mean_current_elapsed_seconds": 0.27881030757998815, + "tool_seconds": 0, + "stop_reasons": { + "single_completed": 50 + } + }, + "fixed": { + "structural_valid": 50, + "validated_status": 47, + "review_required": 3, + "estimated_usd": 0.0216285, + "uncached_usd": 0.0357501, + "logical_model_calls": 62, + "tool_calls": 0, + "tool_errors": 0, + "mean_logical_request_seconds": 1.2173710166415548, + "mean_current_elapsed_seconds": 0.48350175003812185, + "tool_seconds": 0, + "stop_reasons": { + "no_review_signal": 38, + "fixed_completed": 12 + } + }, + "budget_review": { + "structural_valid": 50, + "validated_status": 47, + "review_required": 3, + "estimated_usd": 0.029965049999999997, + "uncached_usd": 0.05073945, + "logical_model_calls": 86, + "tool_calls": 0, + "tool_errors": 0, + "mean_logical_request_seconds": 1.6767308058022172, + "mean_current_elapsed_seconds": 0.9213408549604355, + "tool_seconds": 0, + "stop_reasons": { + "no_review_signal": 38, + "budget_review_completed": 12 + } + }, + "adaptive": { + "structural_valid": 50, + "validated_status": 47, + "review_required": 3, + "estimated_usd": 0.023436899999999997, + "uncached_usd": 0.0374337, + "logical_model_calls": 64, + "tool_calls": 3, + "tool_errors": 0, + "mean_logical_request_seconds": 1.2846497933019418, + "mean_current_elapsed_seconds": 0.5065559900004882, + "tool_seconds": 0.017832458994234912, + "stop_reasons": { + "no_review_signal": 38, + "adaptive_completed": 11, + "model_call_limit": 1 + } + } + }, + "human_gold_verified": 0, + "actual_success_receipt_cost_usd": 0.04003905, + "actual_success_calls": 112, + "uncertain_calls": 0, + "fairness": { + "same_initial_payload_and_response": true, + "shared_final_contract": true, + "complete_input_and_dictionary_all_arms": true, + "equal_max_model_calls_for_budget_review_and_adaptive": true, + "same_actual_token_budget": false + }, + "limitations": [ + "Shared initial completion design; logical arm costs include the reused base receipt", + "Request seconds include historical shared receipt latency; current elapsed excludes MCP session startup", + "No human semantic gold; authored regression checks are development-only", + "Equal call ceilings are not equal realized token spend" + ], + "usefulness_gate": { + "passed": false, + "status": "pending_external_evidence_review", + "reason": "Structural metrics and authored development constraints alone do not establish useful adaptive-agent superiority or semantic accuracy." + } +} diff --git a/experiments/consultation-agent/docs/evidence/operational-before-after.json b/experiments/consultation-agent/docs/evidence/operational-before-after.json new file mode 100644 index 0000000..fece8d6 --- /dev/null +++ b/experiments/consultation-agent/docs/evidence/operational-before-after.json @@ -0,0 +1,26 @@ +{ + "kind": "deterministic_injected_fault_test", + "real_llm_calls": 0, + "consultation_fixture_count": 1, + "conditions": 5, + "known_receipt_summary": { + "final_only": { + "cases": 4, + "completed": 4, + "model_calls": 18, + "tool_calls": 6 + }, + "step_receipts": { + "cases": 4, + "completed": 4, + "model_calls": 12, + "tool_calls": 4 + } + }, + "limitations": [ + "Scripted identical model and tools; not semantic accuracy", + "Final-only baseline models checkpoint placement, not a full historical release benchmark", + "Unknown in-flight response stops rather than claiming exactly-once API execution", + "Not a 2000-case run or production outage measurement" + ] +} diff --git a/experiments/consultation-agent/docs/evidence/provenance.json b/experiments/consultation-agent/docs/evidence/provenance.json new file mode 100644 index 0000000..239d25c --- /dev/null +++ b/experiments/consultation-agent/docs/evidence/provenance.json @@ -0,0 +1,26 @@ +[ + { + "published_file": "human-keyword-scores.json", + "original_relative_path": "runs/human_keywords_v1/keyword_scores.json", + "original_sha256": "aed6a0d618c0871a7da7cab7ad3a68005151b1d0ef755fc7235c8a55abe4e7a6", + "transformation": "Remove per-case details; operational report retains only aggregate fields. No metric recalculation." + }, + { + "published_file": "human-run-summary.json", + "original_relative_path": "runs/human_keywords_v1/summary.json", + "original_sha256": "b59b543510094b244c2912773d2906ea8dcdbb5e6c5a846a52daa33d4aea67a1", + "transformation": "Remove per-case details; operational report retains only aggregate fields. No metric recalculation." + }, + { + "published_file": "catalog-replay-summary.json", + "original_relative_path": "runs/catalog_v3/summary.json", + "original_sha256": "893cd295a08e13019e07fe3a002081e5f0594b9c62419823e82efbd88ceceb81", + "transformation": "Remove per-case details; operational report retains only aggregate fields. No metric recalculation." + }, + { + "published_file": "operational-before-after.json", + "original_relative_path": "evidence/operational_before_after.json", + "original_sha256": "a1c56b907ce671e76779fa98734ceb37b7e16f99bb9103fa52062bb916895ea5", + "transformation": "Remove per-case details; operational report retains only aggregate fields. No metric recalculation." + } +] From a9c09378cebb860dc7d373c978f29b78555a0efe Mon Sep 17 00:00:00 2001 From: tkv00 Date: Tue, 15 Sep 2026 18:11:18 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[HSC-426]=20docs:=20=EB=B9=84=EC=9A=A9=20?= =?UTF-8?q?=EC=A6=9D=EA=B0=80=EC=99=80=20=EA=B2=80=EC=A6=9D=20=EC=8B=A4?= =?UTF-8?q?=ED=8C=A8=EB=A5=BC=20=ED=91=9C=EC=99=80=20=EB=8B=A4=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=EA=B7=B8=EB=9E=A8=EC=9C=BC=EB=A1=9C=20=EA=B8=B0?= =?UTF-8?q?=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- experiments/consultation-agent/README.md | 5 ++ .../consultation-agent/docs/RESULTS.md | 47 +++++++++++++++++++ experiments/consultation-agent/docs/TESTS.md | 45 ++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 experiments/consultation-agent/docs/RESULTS.md create mode 100644 experiments/consultation-agent/docs/TESTS.md diff --git a/experiments/consultation-agent/README.md b/experiments/consultation-agent/README.md index 038d936..a694704 100644 --- a/experiments/consultation-agent/README.md +++ b/experiments/consultation-agent/README.md @@ -50,3 +50,8 @@ python3 -m venv .venv 준비 단계는 API를 호출하지 않는다. 실행은 최대 50건으로 제한한다. `run_human50.py`는 별도로 동결한 `runs/human_keywords_v1`이 있어야 하며, 원자료 없이 실행할 수 없다. `replay_catalog.py`는 완료된 `runs/development_v2`의 최초 응답 50개를 재사용한다. 원본 실험의 코드 스냅샷 해시는 원본에 대한 기록이다. 경로 정리 후 코드는 해시가 달라지므로 과거 실행의 protocol을 그대로 재사용하지 않는다. 새 실행을 준비하면 현재 소스와 입력으로 새 해시가 만들어진다. + +## 결과와 검증 기록 + +- [비교 결과와 한계](docs/RESULTS.md) +- [테스트 성공·실패 기록](docs/TESTS.md) diff --git a/experiments/consultation-agent/docs/RESULTS.md b/experiments/consultation-agent/docs/RESULTS.md new file mode 100644 index 0000000..7f52444 --- /dev/null +++ b/experiments/consultation-agent/docs/RESULTS.md @@ -0,0 +1,47 @@ +# 상담 분석 비교 결과와 한계 + +사람 정답 50건에서는 네 방식의 원시 키워드 집합이 사례별로 모두 같았다. 에이전트 비용은 단일 호출보다 33.96% 높았다. 현재 키워드 과제에서 에이전트의 추가 이점을 확인하지 못했다. + +| 방식 | 원시 Micro-F1 | 전달 Micro-F1 | 보류 | 모델 호출 | 추정 비용 USD | +|---|---:|---:|---:|---:|---:| +| 단일 호출 | 76.23% | 76.34% | 1 | 50 | 0.0174957 | +| 조건부 재검토 | 76.23% | 74.51% | 3 | 62 | 0.0216285 | +| 반복 재검토 | 76.23% | 74.51% | 3 | 86 | 0.02996505 | +| MCP 에이전트 | 76.23% | 74.51% | 3 | 64 | 0.0234369 | + +```mermaid +xychart-beta + title "사람 정답 50건: 방식별 논리적 추정 비용" + x-axis [단일, 조건부, 반복, MCP] + y-axis "USD" 0 --> 0.032 + bar [0.0174957, 0.0216285, 0.02996505, 0.0234369] +``` + +공유한 최초 응답 비용이 방식별 비용에 각각 포함된다. 성공한 신규 API 응답 112회의 추정 비용 합계는 $0.04003905다. 청구서의 확정 금액은 아니다. 첫 샌드박스 실행의 DNS 실패는 성공 응답 비용과 구분했다. + +### 개발 자료에서 확인한 변화 + +| 비교 | 변경 전 | 변경 후 | 해석 | +|---|---:|---:|---| +| 중복 구조 검사 제거: 모델 호출 | 82 | 67 | 개발 50건의 에이전트 내부 비교 | +| 같은 비교: 도구 호출 | 16 | 1 | 호스트가 이미 하던 검사를 모델 도구 목록에서 제거 | +| 같은 비교: 추정 비용 | $0.0571458 | $0.0482058 | 15.64% 감소, 단일 호출 대비 절감이 아님 | +| 같은 비교: 검토 보류 | 0 | 2 | 의미 품질 유지까지 확인한 결과가 아님 | +| 장애 주입: 모의 모델 호출 | 18 | 12 | 알려진 응답 기록이 있는 네 조건 | +| 장애 주입: 모의 도구 호출 | 6 | 4 | 운영 장애율·실제 비용 측정이 아님 | + +초기 단일 2,000건 실행과 에이전트 부분 실행 기록은 존재한다. 이후 MCP 개선판의 새 2,000건 확대 검증은 하지 않았다. 서로 다른 자료·비교 조건을 하나의 성과로 합산하지 않는다. + +## 근거 파일 + +- [사람 정답 키워드 채점](evidence/human-keyword-scores.json) +- [호출·비용 집계](evidence/human-run-summary.json) +- [도구 목록 변경 전후](evidence/catalog-replay-summary.json) +- [장애 주입 집계](evidence/operational-before-after.json) +- [원본 경로와 SHA-256](evidence/provenance.json) + +집계 파일의 수치는 기존 실험에서 가져왔다. 이번 PR 준비 중 유료 모델 비교를 다시 실행하지 않았다. 사례별 상세와 상담 원문은 배포하지 않으므로 공개 파일만으로 원래 50건을 다시 채점할 수는 없다. + +`human-run-summary.json`의 `human_gold_verified: 0`은 공통 실행기가 사람 정답을 읽지 않는다는 기록이다. 사람 제공 키워드 정답은 실행 후 별도 `human-keyword-scores.json`에서 채점했다. 감정 정확도나 근거 문장의 의미 적절성은 검증하지 않았다. + +개발 자료 50건의 중복 검사 제거에서는 결과 두 건이 바뀌고 보류가 늘었다. 비용 감소만으로 의미 품질이 유지됐다고 판단하지 않았다. 장애 주입에서는 응답 기록 전 중단 시 `STOPPED_UNCERTAIN`으로 멈췄다. 무조건적인 완료나 외부 API의 정확히 한 번 실행을 보장하지 않는다. diff --git a/experiments/consultation-agent/docs/TESTS.md b/experiments/consultation-agent/docs/TESTS.md new file mode 100644 index 0000000..9c56826 --- /dev/null +++ b/experiments/consultation-agent/docs/TESTS.md @@ -0,0 +1,45 @@ +# 게시 전 테스트 기록 + +검증 날짜: 2026-09-15. Python 3.12, mcp 2.2.0의 기존 실험용 가상환경을 사용했다. 테스트는 실제 과금 모델을 호출하지 않는다. + +| 대상 | 명령 | 결과 | +|---|---|---| +| 원본, 기본 Python | `python3 -m unittest discover -s tests -v` | 48개 탐색, 오류 9개. mcp 미설치로 일부 테스트 수집 실패 | +| 원본, MCP 가상환경 | `python -m unittest discover -s tests -v` | 50개 통과, 1.682초 | +| 실행 엔진만 분리 | 같은 명령 | 39개 통과, 1.487초 | +| 환경변수 연결 구현 전 | `python -m unittest discover -s tests -p test_portable_client.py` | 2개 오류. client_from_env 미구현 확인 | +| 비교 실행기와 환경변수 연결 포함 | `python -m unittest discover -s tests -v` | 52개 통과, 1.194초 | + +명령은 `experiments/consultation-agent`에서 실행한다. 준비 중 저장소 루트에서 테스트 경로만 지정한 한 번의 실행은 `experiment` 모듈을 찾지 못해 수집에 실패했다. 문서의 실행 위치로 이동해 다시 실행했다. + +## 확인한 동작 + +| 영역 | 확인 내용 | +|---|---| +| 입력·출력 | 공통 최초 응답, 같은 출력 계약, 상담원 발화를 고객 근거로 사용하지 않음 | +| MCP | 실제 stdio 연결, 도구 목록과 호출 결과, 입력 해시 불일치 거부 | +| 실행 | 호출·비용 상한, 반복 도구 호출 중단, 도구 오류와 잘못된 응답 기록 | +| 복구 | 완료 결과 재사용, 단계 응답 재사용, 불확실한 외부 호출 자동 반복 금지 | +| 채점 | 누락 짝 거부, 과검출·누락 계산, 보류를 완전 일치로 세지 않음 | +| 인증 | OPENAI_API_KEY 전달, 키가 없으면 HTTP 클라이언트 생성 전 중단 | + +```mermaid +sequenceDiagram + participant T as 테스트 + participant R as 실행기 + participant J as SQLite 기록 + participant M as 모의 모델 + T->>R: 상담 분석 실행 + R->>J: 호출 시작 기록 + R->>M: 요청 + M-->>R: 응답 + R->>J: 응답 저장 + T->>R: 중단 후 재개 + R->>J: 저장된 응답 조회 + J-->>R: 같은 응답 재사용 + R-->>T: 결과 확인 +``` + +## 남은 범위 + +FastAPI 서버 전체 테스트와 운영 배포 검증은 실행하지 않았다. 코드가 추가된 독립 실험 디렉터리의 동작을 확인했다. 감정 정확도, 실제 고객 조치와 이탈률 변화는 이 테스트로 증명하지 않는다. From e05fbcbbf95fef958e70b64df2ef624926d1ea22 Mon Sep 17 00:00:00 2001 From: tkv00 Date: Tue, 15 Sep 2026 18:18:19 +0900 Subject: [PATCH 3/3] =?UTF-8?q?[HSC-426]=20fix:=20Mermaid=20=EB=B2=94?= =?UTF-8?q?=EC=A3=BC=20=EC=B6=95=20=EB=AC=B8=EC=9E=90=EC=97=B4=20=EA=B5=AC?= =?UTF-8?q?=EB=AC=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- experiments/consultation-agent/docs/RESULTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experiments/consultation-agent/docs/RESULTS.md b/experiments/consultation-agent/docs/RESULTS.md index 7f52444..9bb82c3 100644 --- a/experiments/consultation-agent/docs/RESULTS.md +++ b/experiments/consultation-agent/docs/RESULTS.md @@ -12,7 +12,7 @@ ```mermaid xychart-beta title "사람 정답 50건: 방식별 논리적 추정 비용" - x-axis [단일, 조건부, 반복, MCP] + x-axis ["단일", "조건부", "반복", "MCP"] y-axis "USD" 0 --> 0.032 bar [0.0174957, 0.0216285, 0.02996505, 0.0234369] ```