--- id: lessons-learned-library title: "교훈 라이브러리 Lessons Learned" category: "Software_Engineering" status: "draft" verification_status: "applied" canonical_id: "" aliases: ["lessons learned", "교훈", "버그 사후기록", "post-mortem", "재사용 가능한 교훈"] duplicate_of: "" source_trust_level: "A" confidence_score: 0.91 created_at: 2026-06-13 updated_at: 2026-06-13 review_reason: "" merge_history: [] tags: ["lessons", "post-mortem", "engineering", "bugs", "astraai"] raw_sources: ["AstraAI/src/core/lock.ts", "AstraAI/src/retrieval/index.ts", "AstraAI/src/agents/AgentWorkflowManager.ts", "AstraAI/src/features/company/dispatcher.ts", "AstraAI/src/core/services.ts"] applied_in: ["AstraAI"] github_commit: "" --- # [[교훈 라이브러리 Lessons Learned]] ## 🎯 한 줄 통찰 (One-line insight) AstraAI 의 주석에는 실제 겪은 버그·오설계의 사후기록이 박혀 있다 — 각 교훈을 (문제→근본원인→해결→교훈→향후 권고)로 정리하면, 작은 모델이 *같은 실수를 코드 작성 단계에서 회피* 하는 재사용 지식이 된다. ## 🧠 핵심 개념 (Core concepts) - 교훈 형식: **Problem → Root Cause → Solution → Lesson → Future Recommendation**. - 코드 설명이 아니라 *전이 가능한 엔지니어링 지식* 을 추출하는 것이 목적. ## 📖 세부 내용 (Details · 교훈 모음) ### L-01. Promise 동일성 비교는 항상 실패한다 - **Problem:** 비동기 락 cleanup 이 동작하지 않아 락이 새거나 다른 작업 entry 를 지움. - **Root Cause:** `map.get(id) === prev.then(()=>next)` 로 비교했는데 `.then()` 은 *매번 새 Promise* 를 반환 → 동일성 비교가 항상 false. 또 release 시 무조건 delete → race. - **Solution:** 각 entry 에 고유 `Symbol` 토큰을 부여, "내 토큰이 Map 의 최신일 때만" 정리. - **Lesson:** Promise·객체 동일성(`===`)에 로직을 걸지 말 것. 식별이 필요하면 명시적 토큰/ID 를 써라. - **Future Recommendation:** 공유 자원 정리는 "내가 최신 소유자인가" 를 토큰으로 확인 후 수행 [S1]. ### L-02. 하이브리드 점수는 같은 스케일로 정규화해야 한다 - **Problem:** 임베딩을 섞었더니 검색 품질이 *나빠짐*. - **Root Cause:** ① 벡터 있는 후보만 0..1 로 줄이면 벡터 없는 후보의 raw 점수(≫1)가 상위 독식 → blend 무효. ② cosine 절대값 가산은 무관 문서도 0.5~0.7 이라 균일 노이즈로 sparse 정밀도 훼손. - **Solution:** *모든* 후보를 maxTfidf 로 정규화, cosine 은 후보군 내 min-max 정규화 후 혼합. - **Lesson:** 서로 다른 점수를 합칠 땐 *동일 스케일* 로 정규화하라. 부분 정규화는 편향을 만든다. - **Future Recommendation:** 점수 융합 전 각 신호의 분포를 측정하고 정규화 방식을 명시 [S2]. ### L-03. 멀티에이전트 hop 은 컨텍스트를 누적하고 본문을 잃는다 - **Problem:** 본문 분석 요청에 "분석 방법론" 만 생성. - **Root Cause:** 5-persona 파이프라인이 hop 마다 컨텍스트를 쌓고 원본 본문을 추상화로 손실. - **Solution:** 단일 작성자가 역할을 번갈아 수행, 본문을 매 호출에 직접 전달. - **Lesson:** 에이전트를 늘리기 전에 "원본 데이터가 hop 을 거치며 손실되는가" 를 점검하라. 에이전트 수 ≠ 품질. - **Future Recommendation:** 정보 손실 위험이 있으면 hop 을 줄이고 원자료를 끝까지 보존 [S3]. ### L-04. 자원 제약은 동시성 모델을 결정한다 - **Problem:** 병렬 에이전트가 단일 GPU 에서 OOM/로드 실패. - **Root Cause:** 병렬은 여러 모델 동시 상주를 강요 — 제한 RAM 초과. - **Solution:** 순차 디스패치 + "한 번에 한 모델 상주" 불변식(lifecycle unload/load). - **Lesson:** 동시성은 알고리즘이 아니라 *배포 환경* 이 결정한다. 자원을 모르면 동시성을 정할 수 없다. - **Future Recommendation:** 설계 전 타깃 하드웨어(RAM/GPU)를 먼저 못박아라 [S4]. ### L-05. 작은 모델은 system 없으면 환각 거절한다 - **Problem:** 짧고 모호한 입력에 "시는 못 써드려요" 류 거절. - **Root Cause:** system 프롬프트 없이 user 만 주면 작은 모델이 의도를 못 잡고 방어적 거절. - **Solution:** grounding 경로는 system 을 반드시 채운다(역할·규칙 명시). - **Lesson:** 모델이 작을수록 *명시적 지시* 의존도가 크다. "알아서 하겠지" 가 안 통한다. - **Future Recommendation:** 모든 LLM 호출에 최소한의 역할 system 을 기본 제공 [S5]. ### L-06. 빈 catch 는 "이유 주석" 과 함께만 안전하다 - **Problem:** 부가 작업(메모리 추출/증류) 실패가 대화 전체를 깨뜨릴 위험. - **Root Cause:** 핵심 흐름에 부가 작업을 직렬로 엮으면 부가 실패가 본류를 막는다. - **Solution:** 부가 작업을 `try { } catch { /* should never break main flow */ }` 로 격리, *반드시 이유 주석*. - **Lesson:** 실패를 삼키는 것은 *부가 작업에 한해, 의도를 명시* 할 때만 정당하다. - **Future Recommendation:** 빈 catch 마다 "왜 안전한가" 를 1줄로 남겨 리뷰어/모델이 구분하게 [S6]. ### L-07. 동적 require 는 이유가 사라지면 정적 import 로 - **Problem:** 매 stage 마다 `await import(...)` 8회 — 흐름 불명확. - **Root Cause:** 과거 cyclic import 회피로 짐작됐으나, 실제로는 해당 모듈들이 dispatcher 를 import 하지 않아 순환이 없었음. - **Solution:** 정적 import 로 promote — 코드 명료 + require 8회→0회(모듈 캐시). - **Lesson:** "왜 이렇게 했는지" 가 불명한 우회 코드는 가정을 검증하고 단순화하라. - **Future Recommendation:** 우회(workaround)에는 이유를 적고, 주기적으로 "아직 필요한가" 재검토 [S4]. ## ⚖️ 모순 및 업데이트 (Contradictions & updates) 교훈은 *그 맥락에서* 참이다. 예: L-04(순차)는 단일 GPU 전제 — 서버에선 반대가 교훈이 된다. 교훈을 적용하기 전 전제가 같은지 확인하라. ## 🛠️ 적용 사례 (Applied in summary) 각 교훈은 실제 AstraAI 주석/리팩터링에서 추출. AstraAI 의 lessons/ 폴더와 correctionLoop 이 이런 교훈을 자동 적립하는 시스템이기도 하다 → [[Intelligence 검증 레이어]]. ## 🔗 지식 그래프 (Knowledge Graph) - **상위/루트:** [[AstraAI 아키텍처 개요]] - **관련 개념:** [[안티패턴 카탈로그]], [[디버깅 플레이북]], [[엔지니어링 트레이드오프 분석]], [[코딩 컨벤션과 주석 철학]] - **참조 맥락:** 로컬 LLM 이 코드를 작성하기 전 "이 상황에서 알려진 함정" 을 회피하는 체크리스트로 참조. ## 📚 출처 (Sources) - [S1] AstraAI/src/core/lock.ts — Promise 동일성/토큰 정리 post-mortem - [S2] AstraAI/src/retrieval/index.ts — 하이브리드 스케일 정규화 버그 - [S3] AstraAI/src/agents/AgentWorkflowManager.ts — 멀티에이전트 hop 손실 - [S4] AstraAI/src/features/company/dispatcher.ts — 자원 제약, 동적 require 통합 - [S5] AstraAI/src/core/services.ts — 작은 모델 system grounding - [S6] AstraAI/src/memory/index.ts — 의도적 빈 catch ## 📝 변경 이력 (Change history) - 2026-06-13: AstraAI 코드 사후기록 기반 교훈 추출.