wiki: Topic_Blog 신규 문서 일괄 추가 + ASTRA 성장 자산 동기화
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
---
|
||||
id: topic-programming-index
|
||||
title: "Topic Programming 인덱스"
|
||||
category: "Index"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["프로그래밍 위키 인덱스", "Topic_Programming 목차", "second brain coding index", "코딩 제2뇌 목차"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.95
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["index", "navigation", "programming", "second-brain", "astraai"]
|
||||
raw_sources: ["Topic_Programming 전체"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Topic Programming 인덱스]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
이 위키는 "로컬 작은 LLM(Gemma/Qwen/Llama 등)의 코딩·설계 능력을 제2뇌 지식으로 끌어올린다" 는 목적의 지식 베이스로, AstraAI 코드 분석에서 출발해 **언어 → 아키텍처 → 서브시스템 → 설계 결정(ADR) → 패턴 → 실패 → 플랫폼 → 일반 원칙** 으로 추상도를 높여간다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
- **목적:** 코드 설명이 아니라 *전이 가능한 엔지니어링 지능* 을 작은 모델에 제공.
|
||||
- **출처:** 1차 코드는 AstraAI(Astra) VS Code 확장(TypeScript, 308 파일). 일반 지식은 표준 소프트웨어 공학.
|
||||
- **포맷:** P-Reinforce v3.1(frontmatter + 이모지 섹션 + [[위키링크]] + 출처).
|
||||
|
||||
## 📖 세부 내용 (Details · 전체 지도)
|
||||
|
||||
### 작은 모델 권장 학습 순서 (사용자 우선순위)
|
||||
1. **프로젝트 위키** → 2. **설계 결정(ADR)** → 3. **패턴 라이브러리** → 4. **실패 라이브러리** → 5. **플랫폼별 개발 패턴** → 6. **일반 원칙**.
|
||||
|
||||
### 1) 언어 지식 (Language/)
|
||||
- [[TypeScript 기초와 타입 시스템]] · [[TypeScript 고급 타입]] · [[비동기 프로그래밍 Promise async await]] · [[모듈 시스템과 프로젝트 구성]] · [[에러 처리와 커스텀 에러]]
|
||||
|
||||
### 2) 아키텍처·설계 (Architecture/)
|
||||
- [[AstraAI 아키텍처 개요]] · [[VSCode 확장 구조와 생명주기]] · [[의존성 주입과 서비스 인터페이스]] · [[이벤트 소싱 스토어 패턴]] · [[동시성 제어 Lock Queue Transaction]]
|
||||
|
||||
### 3) 서브시스템 심층 (Subsystems/)
|
||||
- [[5계층 메모리 시스템]] · [[RAG 검색 파이프라인]] · [[TF-IDF 이중언어 스코어링]] · [[LLM 프로바이더 추상화]] · [[Intelligence 검증 레이어]] · [[Agent 오케스트레이터 분해]]
|
||||
|
||||
### 4) 컨벤션 (Conventions/)
|
||||
- [[코딩 컨벤션과 주석 철학]] · [[프롬프트 엔지니어링 패턴]]
|
||||
|
||||
### 5) 설계 결정 — ADR (Engineering_Intelligence/ADR/)
|
||||
- [[ADR-0001 이벤트 소싱 채택]] · [[ADR-0002 5계층 메모리 분리]] · [[ADR-0003 단일작성자 다중역할 멀티에이전트]] · [[ADR-0004 순차 디스패치 채택]] · [[ADR-0005 파일 기반 저장 채택]] · [[ADR-0006 수동 의존성주입 인터페이스 서비스]] · [[ADR-0007 하이브리드 검색 결정론 우선]] · [[ADR-0008 로컬우선 LLM 클라우드 폴백]] · [[ADR-0009 결정론 항상 LLM검증 조건부]] · [[ADR-0010 오케스트레이터 골격 모듈추출]]
|
||||
|
||||
### 6) 엔지니어링 지능 (Engineering_Intelligence/)
|
||||
- [[엔지니어링 트레이드오프 분석]] · [[교훈 라이브러리 Lessons Learned]] · [[안티패턴 카탈로그]] · [[아키텍처 휴리스틱]] · [[리팩토링 플레이북]] · [[디버깅 플레이북]]
|
||||
- AI 학습 추출: [[AITRAIN 메모리 시스템]] · [[AITRAIN RAG 검색]] · [[AITRAIN 에이전트 오케스트레이션]] · [[AITRAIN 검증 레이어]] · [[AITRAIN 이벤트소싱 저장]] · [[AITRAIN 동시성 제어]] · [[AITRAIN 프로바이더 추상화]]
|
||||
|
||||
### 7) 패턴 카탈로그 (Pattern_Catalog/) → [[패턴 카탈로그 인덱스]]
|
||||
- AI · Cross-cutting · Web · Mobile · Desktop 패턴 27종.
|
||||
|
||||
### 8) 실패 라이브러리 (Failure_Library/)
|
||||
- [[소프트웨어 실패 라이브러리]]
|
||||
|
||||
### 9) 플랫폼 가이드 (Platform_Guides/) → [[플랫폼 개발 가이드 인덱스]]
|
||||
- [[웹 개발 가이드]] · [[데스크탑 앱 개발 가이드]] · [[모바일 개발 가이드]] · [[백엔드 API 개발 가이드]] · [[AI 에이전트 개발 가이드]]
|
||||
|
||||
### 10) 일반 원칙 (Generalized_Principles/)
|
||||
- [[프로젝트 독립 설계 원칙]] — 모든 것의 capstone(12원칙).
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
AstraAI 사례 기반 지식은 *로컬·단일 사용자·작은 모델* 전제다. 다른 환경에선 [[엔지니어링 트레이드오프 분석]] 으로 재평가하라. 모든 문서는 draft — 사용하며 검증/보강.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
이 인덱스를 진입점으로, 작은 모델은 질의에 맞는 계층(언어/패턴/실패/원칙)을 RAG 로 회수해 컨텍스트에 주입한다.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[Topic Programming 인덱스]]
|
||||
- **관련 개념:** [[AstraAI 아키텍처 개요]] · [[패턴 카탈로그 인덱스]] · [[플랫폼 개발 가이드 인덱스]] · [[프로젝트 독립 설계 원칙]]
|
||||
- **참조 맥락:** 제2뇌 전체의 목차이자 진입점.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] Topic_Programming 전체 문서 + AstraAI 소스 분석
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 제2뇌 코딩 지식 베이스 마스터 인덱스 생성.
|
||||
@@ -0,0 +1,104 @@
|
||||
---
|
||||
id: astraai-architecture-overview
|
||||
title: "AstraAI 아키텍처 개요"
|
||||
category: "Architecture"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["Astra", "AstraAI", "feature-based architecture", "전체 구조", "모듈 아키텍처", "제2뇌 OS"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "S"
|
||||
confidence_score: 0.95
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["architecture", "astraai", "feature-based", "layering", "overview"]
|
||||
raw_sources: ["AstraAI/src/extension.ts", "AstraAI/src 트리(308 TS 파일)", "AstraAI/package.json", "AstraAI/src/core/services.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[AstraAI 아키텍처 개요]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
AstraAI(Astra)는 "로컬 LLM 을 두뇌로 쓰는 VS Code 확장형 자기진화 지식 OS"이며, **기능별 폴더 경계 + 얇은 entry point + 핵심 인프라(core) 위에 도메인(features)을 쌓는 계층형 모듈 아키텍처**로 308개 파일을 조직한다 [S1][S2].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **Feature-based 구조:** `src/features/` 아래 각 폴더가 독립 기능(stocks, calendar, company, datacollect, devilAgent…). 기능 간 결합을 최소화하고, 공통 인프라만 `core/`/`lib/` 에서 공유 [S2].
|
||||
2. **계층 분리:** `core`(인프라) → `lib`/`memory`/`retrieval`/`intelligence`(역량) → `features`(기능) → `extension.ts`(조립). 아래 계층은 위를 모른다 [S2].
|
||||
3. **얇은 entry point:** `extension.ts` 의 `activate()` 는 *조립과 등록만* 한다 — 객체 생성, 의존성 주입, 명령 등록, 워처 시작. 로직은 전부 모듈에 위임 [S1].
|
||||
4. **의존성 주입:** 생성자에 옵션 객체로 협력자를 주입(`new AgentExecutor(context, { lmStudioStreamer, approvalQueue, ... })`) — 테스트·교체 용이 [S1].
|
||||
5. **싱글톤 인프라:** 프로세스 전역이 자연스러운 자원(`lockManager`, `actionQueue`)은 모듈 싱글톤으로 export [S1].
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **God-class 분해:** 거대해지는 orchestrator(`agent.ts`)를 `handlePrompt/`, `llm/`, `actions/`, `multiAgent/`, `sessions/` 하위 모듈로 쪼개 함수 단위로 추출하고, orchestrator 는 이들을 호출만 한다 [참조: [[Agent 오케스트레이터 분해]]].
|
||||
- **인터페이스 우선 서비스:** `IAIService`/`IBrainService` 인터페이스를 두고 구현(`AIService`)을 분리 — 엔진 폴백 같은 정책을 구현체에 캡슐화 [S3].
|
||||
- **자기등록 핸들러:** slashRouter 에 핸들러가 side-effect import 로 자기 등록 — 새 명령 추가 시 중앙 등록표를 건드리지 않음 [S1].
|
||||
- **부트스트랩 분리:** 활성화 시 필요한 초기화(brain 디렉터리, 임베딩 감지, 기능 인벤토리)를 `extension/*Bootstrap.ts` 로 분리해 entry point 를 얇게 유지 [S1].
|
||||
- **disposable 수명 관리:** 생성한 모든 자원을 `context.subscriptions.push(...)` 로 등록해 확장 종료 시 일괄 정리 [S1].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### 디렉터리 지도 (역할별)
|
||||
- **core/** — 횡단 인프라: `lock`, `queue`, `transaction`, `errors`, `errorHandler`, `services`(AI/Brain 서비스), `session`, `events`, `health`, `telemetry`, `statusBar`.
|
||||
- **memory/** — 5계층 인지 메모리(Short/Long/Project/Procedural/Episodic) + `distillation`. → [[5계층 메모리 시스템]].
|
||||
- **retrieval/** — RAG 파이프라인: `chunker`, `scoring`(TF-IDF), `embeddings`, `brainIndex`, `contextBudget`, rerank 류. → [[RAG 검색 파이프라인]].
|
||||
- **intelligence/** — 검증·자기평가: `criticAgent`, `confidenceEngine`, `correctionLoop`, `epistemicGuardBlock`, `knowledgeValidation`. → [[Intelligence 검증 레이어]].
|
||||
- **lib/contextBuilders/** — 프롬프트에 들어갈 컨텍스트 블록을 조립하는 순수 함수 모음(메모리·프로젝트·일정·자기인식 등 30+개).
|
||||
- **features/** — 도메인 기능. 각자 `index.ts`(공개 API) + store + handler + prompt 로 구성되는 경향.
|
||||
- **agent/** + **agents/** — 에이전트 실행 세부와 다중 에이전트 워크플로 매니저.
|
||||
- **integrations/** — 외부 연동(telegram).
|
||||
- **sidebar/** + **sidebarProvider.ts** — 웹뷰 UI 와 메시지 핸들러.
|
||||
- **system/**, **lmstudio/**, **scaffolder/**, **skills/** — 시스템 사양 탐지, LM Studio SDK 수명관리, 프로젝트 스캐폴딩, 스킬 로딩.
|
||||
|
||||
### 제어 흐름 (한 턴의 처리)
|
||||
1. 웹뷰(사이드바)에서 사용자 입력 → `sidebar/chatHandlers` → `AgentExecutor`.
|
||||
2. `agent/handlePrompt/*` 가 컨텍스트 블록(메모리·RAG·프로젝트·일정)을 조립.
|
||||
3. 모델 라우팅: 클라우드 prefix 면 provider 어댑터, 아니면 로컬 엔진(LM Studio/Ollama). → [[LLM 프로바이더 추상화]].
|
||||
4. 스트리밍 응답 → 후처리(sanitize, devil rebuttal) → post-answer hooks(critic 검수, 교정 캡처).
|
||||
5. 세션 종료 시 메모리 추출/증류, 성장 사이클 워처가 폐루프로 학습.
|
||||
|
||||
### 빌드/런타임
|
||||
- esbuild 단일 번들(`out/extension.js`), `vscode` external. 런타임 의존성은 `@lmstudio/sdk`, `pdf-parse` 둘뿐 — 나머지는 native API(fetch 등)로 자급 [S2].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **단일 거대 agent.ts(1681줄):** 분해를 했음에도 orchestrator 가 여전히 크다. 이는 "한 턴의 제어 흐름을 한 곳에서 읽을 수 있게" 하려는 의도적 트레이드오프 — 세부는 추출하되 흐름의 골격은 남긴다.
|
||||
- **features 간 결합:** 일부 기능(company, stocks)은 텔레그램·시트 등 여러 통합을 동시에 참조해 완전 독립은 아니다. core/lib 를 통한 간접 결합으로 완화.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/extension.ts` 의 `activate()` 전체가 "얇은 조립 entry point" 의 교과서적 예 — 25개+ 모듈을 생성·주입·등록하지만 비즈니스 로직은 0 [S1].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// activate(): 조립과 등록만 — 로직은 모듈에 위임 (src/extension.ts 발췌)
|
||||
export async function activate(context: vscode.ExtensionContext) {
|
||||
await ensureDefaultBrainConfigured(); // 부트스트랩 분리
|
||||
void ensureEmbeddingConfigured(context); // 비차단 best-effort
|
||||
initAstraPathResolver(context);
|
||||
|
||||
const lmStudioClient = new LMStudioClient(getConfig().ollamaUrl);
|
||||
const agent = new AgentExecutor(context, { // 생성자 의존성 주입
|
||||
onStreamLifecycle: { start: () => lifecycle.onStreamStart(), end: () => lifecycle.onStreamEnd() },
|
||||
lmStudioStreamer, approvalQueue,
|
||||
});
|
||||
const provider = new SidebarChatProvider(context.extensionUri, context, agent, { lifecycle, /* ... */ });
|
||||
|
||||
context.subscriptions.push( // 수명 관리: 종료 시 일괄 dispose
|
||||
vscode.commands.registerCommand('g1nation.openChat', () => provider.openAsPanel(vscode.ViewColumn.Three)),
|
||||
...registerProviderCommands(context, { getProvider: () => provider }),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[VSCode 확장 구조와 생명주기]], [[의존성 주입과 서비스 인터페이스]], [[Agent 오케스트레이터 분해]], [[모듈 시스템과 프로젝트 구성]]
|
||||
- **참조 맥락:** 로컬 LLM 이 새 기능을 "어느 계층/폴더에 어떤 형태로" 추가할지 판단할 때 최상위 지도로 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/extension.ts — activate/deactivate, 조립·주입·등록·부트스트랩
|
||||
- [S2] AstraAI/src 디렉터리 트리(308 TS 파일) + package.json — 계층/번들 구성
|
||||
- [S3] AstraAI/src/core/services.ts — IAIService/IBrainService 인터페이스 우선 설계
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 전체 코드 분석 기반 초안 생성.
|
||||
@@ -0,0 +1,122 @@
|
||||
---
|
||||
id: vscode-extension-structure-lifecycle
|
||||
title: "VSCode 확장 구조와 생명주기"
|
||||
category: "Architecture"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["VS Code Extension", "activate", "deactivate", "Disposable", "Webview", "command 등록", "extension API"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.93
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["vscode", "extension", "lifecycle", "disposable", "webview", "astraai"]
|
||||
raw_sources: ["AstraAI/src/extension.ts", "AstraAI/package.json", "AstraAI/src/features/_shared/eventSourcedStore.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[VSCode 확장 구조와 생명주기]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
VS Code 확장은 `activate(context)` 에서 깨어나 명령·뷰·이벤트를 등록하고 `deactivate()` 에서 정리되며, 모든 자원을 **`context.subscriptions` 에 Disposable 로 등록**해 두면 확장 종료 시 메모리/타이머/리스너가 누수 없이 일괄 정리된다 [S1].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **`activate(context)`:** 확장 진입점. `package.json` 의 activationEvents 조건이 충족되면 호출된다. `context: ExtensionContext` 가 전역 상태·구독·시크릿 저장소를 제공 [S1].
|
||||
2. **`deactivate()`:** 종료 훅. 명시적으로 풀어야 하는 자원(외부 프로세스, 봇, 모델 언로드)을 여기서 정리 [S1].
|
||||
3. **Disposable 패턴:** `{ dispose(): void }` 를 가진 객체. `context.subscriptions.push(disposable)` 하면 VS Code 가 종료 시 `dispose()` 를 호출 [S1].
|
||||
4. **Command:** `vscode.commands.registerCommand(id, handler)` 로 등록, `package.json` 의 `contributes.commands` 에 선언. 반환값이 Disposable [S1].
|
||||
5. **Webview:** HTML 기반 커스텀 UI. 확장↔웹뷰는 `postMessage` 로 통신. AstraAI 는 사이드바 대신 *에디터 컬럼* 에 패널로 띄운다 [S1].
|
||||
6. **Configuration:** `vscode.workspace.getConfiguration('g1nation')` 으로 설정 읽기, `onDidChangeConfiguration` 으로 변경 반응 [S1].
|
||||
7. **SecretStorage:** 토큰 등 민감정보는 `context.secrets` 에 저장(평문 설정 금지) [S1].
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **모든 자원을 subscriptions 로:** 명령·리스너·상태바·타이머·커스텀 dispose 콜백까지 전부 `context.subscriptions.push(...)` — 정리를 잊지 않는 구조적 보장 [S1].
|
||||
- **설정 변경 반응:** `onDidChangeConfiguration((e) => { if (!e.affectsConfiguration('g1nation.ollamaUrl')) return; ... })` — 관심 키만 필터링해 재설정 [S1].
|
||||
- **lazy webview 전송:** 매우 이른 활성화 시점엔 웹뷰가 아직 없을 수 있어 `provider?._sendModels(...)` 옵셔널 체이닝 + best-effort [S1].
|
||||
- **getter 콜백으로 늦은 바인딩:** 아직 안 만들어진 객체는 `getProvider: () => provider` 처럼 getter 로 주입 — 순환 의존/초기화 순서 문제 회피 [S1].
|
||||
- **워처 = disposable 반환 함수:** `startStocksWatcher(context)` 가 타이머를 만들고 disposable 을 반환해 subscriptions 에 등록 → 종료 시 timer cleanup [S1].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### activate 의 책임 순서 (AstraAI 실제 순서)
|
||||
1. 가시화(버전 popup/console) → 환경 진단.
|
||||
2. 부트스트랩(brain 디렉터리, 임베딩 감지, 기능 인벤토리) — 일부는 `void` 비차단.
|
||||
3. 인프라 초기화(health monitor, path resolver, config 검증).
|
||||
4. 핵심 객체 생성·주입(LMStudioClient, lifecycle, AgentExecutor, SidebarChatProvider, BridgeServer).
|
||||
5. 명령·리스너 등록.
|
||||
6. 워처 시작(stocks, daily briefing, growth cycle, sleep digest).
|
||||
7. 웹뷰 자동 오픈.
|
||||
|
||||
### deactivate 의 책임
|
||||
`HealthCheckMonitor.dispose()`, 인메모리 인덱스 해제(`clearBrainTokenIndex()` — Map 이 프로세스 수명 동안 안 비는 것 방지), 텔레그램 봇 stop, 모델 lifecycle dispose+unload. *명시적 정리가 필요한 것만* 여기서 처리하고, subscriptions 로 등록된 것은 VS Code 가 알아서 정리한다 [S1].
|
||||
|
||||
### 설정·시크릿
|
||||
```typescript
|
||||
const cfg = vscode.workspace.getConfiguration('g1nation');
|
||||
const timeout = cfg.get<number>('lmStudio.idleTimeoutMs', 300000); // 기본값 동반
|
||||
const token = await context.secrets.get(TELEGRAM_TOKEN_SECRET_KEY); // 민감정보는 secrets
|
||||
```
|
||||
|
||||
### Webview 통신
|
||||
확장→웹뷰는 `webview.postMessage({ type: 'streamChunk', value })`, 웹뷰→확장은 메시지 핸들러(`sidebar/chatHandlers`). 스트리밍은 `streamStart`/`streamChunk`/`streamEnd` 의 메시지 프로토콜로 표현 [참조: [[Agent 오케스트레이터 분해]]].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **사이드바 뷰 제거(v2.81):** 과거엔 activity bar 사이드바에 webview view 를 등록했으나, 현재는 에디터 컬럼 3에 패널로 띄운다. 대신 activity bar 에는 명령 링크만 있는 빈 TreeView 를 둔다 — 탭이 닫혀도 다시 열 수 있게 [S1].
|
||||
- **activationEvents:** 너무 광범위하면(예: `*`) 시작이 느려진다. 필요한 이벤트로 좁히는 것이 좋다(AstraAI 는 명령/뷰 기반).
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/extension.ts` — activate/deactivate 의 전 과정, subscriptions 등록, 설정 반응, secrets 사용, 워처 등록이 모두 한 파일에 [S1].
|
||||
- `AstraAI/src/features/_shared/eventSourcedStore.ts` — `vscode.workspace.workspaceFolders` 로 워크스페이스 경로 해석(확장에서 파일 경로 다루는 표준 방식) [S3].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// 1) 명령 등록 → 반환된 Disposable 을 subscriptions 로 (src/extension.ts)
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand('g1nation.clearChat', () => provider.clearChat()),
|
||||
);
|
||||
|
||||
// 2) 설정 변경 반응 — 관심 키만 (src/extension.ts)
|
||||
context.subscriptions.push(
|
||||
vscode.workspace.onDidChangeConfiguration((e) => {
|
||||
if (!e.affectsConfiguration('g1nation.ollamaUrl')) return;
|
||||
const newUrl = vscode.workspace.getConfiguration('g1nation').get<string>('ollamaUrl', '');
|
||||
lmStudioClient.setBaseUrl(newUrl);
|
||||
}),
|
||||
);
|
||||
|
||||
// 3) 커스텀 dispose 콜백도 disposable 로 등록
|
||||
context.subscriptions.push({ dispose: () => activityTracker.dispose() });
|
||||
|
||||
// 4) getter 콜백으로 늦은 바인딩 (순환/초기화 순서 회피)
|
||||
const telegramBot = createTelegramBot(context, { telegramClient, getProvider: () => provider });
|
||||
|
||||
// 5) deactivate — 명시 정리가 필요한 것만
|
||||
export async function deactivate() {
|
||||
HealthCheckMonitor.dispose();
|
||||
clearBrainTokenIndex();
|
||||
if (_telegramBot) { try { await _telegramBot.stop(); } catch {} }
|
||||
}
|
||||
```
|
||||
|
||||
## ✅ 검증 상태 및 신뢰도
|
||||
- **상태:** draft
|
||||
- **검증 단계:** applied
|
||||
- **출처 신뢰도:** A
|
||||
- **신뢰 점수:** 0.93
|
||||
- **중복 검사 결과:** 신규 생성 (New discovery)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[의존성 주입과 서비스 인터페이스]], [[모듈 시스템과 프로젝트 구성]], [[동시성 제어 Lock Queue Transaction]]
|
||||
- **참조 맥락:** 로컬 LLM 이 VS Code 확장의 명령/뷰/설정/수명관리 코드를 작성·수정할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/extension.ts — activate/deactivate, subscriptions, 명령/설정/시크릿/웹뷰/워처
|
||||
- [S2] AstraAI/package.json — engines.vscode, main, contributes(명령/뷰)
|
||||
- [S3] AstraAI/src/features/_shared/eventSourcedStore.ts — workspaceFolders 경로 해석
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.
|
||||
@@ -0,0 +1,129 @@
|
||||
---
|
||||
id: concurrency-lock-queue-transaction
|
||||
title: "동시성 제어 Lock Queue Transaction"
|
||||
category: "Architecture"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["concurrency", "AsyncLock", "mutex", "race condition", "동시성", "큐", "concurrency limit", "트랜잭션"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.94
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["architecture", "concurrency", "lock", "queue", "transaction", "astraai"]
|
||||
raw_sources: ["AstraAI/src/core/lock.ts", "AstraAI/src/core/queue.ts", "AstraAI/src/core/transaction.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[동시성 제어 Lock Queue Transaction]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
단일 스레드 JavaScript 도 `await` 사이에 다른 작업이 끼어들어 *경쟁 상태(race condition)* 가 생기며, AstraAI 는 **자원별 비동기 락(AsyncLock)·동시성 제한 큐·파일 보상 트랜잭션** 세 가지로 "한 번에 하나만·자원을 폭주시키지 않고·실패하면 되돌리는" 동시성 안전을 확보한다 [S1][S2][S3].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **JS 의 동시성:** 단일 스레드라도 `await` 지점에서 제어가 넘어가므로, 같은 파일을 동시에 읽고-수정-쓰면 갱신 손실이 난다. 직렬화가 필요 [S1].
|
||||
2. **비동기 뮤텍스 (AsyncLock):** 자원 ID 별로 "이전 작업이 끝나야 다음이 시작"되는 Promise 체인. `acquire` 가 release 함수를 반환, `try/finally` 로 반드시 해제 [S1].
|
||||
3. **데드락 방지 타임아웃:** 락 대기를 `Promise.race([previous, timeout])` 로 감싸 무한 대기 차단 [S1].
|
||||
4. **동시성 제한 큐:** 동시에 실행되는 작업 수를 `max(2, cpus-1)` 로 제한해 I/O·메모리 폭주 방지 [S2].
|
||||
5. **보상 트랜잭션:** 파일시스템에 트랜잭션이 없으므로, 변경 전 백업→실패 시 복원으로 원자성을 흉내 [S3].
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **고유 토큰으로 안전한 정리:** 각 락 entry 에 `Symbol` 토큰을 부여하고, cleanup/release 시 "내 토큰이 아직 Map 의 최신인지" 확인 후에만 삭제 — 연쇄 호출 시 다른 작업 entry 를 지우는 race 방지 [S1].
|
||||
- **release 는 반드시 try/finally:** `const release = await lock.acquire(id); try { ... } finally { release(); }` — 예외가 나도 락이 풀리게 [S1].
|
||||
- **enqueue 가 Promise 반환:** `enqueue<T>(task)` 가 작업 결과 Promise 를 돌려주되 실행은 슬롯이 빌 때 — 호출부는 평소처럼 await [S2].
|
||||
- **micro-delay 로 숨통:** 무거운 I/O 사이 `await sleep(10)` 로 시스템에 여유 [S2].
|
||||
- **begin/record/commit/rollback:** 변경 전 `record(파일)` 로 백업, 성공 `commit`(백업 폐기), 실패 `rollback`(원복) [S3].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### AsyncLock 의 핵심 — Promise 체인 + 토큰
|
||||
```typescript
|
||||
const previousPromise = this.locks.get(resourceId)?.promise ?? Promise.resolve();
|
||||
const token = Symbol(`lock:${resourceId}`);
|
||||
let release!: () => void;
|
||||
const newPromise = new Promise<void>((resolve) => { release = resolve; });
|
||||
this.locks.set(resourceId, { promise: previousPromise.then(() => newPromise), token });
|
||||
await Promise.race([previousPromise, timeoutPromise]); // 앞 작업 끝날 때까지(타임아웃 보호)
|
||||
return () => { release(); if (this.locks.get(resourceId)?.token === token) this.locks.delete(resourceId); };
|
||||
```
|
||||
**버그 사후기록(주석)**: 옛 구현은 `.then(...)` 이 매번 새 Promise 를 반환해 동일성 비교가 *항상 false* → cleanup 실패. 또 release 시 무조건 `delete` 해서 연쇄 호출 시 다른 작업 entry 를 지우는 race. → 각 entry 에 고유 symbol 을 부여하고 "내 토큰이 최신일 때만" 정리하도록 수정 [S1].
|
||||
|
||||
### 동시성 제한 큐
|
||||
```typescript
|
||||
function defaultConcurrencyLimit() { return Math.max(2, (os.cpus()?.length ?? 4) - 1); } // UI 스레드 여유
|
||||
public async enqueue<T>(task: () => Promise<T>): Promise<T> {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
this.queue.push(async () => { try { resolve(await task()); } catch (e) { reject(e); } });
|
||||
this.processNext();
|
||||
});
|
||||
}
|
||||
```
|
||||
`processNext` 는 `activeCount < limit` 일 때만 다음 작업을 꺼내 실행하고, `finally` 에서 `activeCount--` 후 재귀로 다음을 당긴다. 무거운 LLM 호출은 큐가 아니라 `missionId` 락으로 직렬화하므로 큐는 단순하게 유지 [S2].
|
||||
|
||||
### 보상 트랜잭션 (파일 원자성)
|
||||
`isTransactionActive` 가드로 중복 begin 방지. `record` 는 같은 파일을 한 번만 백업(이미 있으면 skip). rollback 은 `created` 파일은 삭제, `modified` 는 원본 내용으로 복원. 외부 API 호출 성공 여부도 `recordExternalAction` 으로 추적해 `isFullyVerified()` 로 전체 검증 [S3].
|
||||
|
||||
## ⚖️ 비교 및 선택 기준 (Comparison & decision criteria)
|
||||
|
||||
| 도구 | 막는 문제 | 사용 시점 |
|
||||
|---|---|---|
|
||||
| AsyncLock (자원별) | 같은 자원 동시 수정(갱신 손실) | 파일/세션 등 공유 자원 read-modify-write |
|
||||
| 동시성 제한 큐 | 자원 폭주(메모리/IO/소켓) | 대량 작업을 일정 동시성으로 처리 |
|
||||
| 보상 트랜잭션 | 부분 실패로 인한 불일치 | 여러 파일을 한 단위로 변경 |
|
||||
| 외부 abort signal | 취소 불가 | 사용자 Stop / 타임아웃 ([[비동기 프로그래밍 Promise async await]]) |
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **락 타임아웃의 부작용:** 타임아웃으로 깨어난 작업은 자원을 못 얻은 채 throw 한다. 호출부는 이 실패를 재시도/사용자 안내로 처리해야 한다(조용히 진행 금지).
|
||||
- **큐의 static 동시성:** 동적 조정이 없어 부하 급변에 둔감하지만, 무거운 작업이 락으로 직렬화되므로 큐는 단순함을 택했다 — 의도적 단순성.
|
||||
- **메모리 내 트랜잭션:** 백업이 메모리(Map)에 있어 프로세스가 죽으면 롤백이 불가능하다. 진짜 내구성이 필요하면 WAL/DB 가 필요.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/core/lock.ts` — `lockManager` 싱글톤. agent 가 파일/세션 작업 직렬화에 사용 [S1].
|
||||
- `AstraAI/src/core/queue.ts` — `actionQueue` 싱글톤. 대량 액션 처리 [S2].
|
||||
- `AstraAI/src/core/transaction.ts` — AgentExecutor 가 파일 다중 변경을 묶을 때 [S3].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// 1) 락 — 반드시 try/finally 로 해제 (src/core/lock.ts)
|
||||
const release = await lockManager.acquire(filePath);
|
||||
try {
|
||||
const cur = fs.readFileSync(filePath, 'utf-8');
|
||||
fs.writeFileSync(filePath, transform(cur)); // read-modify-write 직렬화
|
||||
} finally {
|
||||
release(); // 예외가 나도 반드시 해제
|
||||
}
|
||||
|
||||
// 2) 동시성 제한 큐 (src/core/queue.ts)
|
||||
const result = await actionQueue.enqueue(() => heavyTask(item)); // 슬롯 빌 때 실행
|
||||
|
||||
// 3) 보상 트랜잭션 (src/core/transaction.ts)
|
||||
tx.begin();
|
||||
try {
|
||||
await tx.record(fileA); fs.writeFileSync(fileA, nextA);
|
||||
await tx.record(fileB); fs.writeFileSync(fileB, nextB);
|
||||
tx.commit();
|
||||
} catch (e) { tx.rollback(); throw e; }
|
||||
```
|
||||
|
||||
## ✅ 검증 상태 및 신뢰도
|
||||
- **상태:** draft
|
||||
- **검증 단계:** applied
|
||||
- **출처 신뢰도:** A
|
||||
- **신뢰 점수:** 0.94
|
||||
- **중복 검사 결과:** 신규 생성 (New discovery)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[비동기 프로그래밍 Promise async await]], [[에러 처리와 커스텀 에러]], [[이벤트 소싱 스토어 패턴]]
|
||||
- **참조 맥락:** 로컬 LLM 이 공유 자원·대량 작업·다중 파일 변경의 동시성 안전 코드를 작성할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/core/lock.ts — AsyncLockManager(토큰 기반), race 타임아웃, 버그 사후기록
|
||||
- [S2] AstraAI/src/core/queue.ts — ActionQueueManager 동시성 제한
|
||||
- [S3] AstraAI/src/core/transaction.ts — 보상 트랜잭션(begin/record/commit/rollback)
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.
|
||||
@@ -0,0 +1,128 @@
|
||||
---
|
||||
id: dependency-injection-service-interface
|
||||
title: "의존성 주입과 서비스 인터페이스"
|
||||
category: "Architecture"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["DI", "dependency injection", "인터페이스", "service interface", "느슨한 결합", "testability", "전략 패턴"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.93
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["architecture", "dependency-injection", "interface", "design-pattern", "astraai"]
|
||||
raw_sources: ["AstraAI/src/core/services.ts", "AstraAI/src/extension.ts", "AstraAI/src/intelligence/criticAgent.ts", "AstraAI/src/agent/multiAgent/workflow.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[의존성 주입과 서비스 인터페이스]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
의존성 주입은 "객체가 협력자를 *직접 만들지 않고 밖에서 받는*" 설계이며, AstraAI 는 **인터페이스로 계약을 정의하고, 생성자 옵션 객체·함수 타입으로 구현을 주입**해 모듈을 순수하고 교체·테스트 가능하게 만든다 [S1][S3].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **인터페이스 = 계약:** `IAIService`/`IBrainService` 는 "무엇을 할 수 있는가"만 정의하고 "어떻게" 는 구현에 맡긴다. 호출부는 인터페이스에만 의존 [S1].
|
||||
2. **생성자 주입 (Constructor injection):** 협력자를 `new X(deps)` 처럼 생성 시점에 옵션 객체로 받는다 — 객체가 자기 의존을 숨기지 않고 시그니처에 드러낸다 [S2].
|
||||
3. **함수 주입 (Function injection):** 무거운 의존(LLM 호출)을 *함수 타입* 으로 받아, 모듈 자체는 LLM 을 모른 채 순수 함수로 남는다 (`CritiqueLlmCall`) [S3].
|
||||
4. **getter 주입 (Lazy):** 아직 생성되지 않은 의존은 `getProvider: () => provider` 처럼 getter 로 — 초기화 순서/순환 의존 회피 [S2].
|
||||
5. **deps 번들 객체:** 여러 협력자를 `WorkflowDeps` 같은 인터페이스로 묶어 한 번에 전달 [S4].
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **인터페이스 선언 → 구현 클래스:** `interface IAIService { ... }` + `class AIService implements IAIService { ... }`. 정책(엔진 폴백)은 구현에 캡슐화, 호출부는 인터페이스만 본다 [S1].
|
||||
- **옵션 객체로 생성자 주입:** `new AgentExecutor(context, { onStreamLifecycle, lmStudioStreamer, approvalQueue })` — 위치 인자 대신 명명 옵션으로 가독성·확장성 확보 [S2].
|
||||
- **함수 타입으로 LLM 추상화:** `type CritiqueLlmCall = (system, user, maxTokens) => Promise<string>` 를 주입받아, criticAgent 는 어떤 엔진이든 무관하게 동작하고 테스트 시 가짜 함수를 끼운다 [S3].
|
||||
- **deps 인터페이스 + 콜백 게터:** `WorkflowDeps { getWebview, getAbortSignal, chatHistory, ... }` — 동적으로 바뀌는 상태는 게터로 전달해 stale 참조 방지 [S4].
|
||||
- **싱글톤 vs 주입 구분:** 프로세스 전역 자원(lock/queue)은 싱글톤, 정책·상태를 가진 협력자는 주입 [S2].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### 왜 인터페이스인가
|
||||
`AIService` 는 "LM Studio 먼저, 실패 시 Ollama 폴백, 빈 응답은 soft failure" 같은 *정책* 을 담는다. 호출부(텔레그램 핸들러 등)는 `IAIService.chat()` 만 알면 되고, 정책이 바뀌어도 호출부는 안 바뀐다. 이것이 "구현이 아니라 추상에 의존하라"(DIP)의 실천 [S1].
|
||||
|
||||
### 함수 주입으로 순수성 유지
|
||||
`criticAgent.ts` 헤더 주석은 "모든 LLM 의존은 주입(critique caller) — 모듈 자체는 순수, 테스트 가능" 이라고 명시한다. `runCriticReview({ ..., callLlm })` 는 실제 LLM 을 직접 부르지 않고 주입된 `callLlm` 을 부른다. 덕분에:
|
||||
- 프로덕션: `agent.ts` 의 `callNonStreaming` 을 주입.
|
||||
- 테스트: 고정 문자열을 반환하는 가짜 함수를 주입 → LLM 없이 단위 테스트 [S3].
|
||||
|
||||
### deps 번들 + getter 의 이유
|
||||
멀티에이전트 워크플로는 실행 도중 webview/abort signal 이 바뀔 수 있다. 그래서 값이 아니라 *게터* 를 주입한다:
|
||||
```typescript
|
||||
export interface WorkflowDeps {
|
||||
getWebview: () => vscode.Webview | undefined; // 호출 시점의 최신 webview
|
||||
getAbortSignal: () => AbortSignal | undefined; // 새 controller 의 최신 signal
|
||||
chatHistory: ChatMessage[];
|
||||
}
|
||||
```
|
||||
주석은 "호출자가 stop()+new AbortController() 를 먼저 마쳐야 한다 — getAbortSignal() 은 그 새 controller 의 signal 을 반환해야 함" 이라고 함정을 경고한다 [S4].
|
||||
|
||||
## ⚖️ 비교 및 선택 기준 (Comparison & decision criteria)
|
||||
|
||||
| 항목 (Option) | 장점 | 단점 | 언제 선택 |
|
||||
|---|---|---|---|
|
||||
| 생성자 주입(옵션 객체) | 의존 명시, 교체 쉬움 | 생성 코드 장황 | 상태/정책 가진 협력자 |
|
||||
| 함수 주입 | 모듈 순수, 테스트 최상 | 콜백 시그니처 관리 | LLM·I/O 같은 외부 효과 |
|
||||
| getter 주입 | 늦은 바인딩, 순환 회피 | 호출 시점 의존 | 동적/초기화 순서 문제 |
|
||||
| 싱글톤 import | 간결, 전역 공유 | 테스트 격리 어려움 | 프로세스 전역 인프라(lock/queue) |
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **DI 컨테이너 없음:** AstraAI 는 별도 DI 프레임워크를 쓰지 않고 *수동 주입* (activate 에서 직접 조립)한다. 규모가 작고 조립 지점이 한 곳이라 프레임워크 비용이 불필요 — 큰 시스템이면 컨테이너가 유리할 수 있다.
|
||||
- **싱글톤의 비용:** `lockManager`/`actionQueue` 싱글톤은 편하지만 테스트 격리를 어렵게 한다. AstraAI 는 전역성이 본질인 자원에만 한정해 사용한다.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/core/services.ts` — IAIService/IBrainService 인터페이스 + 구현 [S1].
|
||||
- `AstraAI/src/extension.ts` — AgentExecutor/SidebarChatProvider 생성자 옵션 주입, getProvider 게터 [S2].
|
||||
- `AstraAI/src/intelligence/criticAgent.ts` — CritiqueLlmCall 함수 주입 [S3].
|
||||
- `AstraAI/src/agent/multiAgent/workflow.ts` — WorkflowDeps 게터 번들 [S4].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// 1) 인터페이스 계약 + 구현 분리 (src/core/services.ts)
|
||||
export interface IAIService {
|
||||
call(prompt: string): Promise<string>;
|
||||
chat(req: AIChatRequest): Promise<AIChatResult>;
|
||||
}
|
||||
export class AIService implements IAIService { /* 엔진 폴백 정책 캡슐화 */ }
|
||||
|
||||
// 2) 생성자 옵션 객체 주입 (src/extension.ts)
|
||||
const agent = new AgentExecutor(context, {
|
||||
onStreamLifecycle: { start: () => lifecycle.onStreamStart(), end: () => lifecycle.onStreamEnd() },
|
||||
lmStudioStreamer, approvalQueue,
|
||||
});
|
||||
|
||||
// 3) 함수 주입으로 순수 모듈 (src/intelligence/criticAgent.ts)
|
||||
export type CritiqueLlmCall = (system: string, user: string, maxTokens: number) => Promise<string>;
|
||||
export async function runCriticReview(params: { /* ... */ callLlm: CritiqueLlmCall }) {
|
||||
const raw = await params.callLlm(system, user, opts.maxTokens); // 어떤 엔진인지 모름
|
||||
return parseCritique(raw);
|
||||
}
|
||||
|
||||
// 4) getter 번들 (src/agent/multiAgent/workflow.ts)
|
||||
export interface WorkflowDeps {
|
||||
getWebview: () => vscode.Webview | undefined;
|
||||
getAbortSignal: () => AbortSignal | undefined;
|
||||
}
|
||||
```
|
||||
|
||||
## ✅ 검증 상태 및 신뢰도
|
||||
- **상태:** draft
|
||||
- **검증 단계:** applied
|
||||
- **출처 신뢰도:** A
|
||||
- **신뢰 점수:** 0.93
|
||||
- **중복 검사 결과:** 신규 생성 (New discovery)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[TypeScript 고급 타입]], [[Intelligence 검증 레이어]], [[VSCode 확장 구조와 생명주기]]
|
||||
- **참조 맥락:** 로컬 LLM 이 협력 객체를 가진 모듈을 테스트 가능하고 교체 가능하게 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/core/services.ts — IAIService/IBrainService + AIService 구현
|
||||
- [S2] AstraAI/src/extension.ts — 생성자 옵션 주입, getProvider 게터
|
||||
- [S3] AstraAI/src/intelligence/criticAgent.ts — CritiqueLlmCall 함수 주입(순수 모듈)
|
||||
- [S4] AstraAI/src/agent/multiAgent/workflow.ts — WorkflowDeps 게터 번들
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.
|
||||
@@ -0,0 +1,135 @@
|
||||
---
|
||||
id: event-sourced-store-pattern
|
||||
title: "이벤트 소싱 스토어 패턴"
|
||||
category: "Architecture"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["event sourcing", "append-only", "JSONL", "이벤트 스토어", "팩토리 함수", "computeStates"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.92
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["architecture", "event-sourcing", "persistence", "factory", "astraai"]
|
||||
raw_sources: ["AstraAI/src/features/_shared/eventSourcedStore.ts", "AstraAI/src/memory/types.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[이벤트 소싱 스토어 패턴]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
이벤트 소싱은 "현재 상태를 덮어쓰지 않고 *일어난 일(event)을 추가만(append-only)* 기록"하는 영속화 방식이며, AstraAI 는 이를 **JSONL 파일 + 제네릭 팩토리(`createEventStore<E>`)** 로 구현해 4개 도메인 스토어의 ~240줄 중복을 한 곳으로 통합한다 [S1].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **Append-only:** 데이터를 수정·삭제하지 않고 끝에 줄을 추가만 한다. 이력이 전부 남아 감사·재현·디버깅에 강하다 [S1].
|
||||
2. **JSONL (JSON Lines):** 한 줄에 JSON 객체 하나. 스트리밍 append 가 쉽고, 한 줄이 손상돼도 나머지는 읽을 수 있다 [S1].
|
||||
3. **이벤트 → 상태 계산:** 저장은 이벤트로, *현재 상태* 는 이벤트들을 재생(`computeStates`)해 도출한다 — 도메인 파일의 책임 [S1].
|
||||
4. **제네릭 팩토리 + 검증 주입:** I/O(읽기/추가/카운트)는 공통 모듈이, 도메인 로직은 호출부가 — 관심사 분리 [S1].
|
||||
5. **내결함 파싱:** 손상된 줄은 skip 하고 계속 — append-only 라 1줄 손상이 전체를 무력화하면 안 된다 [S1].
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **중복 4벌 → 제네릭 1벌:** customers/hire/runway/feedback 이 같은 `getXFilePath/readX/appendX/countX` 를 반복 → `createEventStore<E>` 로 흡수. BOM/인코딩 등 edge case fix 도 한 번에 전파 [S1].
|
||||
- **팩토리 함수 + 클로저:** 클래스 대신 함수가 내부 함수들을 담은 객체를 반환 — 캡슐화는 클로저로, `new` 불필요 [S1].
|
||||
- **타입 가드 검증을 옵션으로:** `validate: (e) => e is E` 를 주입해 파싱 결과의 유효성을 도메인이 정의 [S1].
|
||||
- **결과를 판별 유니온으로:** `append` 가 `{ ok: true; filePath } | { ok: false; error }` 반환 — 워크스페이스 없음 등 흔한 실패를 예외 없이 전달 [S1].
|
||||
- **워크스페이스 상대경로:** `relPath: '.astra/customers.jsonl'` 를 워크스페이스 루트 기준으로 해석 [S1].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### 왜 이벤트 소싱인가 (이 코드에서)
|
||||
고객/채용/런웨이/피드백 같은 도메인은 "변경 이력 자체가 가치" 다. 마지막 상태만 저장하면 "언제 무엇이 바뀌었나"를 잃는다. 이벤트를 append 하면 전체 타임라인이 보존되고, 현재 상태는 필요할 때 재생으로 만든다 [S1].
|
||||
|
||||
### 공통 I/O vs 도메인 로직 경계
|
||||
모듈 헤더 주석이 경계를 명확히 한다: "도메인별 로직(computeStates 등)은 그대로 도메인 파일에 남음 — 본 모듈은 I/O 만 추상화." 즉 `createEventStore` 는 read/append/count/getFilePath 만 제공하고, "이벤트들로 현재 고객 목록을 만드는" 로직은 customers 도메인에 둔다 [S1].
|
||||
|
||||
### 내결함 읽기
|
||||
```typescript
|
||||
for (const line of content.split('\n')) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed) continue;
|
||||
try {
|
||||
const parsed = JSON.parse(trimmed);
|
||||
if (opts.validate(parsed)) out.push(parsed);
|
||||
} catch { /* skip malformed — append-only 라 손상 1줄이 전체 무력화하면 안 됨 */ }
|
||||
}
|
||||
```
|
||||
한 줄 파싱 실패나 검증 실패는 그 줄만 버리고 계속한다 — 견고성의 핵심 [S1].
|
||||
|
||||
### 안전한 append
|
||||
`fs.mkdirSync(dirname, { recursive: true })` 로 디렉터리 보장 후 `appendFileSync(... + '\n')`. 실패는 throw 가 아니라 `{ ok: false, error }` 로 반환해 호출부가 사용자에게 안내할 수 있게 한다 [S1].
|
||||
|
||||
## ⚖️ 비교 및 선택 기준 (Comparison & decision criteria)
|
||||
|
||||
| 항목 (Option) | 장점 | 단점 | 언제 선택 |
|
||||
|---|---|---|---|
|
||||
| Append-only 이벤트(JSONL) | 이력 보존, 내결함, 단순 | 상태 재생 비용, 파일 증가 | 변경 이력이 가치 있을 때 |
|
||||
| 상태 덮어쓰기(JSON 1개) | 읽기 즉시, 작음 | 이력 손실, 동시쓰기 충돌 | 마지막 값만 중요할 때 |
|
||||
| SQLite/DB | 쿼리·인덱스·트랜잭션 | 의존성·운영 비용 | 대량·복잡 쿼리 |
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **파일 무한 증가:** append-only 는 파일이 계속 커진다. 주기적 compaction(스냅샷 + 이후 이벤트만 유지)이 필요할 수 있다 — 현재 모듈은 compaction 을 제공하지 않으므로 도메인이 관리.
|
||||
- **동시 append:** 단일 프로세스 내 순차 append 는 안전하나, 멀티 프로세스/동시 쓰기는 잠금이 필요하다. AstraAI 는 무거운 작업을 [[동시성 제어 Lock Queue Transaction]] 의 lockManager 로 직렬화한다.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/features/_shared/eventSourcedStore.ts` — 제네릭 이벤트 스토어 본체. customers/hire/runway/feedback 도메인이 이를 인스턴스화해 사용 [S1].
|
||||
- 메모리 계층의 episodic/long-term 도 유사하게 버전 필드를 가진 직렬화 스토어 형태(`EpisodicStore { version, episodes, lastUpdated }`)를 쓴다 [S2].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// 제네릭 이벤트 스토어 (src/features/_shared/eventSourcedStore.ts)
|
||||
export function createEventStore<E>(opts: EventStoreOptions<E>): EventStore<E> {
|
||||
function getFilePath(): string | null {
|
||||
const folders = vscode.workspace.workspaceFolders;
|
||||
if (!folders?.length) return null;
|
||||
return path.join(folders[0].uri.fsPath, opts.relPath); // 워크스페이스 상대경로
|
||||
}
|
||||
function read(): E[] {
|
||||
const fp = getFilePath();
|
||||
if (!fp || !fs.existsSync(fp)) return [];
|
||||
const out: E[] = [];
|
||||
for (const line of fs.readFileSync(fp, 'utf-8').split('\n')) {
|
||||
const t = line.trim(); if (!t) continue;
|
||||
try { const p = JSON.parse(t); if (opts.validate(p)) out.push(p); }
|
||||
catch { /* 손상 줄 skip */ }
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function append(event: E) {
|
||||
const fp = getFilePath();
|
||||
if (!fp) return { ok: false, error: '워크스페이스 폴더가 없어 저장 불가.' } as const;
|
||||
try {
|
||||
fs.mkdirSync(path.dirname(fp), { recursive: true });
|
||||
fs.appendFileSync(fp, JSON.stringify(event) + '\n', 'utf-8');
|
||||
return { ok: true, filePath: fp } as const;
|
||||
} catch (e: any) { return { ok: false, error: e?.message || String(e) } as const; }
|
||||
}
|
||||
return { getFilePath, read, append, count };
|
||||
}
|
||||
// 도메인 사용:
|
||||
const store = createEventStore<CustomerEvent>({
|
||||
relPath: '.astra/customers.jsonl',
|
||||
validate: (e): e is CustomerEvent => typeof (e as any).id === 'string',
|
||||
});
|
||||
```
|
||||
|
||||
## ✅ 검증 상태 및 신뢰도
|
||||
- **상태:** draft
|
||||
- **검증 단계:** applied
|
||||
- **출처 신뢰도:** A
|
||||
- **신뢰 점수:** 0.92
|
||||
- **중복 검사 결과:** 신규 생성 (New discovery)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[TypeScript 고급 타입]], [[5계층 메모리 시스템]], [[동시성 제어 Lock Queue Transaction]]
|
||||
- **참조 맥락:** 로컬 LLM 이 이력·로그·상태를 파일로 영속화하는 스토어를 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/features/_shared/eventSourcedStore.ts — createEventStore 제네릭 팩토리, 내결함 파싱, 판별 유니온 결과
|
||||
- [S2] AstraAI/src/memory/types.ts — 버전 필드를 가진 직렬화 스토어(EpisodicStore/LongTermStore)
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.
|
||||
@@ -0,0 +1,110 @@
|
||||
---
|
||||
id: coding-conventions-comment-philosophy
|
||||
title: "코딩 컨벤션과 주석 철학"
|
||||
category: "Software_Engineering"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["코딩 스타일", "주석 철학", "why comment", "post-mortem comment", "naming", "graceful degradation", "코드 컨벤션"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.93
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["conventions", "style", "comments", "readability", "astraai"]
|
||||
raw_sources: ["AstraAI/src/core/lock.ts", "AstraAI/src/retrieval/index.ts", "AstraAI/src/features/company/dispatcher.ts", "AstraAI/src/extension.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[코딩 컨벤션과 주석 철학]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
AstraAI 코드의 가장 큰 특징은 "**주석이 '무엇'이 아니라 '왜'와 '왜 다른 방법이 아니었는지'를 적고, 버그 사후기록(post-mortem)을 코드 옆에 남긴다**"는 점이며, 이것이 작은 LLM 이 *의도까지* 학습하게 하는 핵심 자료다 [S1][S3].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **Why 주석:** 코드가 '무엇을 하는지'는 코드로 읽고, 주석은 '왜 이렇게 했는지'·제약·트레이드오프를 적는다 [S1].
|
||||
2. **Post-mortem 주석:** 과거 버그의 원인과 수정 근거를 코드 옆에 남겨 같은 실수를 막는다 [S1].
|
||||
3. **모듈 헤더 docstring:** 각 파일 상단에 그 모듈의 책임·배경·다른 모듈과의 분업을 설명 [S1][S4].
|
||||
4. **결정 근거 주석:** "왜 순차인가", "왜 handlePrompt 를 안 쓰나" 같은 설계 결정을 인라인으로 [S3].
|
||||
5. **방어적 기본값/널 처리 + 의도 명시:** `??` vs `||`, `void` fire-and-forget, 의도적 빈 catch 를 주석으로 [S2][S4].
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **named export 일관:** default export 를 배제하고 named export 만 — 자동완성·리네이밍 안전 [S4].
|
||||
- **단일 진입점 헬퍼:** 설정은 `getConfig()`, 경로는 path resolver 처럼 한 곳을 통해 — 파싱/coercion 중복 방지 [S4].
|
||||
- **`??` 로 의미 있는 0/'' 보존:** `brainFileLimit ?? 8` (0 이 유효), `req.timeoutMs ?? config.timeout` [S2].
|
||||
- **의도된 graceful degradation:** 부가 작업 실패를 `catch { /* should never break main flow */ }` 로 — 빈 catch 에 *반드시* 이유 주석 [S2].
|
||||
- **단계 로그(추적성):** 복잡 로직은 `fusionLog.push(...)` 처럼 단계별 기록을 남겨 디버깅 [S2].
|
||||
- **상수 중앙화:** 가중치/임계값/불용어를 설정 객체 한 곳에(`SCORING_CONFIG`) [S2].
|
||||
- **한국어 주석 + 영어 식별자:** 식별자·타입은 영어, 설명 주석은 한국어 — 팀 가독성 우선 [S1].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### 주석이 의도를 가르친다 (이 위키의 핵심 가치)
|
||||
`lock.ts` 의 주석은 옛 구현이 왜 틀렸는지를 적는다: "`.then(...)` 은 매 호출마다 새 Promise instance 를 반환해서 사실상 항상 false — cleanup 이 안 됨." 이런 주석은 *코드만 봐서는 절대 알 수 없는* 함정을 전수한다. 작은 LLM 이 비슷한 코드를 쓸 때 같은 함정을 피하게 만드는 최고의 학습 신호다 [S1].
|
||||
|
||||
### "왜 다른 방법이 아니었나" 를 적는다
|
||||
`dispatcher.ts` 헤더는 "Why sequential?", "Why not use handlePrompt?" 를 명시한다. 대안을 검토하고 *기각한 이유* 까지 적어, 미래의 개발자(또는 LLM)가 같은 고민을 반복하지 않게 한다 [S3].
|
||||
|
||||
### 방어적이되 명시적
|
||||
```typescript
|
||||
const brainFileLimit = options.brainFileLimit ?? 8; // 0 이 의미 있음 → || 아님
|
||||
void ensureEmbeddingConfigured(context); // 비차단 의도를 void 로 명시
|
||||
try { extract(); } catch { /* memory extraction should never break the main flow */ }
|
||||
```
|
||||
빈 catch·fire-and-forget 같은 "위험해 보이는" 패턴에는 *왜 안전한지* 를 항상 주석으로 정당화한다 [S2][S4].
|
||||
|
||||
### 네이밍
|
||||
- 함수는 동사구(`buildContext`, `searchBrainFiles`, `parseModelPrefix`), boolean 은 `is*`/`should*`/`has*`(`isOperationalPath`, `shouldUseMultiAgentWorkflow`).
|
||||
- 내부 전용은 `_` 접두사(`_ensureBrainDir`, `_getBrainDir`).
|
||||
- 타입은 PascalCase 인터페이스(`RetrievalChunk`, `ConfidenceResult`), 상수는 UPPER_SNAKE(`PEER_OUTPUT_BUDGET`).
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **주석 과다 vs 적정:** "코드가 자명하면 주석 불필요" 라는 원칙과 충돌할 수 있다. AstraAI 의 기준은 *비자명한 why/제약/함정만* 적는 것 — "다음 줄이 무엇을 하는지" 류의 노이즈 주석은 피한다.
|
||||
- **주석의 노후화:** 코드가 바뀌면 주석이 거짓이 될 위험. post-mortem 주석은 역사적 사실이라 비교적 안전하나, "현재 동작" 주석은 변경 시 함께 갱신해야 한다.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/core/lock.ts` — 버그 post-mortem 주석의 모범 [S1].
|
||||
- `AstraAI/src/features/company/dispatcher.ts` — 결정 근거(왜 순차/왜 분리) 주석 [S3].
|
||||
- `AstraAI/src/retrieval/index.ts` — 단계 로그, 상수 중앙화, `??` 보존 [S2].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// 1) Post-mortem 주석 — 코드로 알 수 없는 함정 전수 (src/core/lock.ts)
|
||||
// 옛 구현은 `this.locks.get(id) === prev.then(() => next)` 로 Promise 동일성을 비교했는데,
|
||||
// `.then(...)` 은 매번 새 Promise 를 반환 → 항상 false → cleanup 실패. 그래서 고유 symbol
|
||||
// 토큰을 부여하고 "내 토큰이 최신일 때만" 정리한다.
|
||||
|
||||
// 2) 의도적 graceful degradation — 빈 catch 에 이유 명시 (src/memory/index.ts)
|
||||
try { this.extractor.extractFromSession(...); }
|
||||
catch { /* memory extraction should never break the main flow */ }
|
||||
|
||||
// 3) ?? 로 의미 있는 0 보존 (src/retrieval/index.ts)
|
||||
const brainFileLimit = options.brainFileLimit ?? 8; // 명시적 0 = "검색 끔"
|
||||
|
||||
// 4) 단계 로그로 추적성 (src/retrieval/index.ts)
|
||||
fusionLog.push(`Brain search: ${brainChunks.length} chunks found`);
|
||||
fusionLog.push(`Selected: ${selectedChunks.length}, Dropped: ${dropped.length}, Tokens: ${tokensUsed}`);
|
||||
```
|
||||
|
||||
## ✅ 검증 상태 및 신뢰도
|
||||
- **상태:** draft
|
||||
- **검증 단계:** applied
|
||||
- **출처 신뢰도:** A
|
||||
- **신뢰 점수:** 0.93
|
||||
- **중복 검사 결과:** 신규 생성 (New discovery)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[에러 처리와 커스텀 에러]], [[모듈 시스템과 프로젝트 구성]], [[프롬프트 엔지니어링 패턴]]
|
||||
- **참조 맥락:** 로컬 LLM 이 코드를 작성할 때 네이밍·주석·방어 코드의 스타일을 AstraAI 와 일치시키도록 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/core/lock.ts — post-mortem 주석, 모듈 헤더
|
||||
- [S2] AstraAI/src/retrieval/index.ts — ?? 보존, 단계 로그, 상수 중앙화
|
||||
- [S3] AstraAI/src/features/company/dispatcher.ts — 결정 근거 주석
|
||||
- [S4] AstraAI/src/extension.ts — named export, 단일 진입점, void/getter 패턴
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.
|
||||
@@ -0,0 +1,110 @@
|
||||
---
|
||||
id: prompt-engineering-patterns
|
||||
title: "프롬프트 엔지니어링 패턴"
|
||||
category: "AI_and_ML"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["prompt engineering", "system prompt", "프롬프트 조립", "context block", "JSON output", "grounding", "프롬프트 설계"]
|
||||
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: ["prompt-engineering", "llm", "ai", "system-prompt", "astraai"]
|
||||
raw_sources: ["AstraAI/src/intelligence/epistemicGuardBlock.ts", "AstraAI/src/intelligence/correctionLoop.ts", "AstraAI/src/intelligence/criticAgent.ts", "AstraAI/src/features/datacollect/prompts/wikifyPrompt.ts", "AstraAI/src/core/services.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[프롬프트 엔지니어링 패턴]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
좋은 프롬프트는 "**조립 가능한 블록**으로 만들고(역할·규칙·컨텍스트·출력형식), 작은 모델일수록 system 으로 강하게 grounding 하고, 출력은 파싱 가능한 JSON/템플릿으로 강제하며, 결정론적 신호로 동적으로 강도를 조절"한다 — AstraAI 의 검증 레이어가 이를 그대로 실천한다 [S1][S3][S4].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **블록 조립:** 시스템 프롬프트를 `[EPISTEMIC GUARD]`, `[MEMORY CONTEXT]`, `[자기검토]` 같은 명명 블록으로 만들어 필요 시 합친다 [S1][S5].
|
||||
2. **작은 모델엔 강한 system grounding:** gemma 류는 system 이 없으면 짧고 모호한 입력에 "시는 못 써드려요" 같은 환각 거절을 한다 — system 을 반드시 채운다 [S5].
|
||||
3. **출력 형식 강제:** "반드시 아래 JSON 만 출력" + 예시 스키마. 파싱은 균형 괄호 스캔으로 잡설 내성 [S3].
|
||||
4. **동적 강도 조절:** 검색 근거가 없을수록 가드 지시를 강화(`chunkCount === 0` 이면 "단정 금지·질문 우선") [S1].
|
||||
5. **few-shot 대신 규칙+제약:** 길고 명시적인 규칙 목록 + "근거 없으면 지어내지 말 것" 같은 negative constraint [S4].
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **명명 블록 + 닫는 태그:** `[EPISTEMIC GUARD] ... [/EPISTEMIC GUARD]` — 모델이 블록 경계를 인식 [S1].
|
||||
- **3등급 인식론 강제:** 확실/추정/모름 등급 표시 — "모름 인정이 그럴듯한 오답보다 낫다" 를 명문화 [S1].
|
||||
- **조건부 블록 주입:** 통계가 임계(같은 태그 2회+)를 넘을 때만 자기검토 블록 주입 — 노이즈 방지 [S2].
|
||||
- **태그별 맞춤 지시:** 오류 태그(사실오류/근거누락…)마다 다른 자기검토 문장 매핑 [S2].
|
||||
- **system/user 분리 빌더:** `buildCritiquePrompt` 가 `{ system, user }` 를 반환 — 역할(검수자)과 데이터(초안)를 분리 [S3].
|
||||
- **입력 잘라내기(budget):** 초안/필드를 `maxDraftChars`/`MAX_FIELD_CHARS` 로 잘라 토큰·비용 통제 [S3].
|
||||
- **출력 후처리:** 작은 모델이 흘리는 `##`/`**` 마커를 사후 제거하고 history 에도 정제본만 저장(마커 재학습 방지) [참조: [[Agent 오케스트레이터 분해]]].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### 왜 블록 조립인가
|
||||
한 턴의 system 프롬프트는 정체성·모드·메모리·가드·자기검토 등 여러 관심사가 합쳐진다. 각 관심사를 독립 빌더 함수(`buildEpistemicGuardBlock`, `buildSelfReviewBlock`)로 만들면, 조건에 따라 켜고 끄며 조합할 수 있고 단위 테스트가 쉽다 [S1][S2].
|
||||
|
||||
### 작은 모델 대응 (이 프로젝트의 핵심 제약)
|
||||
- system 으로 강하게 grounding (services.ts 주석: system 없으면 환각 거절) [S5].
|
||||
- 규칙을 *명시적이고 번호 매겨* 제시(wikify 프롬프트의 "필수 규칙 1~6 + 공통 규칙 7~15") [S4].
|
||||
- "본문에 없으면 지어내지 말고 '확인되지 않음' 표시" 같은 negative constraint 를 반복 [S4].
|
||||
- 출력 형식을 템플릿으로 못박고, 흘러나온 마커는 사후 정제.
|
||||
|
||||
### JSON 출력 + 강건 파싱
|
||||
"반드시 JSON 한 줄만" 을 지시해도 작은 모델은 코드펜스·잡설을 섞는다. 그래서 첫 균형 `{}` 블록을 스캔(문자열/이스케이프 인식)해 추출하고, 실패 시 휴리스틱 fallback 으로 분류한다 — *프롬프트와 파서를 함께 설계* [S3].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **긴 프롬프트 vs 컨텍스트 한도:** 블록을 다 합치면 길어져 작은 모델의 컨텍스트를 압박한다. 그래서 [[RAG 검색 파이프라인]] 의 토큰 예산과 조건부 주입으로 길이를 통제한다.
|
||||
- **JSON 강제의 취약성:** 모델이 형식을 어기면 파싱 실패. 강건 파서 + fallback 이 필수 — "프롬프트만 믿지 말고 파서로 방어".
|
||||
- **few-shot 비용:** 예시를 많이 넣으면 정확하지만 토큰이 비싸다. AstraAI 는 예시 최소화 + 규칙/제약 위주로 절충.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/intelligence/epistemicGuardBlock.ts` — 명명 블록, 동적 강도 [S1].
|
||||
- `AstraAI/src/intelligence/correctionLoop.ts` — 조건부·태그별 자기검토 블록 [S2].
|
||||
- `AstraAI/src/intelligence/criticAgent.ts` — system/user 분리, JSON 강제+강건 파싱 [S3].
|
||||
- `AstraAI/src/features/datacollect/prompts/wikifyPrompt.ts` — 번호 규칙 + negative constraint + 템플릿 강제 [S4].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// 1) 명명 블록 + 동적 강도 (src/intelligence/epistemicGuardBlock.ts)
|
||||
lines.push('[EPISTEMIC GUARD]');
|
||||
lines.push('- **모름 / 확인 필요** — 근거 없음. 지어내지 말고 "(확인 필요)" 표시.');
|
||||
if (signals.chunkCount === 0) lines.push('⚠️ 이번 턴은 검색 근거가 없음 — 단정하지 말 것.');
|
||||
lines.push('[/EPISTEMIC GUARD]');
|
||||
|
||||
// 2) 출력 형식 강제 (src/intelligence/criticAgent.ts)
|
||||
const system = [
|
||||
'너는 업무 산출물 검수자(Critic)다.',
|
||||
'반드시 아래 JSON 만 출력 (다른 텍스트 금지):',
|
||||
'{"pass": true|false, "issues": [{"severity":"major"|"minor","description":"..."}], "supplement":"..."}',
|
||||
].join('\n');
|
||||
|
||||
// 3) 작은 모델 grounding — system 필수 (src/core/services.ts 주석)
|
||||
// gemma 같은 작은 모델은 system 이 없으면 짧은/모호한 입력에 환각 거절을 하는 경향 → system 을 반드시 채운다.
|
||||
|
||||
// 4) 조건부 주입 — 임계 넘을 때만 (src/intelligence/correctionLoop.ts)
|
||||
const significant = profile.tagCounts.filter(t => t.count >= 2).slice(0, 2);
|
||||
if (significant.length === 0) return ''; // 1회성 실수로 프롬프트 어지럽히지 않음
|
||||
```
|
||||
|
||||
## ✅ 검증 상태 및 신뢰도
|
||||
- **상태:** draft
|
||||
- **검증 단계:** applied
|
||||
- **출처 신뢰도:** A
|
||||
- **신뢰 점수:** 0.91
|
||||
- **중복 검사 결과:** 신규 생성 (New discovery)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[Intelligence 검증 레이어]], [[RAG 검색 파이프라인]], [[코딩 컨벤션과 주석 철학]], [[Reflection Pattern]], [[Critic Pattern]]
|
||||
- **참조 맥락:** 로컬 LLM 이 다른(또는 자기 자신) 모델을 호출하는 프롬프트를 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/intelligence/epistemicGuardBlock.ts — 명명 블록, 3등급, 동적 강도
|
||||
- [S2] AstraAI/src/intelligence/correctionLoop.ts — 조건부·태그별 자기검토 주입
|
||||
- [S3] AstraAI/src/intelligence/criticAgent.ts — system/user 분리, JSON 강제+강건 파싱, 입력 budget
|
||||
- [S4] AstraAI/src/features/datacollect/prompts/wikifyPrompt.ts — 번호 규칙, negative constraint, 템플릿
|
||||
- [S5] AstraAI/src/core/services.ts — 작은 모델 system grounding 근거
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
id: adr-0001-event-sourcing
|
||||
title: "ADR-0001 이벤트 소싱 채택"
|
||||
category: "Architecture_Decision"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["ADR event sourcing", "왜 이벤트 소싱", "append-only 결정", "JSONL 결정"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.9
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["adr", "event-sourcing", "decision", "persistence", "astraai"]
|
||||
raw_sources: ["AstraAI/src/features/_shared/eventSourcedStore.ts", "AstraAI/src/memory/types.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[ADR-0001 이벤트 소싱 채택]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
도메인 데이터(고객·채용·런웨이·피드백)를 "상태 덮어쓰기" 대신 **append-only JSONL 이벤트**로 저장하기로 결정했다 — 이력 보존·내결함·중복 제거(제네릭 팩토리)를 한 번에 얻기 위해 [S1].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
- **결정:** `createEventStore<E>` 제네릭 팩토리로 모든 도메인 스토어를 append-only JSONL 위에 구현.
|
||||
- **상태:** 현재 상태는 이벤트 재생(`computeStates`)으로 도출, 저장은 이벤트만.
|
||||
- 자세한 구현은 [[이벤트 소싱 스토어 패턴]] 참조.
|
||||
|
||||
## 📖 세부 내용 (Details · ADR)
|
||||
### Problem (문제)
|
||||
customers/hire/runway/feedback 4개 도메인이 각자 `getXFilePath/readX/appendX/countX` 를 복붙해 ~240줄 byte-for-byte 중복. 동시에 "언제 무엇이 바뀌었나" 이력이 필요한 도메인인데 마지막 상태만 저장하면 그 정보를 잃는다 [S1].
|
||||
|
||||
### Context (맥락)
|
||||
- 단일 사용자 로컬 VS Code 확장 — 무거운 DB 운영 비용을 감당할 이유가 적다.
|
||||
- 데이터 규모가 작고(수백~수천 행), 사람이 직접 파일을 열어보는 투명성이 가치.
|
||||
- 부분 손상(파일 1줄 깨짐)에도 나머지를 살려야 한다.
|
||||
|
||||
### Options Considered (고려한 대안)
|
||||
1. **상태 JSON 1개 덮어쓰기** — 단순하지만 이력 손실·동시쓰기 시 전체 덮어쓰기 위험.
|
||||
2. **SQLite** — 쿼리/인덱스 강력하지만 의존성·마이그레이션·운영 복잡도 추가.
|
||||
3. **append-only JSONL 이벤트 + 제네릭 팩토리** — 이력 보존 + 한 줄 추가의 단순함 + 내결함.
|
||||
|
||||
### Chosen Solution (선택)
|
||||
3번. `createEventStore<E>({ relPath, validate })` 가 read/append/count/getFilePath 를 제공하고, 도메인은 이벤트 타입 `E` 와 `computeStates` 만 정의 [S1].
|
||||
|
||||
### Why It Was Chosen (선택 이유)
|
||||
- 이력이 그 자체로 가치 있는 도메인에 자연스럽다.
|
||||
- 제네릭으로 4벌 중복을 1벌로 — BOM/인코딩 fix 도 한 곳에서 전파.
|
||||
- 한 줄 손상이 전체를 무력화하지 않는 내결함(파싱 실패 줄 skip).
|
||||
- 외부 의존 0 (Node fs 만) — 번들 가벼움 유지.
|
||||
|
||||
### Benefits (장점)
|
||||
이력 감사·재현·디버깅 용이, 단순한 append I/O, 사람이 읽고 고칠 수 있는 투명성, 타입 안전한 재사용.
|
||||
|
||||
### Drawbacks (단점)
|
||||
파일이 단조 증가(compaction 없음), 현재 상태를 매번 재생하는 비용, 멀티프로세스 동시 append 는 별도 잠금 필요.
|
||||
|
||||
### Future Risks (미래 위험)
|
||||
- 이벤트 수가 수만을 넘으면 재생 비용/메모리 증가 → 스냅샷+증분 compaction 필요.
|
||||
- 이벤트 스키마 진화 시 구버전 이벤트 호환(버전 필드/업캐스팅) 관리 부담.
|
||||
|
||||
### Alternative Approaches (대안 접근)
|
||||
규모가 커지면 SQLite(+WAL)로 이전하거나, 이벤트는 유지하되 주기적 스냅샷을 도입. 읽기 빈도가 매우 높으면 메모리 캐시 + 파일 watch.
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"이력 보존" 이 목표가 아니라면(마지막 값만 중요) 이 결정은 과설계다. 그 경우 상태 1개 파일이 더 단순하다.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
`AstraAI/src/features/_shared/eventSourcedStore.ts` — 결정의 구현체 [S1].
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[이벤트 소싱 스토어 패턴]], [[Event Bus Pattern]], [[ADR-0005 파일 기반 저장 채택]], [[엔지니어링 트레이드오프 분석]]
|
||||
- **참조 맥락:** 로컬 LLM 이 "이력 저장 vs 상태 저장" 을 결정할 때 판단 근거로 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/features/_shared/eventSourcedStore.ts — 제네릭 이벤트 스토어, 중복 통합 배경 주석
|
||||
- [S2] AstraAI/src/memory/types.ts — 버전 필드 직렬화 스토어
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 ADR 작성.
|
||||
@@ -0,0 +1,79 @@
|
||||
---
|
||||
id: adr-0002-memory-layer-separation
|
||||
title: "ADR-0002 5계층 메모리 분리"
|
||||
category: "Architecture_Decision"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["ADR memory layers", "왜 메모리를 분리", "메모리 계층 결정"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.9
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["adr", "memory", "decision", "ai", "astraai"]
|
||||
raw_sources: ["AstraAI/src/memory/index.ts", "AstraAI/src/memory/types.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[ADR-0002 5계층 메모리 분리]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
에이전트의 "기억"을 단일 저장소가 아니라 **시간 범위·용도가 다른 5계층(단기·장기·프로젝트·절차·일화)**으로 분리하기로 결정했다 — 계층마다 검색·만료·승급 정책이 달라야 하기 때문 [S1].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
- **결정:** MemoryManager 가 5개 독립 계층을 보유, 각 계층이 query 에 대해 관련도를 매겨 컨텍스트에 합침.
|
||||
- 구현 상세는 [[5계층 메모리 시스템]] 참조.
|
||||
|
||||
## 📖 세부 내용 (Details · ADR)
|
||||
### Problem
|
||||
모든 기억을 한 통에 넣으면 "현재 대화"·"사용자 영구 취향"·"프로젝트 결정"·"반복 절차"·"과거 세션 요약"이 같은 정책으로 다뤄진다. 그러나 이들은 수명·만료·우선순위·검색 방식이 전부 다르다 [S1].
|
||||
|
||||
### Context
|
||||
- 로컬 작은 모델은 컨텍스트 한도가 작아, 무엇을 넣을지 *정교한 선별* 이 필수.
|
||||
- 시한부 지식(분기 계획)과 영구 지식(사용자 선호)이 공존.
|
||||
- 과거 세션을 "지난번에 한 일"로 떠올릴 수 있어야 한다.
|
||||
|
||||
### Options Considered
|
||||
1. **단일 메모리 버퍼(최근 N 메시지)** — 단순하나 장기·프로젝트·절차 기억 불가.
|
||||
2. **벡터 DB 단일 저장** — 의미 검색은 좋지만 만료·승급·계층별 정책 표현이 어렵고 인프라 부담.
|
||||
3. **역할별 5계층 분리 + 통합 매니저** — 계층별 정책 + 단일 진입점.
|
||||
|
||||
### Chosen Solution
|
||||
3번. 단기(FIFO)·장기(category/confidence/expiresAt)·프로젝트(workspace별 ADR/버그)·절차(trigger→steps)·일화(세션 요약, distillation 승급) [S1][S2].
|
||||
|
||||
### Why It Was Chosen
|
||||
계층마다 다른 정책을 자연스럽게 표현(만료, 승급, lazy 생성). 컨텍스트 예산이 빠듯한 작은 모델에 "관련도 높은 계층부터" 선별 주입 가능. 인간 인지 메타포로 이해·확장 용이.
|
||||
|
||||
### Benefits
|
||||
정밀한 컨텍스트 선별, 시한부/영구 지식 공존, 일화→장기 증류로 자동 정리, RAG 소스로 통합 가능.
|
||||
|
||||
### Drawbacks
|
||||
계층 경계의 모호성(장기 decision vs 프로젝트 ADR), 매니저 조립 복잡도, 계층별 저장 파일 증가.
|
||||
|
||||
### Future Risks
|
||||
계층이 더 늘면(예: 감정/사회적 기억) 관리 폭증. 관련도 점수가 휴리스틱이라 잘못 선별 시 핵심 기억 누락 가능.
|
||||
|
||||
### Alternative Approaches
|
||||
의미 검색이 핵심이면 각 계층 *내부* 에 임베딩을 도입(하이브리드)하거나, 계층 수를 3개(작업·세션·영구)로 단순화. 대규모면 벡터 DB + 메타데이터 필드로 계층을 표현.
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
계층이 많을수록 표현력은 커지나 "어디에 저장할지" 결정 비용도 커진다 — 명확한 분류 규칙([[아키텍처 휴리스틱]])이 없으면 오히려 혼란.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
`AstraAI/src/memory/index.ts`, `types.ts` [S1][S2].
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[5계층 메모리 시스템]], [[Memory Pattern]], [[아키텍처 휴리스틱]], [[엔지니어링 트레이드오프 분석]]
|
||||
- **참조 맥락:** 로컬 LLM 이 에이전트 메모리 구조를 설계할 때 "한 통 vs 계층 분리" 판단에 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/memory/index.ts — MemoryManager 5계층 통합
|
||||
- [S2] AstraAI/src/memory/types.ts — 계층별 타입·만료·승급 필드
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 ADR 작성.
|
||||
@@ -0,0 +1,82 @@
|
||||
---
|
||||
id: adr-0003-single-writer-multi-role
|
||||
title: "ADR-0003 단일작성자 다중역할 멀티에이전트"
|
||||
category: "Architecture_Decision"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["ADR multi-agent", "왜 병렬 persona 를 버렸나", "ChunkedWriter 결정", "멀티에이전트 결정"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.88
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["adr", "multi-agent", "decision", "ai", "astraai"]
|
||||
raw_sources: ["AstraAI/src/agents/AgentWorkflowManager.ts", "AstraAI/src/features/company/dispatcher.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[ADR-0003 단일작성자 다중역할 멀티에이전트]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
"여러 persona 를 병렬/직렬로 줄세우는 멀티에이전트" 대신, 일반 작성 작업은 **단일 작성자가 outline→section→polish 역할을 번갈아 수행**하고, 진짜 다중 전문가가 필요한 회사 모드는 **순차 디스패치(한 번에 한 모델 상주)**로 가기로 결정했다 [S1][S2].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
- **결정 1:** 5-persona 파이프라인 폐기 → 단일 `ChunkedWriter` 다중 역할.
|
||||
- **결정 2:** 다중 전문가는 병렬이 아니라 순차 + peer-context 전달.
|
||||
- 구현은 [[Agent 오케스트레이터 분해]] 참조.
|
||||
|
||||
## 📖 세부 내용 (Details · ADR)
|
||||
### Problem
|
||||
초기 planner/researcher/reflector/writer/synthesizer 5-persona 파이프라인은 (1) hop 마다 컨텍스트가 누적되고 (2) 원본 본문이 추상화로 손실돼, 사용자가 본문 분석을 요청해도 "분석 방법론" 만 만들어내는 사고가 났다 [S1]. 또 병렬 에이전트는 단일 GPU/제한 RAM 에서 여러 모델을 동시 상주시켜야 한다 [S2].
|
||||
|
||||
### Context
|
||||
- 타깃 환경: 단일 GPU/CPU, 제한된 RAM, 로컬 작은 모델(gemma 등).
|
||||
- LM Studio lifecycle 매니저가 모델 load/unload 를 관리 — "한 번에 하나" 가 자연스럽다.
|
||||
- 작업 종류: 대부분 단일 문서 작성, 일부만 진짜 다중 전문가 협업(회사 모드).
|
||||
|
||||
### Options Considered
|
||||
1. **병렬 멀티에이전트(persona N개 동시)** — 빠르지만 모델 다중 상주·자원 폭주, 컨텍스트/본문 손실.
|
||||
2. **직렬 5-persona 파이프라인** — 자원은 낫지만 hop 누적·본문 추상화 손실(실제 발생한 사고).
|
||||
3. **단일 작성자 다중 역할(+필요 시 순차 전문가)** — 컨텍스트 작고 본문 직접 전달, 한 모델만 상주.
|
||||
|
||||
### Chosen Solution
|
||||
3번. 일반 작성은 `ChunkedWriter`(outline/section/polish 한 모델 번갈아). 다중 전문가는 company `dispatcher` 가 CEO 플래너→전문가 순차(peer-context 잘라 전달)→CEO 리포터 [S1][S2].
|
||||
|
||||
### Why It Was Chosen
|
||||
- 본문이 매 호출에 직접 전달돼 손실 없음(초기 사고의 직접 해결).
|
||||
- 각 호출이 작아 작은 모델의 컨텍스트 한도를 지킴.
|
||||
- "정확히 한 모델만 상주" 로 VRAM 안전 + lifecycle 단순.
|
||||
|
||||
### Benefits
|
||||
자원 안전, 본문 보존, 컨텍스트 폭증 방지, 디버깅 단순(한 번에 한 단계).
|
||||
|
||||
### Drawbacks
|
||||
총 응답 시간이 길다(순차). 단일 모델 품질에 결과가 좌우된다. 병렬로 얻는 다양성·속도를 포기.
|
||||
|
||||
### Future Risks
|
||||
작업이 진짜 병렬성을 요구하거나(대규모 리서치), 멀티 GPU 환경이 표준이 되면 이 결정이 병목이 된다.
|
||||
|
||||
### Alternative Approaches
|
||||
자원이 충분하면 병렬 persona + 합의(judge panel). 또는 역할별로 작은 특화 모델을 동시에. 속도가 critical 하면 outline/section 을 병렬화하고 polish 만 직렬.
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"멀티에이전트가 항상 낫다" 는 통념과 반대다 — *자원 제약 하에서는* 잘 구성된 단일 작성자가 어설픈 병렬 파이프라인보다 낫다는 실측 교훈. 환경이 바뀌면 재평가 대상.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
`AgentWorkflowManager.ts`(ChunkedWriter), `company/dispatcher.ts`(순차) [S1][S2].
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[Agent 오케스트레이터 분해]], [[Agent Orchestration Pattern]], [[ADR-0004 순차 디스패치 채택]], [[엔지니어링 트레이드오프 분석]]
|
||||
- **참조 맥락:** 로컬 LLM 이 멀티에이전트를 도입할지/어떻게 구성할지 자원 제약 하에 판단할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/agents/AgentWorkflowManager.ts — 5-persona 폐기 post-mortem, ChunkedWriter
|
||||
- [S2] AstraAI/src/features/company/dispatcher.ts — 순차 디스패치 근거
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 ADR 작성.
|
||||
@@ -0,0 +1,77 @@
|
||||
---
|
||||
id: adr-0004-sequential-dispatch
|
||||
title: "ADR-0004 순차 디스패치 채택"
|
||||
category: "Architecture_Decision"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["ADR sequential dispatch", "왜 순차 실행", "한 번에 한 모델"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.9
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["adr", "concurrency", "decision", "resource", "astraai"]
|
||||
raw_sources: ["AstraAI/src/features/company/dispatcher.ts", "AstraAI/src/lmstudio/lifecycleManager.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[ADR-0004 순차 디스패치 채택]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
다중 에이전트/모델 작업을 **순차로 실행하고 한 번에 정확히 하나의 모델만 메모리에 상주**시키기로 결정했다 — 단일 GPU/제한 RAM 에서 병렬은 여러 모델 동시 로드를 강요해 OOM·스왑을 부르기 때문 [S1].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
- **결정:** company 턴은 전문가를 순차 실행, LM Studio lifecycle 가 이전 모델 unload → 다음 load.
|
||||
- 무거운 LLM 작업은 `missionId` 락으로도 직렬화.
|
||||
|
||||
## 📖 세부 내용 (Details · ADR)
|
||||
### Problem
|
||||
병렬 에이전트는 동시에 여러 모델을 상주시켜야 하는데, 타깃 사용자는 단일 GPU/제한 RAM 으로 Astra 를 돌린다 → 동시 로드 시 메모리 초과/스왑/로드 실패 [S1].
|
||||
|
||||
### Context
|
||||
로컬 우선 설계, 작은 모델, LM Studio SDK 의 load/unload 수명관리. 응답 지연보다 *동작 보장* 이 우선.
|
||||
|
||||
### Options Considered
|
||||
1. **병렬 실행** — 빠르지만 다중 모델 상주 필요(자원 초과).
|
||||
2. **순차 + 매번 같은 모델** — 단순하나 역할별 특화 모델 사용 불가.
|
||||
3. **순차 + 에이전트별 모델 override(lifecycle unload/load)** — 한 번에 하나, 역할별 모델 가능.
|
||||
|
||||
### Chosen Solution
|
||||
3번. 전문가마다 모델 override 가능, 디스패처가 순차로 돌며 lifecycle 가 교체. peer-context 를 잘라 다음 에이전트에 전달 [S1].
|
||||
|
||||
### Why It Was Chosen
|
||||
"한 모델만 상주" 불변식이 자원 안전을 보장하고, 그러면서도 단계별 최적 모델을 쓸 수 있다.
|
||||
|
||||
### Benefits
|
||||
OOM 회피, 예측 가능한 메모리, 역할별 모델 유연성, 진행 단계 가시화 용이.
|
||||
|
||||
### Drawbacks
|
||||
총 시간이 길다(모델 교체 오버헤드 포함). 병렬 처리량 포기.
|
||||
|
||||
### Future Risks
|
||||
멀티 GPU/대용량 RAM 이 표준이 되면 과도한 제약. 작업 수가 많으면 누적 지연이 사용자 인내를 초과.
|
||||
|
||||
### Alternative Approaches
|
||||
자원 충분 시 워커 풀 + 모델 핀닝으로 병렬. 또는 빠른 단계는 작은 모델로 병렬, 합성만 큰 모델로 직렬(하이브리드).
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
처리량 최적화와 정면 충돌하는 결정 — 환경(자원)이 전제이므로, 서버 배포 시엔 [[엔지니어링 트레이드오프 분석]] 기준으로 재검토.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
`company/dispatcher.ts` 의 순차 루프 + lifecycle [S1].
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[ADR-0003 단일작성자 다중역할 멀티에이전트]], [[동시성 제어 Lock Queue Transaction]], [[Background Worker Pattern]]
|
||||
- **참조 맥락:** 로컬 LLM 이 자원 제약 환경에서 병렬 vs 순차를 결정할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/features/company/dispatcher.ts — "Why sequential?" 근거 주석
|
||||
- [S2] AstraAI/src/lmstudio/lifecycleManager.ts — 모델 load/unload 수명관리
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 ADR 작성.
|
||||
@@ -0,0 +1,80 @@
|
||||
---
|
||||
id: adr-0005-file-based-storage
|
||||
title: "ADR-0005 파일 기반 저장 채택"
|
||||
category: "Architecture_Decision"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["ADR storage", "왜 DB 안 쓰나", "Markdown JSONL 저장", "파일 저장 결정"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.89
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["adr", "storage", "decision", "filesystem", "astraai"]
|
||||
raw_sources: ["AstraAI/src/core/services.ts", "AstraAI/src/features/_shared/eventSourcedStore.ts", "AstraAI/src/intelligence/correctionLoop.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[ADR-0005 파일 기반 저장 채택]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
지식·메모리·로그를 DB 가 아니라 **Markdown(.md) + JSON/JSONL 파일**로 저장하기로 결정했다 — 사람이 직접 열어 읽고/고치는 투명성(Permission Based Learning)과 무의존성이 단일 사용자 로컬 도구에 최적이기 때문 [S1][S3].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
- **결정:** brain 지식=Markdown(frontmatter), 이벤트/케이스=JSONL, 설정/프로필=JSON.
|
||||
- 검색은 파일 위 TF-IDF/임베딩 인덱스([[RAG 검색 파이프라인]]).
|
||||
|
||||
## 📖 세부 내용 (Details · ADR)
|
||||
### Problem
|
||||
지식/메모리/학습 데이터를 어디에 저장할 것인가. DB 는 강력하지만 단일 사용자 로컬 확장에 운영·마이그레이션·불투명성 비용을 더한다.
|
||||
|
||||
### Context
|
||||
- 사용자가 두뇌 내용을 직접 보고 수정/삭제할 수 있어야 한다(투명성·신뢰).
|
||||
- VS Code/에디터로 그대로 열람 가능해야(Markdown).
|
||||
- 번들 의존성 최소화(런타임 deps 2개).
|
||||
|
||||
### Options Considered
|
||||
1. **SQLite/임베디드 DB** — 쿼리·트랜잭션 강력, 그러나 불투명·의존성·스키마 관리.
|
||||
2. **벡터 DB** — 의미 검색 최적, 그러나 인프라·운영 부담, 사람이 못 읽음.
|
||||
3. **파일 기반(Markdown + JSONL + JSON)** — 투명·무의존·버전관리(git) 친화.
|
||||
|
||||
### Chosen Solution
|
||||
3번. 지식은 frontmatter 달린 Markdown, 이벤트/정정 케이스는 append-only JSONL, 프로필/설정은 JSON. 검색은 파일 위 인덱스로 보강 [S1][S2][S3].
|
||||
|
||||
### Why It Was Chosen
|
||||
사람이 읽고 고치는 투명성이 신뢰의 핵심(특히 자기학습 시스템). git diff 로 변경 추적. 의존성 0 으로 배포 단순.
|
||||
|
||||
### Benefits
|
||||
투명성, 무의존, git 친화, 에디터 직접 열람, 백업/이동 단순(폴더 복사).
|
||||
|
||||
### Drawbacks
|
||||
복잡한 쿼리/조인 불가, 대량 데이터에서 스캔 비용, 동시쓰기 잠금 직접 관리, 인덱스를 직접 구축해야 함.
|
||||
|
||||
### Future Risks
|
||||
brain 이 수만 파일로 커지면 파일 스캔/인덱싱 비용 급증. 트랜잭션이 약해 다중 파일 일관성은 보상 트랜잭션에 의존.
|
||||
|
||||
### Alternative Approaches
|
||||
규모 확대 시 SQLite(메타데이터) + 파일(본문) 하이브리드, 또는 임베딩만 벡터 DB 로 외부화하고 본문은 파일 유지.
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"검색·쿼리 성능" 만 보면 DB 가 우위다. 이 결정은 *투명성·무의존* 을 성능보다 우선한 가치 판단 — 멀티유저/대규모면 뒤집힌다.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
brain Markdown(BrainService.inject), JSONL 이벤트 스토어, corrections.jsonl / weakness-profile.json [S1][S2][S3].
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[ADR-0001 이벤트 소싱 채택]], [[이벤트 소싱 스토어 패턴]], [[Local Storage Pattern]], [[Caching Pattern]]
|
||||
- **참조 맥락:** 로컬 LLM 이 "DB vs 파일" 저장 방식을 결정할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/core/services.ts — BrainService Markdown 저장
|
||||
- [S2] AstraAI/src/features/_shared/eventSourcedStore.ts — JSONL 이벤트
|
||||
- [S3] AstraAI/src/intelligence/correctionLoop.ts — JSONL/JSON 케이스·프로필(투명성)
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 ADR 작성.
|
||||
@@ -0,0 +1,78 @@
|
||||
---
|
||||
id: adr-0006-manual-di-interface-services
|
||||
title: "ADR-0006 수동 의존성주입과 인터페이스 서비스"
|
||||
category: "Architecture_Decision"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["ADR DI", "왜 DI 컨테이너 안 쓰나", "수동 주입 결정", "인터페이스 서비스 결정"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.89
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["adr", "dependency-injection", "decision", "architecture", "astraai"]
|
||||
raw_sources: ["AstraAI/src/extension.ts", "AstraAI/src/core/services.ts", "AstraAI/src/intelligence/criticAgent.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[ADR-0006 수동 의존성주입과 인터페이스 서비스]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
의존성 주입을 **DI 프레임워크 없이 entry point(`activate`)에서 손으로 조립**하고, 외부 효과를 가진 협력자는 **인터페이스/함수 타입으로 추상화**해 주입하기로 결정했다 — 조립 지점이 하나뿐이라 컨테이너의 비용이 불필요하기 때문 [S1][S2].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
- **결정:** 수동 생성자/함수/getter 주입 + IAIService/IBrainService/CritiqueLlmCall 추상화.
|
||||
- 구현 상세는 [[의존성 주입과 서비스 인터페이스]] 참조.
|
||||
|
||||
## 📖 세부 내용 (Details · ADR)
|
||||
### Problem
|
||||
협력자(AI 서비스, 스트리머, 큐, LLM 호출)를 객체가 직접 생성하면 결합이 강해지고 테스트가 어렵다. 그러나 DI 컨테이너는 학습·설정·런타임 마법 비용이 있다.
|
||||
|
||||
### Context
|
||||
조립 지점이 사실상 `activate` 한 곳. 모듈 수는 많지만 의존 그래프는 명시적. 테스트는 순수 함수 + 가짜 주입으로 충분.
|
||||
|
||||
### Options Considered
|
||||
1. **DI 컨테이너(tsyringe 등)** — 자동 해석/수명관리, 그러나 의존성·매직·디버깅 비용.
|
||||
2. **싱글톤 남발** — 간단하나 테스트 격리 불가, 숨은 결합.
|
||||
3. **수동 주입 + 인터페이스/함수 추상화** — 명시적, 무의존, 테스트 용이.
|
||||
|
||||
### Chosen Solution
|
||||
3번. 생성자 옵션 객체(`new AgentExecutor(ctx, {...})`), 함수 타입 주입(`CritiqueLlmCall`), getter 주입(`getProvider`). 전역이 본질인 자원만 싱글톤(lock/queue) [S1][S2].
|
||||
|
||||
### Why It Was Chosen
|
||||
조립이 한 곳이라 컨테이너의 이득이 작고, 수동 주입이 흐름을 가장 투명하게 만든다. 함수 주입으로 검증 모듈을 순수하게 유지(테스트 시 가짜 LLM).
|
||||
|
||||
### Benefits
|
||||
무의존·투명한 조립, 뛰어난 테스트성, 명시적 의존 그래프, 교체 용이.
|
||||
|
||||
### Drawbacks
|
||||
조립 코드가 장황(activate 가 큼), 의존이 늘면 수동 배선 부담, 수명관리 직접.
|
||||
|
||||
### Future Risks
|
||||
모듈/조립 지점이 폭증하면 수동 배선이 한계 → 부분적 컨테이너 도입 필요. 싱글톤은 테스트 격리를 점점 어렵게.
|
||||
|
||||
### Alternative Approaches
|
||||
규모 확대 시 경량 컨테이너 또는 팩토리 레이어. 또는 기능별 "composition root" 를 여러 개로 분리.
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"엔터프라이즈엔 DI 컨테이너" 통념과 다르다 — 단일 composition root 소규모에선 수동 주입이 더 단순·명확. 규모가 결정 인자.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
`extension.ts`(수동 조립), `services.ts`(인터페이스), `criticAgent.ts`(함수 주입) [S1][S2][S3].
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[의존성 주입과 서비스 인터페이스]], [[Repository Pattern]], [[엔지니어링 트레이드오프 분석]]
|
||||
- **참조 맥락:** 로컬 LLM 이 "DI 컨테이너 vs 수동 주입" 을 규모 기준으로 결정할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/extension.ts — activate 수동 조립, getter/옵션 주입
|
||||
- [S2] AstraAI/src/core/services.ts — IAIService/IBrainService
|
||||
- [S3] AstraAI/src/intelligence/criticAgent.ts — CritiqueLlmCall 함수 주입
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 ADR 작성.
|
||||
@@ -0,0 +1,77 @@
|
||||
---
|
||||
id: adr-0007-hybrid-retrieval-deterministic-first
|
||||
title: "ADR-0007 하이브리드 검색과 결정론 우선"
|
||||
category: "Architecture_Decision"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["ADR retrieval", "왜 TF-IDF 먼저", "하이브리드 검색 결정", "결정론 우선"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.9
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["adr", "rag", "retrieval", "decision", "astraai"]
|
||||
raw_sources: ["AstraAI/src/retrieval/index.ts", "AstraAI/src/retrieval/scoring.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[ADR-0007 하이브리드 검색과 결정론 우선]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
검색의 기본은 **TF-IDF(sparse)로 항상 동작**하게 하고, 임베딩(dense)은 *가용할 때만 가산 혼합* 하기로 결정했다 — 임베딩 엔진이 없거나 미색인이어도 검색이 절대 망가지지 않게 하기 위해 [S1].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
- **결정:** TF-IDF 기본 + 임베딩 blend(α). 벡터 없는 문서는 순수 sparse 유지.
|
||||
- 구현은 [[RAG 검색 파이프라인]], [[TF-IDF 이중언어 스코어링]] 참조.
|
||||
|
||||
## 📖 세부 내용 (Details · ADR)
|
||||
### Problem
|
||||
의미 검색(임베딩)은 강력하지만 임베딩 모델 가용성·색인 상태에 의존한다. 그것에만 의존하면 모델이 없을 때 검색이 죽는다. 반대로 키워드만 쓰면 환언/동의를 놓친다.
|
||||
|
||||
### Context
|
||||
로컬 환경에서 임베딩 모델이 있을 수도/없을 수도. brain 은 한/영 혼용. "검색은 언제나 동작" 이 신뢰의 기본.
|
||||
|
||||
### Options Considered
|
||||
1. **임베딩 단독(dense only)** — 의미 강하나 가용성·비용 의존, 무관 문서도 높은 cos.
|
||||
2. **키워드 단독(sparse only)** — 항상 동작·설명가능하나 환언 놓침.
|
||||
3. **하이브리드(결정론 우선 + 임베딩 가산)** — 기본 보장 + 의미 보강.
|
||||
|
||||
### Chosen Solution
|
||||
3번. TF-IDF 로 점수, 임베딩이 있으면 `(1-α)·sparse + α·dense`. 모든 후보를 maxTfidf 로 정규화(벡터 있는 것만 줄이면 안 됨), cosine 은 후보군 min-max 정규화 [S1].
|
||||
|
||||
### Why It Was Chosen
|
||||
가용성 보장(임베딩 없어도 동작), 설명가능(왜 매치됐는지), 그러면서 의미 검색의 이득을 더한다. 실측 버그(스케일 불일치)를 정규화로 해결.
|
||||
|
||||
### Benefits
|
||||
무중단 검색, 점진 도입(임베딩 색인이 늘수록 좋아짐), 설명가능, 한/영 교차 매칭(동의어 확장).
|
||||
|
||||
### Drawbacks
|
||||
스케일 정규화가 까다로움(2건의 실측 버그), 수작업 동의어 사전 유지, 형태소 분석 부재.
|
||||
|
||||
### Future Risks
|
||||
brain 규모↑ 시 sparse 인덱스 메모리·시간 증가. 동의어 사전 누락이 recall 을 갉아먹음.
|
||||
|
||||
### Alternative Approaches
|
||||
대규모면 BM25 + 벡터 DB 하이브리드, 또는 reranker 모델 도입. 한국어 정밀도가 critical 하면 형태소 분석기.
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"임베딩이 최신이고 우월" 통념과 달리, *가용성·설명가능성* 을 위해 결정론을 1순위로 둔다 — 단, 의미 검색을 버리지 않고 가산.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
`retrieval/index.ts`(하이브리드 blend), `scoring.ts`(TF-IDF/토크나이저) [S1].
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[RAG 검색 파이프라인]], [[TF-IDF 이중언어 스코어링]], [[RAG Pattern]], [[Caching Pattern]]
|
||||
- **참조 맥락:** 로컬 LLM 이 검색을 설계할 때 "dense only vs 하이브리드" 와 가용성 보장을 판단할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/retrieval/index.ts — 하이브리드 blend, 스케일 정규화 버그 기록
|
||||
- [S2] AstraAI/src/retrieval/scoring.ts — TF-IDF, 이중언어 토크나이저, 동의어
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 ADR 작성.
|
||||
@@ -0,0 +1,77 @@
|
||||
---
|
||||
id: adr-0008-local-first-llm-cloud-fallback
|
||||
title: "ADR-0008 로컬 우선 LLM과 클라우드 폴백"
|
||||
category: "Architecture_Decision"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["ADR local-first", "엔진 폴백 결정", "로컬 LLM 우선", "프로바이더 라우팅 결정"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.9
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["adr", "llm", "provider", "decision", "fallback", "astraai"]
|
||||
raw_sources: ["AstraAI/src/core/services.ts", "AstraAI/src/features/providers/types.ts", "AstraAI/src/features/providers/index.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[ADR-0008 로컬 우선 LLM과 클라우드 폴백]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
기본은 **로컬 엔진(LM Studio/Ollama)을 우선**하고 로컬끼리 폴백하며, 클라우드(OpenRouter/Anthropic/Gemini)는 **model id prefix 로 옵션 선택**하기로 결정했다 — 프라이버시·비용·오프라인을 기본값으로, 필요 시 클라우드 품질을 끌어쓰기 위해 [S1][S2].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
- **결정:** prefix 없으면 로컬, 있으면 클라우드 어댑터. 로컬은 LM Studio↔Ollama 자동 폴백.
|
||||
- 구현은 [[LLM 프로바이더 추상화]] 참조.
|
||||
|
||||
## 📖 세부 내용 (Details · ADR)
|
||||
### Problem
|
||||
어떤 LLM 을 어떻게 선택/실패 처리할 것인가. 로컬은 무료·프라이버시·오프라인이지만 품질·가용성이 들쭉날쭉. 클라우드는 품질↑ 비용·프라이버시 우려.
|
||||
|
||||
### Context
|
||||
제2뇌는 개인 지식을 다룸 → 프라이버시 중요. 로컬 엔진은 가끔 빈 응답/전송 오류. 사용자가 작업별로 품질을 올리고 싶을 때가 있음.
|
||||
|
||||
### Options Considered
|
||||
1. **클라우드 전용** — 품질·간편, 그러나 비용·프라이버시·오프라인 불가.
|
||||
2. **로컬 전용** — 프라이버시·무료, 그러나 실패 시 대안 없음.
|
||||
3. **로컬 우선 + 로컬 폴백 + 클라우드 옵션(prefix)** — 기본 안전 + 선택적 품질.
|
||||
|
||||
### Chosen Solution
|
||||
3번. `AIService.chat` 이 설정 엔진→다른 로컬 엔진 폴백(빈 응답=soft failure). 클라우드는 `parseModelPrefix` 로 라우팅, 어댑터가 SSE 정규화 [S1][S2].
|
||||
|
||||
### Why It Was Chosen
|
||||
프라이버시·비용·오프라인을 기본으로 보장하면서, 로컬 불안정을 폴백으로 메우고, 필요 시 클라우드 품질을 prefix 하나로 선택.
|
||||
|
||||
### Benefits
|
||||
프라이버시 기본, 가용성↑(폴백), 유연성(작업별 클라우드), 호출부 공급자 무관.
|
||||
|
||||
### Drawbacks
|
||||
폴백이 지연을 더함, 로컬/클라우드 응답 형식 차이를 어댑터가 흡수해야 함, 클라우드 키 관리.
|
||||
|
||||
### Future Risks
|
||||
클라우드 모델 id/형식 변경 시 어댑터 유지보수, 로컬 모델 품질이 작업을 못 받치면 사용자 불만.
|
||||
|
||||
### Alternative Approaches
|
||||
품질이 절대 우선이면 클라우드 기본 + 로컬 폴백(역순). 또는 작업 난이도 자동 분류로 라우팅(쉬운 건 로컬, 어려운 건 클라우드).
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"좋은 클라우드 모델을 쓰면 되지" 라는 입장과 충돌 — 이 결정은 *프라이버시·비용·오프라인* 을 품질보다 우선한 가치 판단. 사용은 prefix 로 자유.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
`services.ts`(폴백), `providers/types.ts`+`index.ts`(prefix 라우팅) [S1][S2].
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[LLM 프로바이더 추상화]], [[API Client Pattern]], [[Tool Calling Pattern]]
|
||||
- **참조 맥락:** 로컬 LLM 이 다중 추론 백엔드 전략(로컬/클라우드/폴백)을 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/core/services.ts — 로컬 엔진 폴백, soft failure
|
||||
- [S2] AstraAI/src/features/providers/types.ts, index.ts — prefix 라우팅, 어댑터 dispatch
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 ADR 작성.
|
||||
@@ -0,0 +1,78 @@
|
||||
---
|
||||
id: adr-0009-deterministic-always-llm-conditional
|
||||
title: "ADR-0009 결정론 항상, LLM 검증 조건부"
|
||||
category: "Architecture_Decision"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["ADR verification", "왜 조건부 critic", "결정론 우선 검증", "확신도 결정론"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.9
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["adr", "verification", "intelligence", "decision", "astraai"]
|
||||
raw_sources: ["AstraAI/src/intelligence/confidenceEngine.ts", "AstraAI/src/intelligence/criticAgent.ts", "AstraAI/src/intelligence/epistemicGuardBlock.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[ADR-0009 결정론 항상, LLM 검증 조건부]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
답변 검증에서 **저렴한 결정론적 검사(정규식/카운트/그라운딩 신호)는 매 턴 실행**하고, **비싼 LLM 검수(Critic)는 결정론 검사가 문제를 신호할 때만** 돌리기로 결정했다 — 로컬 모델의 latency 비용 안에서 신뢰를 확보하기 위해 [S1][S2].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
- **결정:** Epistemic Guard(사전, 무비용) + Confidence Engine(결정론, 무LLM) 항상 / Critic(LLM) 조건부 1-pass.
|
||||
- 구현은 [[Intelligence 검증 레이어]] 참조.
|
||||
|
||||
## 📖 세부 내용 (Details · ADR)
|
||||
### Problem
|
||||
작은 로컬 모델은 환각이 잦다. 매 답변을 LLM 으로 재검수하면 정확하지만 latency·비용이 2배 이상으로 사용성이 무너진다.
|
||||
|
||||
### Context
|
||||
로컬 Gemma 류, 단일 GPU. 매 턴 추가 LLM 호출은 체감 지연이 큼. 그러나 사실오류/근거누락은 잡아야 함.
|
||||
|
||||
### Options Considered
|
||||
1. **항상 LLM 재검수(full debate)** — 가장 정확, 그러나 latency·비용 폭증.
|
||||
2. **검증 없음** — 빠르나 환각 방치.
|
||||
3. **결정론 항상 + LLM 조건부** — 비용 통제 + 위험 신호 시 정밀 검수.
|
||||
|
||||
### Chosen Solution
|
||||
3번. 매 턴 Epistemic Guard 주입 + 결정론 Confidence(0~100) 산출. "커버리지 누락 또는 확신도 <70" 일 때만 Critic LLM 1회 호출, 보완 카드 표시. 다회전 debate 는 knob 만 준비 [S1][S2].
|
||||
|
||||
### Why It Was Chosen
|
||||
대부분의 답변은 결정론 신호로 충분히 걸러지고, 진짜 위험할 때만 비싼 검수를 써 비용 대비 신뢰를 극대화. "모름 인정이 오답보다 낫다" 를 사전 가드로 구조화.
|
||||
|
||||
### Benefits
|
||||
낮은 평균 latency, 위험 시 정밀 검수, 설명가능한 확신도, 사용자 검토 유도(에스컬레이션).
|
||||
|
||||
### Drawbacks
|
||||
조건 임계가 잘못되면 위험 답변을 놓치거나 불필요 검수. 확신도 가중치가 휴리스틱(보정 필요). 1-pass 는 다회전보다 약함.
|
||||
|
||||
### Future Risks
|
||||
임계/가중치가 데이터 없이 고정되면 오탐/미탐. 모델 교체 시 신호 분포가 바뀌어 재보정 필요.
|
||||
|
||||
### Alternative Approaches
|
||||
골든셋으로 가중치 학습, 위험 도메인만 다회전 debate, 또는 작은 전용 검증 모델 상시 가동.
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"항상 검증해야 안전" 과 "검증은 비싸다" 의 균형점 — 환경(로컬 latency)이 임계를 정한다. 서버/대형 모델이면 더 자주 LLM 검수가 합리적.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
`confidenceEngine.ts`(결정론), `criticAgent.ts`(조건부), `epistemicGuardBlock.ts`(사전) [S1][S2][S3].
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[Intelligence 검증 레이어]], [[Critic Pattern]], [[Reflection Pattern]], [[엔지니어링 트레이드오프 분석]]
|
||||
- **참조 맥락:** 로컬 LLM 이 자기검증 비용/정확도 균형을 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/intelligence/confidenceEngine.ts — 결정론 확신도(매 턴)
|
||||
- [S2] AstraAI/src/intelligence/criticAgent.ts — 조건부 1-pass 검수
|
||||
- [S3] AstraAI/src/intelligence/epistemicGuardBlock.ts — 사전 가드
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 ADR 작성.
|
||||
@@ -0,0 +1,77 @@
|
||||
---
|
||||
id: adr-0010-orchestrator-skeleton-module-extraction
|
||||
title: "ADR-0010 오케스트레이터 골격과 모듈 추출"
|
||||
category: "Architecture_Decision"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["ADR orchestrator", "god class 분해 결정", "흐름 골격 유지", "모듈 추출"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.87
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["adr", "architecture", "refactoring", "decision", "astraai"]
|
||||
raw_sources: ["AstraAI/src/agent.ts", "AstraAI/src/extension.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[ADR-0010 오케스트레이터 골격과 모듈 추출]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
거대해지는 `agent.ts` 를 완전히 잘게 쪼개 흩어버리는 대신, **한 턴의 흐름 골격은 orchestrator 에 남기고 세부 구현만 모듈로 추출**하기로 결정했다 — "흐름을 한 곳에서 읽을 수 있음" 의 가치를 위해 [S1].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
- **결정:** handlePrompt/·llm/·actions/·sessions/·multiAgent/·contextBuilders/ 로 구현 추출, 흐름은 agent.ts 가 호출 순서로 표현.
|
||||
- 구현은 [[Agent 오케스트레이터 분해]] 참조.
|
||||
|
||||
## 📖 세부 내용 (Details · ADR)
|
||||
### Problem
|
||||
한 턴 처리(컨텍스트 조립·라우팅·스트리밍·후처리·학습)가 한 파일에 쌓이면 수천 줄 god-class 가 된다. 반대로 전부 잘게 쪼개면 흐름이 파일 사이를 떠돌아 추적이 어렵다.
|
||||
|
||||
### Context
|
||||
복잡한 단일 흐름(분기 많음), 다수 협력 모듈, 디버깅 시 "이 턴이 무슨 순서로 처리되나" 를 빨리 파악해야 함.
|
||||
|
||||
### Options Considered
|
||||
1. **단일 god-class** — 흐름은 한눈, 그러나 거대·테스트 불가·병합 충돌.
|
||||
2. **완전 분해(흐름도 분산)** — 모듈은 작으나 흐름 추적이 산만.
|
||||
3. **골격 유지 + 세부 추출** — 흐름은 orchestrator, 구현은 순수/작은 모듈.
|
||||
|
||||
### Chosen Solution
|
||||
3번. orchestrator 는 buildTurnContextBlocks→system prompt 빌드→budget→stream→processFinalAnswer→postAnswerHooks 순서를 *호출* 만 하고, 각 단계 구현은 추출된 함수/모듈 [S1].
|
||||
|
||||
### Why It Was Chosen
|
||||
디버깅·온보딩 시 한 턴의 흐름을 orchestrator 한 곳에서 읽고, 세부가 궁금하면 해당 모듈로 내려간다. 추출된 함수는 순수해 테스트 가능.
|
||||
|
||||
### Benefits
|
||||
흐름 가독성 + 모듈 테스트성, 병합 충돌 감소, 점진적 추출 가능.
|
||||
|
||||
### Drawbacks
|
||||
orchestrator 가 여전히 큼(import 100+줄), 추출 경계 설정에 판단 필요, 과도하면 "얇은 래퍼 지옥".
|
||||
|
||||
### Future Risks
|
||||
흐름 분기가 더 늘면 orchestrator 가 다시 비대 → 모드별 서브-오케스트레이터로 분할 필요.
|
||||
|
||||
### Alternative Approaches
|
||||
파이프라인/미들웨어 체인으로 단계를 데이터로 표현, 또는 모드(chat/agent/company)별 orchestrator 분리.
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"god-class 는 무조건 나쁘다" 는 단순 규칙과 다르다 — *흐름 가독성* 이라는 명확한 이득이 있으면 골격을 남기는 것이 합리적. 단, 크기 상한을 정하지 않으면 다시 비대해진다.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
`agent.ts` 의 import/호출 구조, `extension.ts` 의 얇은 조립 [S1][S2].
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[Agent 오케스트레이터 분해]], [[리팩토링 플레이북]], [[안티패턴 카탈로그]]
|
||||
- **참조 맥락:** 로컬 LLM 이 거대 함수/클래스를 리팩터링할 때 "어디까지 추출할지" 판단에 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/agent.ts — 골격 + 추출 모듈 import
|
||||
- [S2] AstraAI/src/extension.ts — 얇은 조립 entry point
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 ADR 작성.
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
id: aitrain-rag-retrieval
|
||||
title: "AITRAIN RAG 검색"
|
||||
category: "AI_Training"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["AI training RAG", "검색 학습 추출", "RAG 원리"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.9
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["ai-training", "rag", "retrieval", "transferable", "astraai"]
|
||||
raw_sources: ["AstraAI/src/retrieval/index.ts", "AstraAI/src/retrieval/scoring.ts", "AstraAI/src/retrieval/chunker.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[AITRAIN RAG 검색]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
RAG 의 전이 원리는 "여러 소스를 같은 스케일로 융합하고, 결정론을 기본으로 의미검색을 가산하며, 토큰 예산 안에서 선별한다" 이다 — 구현은 [[RAG 검색 파이프라인]]·[[TF-IDF 이중언어 스코어링]], 결정 근거는 [[ADR-0007 하이브리드 검색 결정론 우선]].
|
||||
|
||||
## 📖 세부 내용 (Details · 8-field 추출)
|
||||
- **Concept:** 답하기 전에 근거를 찾아 컨텍스트에 주입. 검색 = 후보 생성 → 점수 → 융합 → 예산 선택.
|
||||
- **Implementation:** tokenize(이중언어)→expandQuery(동의어)→TF-IDF→임베딩 blend→소스 정규화+가중→actionability/hierarchical rerank→토큰 예산. 섹션 청킹으로 정밀도↑. mtime 인덱스로 재계산 회피.
|
||||
- **Design Reasoning:** 임베딩 가용성에 의존하지 않으려 결정론(TF-IDF)을 기본; 설명가능성·무중단을 우선. 긴 문서는 청크해야 매치 정밀.
|
||||
- **Tradeoffs:** 가용성·설명가능 ↔ 스케일 정규화 복잡·동의어 수작업.
|
||||
- **Failure Modes:** 부분 정규화 편향(L-02), 동의어 누락 recall↓, 운영 로그 오염, stale 인덱스.
|
||||
- **Debugging Strategy:** fusionLog 단계 카운트, rankBrainForEval recall@k, 점수 분포, 토큰 예산.
|
||||
- **Improvement Ideas:** reranker 모델, BM25, 형태소 분석, 동의어 자동 학습, 청크별 임베딩.
|
||||
- **Reusable Principles:** ① 신호를 합칠 땐 *동일 스케일* 정규화. ② 외부 의존(임베딩) 없이도 동작하는 *바닥선* 을 둬라. ③ 긴 문서는 *의미 단위(섹션)* 로 잘라라. ④ 평가와 프로덕션은 *같은 코드 경로* 로(측정 무결성). ⑤ 변하지 않은 입력은 *재계산하지 말라*(mtime 캐시).
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[RAG 검색 파이프라인]], [[RAG Pattern]], [[Caching Pattern]], [[프로젝트 독립 설계 원칙]]
|
||||
- **참조 맥락:** 작은 모델이 다른 프로젝트에서 검색/RAG 를 설계할 때 원리로 전이.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/retrieval/index.ts, scoring.ts, chunker.ts
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AI 학습용 지식 추출 초안.
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
id: aitrain-verification-layer
|
||||
title: "AITRAIN 검증 레이어"
|
||||
category: "AI_Training"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["AI training verification", "검증 학습 추출", "환각 방지 원리", "critic 원리"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.9
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["ai-training", "verification", "hallucination", "transferable", "astraai"]
|
||||
raw_sources: ["AstraAI/src/intelligence/confidenceEngine.ts", "AstraAI/src/intelligence/criticAgent.ts", "AstraAI/src/intelligence/epistemicGuardBlock.ts", "AstraAI/src/intelligence/correctionLoop.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[AITRAIN 검증 레이어]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
LLM 검증의 전이 원리는 "저렴한 결정론 검사는 항상, 비싼 LLM 검수는 조건부; 모름 인정을 보상; 사용자 정정을 학습으로 환원" 이다 — 구현은 [[Intelligence 검증 레이어]], 결정 근거는 [[ADR-0009 결정론 항상 LLM검증 조건부]].
|
||||
|
||||
## 📖 세부 내용 (Details · 8-field 추출)
|
||||
- **Concept:** 답변의 신뢰도를 측정/억제/검수/학습하는 다단 안전망.
|
||||
- **Implementation:** Epistemic Guard(사전 프롬프트 억제)+Confidence Engine(결정론 0~100)+Critic(조건부 1-pass LLM)+Correction Loop(정정→레슨→약점프로필→프롬프트).
|
||||
- **Design Reasoning:** 작은 모델은 환각이 잦고 매 턴 LLM 검수는 비싸다 → 결정론으로 거르고 위험 시만 LLM. "모름>그럴듯한 오답".
|
||||
- **Tradeoffs:** 낮은 latency ↔ 임계 오설정 위험·휴리스틱 가중치.
|
||||
- **Failure Modes:** 임계 미탐/오탐, JSON 파싱 실패, 정정 오탐 노이즈, 모델 교체 후 신호 분포 변화.
|
||||
- **Debugging Strategy:** 확신도 factor 분해, 검색 청크 수, Critic 발동 여부, raw 응답.
|
||||
- **Improvement Ideas:** 골든셋 가중치 학습, 다회전 debate, 전용 검증 모델, 정정 감지 정교화.
|
||||
- **Reusable Principles:** ① 검증은 *계층화* 하라(사전/측정/사후/학습). ② 비용은 위험에 비례 배분(조건부). ③ 불확실성을 *드러내는* 답을 보상. ④ 사용자 피드백 1회를 *시스템 변화* 로 자동 환원. ⑤ LLM 출력은 *파서로 방어*(형식만 믿지 마라).
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[Critic Pattern]], [[Reflection Pattern]], [[프롬프트 엔지니어링 패턴]], [[프로젝트 독립 설계 원칙]]
|
||||
- **참조 맥락:** 작은 모델이 자기검증/피드백 학습을 다른 프로젝트에 적용할 때 원리로 전이.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/intelligence/confidenceEngine.ts, criticAgent.ts, epistemicGuardBlock.ts, correctionLoop.ts
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AI 학습용 지식 추출 초안.
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
id: aitrain-concurrency-control
|
||||
title: "AITRAIN 동시성 제어"
|
||||
category: "AI_Training"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["AI training concurrency", "동시성 학습 추출", "락 큐 트랜잭션 원리"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.9
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["ai-training", "concurrency", "transferable", "astraai"]
|
||||
raw_sources: ["AstraAI/src/core/lock.ts", "AstraAI/src/core/queue.ts", "AstraAI/src/core/transaction.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[AITRAIN 동시성 제어]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
동시성의 전이 원리는 "단일 스레드라도 await 사이에 race 가 생긴다; 자원은 락으로 직렬화, 폭주는 큐로 제한, 다중 변경은 보상 트랜잭션으로 원자화" 이다 — 구현은 [[동시성 제어 Lock Queue Transaction]].
|
||||
|
||||
## 📖 세부 내용 (Details · 8-field 추출)
|
||||
- **Concept:** 공유 자원 동시 접근/자원 폭주/부분 실패를 제어하는 세 도구(락·큐·트랜잭션).
|
||||
- **Implementation:** 토큰 기반 AsyncLock(race 타임아웃, try/finally release), 동시성 제한 큐(max(2,cpus-1)), 보상 트랜잭션(begin/record/commit/rollback).
|
||||
- **Design Reasoning:** JS 비동기에도 갱신 손실이 발생; 무한 병렬은 자원 고갈; FS 엔 트랜잭션이 없어 백업/복원으로 원자성 흉내.
|
||||
- **Tradeoffs:** 안전 ↔ 지연(직렬화)·복잡도. 메모리 트랜잭션은 프로세스 사망 시 롤백 불가.
|
||||
- **Failure Modes:** 데드락, 락 누수(release 누락), 동일성 비교 실수, 메모리 백업 유실.
|
||||
- **Debugging Strategy:** active lock 수 추세, 타임아웃 위치, 경합 resourceId 로그.
|
||||
- **Improvement Ideas:** 동적 동시성, WAL/DB 내구 트랜잭션, 분산 락(멀티프로세스).
|
||||
- **Reusable Principles:** ① `await` 가 있으면 race 를 의심하라. ② 락은 *반드시 try/finally*. ③ 식별은 객체 동일성 아닌 *명시 토큰*. ④ 대량 작업엔 *동시성 상한*. ⑤ 다중 쓰기는 *전부 또는 무*(보상 트랜잭션). ⑥ 동시성 수준은 *하드웨어* 가 정한다.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[Background Worker Pattern]], [[Background Task Pattern]], [[프로젝트 독립 설계 원칙]]
|
||||
- **참조 맥락:** 작은 모델이 공유 자원/대량 작업/다중 변경 코드를 다른 프로젝트에서 작성할 때 전이.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/core/lock.ts, queue.ts, transaction.ts
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AI 학습용 지식 추출 초안.
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
id: aitrain-memory-system
|
||||
title: "AITRAIN 메모리 시스템"
|
||||
category: "AI_Training"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["AI training memory", "메모리 학습 추출", "에이전트 메모리 원리"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.9
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["ai-training", "memory", "transferable", "astraai"]
|
||||
raw_sources: ["AstraAI/src/memory/index.ts", "AstraAI/src/memory/types.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[AITRAIN 메모리 시스템]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
에이전트 메모리는 "수명·용도가 다른 기억을 분리하고, 관련도로 선별해, 만료/승급으로 자정한다" 는 전이 가능한 원리로 추출된다 — 구현 세부는 [[5계층 메모리 시스템]], 결정 근거는 [[ADR-0002 5계층 메모리 분리]].
|
||||
|
||||
## 📖 세부 내용 (Details · 8-field 추출)
|
||||
- **Concept (개념):** 단일 버퍼가 아닌 다계층 인지 메모리. 각 계층 = (수명 × 용도 × 검색정책).
|
||||
- **Implementation (구현):** MemoryManager 가 5계층(단기 FIFO / 장기 entry / 프로젝트 ADR·버그 / 절차 trigger→steps / 일화 요약)을 보유, `buildContext` 가 관련도순으로 합치고 `onSessionEnd` 가 추출·증류.
|
||||
- **Design Reasoning (설계 이유):** 작은 모델은 컨텍스트 한도가 좁다 → "무엇을 넣을지" 의 선별이 품질을 좌우. 계층마다 만료/우선순위가 달라 분리가 자연스럽다.
|
||||
- **Tradeoffs:** 정밀 선별 ↔ 분류 결정 비용·복잡도. ([[엔지니어링 트레이드오프 분석]])
|
||||
- **Failure Modes:** 만료 미설정으로 옛 사실 재현, 관련도 휴리스틱 오선별, 계층 경계 모호.
|
||||
- **Debugging Strategy:** 계층별 buildContext 출력 확인, expiresAt 점검, distillation 로그 ([[디버깅 플레이북]]).
|
||||
- **Improvement Ideas:** 관련도 학습화, 계층별 임베딩, 분류 규칙 명문화/자동화.
|
||||
- **Reusable Principles:** ① 컨텍스트는 *선별* 의 문제다. ② 시한부 지식엔 만료를. ③ 오래된 기억은 *버리지 말고 압축(증류)*. ④ 기억의 수명이 다르면 저장소도 달라야 한다.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[5계층 메모리 시스템]], [[Memory Pattern]], [[ADR-0002 5계층 메모리 분리]], [[프로젝트 독립 설계 원칙]]
|
||||
- **참조 맥락:** 작은 모델이 *다른 프로젝트* 에서 에이전트 메모리를 설계할 때 원리로 전이.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/memory/index.ts, types.ts
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AI 학습용 지식 추출 초안.
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
---
|
||||
id: aitrain-agent-orchestration
|
||||
title: "AITRAIN 에이전트 오케스트레이션"
|
||||
category: "AI_Training"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["AI training agent", "에이전트 학습 추출", "오케스트레이션 원리"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.88
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["ai-training", "agent", "orchestration", "transferable", "astraai"]
|
||||
raw_sources: ["AstraAI/src/agent.ts", "AstraAI/src/agents/AgentWorkflowManager.ts", "AstraAI/src/features/company/dispatcher.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[AITRAIN 에이전트 오케스트레이션]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
에이전트 오케스트레이션의 전이 원리는 "에이전트 수를 늘리기 전에 정보 손실과 자원을 점검하고, 흐름 골격은 한 곳에 남긴다" 이다 — 구현은 [[Agent 오케스트레이터 분해]], 결정 근거는 [[ADR-0003 단일작성자 다중역할 멀티에이전트]]·[[ADR-0010 오케스트레이터 골격 모듈추출]].
|
||||
|
||||
## 📖 세부 내용 (Details · 8-field 추출)
|
||||
- **Concept:** 복잡한 작업을 단계/역할로 나눠 LLM 을 여러 번 호출하되, 흐름을 한 곳에서 조율.
|
||||
- **Implementation:** orchestrator(agent.ts)가 흐름 골격, 세부는 추출 모듈. 일반 작성은 단일 ChunkedWriter(outline→section→polish). 다중 전문가는 순차 디스패치(peer-context 전달).
|
||||
- **Design Reasoning:** 병렬 persona 는 hop 컨텍스트 누적·본문 손실·자원 폭주를 부른다(실측). 자원 제약(단일 GPU)이 순차를 강제. 흐름 가독성을 위해 골격은 분해하지 않음.
|
||||
- **Tradeoffs:** 자원 안전·본문 보존 ↔ 속도(순차)·단일 모델 의존.
|
||||
- **Failure Modes:** 에이전트 남발로 "방법론만 생성", OOM(병렬 다중 상주), orchestrator 재비대.
|
||||
- **Debugging Strategy:** 단계 인디케이터 추적, peer-context 길이, 모델 lifecycle, 한 단계씩 격리.
|
||||
- **Improvement Ideas:** 자원 감지 후 조건부 병렬, judge panel, 모드별 서브-오케스트레이터.
|
||||
- **Reusable Principles:** ① 에이전트 추가 전 "원본이 hop 에서 손실되는가" 점검. ② 동시성은 *배포 환경* 이 결정. ③ 흐름은 한 곳에서 읽히게, 구현만 추출. ④ 진행을 사용자에게 *가시화* 해 순차 지연 체감을 완화. ⑤ 단계별로 같은 모델이 역할만 바꾸는 것이 종종 N-에이전트보다 낫다.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[Agent Orchestration Pattern]], [[Reflection Pattern]], [[Critic Pattern]], [[프로젝트 독립 설계 원칙]]
|
||||
- **참조 맥락:** 작은 모델이 멀티에이전트/파이프라인을 설계할 때 과설계 회피 원리로 전이.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/agent.ts, agents/AgentWorkflowManager.ts, features/company/dispatcher.ts
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AI 학습용 지식 추출 초안.
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
id: aitrain-event-sourcing-storage
|
||||
title: "AITRAIN 이벤트소싱 저장"
|
||||
category: "AI_Training"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["AI training storage", "이벤트소싱 학습 추출", "저장 원리"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.89
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["ai-training", "event-sourcing", "storage", "transferable", "astraai"]
|
||||
raw_sources: ["AstraAI/src/features/_shared/eventSourcedStore.ts", "AstraAI/src/core/services.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[AITRAIN 이벤트소싱 저장]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
저장 설계의 전이 원리는 "이력이 가치면 append-only, 단순함·투명성을 위해 파일 우선, 반복 I/O 는 제네릭으로, 손상은 부분 격리" 이다 — 구현은 [[이벤트 소싱 스토어 패턴]], 결정 근거는 [[ADR-0001 이벤트 소싱 채택]]·[[ADR-0005 파일 기반 저장 채택]].
|
||||
|
||||
## 📖 세부 내용 (Details · 8-field 추출)
|
||||
- **Concept:** 상태를 덮어쓰지 않고 이벤트를 추가; 현재 상태는 재생으로 도출. 저장 매체는 사람이 읽는 파일.
|
||||
- **Implementation:** `createEventStore<E>({relPath, validate})` 제네릭 팩토리(JSONL append + 내결함 read + 판별 유니온 결과). 지식은 frontmatter Markdown.
|
||||
- **Design Reasoning:** 단일 사용자 로컬 → DB 운영 비용 회피, 투명성(직접 열람/편집), 무의존. 4벌 중복을 제네릭으로 흡수.
|
||||
- **Tradeoffs:** 이력·투명·무의존 ↔ 쿼리 성능·파일 증가·동시쓰기 잠금 직접.
|
||||
- **Failure Modes:** 파일 단조 증가(compaction 없음), 멀티프로세스 동시 append, 손상 줄.
|
||||
- **Debugging Strategy:** JSONL 줄 단위 파싱 검사, 워크스페이스 경로 해석, 검증 함수 통과율.
|
||||
- **Improvement Ideas:** 스냅샷+증분 compaction, SQLite 메타+파일 본문 하이브리드, 스키마 버전 업캐스팅.
|
||||
- **Reusable Principles:** ① 이력이 가치면 *추가만* 하라. ② 손상 1줄이 전체를 죽이지 않게 *부분 격리*. ③ 반복 I/O 패턴은 *제네릭 1벌* 로. ④ 가능하면 *사람이 읽는* 포맷(신뢰·디버깅). ⑤ 흔한 실패는 예외 대신 *결과 유니온* 으로 호출부에 강제.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[Event Bus Pattern]], [[Local Storage Pattern]], [[Repository Pattern]], [[프로젝트 독립 설계 원칙]]
|
||||
- **참조 맥락:** 작은 모델이 영속화/스토어를 설계할 때 원리로 전이.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/features/_shared/eventSourcedStore.ts, core/services.ts
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AI 학습용 지식 추출 초안.
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
id: aitrain-provider-abstraction
|
||||
title: "AITRAIN 프로바이더 추상화"
|
||||
category: "AI_Training"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["AI training provider", "어댑터 학습 추출", "외부 API 통합 원리"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.89
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["ai-training", "provider", "adapter", "transferable", "astraai"]
|
||||
raw_sources: ["AstraAI/src/features/providers/index.ts", "AstraAI/src/features/providers/anthropic.ts", "AstraAI/src/features/providers/types.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[AITRAIN 프로바이더 추상화]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
외부 API 통합의 전이 원리는 "차이는 가장자리(어댑터)에서 흡수하고 중심은 단일 포맷으로 정규화하며, 라우팅은 명시적 키로" 이다 — 구현은 [[LLM 프로바이더 추상화]], 결정 근거는 [[ADR-0008 로컬우선 LLM 클라우드 폴백]].
|
||||
|
||||
## 📖 세부 내용 (Details · 8-field 추출)
|
||||
- **Concept:** 다수의 이질적 외부 서비스를 호출부 입장에선 하나처럼 보이게 하는 어댑터 계층.
|
||||
- **Implementation:** model id prefix 라우팅(parseModelPrefix), 공급자별 streamX 어댑터, 응답을 공통 OpenAI-SSE 로 변환, 에러는 passthrough, 활성 공급자만 병렬 조회.
|
||||
- **Design Reasoning:** 같은 모델명이 여러 경로에 존재 → 출처 명시 필요; 호출부를 공급자 무관하게 유지하려 정규화; 프라이버시·비용 위해 로컬 우선.
|
||||
- **Tradeoffs:** 호출부 단순·교체 용이 ↔ 어댑터별 구현·정규화 비용·키 관리.
|
||||
- **Failure Modes:** 인증 실패, 응답 형식 차이, 모델 목록 노후화, role 교대/system 위치 같은 공급자 제약.
|
||||
- **Debugging Strategy:** 에러 Response.text(), 어댑터별 입력 정규화 점검, prefix 매칭 확인.
|
||||
- **Improvement Ideas:** prompt caching/tool use, 자동 모델 목록, 난이도 기반 라우팅.
|
||||
- **Reusable Principles:** ① *차이는 가장자리에서* 흡수, 중심은 단일 모델. ② 라우팅은 *명시 키(prefix)* 로 모호성 제거. ③ 입력/출력을 *정규화* 해 상위 코드를 공급자 무관하게. ④ 외부 실패는 삼키지 말고 *그대로 전달*해 호출부가 안내. ⑤ 기본은 *프라이버시·비용 안전*, 품질은 옵션.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[API Client Pattern]], [[Tool Calling Pattern]], [[프로젝트 독립 설계 원칙]]
|
||||
- **참조 맥락:** 작은 모델이 다중 외부 API/SDK 통합을 다른 프로젝트에서 설계할 때 전이.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/features/providers/index.ts, anthropic.ts, types.ts
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AI 학습용 지식 추출 초안.
|
||||
@@ -0,0 +1,102 @@
|
||||
---
|
||||
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 코드 사후기록 기반 교훈 추출.
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
id: debugging-playbook
|
||||
title: "디버깅 플레이북"
|
||||
category: "Software_Engineering"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["debugging playbook", "디버깅", "장애 모드", "failure mode", "복구 절차", "진단 단계"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.88
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["debugging", "failure-modes", "diagnostics", "recovery", "astraai"]
|
||||
raw_sources: ["AstraAI/src/core/errorHandler.ts", "AstraAI/src/core/services.ts", "AstraAI/src/retrieval/index.ts", "AstraAI/src/core/lock.ts", "AstraAI/src/lmstudio/lifecycleManager.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[디버깅 플레이북]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
디버깅은 "증상에서 근본 원인으로 좁혀 들어가는" 체계적 절차이며, 서브시스템별로 *흔한 장애 모드·진단 순서·복구·예방* 을 미리 정리하면 사람과 AI 에이전트 모두 빠르게 고친다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
각 서브시스템: **흔한 장애 모드 / 근본 원인 / 진단 단계 / 복구 절차 / 예방**. 공통 원칙: 증상→가설→*측정으로 검증*→최소 변경.
|
||||
|
||||
## 📖 세부 내용 (Details · 서브시스템별)
|
||||
|
||||
### LLM 호출 / 엔진 ([[LLM 프로바이더 추상화]])
|
||||
- **장애:** 빈 응답, timeout, 연결 거부(ECONNREFUSED), 404 모델 없음.
|
||||
- **근본 원인:** 엔진 미실행, 모델 미로드, URL 오설정, 작은 모델의 빈 출력.
|
||||
- **진단:** ErrorTranslator 카테고리 확인 → 엔진 상태(health) → 모델 목록 → fusionLog/로그.
|
||||
- **복구:** 다른 로컬 엔진 폴백(자동), 모델 재선택(lifecycle 재로드), timeout 상향.
|
||||
- **예방:** system 프롬프트 항상 채움(빈 응답↓), 폴백 경로 유지, 빈 응답을 soft failure 로 명시.
|
||||
|
||||
### 동시성 / 락 ([[동시성 제어 Lock Queue Transaction]])
|
||||
- **장애:** 데드락, 락 누수, 갱신 손실, 락 타임아웃.
|
||||
- **근본 원인:** release 누락(try/finally 없음), 동일성 비교 실수(L-02 토큰), 자원 직렬화 누락.
|
||||
- **진단:** `getActiveLockCount()` 추세, 타임아웃 에러 위치, 같은 resourceId 경합 로그.
|
||||
- **복구:** 타임아웃으로 깨운 뒤 재시도/안내, 프로세스 재시작(메모리 락 해제).
|
||||
- **예방:** 락은 반드시 try/finally, 토큰 기반 정리, 무거운 작업은 missionId 직렬화.
|
||||
|
||||
### 검색 / RAG ([[RAG 검색 파이프라인]])
|
||||
- **장애:** 관련 문서 누락(낮은 recall), 무관 문서 상위, 빈 결과.
|
||||
- **근본 원인:** 토큰화/동의어 누락, 하이브리드 스케일 편향, 운영 로그 미제외, 인덱스 stale.
|
||||
- **진단:** `fusionLog` 단계별 카운트, `rankBrainForEval`(recall@k), 토큰/예산 사용량, 청크 점수 분포.
|
||||
- **복구:** 동의어 추가, blend α 조정, 인덱스 clear/재빌드, scopeFolders 점검.
|
||||
- **예방:** 평가 하니스 정기 실행(프로덕션과 동일 경로), 정규화 일관, mtime 인덱스 무결성.
|
||||
|
||||
### 메모리 ([[5계층 메모리 시스템]])
|
||||
- **장애:** 오래된 사실을 현재처럼 답함, 기억 미반영, 잘못된 계층 선택.
|
||||
- **근본 원인:** `expiresAt` 미설정, 추출 실패(빈 catch 삼킴), 관련도 휴리스틱 오선별.
|
||||
- **진단:** 계층별 buildContext 출력 확인, 만료 필드 점검, distillation 로그.
|
||||
- **복구:** 만료 부여/엔트리 삭제(파일 직접 편집 가능 — 투명성), 재추출.
|
||||
- **예방:** 시한부 지식에 expiresAt, 분류 규칙 명문화([[아키텍처 휴리스틱]]).
|
||||
|
||||
### 검증 / 환각 ([[Intelligence 검증 레이어]])
|
||||
- **장애:** 환각(근거 없는 단정), 과도한 헤지, 위험 답변 미검수.
|
||||
- **근본 원인:** 검색 근거 0인데 단정, 확신도 임계 오설정, JSON 파싱 실패.
|
||||
- **진단:** 확신도 factor 분해(footer), 검색 청크 수, Critic 발동 여부, raw 응답 검사.
|
||||
- **복구:** Epistemic Guard 강도↑(근거 없을 때), 임계 조정, 균형 괄호 파서 fallback.
|
||||
- **예방:** "근거 없으면 확인 필요" 강제, 결정론 신호 항상, 파서 방어.
|
||||
|
||||
### 모델 수명 / 메모리(VRAM) ([[ADR-0004 순차 디스패치 채택]])
|
||||
- **장애:** OOM, 모델 로드 실패, VRAM 미해제.
|
||||
- **근본 원인:** 병렬 다중 모델 상주, 이전 모델 미언로드.
|
||||
- **진단:** lifecycle 상태, 시스템 메모리, 모델 전환 로그.
|
||||
- **복구:** 이전 모델 unload 후 재로드, idle timeout 단축, 순차 강제.
|
||||
- **예방:** "한 번에 한 모델" 불변식, gpuOffloadRatio 등 로드 설정 조정.
|
||||
|
||||
### VS Code 확장 ([[VSCode 확장 구조와 생명주기]])
|
||||
- **장애:** 활성화 실패, 명령 미등록, 자원 누수, 패널 안 열림.
|
||||
- **근본 원인:** activate 예외, disposable 미등록, 웹뷰 타이밍.
|
||||
- **진단:** activate console/OutputChannel 로그, subscriptions 등록 여부.
|
||||
- **복구:** 확장 reload, deactivate 정리 확인.
|
||||
- **예방:** 모든 자원 subscriptions 등록, best-effort 옵셔널 체이닝, 부트스트랩 비차단.
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"로그를 보면 답이 있다" 는 빈 catch 가 로그를 삼키면 깨진다 — 그래서 빈 catch 는 이유 주석 + 가능하면 logError 동반이 원칙. 진단은 *측정* 으로 검증하라(추측으로 재시작 금지).
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
ErrorTranslator(증상 분류), fusionLog/rankBrainForEval(검색 진단), 확신도 footer(검증 진단), lifecycle(VRAM) [S1~S5].
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[교훈 라이브러리 Lessons Learned]], [[안티패턴 카탈로그]], [[소프트웨어 실패 라이브러리]], [[리팩토링 플레이북]]
|
||||
- **참조 맥락:** 로컬 LLM/개발자가 장애를 만났을 때 서브시스템별 진단 순서로 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/core/errorHandler.ts — 증상 분류
|
||||
- [S2] AstraAI/src/core/services.ts — 엔진 폴백/빈 응답
|
||||
- [S3] AstraAI/src/retrieval/index.ts — fusionLog/평가 경로
|
||||
- [S4] AstraAI/src/core/lock.ts — 락 진단
|
||||
- [S5] AstraAI/src/lmstudio/lifecycleManager.ts — 모델 수명/VRAM
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 서브시스템별 디버깅 절차 초안.
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
id: refactoring-playbook
|
||||
title: "리팩토링 플레이북"
|
||||
category: "Software_Engineering"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["refactoring playbook", "리팩토링", "기술 부채", "technical debt", "마이그레이션 경로", "확장 우려"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.87
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["refactoring", "technical-debt", "scaling", "migration", "astraai"]
|
||||
raw_sources: ["AstraAI/src/agent.ts", "AstraAI/src/features/_shared/eventSourcedStore.ts", "AstraAI/src/retrieval/index.ts", "AstraAI/src/features/company/dispatcher.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[리팩토링 플레이북]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
리팩토링은 "동작을 바꾸지 않고 구조를 개선" 하는 것이며, AstraAI 의 실제 리팩터링(중복 통합·동적→정적·persona 단순화·god-class 추출)에서 *언제·어떻게 안전하게 진화시키는가* 의 절차를 뽑을 수 있다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
- 현재 한계 → 기술 부채 → 리팩토링 기회 → 확장 우려 → 마이그레이션 경로.
|
||||
- 안전 리팩토링 = 테스트로 동작 고정 → 작은 단계 → 회귀 격리.
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
|
||||
### 현재 한계 (Current limitations)
|
||||
- `agent.ts` orchestrator 가 여전히 큼(import 100+줄) — 모드 분기가 늘면 재비대.
|
||||
- 파일 기반 저장은 brain 이 수만 파일로 커지면 스캔/인덱싱 비용 급증.
|
||||
- 이벤트 JSONL 은 compaction 없어 단조 증가.
|
||||
- 검색 동의어 사전이 수작업이라 도메인 확장 시 누락.
|
||||
- 확신도/검증 가중치가 휴리스틱(데이터 보정 전).
|
||||
- 순차 디스패치는 누적 지연 — 멀티 GPU 미활용.
|
||||
|
||||
### 기술 부채 (Technical debt)
|
||||
- 일부 `as any` 캐스팅(외부 JSON 경계).
|
||||
- 하드코딩 모델 목록(클라우드 어댑터) 노후화.
|
||||
- 메모리 계층 경계 모호(장기 decision vs 프로젝트 ADR).
|
||||
|
||||
### 리팩토링 기회 (Refactoring opportunities)
|
||||
1. **중복 → 제네릭/공통 모듈:** eventSourcedStore 처럼 반복 패턴을 팩토리로 흡수(이미 적용). 다음 후보: contextBuilders 의 유사 블록.
|
||||
2. **동적 → 정적:** 이유가 사라진 `await import` 를 정적 import 로(이미 dispatcher 적용).
|
||||
3. **god-class → 골격+추출:** 모드별 서브-오케스트레이터 분리(chat/agent/company).
|
||||
4. **휴리스틱 → 학습:** 확신도/검색 가중치를 골든셋으로 보정.
|
||||
|
||||
### 확장 우려 (Scaling concerns)
|
||||
- brain 파일 수 ↑ → 인덱싱 시간/메모리. → 파일 watch + 증분 인덱스, 또는 메타데이터 DB.
|
||||
- 이벤트 수 ↑ → 재생 비용. → 스냅샷 + 증분.
|
||||
- 사용자 수 ↑(멀티유저) → 파일 잠금/일관성 한계. → DB 이전.
|
||||
|
||||
### 마이그레이션 경로 (Suggested migration paths)
|
||||
- **저장:** 파일 → (SQLite 메타 + 파일 본문 하이브리드) → 필요 시 벡터 DB 외부화. *본문 투명성은 유지.*
|
||||
- **검색:** TF-IDF → +임베딩(이미) → +reranker 모델 → BM25/벡터 DB.
|
||||
- **에이전트:** 순차 → (자원 감지) → 조건부 병렬(워커 풀). 환경을 런타임 감지해 전략 전환.
|
||||
- **오케스트레이터:** 단일 → 모드별 분리 → 파이프라인/미들웨어 체인.
|
||||
|
||||
### 안전 절차 (How to refactor safely)
|
||||
1. 동작을 테스트로 고정(특히 순수 함수 — chunker/scoring 처럼).
|
||||
2. 회귀 위험을 *플래그로 격리*(예: `chunkLevelRetrieval` 처럼 새 경로를 분리).
|
||||
3. 작은 단계로 커밋, 각 단계 후 평가 하니스(recall@k/회귀 리포트) 재실행.
|
||||
4. 동일 scoring 경로 재사용으로 *측정 무결성* 유지(평가와 프로덕션이 같은 코드).
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
리팩토링은 가치지만 *동작 변경 없는* 범위를 지켜야 한다. 기능 추가와 섞으면 회귀 원인 추적이 어렵다 — 분리된 커밋이 원칙.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
중복 통합(eventSourcedStore), 동적→정적(dispatcher), persona 단순화(ChunkedWriter), 플래그 격리(chunkLevelRetrieval) [S1~S4].
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[디버깅 플레이북]], [[안티패턴 카탈로그]], [[엔지니어링 트레이드오프 분석]], [[아키텍처 휴리스틱]]
|
||||
- **참조 맥락:** 로컬 LLM 이 기존 코드를 개선/확장할 때 안전 절차와 마이그레이션 경로로 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/features/_shared/eventSourcedStore.ts — 중복 통합
|
||||
- [S2] AstraAI/src/features/company/dispatcher.ts — 동적→정적
|
||||
- [S3] AstraAI/src/agents/AgentWorkflowManager.ts — persona 단순화
|
||||
- [S4] AstraAI/src/retrieval/index.ts — 플래그 격리, 평가 무결성
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 리팩터링 사례 기반 플레이북 초안.
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
id: architecture-heuristics
|
||||
title: "아키텍처 휴리스틱"
|
||||
category: "Software_Engineering"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["architecture heuristics", "결정 규칙", "언제 무엇을 쓰나", "design heuristics", "의사결정 규칙"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.89
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["heuristics", "decision-rules", "architecture", "engineering", "astraai"]
|
||||
raw_sources: ["AstraAI 전체 분석", "본 위키 ADR/트레이드오프 모음"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[아키텍처 휴리스틱]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
좋은 설계자는 매번 0부터 고민하지 않고 *결정 규칙(휴리스틱)* 을 적용한다 — "언제 X 를 만들고, 언제 만들지 않는가" 를 명시한 규칙 모음은 작은 모델에게 가장 실용적인 설계 지능이다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
- 휴리스틱 = "조건 → 권장 선택" 의 빠른 판단 규칙. 절대 법칙이 아니라 *기본값*.
|
||||
- AstraAI 의 실제 결정에서 역추출.
|
||||
|
||||
## 📖 세부 내용 (Details · 결정 규칙)
|
||||
|
||||
### 새 서비스(클래스/모듈)를 언제 만드나
|
||||
- **만든다:** 명확한 단일 책임 + 다른 곳에서 재사용 + 교체/테스트 필요 + 외부 효과(I/O·API) 캡슐화. → 인터페이스로 추상화([[의존성 주입과 서비스 인터페이스]]).
|
||||
- **안 만든다:** 한 곳에서만 쓰는 3줄 로직, 상태 없는 순수 변환(그냥 함수), "미래에 필요할지도" (YAGNI).
|
||||
|
||||
### 언제 이벤트(append-only)를 쓰나
|
||||
- **쓴다:** 변경 *이력 자체가 가치*, 감사/재현 필요, 추가만 하고 수정 드뭄, 여러 소비자가 같은 사실을 다르게 투영.
|
||||
- **안 쓴다:** 마지막 값만 중요, 빈번한 in-place 수정, 복잡 조인 쿼리 중심 → 상태 저장/DB.
|
||||
|
||||
### 언제 큐(동시성 제한)를 쓰나
|
||||
- **쓴다:** 대량 작업이 자원(메모리/IO/소켓)을 폭주시킬 수 있을 때, 처리량을 일정하게.
|
||||
- **안 쓴다:** 작업이 소수거나 이미 락으로 직렬화될 때(중복 제어 불필요).
|
||||
|
||||
### 언제 락을 쓰나
|
||||
- **쓴다:** 같은 공유 자원(파일/세션)에 read-modify-write 가 동시에 일어날 수 있을 때.
|
||||
- **안 쓴다:** 불변 데이터, 단일 소유자, append-only 단일 프로세스.
|
||||
|
||||
### 언제 메모리 타입을 나누나
|
||||
- **나눈다:** 수명/만료/우선순위/검색 방식이 다른 기억이 섞일 때([[5계층 메모리 시스템]]).
|
||||
- **안 나눈다:** 단발성 도구(기억 불필요), 또는 전부 같은 정책이면 단일 버퍼.
|
||||
|
||||
### 언제 에이전트를 만드나 / 만들지 않나
|
||||
- **만든다:** 진짜 독립적 전문성 + 산출물이 명확히 분리 + 자원이 여러 모델/순차를 감당.
|
||||
- **만들지 않는다:** 단일 작성자가 역할만 바꿔도 되는 작업, hop 에서 원본 손실 위험, 자원이 빠듯할 때([[ADR-0003 단일작성자 다중역할 멀티에이전트]]). **기본값은 "에이전트를 늘리지 말 것".**
|
||||
|
||||
### 언제 상태를 영속화하나 / 휘발로 두나
|
||||
- **영속:** 세션을 넘어 필요(사용자 선호, 프로젝트 결정, 학습 케이스), 투명성 필요.
|
||||
- **휘발:** 현재 턴/세션 한정(단기 버퍼), 재계산이 싼 파생값, 민감해서 남기면 안 되는 것.
|
||||
|
||||
### 언제 추상화(인터페이스)를 도입하나
|
||||
- **도입:** 구현이 2개 이상이거나 곧 생김(로컬/클라우드 엔진), 테스트에 가짜가 필요(LLM 호출).
|
||||
- **안 함:** 구현이 하나뿐이고 변할 조짐 없음(과추상화 = 비용).
|
||||
|
||||
### 언제 결정론 vs LLM 을 쓰나
|
||||
- **결정론:** 매 턴 돌릴 저비용 신호(정규식·카운트·점수). latency 0 이 중요할 때.
|
||||
- **LLM:** 의미 판단이 필요하고, 결정론 신호가 위험을 표시했을 때만(조건부)([[ADR-0009 결정론 항상 LLM검증 조건부]]).
|
||||
|
||||
### 언제 동기 vs 비동기/병렬을 쓰나
|
||||
- **병렬:** 독립 작업 + 자원 여유. 의존 없으면 `Promise.all`.
|
||||
- **순차:** 자원 제약(모델 상주), 출력이 다음 입력(peer-context), 데드락 위험.
|
||||
|
||||
### 파일 분리/추출 기준
|
||||
- 한 파일이 한 화면을 크게 넘고 *여러 책임* 을 가지면 추출. 단, *흐름 골격* 은 한 곳에 남긴다([[ADR-0010 오케스트레이터 골격 모듈추출]]).
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
휴리스틱은 *기본값* 이지 법칙이 아니다. 충돌하면 [[엔지니어링 트레이드오프 분석]] 으로 내려가 맥락(자원·규모·팀)에 맞춰 판단하라. 가장 강한 메타 규칙: **YAGNI(필요해질 때 만들어라) + 단순함 우선 + 환경이 동시성·저장·검증을 결정한다.**
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
각 규칙은 AstraAI 의 실제 ADR 결정과 1:1 대응. 신규 기능 설계 시 이 목록을 먼저 훑는다.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[엔지니어링 트레이드오프 분석]], [[안티패턴 카탈로그]], [[리팩토링 플레이북]], [[프로젝트 독립 설계 원칙]]
|
||||
- **참조 맥락:** 로컬 LLM 이 "새 것을 만들지 말지" 를 빠르게 판단할 때 1차 규칙으로 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI 전체 ADR/서브시스템 결정의 역추출(본 위키 Engineering_Intelligence 모음)
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 결정 규칙 추출 초안.
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
id: anti-patterns-catalog
|
||||
title: "안티패턴 카탈로그"
|
||||
category: "Software_Engineering"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["anti-patterns", "안티패턴", "피해야 할 것", "코드 냄새", "code smell"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.9
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["anti-pattern", "engineering", "pitfalls", "code-smell", "astraai"]
|
||||
raw_sources: ["AstraAI/src/core/lock.ts", "AstraAI/src/memory/index.ts", "AstraAI/src/retrieval/index.ts", "AstraAI/src/features/company/dispatcher.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[안티패턴 카탈로그]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
안티패턴은 "처음엔 그럴듯하지만 시간이 지나면 버그·복잡도를 부르는 습관" 이며, AstraAI 가 *실제로 겪고 고친* 사례에서 추출한 것이라 작은 모델이 회피해야 할 1순위 목록이다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
각 안티패턴: **설명 / 왜 위험한가 / 증상 / 더 나은 대안 / 이 프로젝트의 사례(있으면)**.
|
||||
|
||||
## 📖 세부 내용 (Details · 안티패턴 모음)
|
||||
|
||||
### A-01. 무음 빈 catch (Silent swallow)
|
||||
- **설명:** `try { ... } catch {}` 로 에러를 이유 없이 삼킴.
|
||||
- **왜 위험:** 실패가 숨겨져 디버깅 불가, 잘못된 상태로 진행.
|
||||
- **증상:** "왜 아무 일도 안 일어나지?", 로그 없는 실패.
|
||||
- **더 나은 대안:** 본류 에러는 throw/처리. 부가 작업만 삼키되 *이유 주석* 필수.
|
||||
- **사례:** AstraAI 는 부가 작업에 한해 `catch { /* should never break main flow */ }` 로 정당화 [S2].
|
||||
|
||||
### A-02. Promise/객체 동일성에 로직 걸기
|
||||
- **설명:** `===` 로 Promise·새 객체를 비교해 분기.
|
||||
- **왜 위험:** `.then()`/`.map()` 등은 매번 새 인스턴스 → 비교 항상 false.
|
||||
- **증상:** cleanup 안 됨, 메모리 누수, 간헐 race.
|
||||
- **더 나은 대안:** 명시적 토큰/ID 비교.
|
||||
- **사례:** lock.ts 의 옛 버그 → Symbol 토큰으로 수정 [S1].
|
||||
|
||||
### A-03. `||` 로 기본값 — 의미 있는 0/''/false 삼킴
|
||||
- **설명:** `limit || 8` 처럼 falsy 전체를 대체.
|
||||
- **왜 위험:** 0/''/false 가 유효값인데 기본값으로 둔갑.
|
||||
- **증상:** "검색 끄기(0)" 가 무시되는 류의 미묘한 버그.
|
||||
- **더 나은 대안:** `??`(nullish) 사용.
|
||||
- **사례:** `brainFileLimit ?? 8` [S3].
|
||||
|
||||
### A-04. 에이전트 남발 (Multi-agent over-engineering)
|
||||
- **설명:** 문제마다 새 persona/에이전트를 추가.
|
||||
- **왜 위험:** hop 마다 컨텍스트 누적·원본 손실, 자원 폭증, 디버깅 난해.
|
||||
- **증상:** "분석 방법론" 만 나오고 실제 결과 없음, OOM.
|
||||
- **더 나은 대안:** 단일 작성자 다중 역할, 정말 필요한 협업만 순차.
|
||||
- **사례:** 5-persona → ChunkedWriter 전환 [S4].
|
||||
|
||||
### A-05. 거대 god-class (흐름·구현 한 덩어리)
|
||||
- **설명:** 모든 로직을 한 클래스/파일에.
|
||||
- **왜 위험:** 테스트 불가, 병합 충돌, 변경 두려움.
|
||||
- **증상:** 수천 줄 파일, "여길 고치면 저기가 깨짐".
|
||||
- **더 나은 대안:** 흐름 골격만 남기고 구현을 순수 모듈로 추출([[ADR-0010 오케스트레이터 골격 모듈추출]]).
|
||||
|
||||
### A-06. 이유 없는 동적 require/import
|
||||
- **설명:** 습관적으로 `await import()` 를 핫패스에서 반복.
|
||||
- **왜 위험:** 흐름 불명확, 불필요 오버헤드, 진짜 이유가 사라져도 잔존.
|
||||
- **증상:** 같은 모듈을 매 호출 동적 로드.
|
||||
- **더 나은 대안:** 순환이 없으면 정적 import. 동적은 *진짜 무거운/드문* 기능에만 + 이유 주석.
|
||||
- **사례:** dispatcher 의 require 8회 → 정적 promote [S4].
|
||||
|
||||
### A-07. 형식만 믿는 LLM 출력 파싱
|
||||
- **설명:** "JSON 만 출력" 을 믿고 `JSON.parse(raw)` 직접.
|
||||
- **왜 위험:** 작은 모델은 코드펜스·잡설을 섞어 파싱 실패.
|
||||
- **증상:** 간헐 파싱 예외, 빈 결과.
|
||||
- **더 나은 대안:** 균형 괄호 스캔 추출 + fallback. "프롬프트와 파서를 함께 설계".
|
||||
- **사례:** criticAgent 의 균형 `{}` 파서 [참조: [[Intelligence 검증 레이어]]].
|
||||
|
||||
### A-08. 점수 부분 정규화 (편향 융합)
|
||||
- **설명:** 여러 신호를 합치며 일부만 정규화.
|
||||
- **왜 위험:** 정규화 안 된 신호가 스케일로 상위 독식.
|
||||
- **증상:** 새 신호를 더했는데 품질이 *나빠짐*.
|
||||
- **더 나은 대안:** 모든 신호를 동일 스케일로 정규화 후 가중 합.
|
||||
- **사례:** 하이브리드 검색 [S3].
|
||||
|
||||
### A-09. 환경 무시한 동시성 가정
|
||||
- **설명:** "병렬이 빠르니 무조건 병렬".
|
||||
- **왜 위험:** 자원(RAM/GPU)을 넘으면 OOM·스왑으로 *더 느려지거나 죽음*.
|
||||
- **증상:** 로컬에서 멀티모델 로드 실패.
|
||||
- **더 나은 대안:** 타깃 하드웨어 기준으로 동시성 결정([[ADR-0004 순차 디스패치 채택]]).
|
||||
|
||||
### A-10. 만료 없는 영구 메모리
|
||||
- **설명:** 모든 기억을 영구 저장.
|
||||
- **왜 위험:** 시한부 사실(분기 계획)이 만료 후에도 검색돼 오답 유발.
|
||||
- **증상:** "지난 분기 계획" 을 현재처럼 답함.
|
||||
- **더 나은 대안:** temporal marker(`expiresAt`)로 자동 제외 + 증류 보존 [참조: [[5계층 메모리 시스템]]].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
일부 "안티패턴" 은 맥락에 따라 정당하다 — god-class(흐름 가독성), 빈 catch(부가 작업), 동적 import(무거운 기능). 핵심은 *이유를 명시하고 의식적으로* 쓰는가다. 무의식적 습관일 때만 안티패턴.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
모두 AstraAI 가 실제로 마주쳐 고치거나 의식적으로 관리하는 사례. [[교훈 라이브러리 Lessons Learned]] 와 짝을 이룬다.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[교훈 라이브러리 Lessons Learned]], [[아키텍처 휴리스틱]], [[디버깅 플레이북]], [[코딩 컨벤션과 주석 철학]]
|
||||
- **참조 맥락:** 로컬 LLM 이 코드 작성/리뷰 시 회피 목록으로 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/core/lock.ts — 동일성 비교 안티패턴
|
||||
- [S2] AstraAI/src/memory/index.ts — 빈 catch(정당화된 형태)
|
||||
- [S3] AstraAI/src/retrieval/index.ts — ?? vs ||, 부분 정규화
|
||||
- [S4] AstraAI/src/features/company/dispatcher.ts, AgentWorkflowManager.ts — 에이전트 남발, 동적 require
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 사례 기반 안티패턴 카탈로그 초안.
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
id: engineering-tradeoff-analysis
|
||||
title: "엔지니어링 트레이드오프 분석"
|
||||
category: "Software_Engineering"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["tradeoff analysis", "트레이드오프", "무엇을 최적화 무엇을 희생", "설계 절충", "언제 실패하나"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.9
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["tradeoff", "engineering", "decision", "architecture", "astraai"]
|
||||
raw_sources: ["AstraAI 전체 서브시스템 분석", "AstraAI/src/core/*", "AstraAI/src/retrieval/*", "AstraAI/src/intelligence/*"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[엔지니어링 트레이드오프 분석]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
모든 설계는 "무언가를 최적화하기 위해 무언가를 희생"한 결과다 — AstraAI 의 각 서브시스템이 *무엇을 얻고 무엇을 포기했으며, 언제 그 선택이 깨지는지* 를 명시하면, 작은 모델이 맥락에 맞는 설계를 고를 수 있다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
- 트레이드오프 분석 = (최적화한 것 / 희생한 것 / 더 단순한 대안 / 더 확장적인 대안 / 이 설계가 실패하는 조건 / 다른 설계가 나은 조건).
|
||||
- 정답은 *맥락 의존* — 같은 결정도 환경이 바뀌면 오답이 된다.
|
||||
|
||||
## 📖 세부 내용 (Details · 서브시스템별 트레이드오프)
|
||||
|
||||
### 1. 이벤트 소싱 JSONL 저장 ([[이벤트 소싱 스토어 패턴]])
|
||||
- **최적화:** 이력 보존, 내결함, 코드 중복 제거, 무의존.
|
||||
- **희생:** 저장 공간(단조 증가), 상태 재생 비용, 복잡 쿼리.
|
||||
- **더 단순한 대안:** 상태 JSON 1개 덮어쓰기(이력 불필요 시).
|
||||
- **더 확장적인 대안:** SQLite/이벤트 스토어 DB + 스냅샷 compaction.
|
||||
- **실패 조건:** 이벤트가 수만 건↑, 멀티프로세스 동시 쓰기, 복잡 조인 필요.
|
||||
- **다른 설계가 나을 때:** 마지막 값만 중요하거나, 분석 쿼리가 핵심일 때.
|
||||
|
||||
### 2. 5계층 메모리 ([[5계층 메모리 시스템]])
|
||||
- **최적화:** 컨텍스트 정밀 선별, 계층별 정책(만료/승급).
|
||||
- **희생:** 분류 결정 비용, 매니저 복잡도, 다중 저장 파일.
|
||||
- **더 단순한 대안:** 최근 N 메시지 버퍼 + 단일 노트 저장.
|
||||
- **더 확장적인 대안:** 계층별 임베딩 + 벡터 DB 메타 필터.
|
||||
- **실패 조건:** 분류 규칙이 모호해 "어디 저장?" 이 매번 논쟁, 관련도 휴리스틱 오선별.
|
||||
- **다른 설계가 나을 때:** 단발성 도구(기억 불필요), 또는 순수 의미검색이 전부일 때.
|
||||
|
||||
### 3. 멀티에이전트(단일 작성자/순차) ([[Agent 오케스트레이터 분해]])
|
||||
- **최적화:** 자원 안전(한 모델 상주), 본문 보존, 컨텍스트 절약.
|
||||
- **희생:** 처리량/속도(순차), 단일 모델 품질 의존, 병렬 다양성.
|
||||
- **더 단순한 대안:** 단일 프롬프트 1회 호출(짧은 작업).
|
||||
- **더 확장적인 대안:** 워커 풀 병렬 + judge panel 합의(자원 충분 시).
|
||||
- **실패 조건:** 멀티 GPU 표준화, 대규모 병렬 리서치 요구, 누적 지연이 인내 초과.
|
||||
- **다른 설계가 나을 때:** 서버 배포·속도 critical.
|
||||
|
||||
### 4. 하이브리드 검색(결정론 우선) ([[RAG 검색 파이프라인]])
|
||||
- **최적화:** 가용성(임베딩 없어도 동작), 설명가능성.
|
||||
- **희생:** 스케일 정규화 복잡, 수작업 동의어 유지, 형태소 미분석.
|
||||
- **더 단순한 대안:** 키워드 includes 매칭.
|
||||
- **더 확장적인 대안:** BM25 + 벡터 DB + reranker 모델.
|
||||
- **실패 조건:** brain 규모 폭증(sparse 인덱스 부담), 동의어 사전 누락 누적.
|
||||
- **다른 설계가 나을 때:** 대규모·고품질 임베딩 상시 가용.
|
||||
|
||||
### 5. 검증(결정론 항상/LLM 조건부) ([[Intelligence 검증 레이어]])
|
||||
- **최적화:** 낮은 평균 latency, 위험 시 정밀 검수.
|
||||
- **희생:** 임계 오설정 시 미탐/오탐, 휴리스틱 가중치, 1-pass 약함.
|
||||
- **더 단순한 대안:** 검증 없음(빠르나 환각 방치).
|
||||
- **더 확장적인 대안:** 골든셋 학습 가중치 + 다회전 debate.
|
||||
- **실패 조건:** 모델 교체로 신호 분포 변화, 위험 도메인에서 1-pass 부족.
|
||||
- **다른 설계가 나을 때:** 대형 모델/서버에서 상시 LLM 검수 감당 가능.
|
||||
|
||||
### 6. 파일 저장(투명성 우선) ([[ADR-0005 파일 기반 저장 채택]])
|
||||
- **최적화:** 투명성, 무의존, git 친화.
|
||||
- **희생:** 쿼리 성능, 동시쓰기 잠금 직접, 인덱스 자가구축.
|
||||
- **실패 조건:** 멀티유저, 수만 파일, 복잡 분석.
|
||||
- **다른 설계가 나을 때:** 다중 사용자 SaaS, 대규모 분석.
|
||||
|
||||
### 7. 수동 DI(단일 composition root) ([[ADR-0006 수동 의존성주입 인터페이스 서비스]])
|
||||
- **최적화:** 투명한 조립, 테스트성, 무의존.
|
||||
- **희생:** 조립 코드 장황, 배선 수작업.
|
||||
- **실패 조건:** 모듈/조립 지점 폭증.
|
||||
- **다른 설계가 나을 때:** 대규모 팀/모듈, 동적 수명관리 필요 시 컨테이너.
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
이 표의 모든 "희생" 은 *현재 환경(로컬·단일 사용자·작은 모델)* 전제다. 환경이 바뀌면 같은 표의 우열이 뒤집힌다 — 트레이드오프는 절대값이 아니라 *맥락 함수*.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
각 행은 대응 ADR/서브시스템 문서의 결정 요약. 신규 설계 시 "내 환경에서 이 희생을 감당할 수 있나?" 를 먼저 묻는다.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[아키텍처 휴리스틱]], [[안티패턴 카탈로그]], [[ADR-0001 이벤트 소싱 채택]], [[리팩토링 플레이북]]
|
||||
- **참조 맥락:** 로컬 LLM 이 설계 선택 시 "무엇을 희생하는지" 와 "언제 깨지는지" 를 평가할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI 서브시스템 분석(core/retrieval/intelligence/memory) 및 본 위키의 ADR 모음
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 트레이드오프 종합 분석 초안 생성.
|
||||
@@ -0,0 +1,120 @@
|
||||
---
|
||||
id: software-failure-library
|
||||
title: "소프트웨어 실패 라이브러리"
|
||||
category: "Software_Engineering"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["failure library", "실패 라이브러리", "failure modes", "장애 모드 카탈로그", "how things break"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.89
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["failure", "engineering", "debugging", "patterns", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI 사후기록(lock/retrieval/dispatcher 등)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[소프트웨어 실패 라이브러리]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
모든 아키텍처 패턴은 *특유의 방식으로 깨진다* — 패턴별 (장애 모드 → 증상 → 근본 원인 → 진단 → 복구 → 예방)을 알면, AI/개발자가 실패를 *조기에 인식하고 회피* 할 수 있다. 이것이 패턴 카탈로그의 어두운 쌍둥이다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
각 패턴 항목 = **Failure Modes / Symptoms / Root Causes / Debugging / Recovery / Prevention**. 패턴 카드의 "실패 사례" 와 [[디버깅 플레이북]] 을 패턴 축으로 재구성.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴별 실패)
|
||||
|
||||
### [[RAG Pattern]] / [[Caching Pattern]]
|
||||
- **Failure Modes:** 낮은 recall, 무관 상위, stale 결과, 빈 결과.
|
||||
- **Symptoms:** "분명 있는데 못 찾음", 엉뚱한 인용, 옛 데이터 제공.
|
||||
- **Root Causes:** 동의어 미확장, 하이브리드 부분 정규화(편향), 청크 과대, 인덱스 stale, 무효화 누락.
|
||||
- **Debugging:** fusionLog 단계 카운트, recall@k 평가, 점수 분포, mtime 비교.
|
||||
- **Recovery:** 동의어 추가, α 조정, 인덱스 재빌드, 캐시 무효화.
|
||||
- **Prevention:** 평가 하니스 정기 실행(프로덕션 동일 경로), 동일 스케일 정규화, 변경 감지 무효화.
|
||||
|
||||
### [[Memory Pattern]]
|
||||
- **Failure Modes:** 옛 사실 재현, 기억 미반영, 잘못된 계층.
|
||||
- **Symptoms:** 만료 지식이 현재처럼, 사용자 정보 망각.
|
||||
- **Root Causes:** expiresAt 미설정, 추출 빈 catch 삼킴, 관련도 오선별, 분류 모호.
|
||||
- **Debugging:** 계층별 컨텍스트 출력, 만료 필드, distillation 로그.
|
||||
- **Recovery:** 만료 부여/엔트리 삭제(파일 편집), 재추출.
|
||||
- **Prevention:** 시한부엔 만료, 분류 규칙 명문화, 증류로 정리.
|
||||
|
||||
### [[Agent Orchestration Pattern]] / [[Reflection Pattern]] / [[Critic Pattern]]
|
||||
- **Failure Modes:** "방법론만 생성", 환각 통과, OOM, latency 폭증, 무한 루프.
|
||||
- **Symptoms:** 실제 산출물 없음, 근거 없는 단정, 모델 로드 실패, 느림.
|
||||
- **Root Causes:** 에이전트 남발(hop 손실), 병렬 다중 상주, 무조건 LLM 검수, 종료 조건 부재, JSON 직접 파싱.
|
||||
- **Debugging:** 단계 인디케이터, peer-context 길이, 확신도 factor, raw 응답, lifecycle.
|
||||
- **Recovery:** 단일 작성자 전환, 순차+한 모델, 조건부 검수, 라운드 상한, 균형 괄호 파서.
|
||||
- **Prevention:** "에이전트 추가 전 정보 손실 점검", 자원 기준 동시성, 결정론 우선 검증.
|
||||
|
||||
### [[Tool Calling Pattern]] / [[Command Pattern]]
|
||||
- **Failure Modes:** 임의 명령 실행, 경로 탈출, 무한 호출, undo 불완전.
|
||||
- **Symptoms:** 보안 사고, 권한 밖 파일 접근, 반복 실행.
|
||||
- **Root Causes:** 모델 출력 미검증, 경로 미검증, 승인 게이트 부재, 멱등성 부재.
|
||||
- **Debugging:** 액션 파싱 로그, 검증 결과, 승인 큐 상태.
|
||||
- **Recovery:** 화이트리스트 제한, 승인 요구, 롤백.
|
||||
- **Prevention:** 모델 출력을 신뢰 안 된 입력으로, validatePath/sanitize, 승인 게이트.
|
||||
|
||||
### [[State Management Pattern]] / [[React State Pattern]] / [[Data Flow Pattern]]
|
||||
- **Failure Modes:** 동기화 버그, stale 파생, 불필요 리렌더, 역류.
|
||||
- **Symptoms:** 같은 데이터 불일치, 화면-데이터 어긋남, 성능 저하.
|
||||
- **Root Causes:** 중복 상태, 파생값 저장, 서버/클라 상태 혼동, 전역 남용, 경계 정규화 누락.
|
||||
- **Debugging:** 상태 출처 추적, 변경 로그, 리렌더 프로파일.
|
||||
- **Recovery:** 단일 출처로 통합, 파생은 계산, 서버 상태 분리.
|
||||
- **Prevention:** SSOT, 단방향 흐름, 경계 정규화.
|
||||
|
||||
### [[Async Concurrency Pattern]] / [[Background Worker Pattern]] / [[Background Task Pattern]]
|
||||
- **Failure Modes:** 데드락, 락 누수, 좀비 작업, OOM, 중복 실행, UI 멈춤.
|
||||
- **Symptoms:** 멈춤, 메모리 증가, 같은 작업 N번, 응답 없음.
|
||||
- **Root Causes:** release 누락, 취소 미전파, 무한 병렬, 재진입, 객체 동일성 비교(L-02), dispose 누락.
|
||||
- **Debugging:** active lock 수, 타임아웃 위치, 큐 길이, 메모리 추세.
|
||||
- **Recovery:** try/finally release, 동시성 상한, 재진입 가드, 토큰 정리.
|
||||
- **Prevention:** 락은 try/finally, AbortSignal 전파, 하드웨어 기준 동시성, 멱등성.
|
||||
|
||||
### [[Event Bus Pattern]] / [[IPC Pattern]] / [[Plugin Architecture Pattern]]
|
||||
- **Failure Modes:** 추적 불가 흐름, 리스너 누수, 직렬화 실패, 플러그인이 코어 크래시.
|
||||
- **Symptoms:** "누가 이걸 했지?", 중복 핸들러, 통신 행, 앱 죽음.
|
||||
- **Root Causes:** 리스너 해제 누락, 외부 입력 미검증, 함수/순환 직렬화, 플러그인 격리 부재, 이벤트 이름 오타.
|
||||
- **Debugging:** 리스너 목록, 메시지 로그, 직렬화 검증, 플러그인 로드 로그.
|
||||
- **Recovery:** 해제 추가, 입력 검증, 명시 타입(enum), 플러그인 try/catch 격리.
|
||||
- **Prevention:** 이벤트 카탈로그, 신뢰 경계 검증, 안정된 확장 계약.
|
||||
|
||||
### [[Repository Pattern]] / [[Local Storage Pattern]] / [[이벤트 소싱 스토어 패턴]] / [[Offline Sync Pattern]]
|
||||
- **Failure Modes:** 데이터 손실/중복, 파일 폭증, 마이그레이션 크래시, 충돌 미해소.
|
||||
- **Symptoms:** 불일치, 업데이트 후 크래시, 동기화 후 데이터 사라짐.
|
||||
- **Root Causes:** 멱등 키 부재, LWW 손실, compaction 부재, 스키마 버전 무시, 손상 줄 미격리, 민감정보 평문.
|
||||
- **Debugging:** 줄 단위 파싱 검사, 버전 필드, outbox 순서, 충돌 로그.
|
||||
- **Recovery:** 멱등 키 도입, 충돌 해소(버전 벡터/사용자), 스냅샷, 부분 격리 파싱.
|
||||
- **Prevention:** 변경에 고유 id, 데이터 성격별 매체, 손상 줄 skip, 보안 저장소.
|
||||
|
||||
### [[JWT Authentication Pattern]] / [[Push Notification Pattern]] / [[Navigation Pattern]] / [[Infinite Scroll Pattern]]
|
||||
- **Failure Modes:** 토큰 탈취 지속, 알림 미수신, 딥링크 깨짐, 목록 중복/렉.
|
||||
- **Symptoms:** 로그아웃 안 됨, 알림 안 옴, 뒤로가기 길 잃음, 스크롤 끊김.
|
||||
- **Root Causes:** localStorage 저장/회전 부재, 전달 보장 가정, 객체 라우트 인자, offset 페이징/가상화 부재.
|
||||
- **Debugging:** 토큰 수명/저장 위치, 전송 로그, 라우트 직렬화, 요청 중복.
|
||||
- **Recovery:** httpOnly+회전, 중요 데이터는 동기화로, 커서 페이징, 가상화.
|
||||
- **Prevention:** 짧은 만료+회전, 알림은 유도만, 직렬화 가능 라우트, 커서+가상화.
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
실패 모드는 *맥락 의존* — 같은 증상도 원인이 다를 수 있다. "증상→가설→*측정으로 검증*→최소 변경" 순서를 지키고, 추측만으로 재시작/롤백하지 마라([[디버깅 플레이북]]).
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI 가 실제로 겪은 실패(락 동일성, 하이브리드 스케일, 에이전트 hop 손실, OOM)가 각 항목의 근거. → [[교훈 라이브러리 Lessons Learned]].
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[디버깅 플레이북]], [[교훈 라이브러리 Lessons Learned]], [[안티패턴 카탈로그]]
|
||||
- **참조 맥락:** 작은 모델이 패턴을 적용할 때 "이 패턴이 어떻게 깨지는가" 를 함께 학습해 회피.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 소프트웨어 장애/디버깅 지식
|
||||
- [S2] AstraAI 사후기록(lock.ts, retrieval/index.ts, dispatcher.ts 등) — 실증 근거
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 패턴별 실패 지식 라이브러리 초안.
|
||||
@@ -0,0 +1,120 @@
|
||||
---
|
||||
id: project-independent-design-principles
|
||||
title: "프로젝트 독립 설계 원칙"
|
||||
category: "Software_Engineering"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["design principles", "설계 원칙", "transferable principles", "project-independent knowledge", "엔지니어링 원칙"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.9
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["principles", "engineering", "transferable", "design", "platform-independent"]
|
||||
raw_sources: ["AstraAI 전체 분석의 일반화", "본 위키 ADR/패턴/교훈 모음"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[프로젝트 독립 설계 원칙]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
AstraAI 라는 *한 프로젝트* 에서 추출한 결정들을 *어느 프로젝트에나 쓰는* 원칙으로 일반화한 것 — "AstraAI 는 X 를 쓴다" 가 아니라 "**언제 X 를 쓰는가**" 의 형태로, 작은 모델에게 진짜 전이 가능한 학습 데이터다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
각 원칙 = (원칙 / 사용 조건 / 장점 / 단점 / 대안 / 실패 신호). AstraAI 사례는 *예시* 일 뿐, 규칙은 프로젝트 독립.
|
||||
|
||||
## 📖 세부 내용 (Details · 일반화된 원칙)
|
||||
|
||||
### P1. 환경이 아키텍처를 결정한다
|
||||
- **원칙:** 동시성·저장·검증 깊이는 알고리즘이 아니라 *배포 환경(자원·사용자 수·네트워크)* 이 정한다.
|
||||
- **조건:** 타깃 하드웨어/규모를 알 때.
|
||||
- **장점:** 과/저설계 회피. **단점:** 환경 변화 시 재평가 필요. **대안:** 런타임 환경 감지 후 전략 전환.
|
||||
- **실패 신호:** "병렬이 빠르니까" 로 OOM; 서버 가정으로 로컬 앱 설계.
|
||||
- 일반화 출처: [[ADR-0004 순차 디스패치 채택]], [[엔지니어링 트레이드오프 분석]].
|
||||
|
||||
### P2. 결정론을 바닥선으로, 비싼 것은 조건부로
|
||||
- **원칙:** 항상 동작해야 하는 기능은 저비용 결정론으로 바닥을 깔고, 비싼(LLM/네트워크) 것은 가산·조건부.
|
||||
- **조건:** 가용성·설명가능성이 중요할 때. **장점:** 무중단·저지연. **단점:** 결정론 한계. **대안:** 항상 고비용(자원 충분 시).
|
||||
- **실패 신호:** 임베딩/외부 의존 없으면 검색이 죽음; 매 턴 LLM 검수로 느림.
|
||||
- 출처: [[ADR-0007 하이브리드 검색 결정론 우선]], [[ADR-0009 결정론 항상 LLM검증 조건부]].
|
||||
|
||||
### P3. 차이는 가장자리에서 흡수, 중심은 단일 모델
|
||||
- **원칙:** 외부(공급자/소스/디바이스)의 차이를 경계 어댑터에서 정규화하고 내부는 하나의 형태로.
|
||||
- **조건:** 이질적 외부가 여럿일 때. **장점:** 호출부 단순·교체 용이. **단점:** 어댑터 비용. **대안:** 직접 결합(소수일 때).
|
||||
- **실패 신호:** 공급자별 분기가 코드 전체에 산재.
|
||||
- 출처: [[LLM 프로바이더 추상화]], [[Data Flow Pattern]].
|
||||
|
||||
### P4. 이력이 가치면 추가만 하라
|
||||
- **원칙:** 변경 이력이 중요하면 상태 덮어쓰기 대신 append-only 이벤트. 현재 상태는 재생.
|
||||
- **조건:** 감사/재현/되돌리기 필요. **장점:** 이력 보존·내결함. **단점:** 파일 증가·재생 비용. **대안:** 상태 저장(마지막 값만 중요).
|
||||
- **실패 신호:** "언제 바뀌었지?" 를 알 수 없음.
|
||||
- 출처: [[ADR-0001 이벤트 소싱 채택]], [[이벤트 소싱 스토어 패턴]].
|
||||
|
||||
### P5. 기억은 수명별로 분리하라
|
||||
- **원칙:** 수명·만료·우선순위가 다른 기억은 다른 계층/저장소에. 시한부엔 만료, 오래된 건 압축.
|
||||
- **조건:** 세션 넘는 상태가 다양할 때. **장점:** 정밀 선별. **단점:** 분류 비용. **대안:** 단일 버퍼(단발성).
|
||||
- **실패 신호:** 옛 사실을 현재처럼 답함.
|
||||
- 출처: [[ADR-0002 5계층 메모리 분리]], [[Memory Pattern]].
|
||||
|
||||
### P6. 추상화는 두 번째 구현에서
|
||||
- **원칙:** 구현이 2개 이상이거나 테스트에 가짜가 필요할 때 인터페이스를 도입. 하나뿐이면 미루라(YAGNI).
|
||||
- **조건:** 교체/테스트 필요. **장점:** 결합↓·테스트성. **단점:** 과추상화 비용. **대안:** 직접 구현.
|
||||
- **실패 신호:** 구현 1개짜리 인터페이스가 가득(얇은 래퍼 지옥).
|
||||
- 출처: [[ADR-0006 수동 의존성주입 인터페이스 서비스]], [[의존성 주입과 서비스 인터페이스]].
|
||||
|
||||
### P7. 모델/외부 출력은 신뢰되지 않은 입력이다
|
||||
- **원칙:** LLM·외부 프로세스·플러그인 출력은 검증·샌드박스·승인 후 사용. JSON 은 강건 파서로.
|
||||
- **조건:** 외부 효과(파일/명령/IPC)가 있을 때. **장점:** 보안·안정. **단점:** 검증 코드. **대안:** 화이트리스트만.
|
||||
- **실패 신호:** 모델이 시키는 대로 실행; JSON.parse 직접 호출 실패.
|
||||
- 출처: [[Tool Calling Pattern]], [[Critic Pattern]], [[IPC Pattern]].
|
||||
|
||||
### P8. 실패는 분류하고 본류를 지켜라
|
||||
- **원칙:** 복구 가능(재시도/폴백)·불가(throw)·부가(이유 주석 후 무시)로 분류. 사용자에겐 행동 지침으로 번역.
|
||||
- **조건:** I/O·외부 의존. **장점:** 복원력. **단점:** 코드량. **대안:** 크래시-온리.
|
||||
- **실패 신호:** 무음 빈 catch 로 실패 은폐; 부가 실패가 본류 중단.
|
||||
- 출처: [[Error Handling Pattern]], [[에러 처리와 커스텀 에러]].
|
||||
|
||||
### P9. 흐름은 한 곳에서 읽히게, 구현은 추출
|
||||
- **원칙:** 거대 함수는 흐름 골격만 남기고 세부를 순수 모듈로. 단, 크기 상한을 정하라.
|
||||
- **조건:** 복잡한 단일 흐름. **장점:** 가독성+테스트성. **단점:** 경계 판단 필요. **대안:** 완전 분해(흐름 분산) 또는 모놀리식.
|
||||
- **실패 신호:** 한 턴 흐름을 파악하려 파일 10개를 떠돔; 또는 5천 줄 god-class.
|
||||
- 출처: [[ADR-0010 오케스트레이터 골격 모듈추출]], [[Architecture Separation Pattern]].
|
||||
|
||||
### P10. 변하지 않은 것은 다시 계산하지 마라
|
||||
- **원칙:** 비싼 계산은 캐시하되 *무효화 전략(변경 감지/버전)* 을 먼저 정하라.
|
||||
- **조건:** 반복 계산·조회. **장점:** 성능. **단점:** stale 위험. **대안:** 매번 계산.
|
||||
- **실패 신호:** 무효화 누락으로 옛 결과; 키 충돌.
|
||||
- 출처: [[Caching Pattern]], mtime 인덱스([[TF-IDF 이중언어 스코어링]]).
|
||||
|
||||
### P11. 주석은 '왜'와 '왜 다른 방법이 아닌지'를 적어라
|
||||
- **원칙:** 코드가 못 말하는 의도·제약·기각한 대안·버그 사후기록을 남겨라.
|
||||
- **조건:** 비자명한 결정/함정. **장점:** 지식 전수(특히 AI 학습). **단점:** 노후화 관리. **대안:** ADR 문서.
|
||||
- **실패 신호:** "이게 왜 이렇지?" 를 아무도 모름; 같은 버그 재발.
|
||||
- 출처: [[코딩 컨벤션과 주석 철학]], [[교훈 라이브러리 Lessons Learned]].
|
||||
|
||||
### P12. 피드백 1회를 시스템 변화로 환원하라
|
||||
- **원칙:** 사용자 정정/오류를 *통계로만* 두지 말고 다음 동작(프롬프트·규칙)을 자동으로 바꿔라.
|
||||
- **조건:** 학습/개선 루프가 필요할 때. **장점:** 자기진화. **단점:** 폭주 위험(임계·상한 필요). **대안:** 수동 개선.
|
||||
- **실패 신호:** 리포트만 쌓이고 행동이 안 바뀜; 1회성 노이즈로 프롬프트 오염.
|
||||
- 출처: [[Intelligence 검증 레이어]](correction loop), [[AITRAIN 검증 레이어]].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
원칙끼리도 충돌한다(예: P6 추상화 미루기 vs P3 어댑터 도입). 충돌 시 [[엔지니어링 트레이드오프 분석]] 으로 내려가 *맥락* 으로 결정. 메타 원칙: **단순함 우선 · YAGNI · 환경이 결정 · 측정으로 검증.**
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
각 원칙은 AstraAI 의 구체 결정에서 일반화. 다른 프로젝트(웹/모바일/백엔드)에 그대로 적용 가능 — [[플랫폼 개발 가이드 인덱스]] 의 가이드들이 이 원칙의 플랫폼별 구체화.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[Topic Programming 인덱스]]
|
||||
- **관련 개념:** [[아키텍처 휴리스틱]], [[엔지니어링 트레이드오프 분석]], [[패턴 카탈로그 인덱스]], [[교훈 라이브러리 Lessons Learned]]
|
||||
- **참조 맥락:** 작은 모델이 *어떤* 프로젝트를 설계하든 최상위 원칙으로 먼저 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI 전체 결정의 일반화(본 위키 ADR/패턴/교훈 모음)
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 설계 원칙을 프로젝트 독립 형태로 일반화.
|
||||
@@ -0,0 +1,142 @@
|
||||
---
|
||||
id: typescript-advanced-types
|
||||
title: "TypeScript 고급 타입"
|
||||
category: "Programming_Language"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["제네릭", "Generics", "타입 가드", "discriminated union", "유틸리티 타입", "Partial", "Omit"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.94
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["typescript", "language", "generics", "type-guard", "advanced", "astraai"]
|
||||
raw_sources: ["AstraAI/src/features/_shared/eventSourcedStore.ts", "AstraAI/src/core/queue.ts", "AstraAI/src/features/providers/types.ts", "AstraAI/src/memory/index.ts", "AstraAI/src/intelligence/criticAgent.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[TypeScript 고급 타입]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
제네릭·판별 유니온·타입 가드·유틸리티 타입은 "중복을 없애면서도 타입 안전을 유지"하는 도구이며, AstraAI 는 이들로 **하나의 제네릭 스토어가 4개 도메인을 안전하게 처리**하고 **함수 결과를 성공/실패로 명확히 분기**한다 [S1].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **제네릭 (Generics):** `createEventStore<E>(...)` 처럼 타입을 파라미터로 받아, 호출부가 `CustomerEvent`/`HireEvent` 등 구체 타입을 끼워 넣으면 그 타입으로 동작한다. 코드는 한 벌, 타입은 N 벌 [S1].
|
||||
2. **판별 유니온 (Discriminated union):** 공통 *판별 필드* 로 갈래를 나눈 union. `{ ok: true; filePath } | { ok: false; error }` 처럼 `ok` 를 검사하면 컴파일러가 나머지 필드를 자동으로 좁힌다 [S1].
|
||||
3. **타입 가드 (Type guard):** 반환 타입을 `x is T` 로 선언한 함수. `validate: (e: unknown) => e is E` 가 true 면 컴파일러가 그 블록에서 `e` 를 `E` 로 취급한다 — 런타임 검증과 컴파일 타입 좁히기를 동시에 [S1].
|
||||
4. **유틸리티 타입 (Utility types):** `Partial<T>`(모든 필드 옵셔널), `Omit<T, K>`(특정 키 제외), `Record<K, V>`(키-값 맵), `Pick<T, K>`. 기존 타입에서 파생 타입을 *연산* 으로 만든다 [S2][S3].
|
||||
5. **`keyof` / 인덱스 시그니처:** 객체 키 집합을 타입으로 (`Record<string, number>`), 동적 키 접근을 안전하게.
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **제네릭 팩토리 + 검증 주입:** `createEventStore<E>({ relPath, validate })` — 타입 파라미터와 런타임 검증을 함께 받아 I/O 를 추상화하고 도메인 로직은 호출부에 남긴다 [S1].
|
||||
- **결과를 판별 유니온으로:** 예외를 던지는 대신 `{ ok: true } | { ok: false; error }` 를 반환해 호출부가 분기를 강제로 처리하게 한다 (Rust 의 `Result` 와 유사) [S1].
|
||||
- **`Partial<T>` 로 설정 병합:** 생성자가 `config?: Partial<MemoryConfig>` 를 받아 기본값과 스프레드 병합 (`{ ...defaults, ...config }`) — 부분 오버라이드 패턴 [S4].
|
||||
- **`Omit<T, 'model'>` 로 파라미터 일부만:** `streamCloudCompletion` 이 `Omit<StreamParams, 'model'>` 을 받아, model 은 내부에서 채운다 — "이미 아는 필드는 받지 않는다" [S3].
|
||||
- **함수 타입 별칭으로 의존성 주입:** `type CritiqueLlmCall = (system, user, maxTokens) => Promise<string>` — LLM 호출을 타입으로 추상화해 모듈을 순수하게 유지 [S5].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### 제네릭의 실전 가치
|
||||
AstraAI 는 customers/hire/runway/feedback 4개 스토어가 같은 CRUD 패턴을 반복해 ~240줄 중복이 있었다. 이를 `createEventStore<E>` 하나로 통합 — 타입 파라미터 `E` 덕분에 각 스토어는 자기 이벤트 타입을 그대로 유지하면서 코드는 공유한다. 제네릭이 없었다면 `any` 로 타입을 잃거나 4벌을 복붙해야 했다 [S1].
|
||||
|
||||
```typescript
|
||||
export interface EventStore<E> {
|
||||
read(): E[];
|
||||
append(event: E): { ok: true; filePath: string } | { ok: false; error: string };
|
||||
count(): number;
|
||||
}
|
||||
export function createEventStore<E>(opts: EventStoreOptions<E>): EventStore<E> { /* ... */ }
|
||||
```
|
||||
|
||||
### 판별 유니온으로 안전한 분기
|
||||
`append` 의 반환값을 보면 호출부는 반드시 `ok` 를 먼저 검사해야 한다:
|
||||
```typescript
|
||||
const r = store.append(ev);
|
||||
if (r.ok) { use(r.filePath); } // 이 블록에서 r.error 는 타입상 존재하지 않음
|
||||
else { show(r.error); } // 이 블록에서 r.filePath 는 존재하지 않음
|
||||
```
|
||||
컴파일러가 갈래별로 접근 가능한 필드를 제한하므로, "성공 경로에서 error 를 읽는" 류의 버그가 원천 차단된다.
|
||||
|
||||
### 타입 가드 = 런타임 검증 + 컴파일 좁히기
|
||||
```typescript
|
||||
validate: (e: unknown) => e is CustomerEvent // 호출부 시그니처
|
||||
// 내부에서
|
||||
if (opts.validate(parsed)) out.push(parsed); // parsed 가 여기서 E 로 좁혀짐
|
||||
```
|
||||
`unknown` 으로 받은 외부 JSON 을 가드 통과 후에만 `E[]` 로 쌓는다 — type erasure 로 런타임에 타입이 없는 한계를 가드로 메운다.
|
||||
|
||||
### 제네릭 제약과 기본 타입 파라미터
|
||||
`enqueue<T>(task: () => Promise<T>): Promise<T>` 처럼 메서드 단위 제네릭도 흔하다. 태스크의 반환 타입 `T` 가 그대로 큐의 반환 타입으로 흐른다 [S2].
|
||||
|
||||
## ⚖️ 비교 및 선택 기준 (Comparison & decision criteria)
|
||||
|
||||
| 항목 (Option) | 장점 | 단점 | 언제 선택 |
|
||||
|---|---|---|---|
|
||||
| 예외 throw | 작성 간단, 호출부 코드 짧음 | 호출부가 처리를 잊기 쉬움 | 진짜 예외적 상황(I/O 실패) |
|
||||
| 판별 유니온 결과 | 호출부가 분기를 강제 처리 | 보일러플레이트 증가 | 실패가 정상 흐름의 일부일 때 (`append`) |
|
||||
| 제네릭 함수 | 타입 안전 + 중복 제거 | 시그니처 복잡해질 수 있음 | 같은 로직이 여러 타입에 반복될 때 |
|
||||
| `any` 캐스팅 | 즉시 통과 | 타입 안전 상실 | 최후의 수단, 외부 라이브러리 경계 |
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **과도한 제네릭은 독:** 타입 파라미터가 3개를 넘거나 조건부 타입이 중첩되면 가독성이 급락한다. AstraAI 는 대부분 단일 `<E>`/`<T>` 수준으로 절제한다.
|
||||
- **결과 유니온 vs 예외:** AstraAI 는 둘을 혼용한다 — 파일 append 같은 "흔한 실패"는 유니온, 트랜잭션 위반 같은 "계약 위반"은 커스텀 예외(throw). 일관 규칙은 "호출부가 정상적으로 마주칠 실패면 유니온".
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/features/_shared/eventSourcedStore.ts` — 제네릭 + 타입 가드 + 판별 유니온이 한 파일에 모두 [S1].
|
||||
- `AstraAI/src/memory/index.ts` — `constructor(brainPath, config?: Partial<MemoryConfig>)` + `{ ...defaults, ...config }` 병합 [S4].
|
||||
- `AstraAI/src/features/providers/index.ts` — `Omit<StreamParams, 'model'>` 로 일부 필드만 받는 함수 [S3].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// 1) 제네릭 팩토리 + 타입 가드 주입 (src/features/_shared/eventSourcedStore.ts)
|
||||
export interface EventStoreOptions<E> {
|
||||
relPath: string;
|
||||
validate: (e: unknown) => e is E; // 타입 가드: 런타임 검증 + 컴파일 좁히기
|
||||
}
|
||||
export function createEventStore<E>(opts: EventStoreOptions<E>): EventStore<E> { /* ... */ }
|
||||
// 사용처:
|
||||
const store = createEventStore<CustomerEvent>({
|
||||
relPath: '.astra/customers.jsonl',
|
||||
validate: (e): e is CustomerEvent =>
|
||||
typeof (e as any).id === 'string' && typeof (e as any).customerId === 'string',
|
||||
});
|
||||
|
||||
// 2) 판별 유니온 결과 — 호출부가 분기 강제
|
||||
function append(event: E): { ok: true; filePath: string } | { ok: false; error: string } {
|
||||
try { /* write */ return { ok: true, filePath }; }
|
||||
catch (e: any) { return { ok: false, error: e?.message || String(e) }; }
|
||||
}
|
||||
|
||||
// 3) Partial<T> 로 부분 설정 병합 (src/memory/index.ts)
|
||||
constructor(brainPath: string, config?: Partial<MemoryConfig>) {
|
||||
this.config = { enabled: true, shortTermLimit: 8, /* ...defaults */ ...config };
|
||||
}
|
||||
|
||||
// 4) 함수 타입 별칭으로 의존성 주입 (src/intelligence/criticAgent.ts)
|
||||
export type CritiqueLlmCall = (system: string, user: string, maxTokens: number) => Promise<string>;
|
||||
```
|
||||
|
||||
## ✅ 검증 상태 및 신뢰도
|
||||
- **상태:** draft
|
||||
- **검증 단계:** applied (AstraAI 1차 코드에서 모든 패턴 확인)
|
||||
- **출처 신뢰도:** A
|
||||
- **신뢰 점수:** 0.94
|
||||
- **중복 검사 결과:** 신규 생성 (New discovery)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[TypeScript 기초와 타입 시스템]]
|
||||
- **관련 개념:** [[이벤트 소싱 스토어 패턴]], [[에러 처리와 커스텀 에러]], [[의존성 주입과 서비스 인터페이스]]
|
||||
- **참조 맥락:** 로컬 LLM 이 중복 제거·안전한 결과 반환·검증 코드를 작성할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/features/_shared/eventSourcedStore.ts — 제네릭, 타입 가드, 판별 유니온 결과
|
||||
- [S2] AstraAI/src/core/queue.ts — 메서드 제네릭 `enqueue<T>`
|
||||
- [S3] AstraAI/src/features/providers/index.ts, types.ts — Omit, union literal, ReadonlyArray
|
||||
- [S4] AstraAI/src/memory/index.ts — Partial<T> + 스프레드 병합
|
||||
- [S5] AstraAI/src/intelligence/criticAgent.ts — 함수 타입 별칭(의존성 주입)
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.
|
||||
@@ -0,0 +1,113 @@
|
||||
---
|
||||
id: typescript-basics-type-system
|
||||
title: "TypeScript 기초와 타입 시스템"
|
||||
category: "Programming_Language"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["TypeScript", "TS", "타입스크립트", "정적 타이핑", "strict mode"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.95
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["typescript", "language", "type-system", "fundamentals", "astraai"]
|
||||
raw_sources: ["AstraAI/tsconfig.json", "AstraAI/src/core/services.ts", "AstraAI/src/memory/types.ts", "TypeScript Handbook (general knowledge)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[TypeScript 기초와 타입 시스템]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
TypeScript 는 JavaScript 에 **정적 타입 계층**을 얹어 "실행 전에 오류를 잡는" 언어이며, AstraAI 처럼 `strict: true` 로 운영하면 컴파일러가 `null`/`undefined`/타입 불일치를 코드 작성 시점에 강제로 드러낸다 [S1].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **점진적 타이핑 (Gradual typing):** JS 코드에 타입을 점진적으로 추가할 수 있다. 타입을 안 쓰면 `any` 로 동작하지만, AstraAI 는 `strict` 모드로 `any` 를 최대한 배제한다 [S1].
|
||||
2. **구조적 타이핑 (Structural typing):** 이름이 아니라 *구조(모양)* 가 같으면 호환된다. `interface IAIService` 를 명시적으로 `implements` 하지 않아도 같은 메서드를 가지면 그 타입으로 통한다 — 다만 AstraAI 는 가독성을 위해 `implements` 를 명시한다 [S2].
|
||||
3. **컴파일 타임 vs 런타임:** 타입은 컴파일 후 *지워진다(type erasure)*. 런타임에는 타입 정보가 없으므로, 외부 입력 검증은 **타입 가드 함수**로 직접 해야 한다 (`validate: (e: unknown) => e is E`) [S3].
|
||||
4. **`strict` 플래그:** `strictNullChecks`, `noImplicitAny` 등을 한 번에 켠다. `null`/`undefined` 가 다른 타입에 섞이지 않게 하여, "정의되지 않음" 버그를 구조적으로 차단한다 [S1].
|
||||
5. **타입 추론 (Inference):** 명시하지 않아도 컴파일러가 초기값·반환값에서 타입을 추론한다. 불필요한 타입 주석은 생략하고, 경계(함수 시그니처·공개 API)에만 명시하는 것이 AstraAI 스타일이다.
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **경계에 타입, 내부에 추론:** 공개 함수/인터페이스는 타입을 명시하고(`public async chat(req: AIChatRequest): Promise<AIChatResult>`), 함수 내부 지역 변수는 추론에 맡긴다 [S2].
|
||||
- **`interface` 로 데이터 형태 선언:** 도메인 데이터는 `interface` 로 모양을 먼저 정의한다 (`LongTermEntry`, `EpisodicEntry`). 구현보다 *형태* 를 먼저 설계하는 타입 우선 접근 [S3].
|
||||
- **`type` 별칭으로 유한 집합 표현:** 고정된 문자열 집합은 union literal type 으로 (`type MemoryLayer = 'short-term' | 'long-term' | ...`). 오타를 컴파일러가 잡고, switch 에서 누락 케이스를 경고한다 [S3].
|
||||
- **`readonly` / `as const` 로 불변 데이터:** 상수 배열은 `as const` 또는 `ReadonlyArray<...>` 로 변경 불가를 표현 (`PROVIDER_PREFIXES`) [S4].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### 기본 타입
|
||||
`string`, `number`, `boolean`, `null`, `undefined`, `bigint`, `symbol`, 그리고 객체 타입(`object`, 배열 `T[]`, 튜플 `[A, B]`). 특수 타입으로 `any`(타입 검사 끔 — 지양), `unknown`(any 의 안전판 — 사용 전 좁히기 강제), `never`(도달 불가), `void`(반환값 없음)가 있다.
|
||||
|
||||
### `interface` vs `type`
|
||||
- `interface`: 객체 *형태* 선언에 적합. 선언 병합(declaration merging)·`extends` 가능. AstraAI 는 도메인 엔티티에 주로 `interface` 사용 (`MemoryContextResult`, `ProjectMemoryStore`) [S3].
|
||||
- `type`: union/intersection/조건부 타입 등 *타입 연산* 에 적합. AstraAI 는 union literal (`type ProviderId = 'openrouter' | 'anthropic' | 'gemini'`) 과 함수 타입 별칭에 사용 [S4].
|
||||
- 실무 규칙: "객체 모양이면 `interface`, 합집합·매핑·연산이면 `type`".
|
||||
|
||||
### `strict` 가 강제하는 것 (AstraAI tsconfig 기준)
|
||||
`module: commonjs`, `target: ES2022`, `lib: ["ES2022", "DOM"]`, `strict: true`, `skipLibCheck: true` 로 설정 [S1]. `strict` 가 켜지면:
|
||||
- `strictNullChecks`: `string | undefined` 는 `string` 에 바로 못 넣는다. 옵셔널 필드(`expiresAt?: number`)는 사용 전 `if (entry.expiresAt)` 같은 좁히기 필요 [S3].
|
||||
- `noImplicitAny`: 타입을 추론할 수 없는 파라미터에 `any` 를 암묵 허용하지 않음 → 명시 강제.
|
||||
- `strictFunctionTypes`, `strictBindCallApply` 등 함수 타입의 안전성 강화.
|
||||
|
||||
### 옵셔널·기본값·널 처리
|
||||
- 옵셔널 프로퍼티 `field?: T` 는 값이 `T | undefined`. 코드에서 `req.timeoutMs ?? config.timeout` 처럼 **nullish 병합(`??`)** 으로 기본값을 준다. `||` 와 달리 `0`/`''`/`false` 를 유효값으로 보존한다 [S2].
|
||||
- 옵셔널 체이닝 `data.choices?.[0]?.message?.content` 로 중첩 접근 중 `undefined` 를 안전하게 통과 [S2].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **`interface` vs `type` 논쟁:** 둘은 많은 경우 호환되며 "무엇을 써야 하는가"에 절대 정답은 없다. AstraAI 의 실제 관례(객체=interface, 연산=type)를 따르는 것이 일관성 측면에서 안전하다.
|
||||
- **`any` vs `unknown`:** 레거시 호환을 위해 AstraAI 도 일부 `as any` 캐스팅을 쓰지만(예: `data` JSON 파싱 후), 새 코드에서는 외부 입력에 `unknown` + 타입 가드를 쓰는 것이 안전하다 [S3].
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/memory/types.ts` — 5계층 메모리의 모든 데이터 형태를 `interface`/`type` 로 선언. 옵셔널 temporal marker(`expiresAt?`)와 union category(`LongTermCategory`)가 strict 환경에서 어떻게 쓰이는지 보여준다 [S3].
|
||||
- `AstraAI/src/core/services.ts` — `interface IAIService` + `class AIService implements IAIService` 로 "인터페이스 선언 → 구현" 패턴 [S2].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// 1) union literal type 으로 유한 집합 — 오타를 컴파일러가 차단 (src/memory/types.ts)
|
||||
export type MemoryLayer = 'short-term' | 'long-term' | 'project' | 'procedural' | 'episodic';
|
||||
|
||||
// 2) interface 로 데이터 형태 선언 + 옵셔널 필드 (strictNullChecks 대응)
|
||||
export interface LongTermEntry {
|
||||
id: string;
|
||||
category: LongTermCategory;
|
||||
confidence: number; // 0.0~1.0
|
||||
expiresAt?: number; // undefined = 영구. 사용 전 좁히기 필요
|
||||
}
|
||||
|
||||
// 3) nullish 병합으로 기본값 — 0/''/false 를 보존 (src/core/services.ts)
|
||||
const timeoutMs = req.timeoutMs ?? config.timeout; // ?? : null/undefined 일 때만 기본값
|
||||
const model = (req.model || config.defaultModel || '').trim() || 'gemma4:e2b'; // || : falsy 전부 대체
|
||||
|
||||
// 4) 옵셔널 체이닝으로 안전한 중첩 접근
|
||||
const content = data.choices?.[0]?.message?.content || '';
|
||||
|
||||
// 5) interface → implements 로 계약 명시
|
||||
export interface IAIService { call(prompt: string): Promise<string>; }
|
||||
export class AIService implements IAIService {
|
||||
public async call(prompt: string): Promise<string> { /* ... */ return ''; }
|
||||
}
|
||||
```
|
||||
|
||||
## ✅ 검증 상태 및 신뢰도
|
||||
- **상태:** draft
|
||||
- **검증 단계:** applied (AstraAI 실제 소스에서 패턴 확인됨)
|
||||
- **출처 신뢰도:** A (언어 사양 + 1차 코드)
|
||||
- **신뢰 점수:** 0.95
|
||||
- **중복 검사 결과:** 신규 생성 (New discovery)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[TypeScript 기초와 타입 시스템]]
|
||||
- **관련 개념:** [[TypeScript 고급 타입]], [[비동기 프로그래밍 Promise async await]], [[에러 처리와 커스텀 에러]]
|
||||
- **참조 맥락:** 로컬 LLM 이 TypeScript 코드를 작성/수정할 때 타입 선언·null 안전·strict 규칙의 기본기로 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/tsconfig.json — strict/target/module 컴파일러 설정
|
||||
- [S2] AstraAI/src/core/services.ts — IAIService 인터페이스, ?? vs || 기본값, 옵셔널 체이닝
|
||||
- [S3] AstraAI/src/memory/types.ts — interface/type 선언, 옵셔널 필드, union literal
|
||||
- [S4] AstraAI/src/features/providers/types.ts — type 별칭, as const, ReadonlyArray
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성 (로컬 LLM 코딩 지식 베이스 구축).
|
||||
@@ -0,0 +1,122 @@
|
||||
---
|
||||
id: module-system-project-structure
|
||||
title: "모듈 시스템과 프로젝트 구성"
|
||||
category: "Programming_Language"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["import", "export", "모듈", "barrel", "side-effect import", "dynamic import", "esbuild", "번들링"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.92
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["typescript", "module", "import", "esbuild", "project-structure", "astraai"]
|
||||
raw_sources: ["AstraAI/src/extension.ts", "AstraAI/src/memory/index.ts", "AstraAI/src/retrieval/index.ts", "AstraAI/package.json", "AstraAI/tsconfig.json"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[모듈 시스템과 프로젝트 구성]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
모듈 시스템은 "무엇을 공개하고(`export`) 무엇을 가져올지(`import`)"로 코드 경계를 긋는 것이며, AstraAI 는 **barrel(index.ts) 재수출·side-effect import 자기등록·동적 import 지연로딩**을 조합해 308개 파일을 esbuild 단일 번들로 묶는다 [S1][S4].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **ES Module 문법:** `import { x } from './m'` / `export function x()`. TypeScript 는 이 문법을 쓰고, tsconfig `module: commonjs` 로 CommonJS 로 컴파일된다 [S5].
|
||||
2. **named vs default export:** AstraAI 는 거의 전부 *named export* 만 쓴다 — 자동완성·일관된 이름·리팩터링 안전성 때문. default export 는 사실상 배제 [S2].
|
||||
3. **Barrel 파일 (index.ts):** 하위 모듈을 한 곳에서 재수출(`export * from './types'`)해 외부가 깔끔한 진입점 하나만 import 하게 한다 [S2][S3].
|
||||
4. **Side-effect import:** `import './features/teamops/handlers'` — 값을 가져오지 않고 *모듈 로드의 부수효과*(핸들러 자기등록)만 노린다 [S1].
|
||||
5. **Dynamic import (`await import(...)`):** 무겁거나 드물게 쓰는 모듈을 실제 호출 시점에 지연 로딩 — 활성화 시간 단축 [S1].
|
||||
6. **번들링 (esbuild):** 모든 모듈을 `out/extension.js` 하나로 묶되 `vscode` 는 external (런타임 제공) [S4].
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **상대경로 import + 명확한 트리:** `../config`, `./types` 같은 상대경로로 모듈을 참조하고, 폴더 구조가 곧 도메인 경계(`features/`, `core/`, `memory/`, `retrieval/`, `intelligence/`).
|
||||
- **barrel 재수출로 진입점 단일화:** `src/memory/index.ts` 가 5개 메모리 클래스 + distillation API + `export * from './types'` 를 한 번에 노출 [S3].
|
||||
- **side-effect import 로 핸들러 자기등록:** entry point 가 `import './features/system/handlers'` 만 하면 그 모듈이 slashRouter 에 자기를 등록 — 등록 코드를 한 곳에 모으지 않는 분산 등록 [S1].
|
||||
- **동적 import 로 무거운 기능 지연:** `const { runDatacollectSetup } = await import('./features/setup/datacollectSetup')` — 명령 실행 시에만 로드 [S1].
|
||||
- **타입 전용 import:** `import type { ChatMessage } from '../../agent'` — 컴파일 후 사라지는 타입만 가져와 순환참조·번들 부담 회피 [S6].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### 폴더 = 도메인 경계
|
||||
```
|
||||
src/
|
||||
core/ 공통 인프라 (lock, queue, transaction, errors, services, events)
|
||||
features/ 기능 도메인 (각 폴더가 독립 기능: stocks, calendar, company, datacollect…)
|
||||
memory/ 5계층 메모리
|
||||
retrieval/ RAG 검색
|
||||
intelligence/ 검증·자기평가 (critic, confidence, correctionLoop)
|
||||
lib/ 순수 헬퍼 + contextBuilders (프롬프트 컨텍스트 조립)
|
||||
agent/ 에이전트 실행 세부 (handlePrompt/, llm/, actions/, multiAgent/)
|
||||
```
|
||||
각 폴더 안에 `index.ts`(barrel)가 있으면 외부는 그 하나만 import 한다.
|
||||
|
||||
### import 순서·스타일
|
||||
실제 코드는 (1) Node 표준(`fs`, `path`), (2) vscode, (3) 내부 모듈 순으로 import 하며, 내부는 도메인별로 묶어 가독성을 유지한다. 거대한 orchestrator(agent.ts)는 import 가 100줄을 넘는데, 이는 *기능을 작은 모듈로 추출하고 다시 끌어모으는* 구조의 자연스러운 결과다 [S1].
|
||||
|
||||
### side-effect import 의 순서 민감성
|
||||
```typescript
|
||||
// slashRouter 가 먼저 로드된 뒤 핸들러가 자기 등록되도록 entry point 에서 import
|
||||
import './features/teamops/handlers';
|
||||
import './features/system/handlers';
|
||||
import './features/datacollect/handlers';
|
||||
```
|
||||
주석이 "왜 여기서 import 하는지"(로드 순서 보장)를 명시한다 — side-effect import 는 순서가 동작에 영향을 주므로 의도를 적는 것이 필수 [S1].
|
||||
|
||||
### 번들/빌드
|
||||
- `compile`: `esbuild src/extension.ts --bundle --platform=node --external:vscode --outfile=out/extension.js` — 단일 파일 번들 [S4].
|
||||
- `watch`: `tsc -watch` (타입 체크용), `test`: `jest`. 런타임 의존성은 `@lmstudio/sdk`, `pdf-parse` 둘뿐이고 axios 대신 native `fetch` 사용 [S4].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **barrel 의 양날:** index.ts 재수출은 진입점을 깔끔히 하지만, 과하면 순환참조와 "한 줄 import 가 거대한 그래프를 끌어옴" 문제를 낳는다. AstraAI 는 무거운 기능을 동적 import 로 분리해 이를 완화 [S1].
|
||||
- **commonjs vs ESM:** tsconfig 는 `commonjs` 로 컴파일하지만 소스는 ESM 문법으로 작성한다 — VS Code 확장 런타임(Node)이 CJS 를 기대하기 때문. 새 프로젝트라면 ESM 출력도 가능하나 호환성 고려 필요 [S5].
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/extension.ts` — side-effect import, 동적 import, 100+줄 named import 의 실제 예 [S1].
|
||||
- `AstraAI/src/memory/index.ts`, `src/retrieval/index.ts` — barrel 재수출 [S2][S3].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// 1) side-effect import — 핸들러 자기등록 (순서 주석 필수) (src/extension.ts)
|
||||
import './features/teamops/handlers';
|
||||
import './features/system/handlers';
|
||||
|
||||
// 2) barrel 재수출로 진입점 단일화 (src/memory/index.ts)
|
||||
export { ShortTermMemory } from './ShortTermMemory';
|
||||
export { LongTermMemory } from './LongTermMemory';
|
||||
export * from './types';
|
||||
|
||||
// 3) 동적 import 로 무거운 기능 지연 (src/extension.ts)
|
||||
vscode.commands.registerCommand('g1nation.setupDatacollect', async () => {
|
||||
const { runDatacollectSetup } = await import('./features/setup/datacollectSetup');
|
||||
await runDatacollectSetup();
|
||||
});
|
||||
|
||||
// 4) 타입 전용 import — 런타임 부담/순환참조 회피
|
||||
import type { AgentExecutorOptions, ChatMessage } from '../../agent';
|
||||
```
|
||||
|
||||
## ✅ 검증 상태 및 신뢰도
|
||||
- **상태:** draft
|
||||
- **검증 단계:** applied
|
||||
- **출처 신뢰도:** A
|
||||
- **신뢰 점수:** 0.92
|
||||
- **중복 검사 결과:** 신규 생성 (New discovery)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[TypeScript 기초와 타입 시스템]]
|
||||
- **관련 개념:** [[AstraAI 아키텍처 개요]], [[VSCode 확장 구조와 생명주기]], [[코딩 컨벤션과 주석 철학]]
|
||||
- **참조 맥락:** 로컬 LLM 이 파일을 나누고 import/export 를 구성할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/extension.ts — side-effect/동적 import, named import 구성
|
||||
- [S2] AstraAI/src/features/providers/index.ts — named export, 재수출
|
||||
- [S3] AstraAI/src/memory/index.ts, src/retrieval/index.ts — barrel(export *) 패턴
|
||||
- [S4] AstraAI/package.json — esbuild 번들 스크립트, 의존성
|
||||
- [S5] AstraAI/tsconfig.json — module/target 설정
|
||||
- [S6] AstraAI/src/agent/multiAgent/workflow.ts — import type
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.
|
||||
@@ -0,0 +1,131 @@
|
||||
---
|
||||
id: async-programming-promise-async-await
|
||||
title: "비동기 프로그래밍 Promise async await"
|
||||
category: "Programming_Language"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["Promise", "async", "await", "비동기", "AbortSignal", "동시성", "스트리밍", "concurrency"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.93
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["typescript", "javascript", "async", "promise", "abortsignal", "astraai"]
|
||||
raw_sources: ["AstraAI/src/core/services.ts", "AstraAI/src/core/lock.ts", "AstraAI/src/core/queue.ts", "AstraAI/src/features/providers/index.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[비동기 프로그래밍 Promise async await]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
`async/await` 는 비동기 코드를 동기처럼 읽히게 하는 문법이고, `Promise` 는 그 토대이며, AstraAI 는 여기에 **`AbortSignal` 결합·타임아웃 경쟁(race)·동시성 제한**을 더해 "취소 가능하고 폭주하지 않는" 비동기를 구현한다 [S1][S2].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **Promise:** 미래의 값을 담는 객체. `pending → fulfilled/rejected` 상태를 가진다. `new Promise((resolve, reject) => ...)` 로 직접 만들거나 `async` 함수가 자동 반환한다 [S2].
|
||||
2. **async/await:** `async` 함수 안에서 `await promise` 는 Promise 가 풀릴 때까지 기다린 *값* 을 돌려준다. 실패하면 예외로 던져져 `try/catch` 로 잡는다 [S1].
|
||||
3. **`Promise.all` / `Promise.race`:** `all` 은 모두 완료될 때까지 병렬 대기(하나라도 실패 시 전체 reject), `race` 는 가장 먼저 끝난 하나를 채택 — AstraAI 는 race 로 "작업 vs 타임아웃" 경쟁을 만든다 [S3].
|
||||
4. **`AbortSignal` / `AbortController`:** 진행 중인 비동기(특히 `fetch`)를 외부에서 취소하는 표준 메커니즘. `AbortSignal.timeout(ms)`, `AbortSignal.any([...])` 로 타임아웃·사용자 취소를 결합 [S1].
|
||||
5. **동시성 제한 (Concurrency limiting):** 무한 병렬은 자원을 고갈시킨다. 큐로 동시 실행 수를 `max(2, cpus-1)` 로 제한 [S4].
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **타임아웃 + 외부 취소 신호 결합:** `AbortSignal.any([req.signal, AbortSignal.timeout(timeoutMs)])` — 둘 중 무엇이 먼저 fire 돼도 fetch 가 즉시 중단된다. 사용자가 "Stop" 을 누르면 LLM 생성 도중에도 끊긴다 [S1].
|
||||
- **race 로 데드락 방지:** lock 획득 시 `Promise.race([previousPromise, timeoutPromise])` — 앞 작업이 영원히 안 끝나도 timeout 이 깨운다 [S2].
|
||||
- **resolve 를 밖으로 빼내는 deferred:** `let release; new Promise(r => { release = r; })` — Promise 를 만들고 그 resolve 함수를 외부에서 호출 가능하게 보관(락 해제 함수로 반환) [S2].
|
||||
- **큐 기반 동시성 캡:** `enqueue<T>` 가 Promise 를 반환하되 실제 실행은 `activeCount < limit` 일 때만 — 초과분은 대기 [S4].
|
||||
- **best-effort 비차단:** `void ensureEmbeddingConfigured(context)` — 결과를 기다리지 않고 백그라운드로 흘려보내는 fire-and-forget (`void` 로 의도 명시) [S1].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### await 의 실패는 예외다
|
||||
`await fetch(...)` 가 네트워크 오류로 reject 되면 그 지점에서 throw 된다. AstraAI 의 `AIService.chat` 은 엔진별 루프 안에서 `try/catch` 로 잡아 `lastError` 에 저장하고 다음 엔진으로 폴백한다 — "한 엔진 실패가 전체 실패가 아니다" [S1].
|
||||
|
||||
### AbortSignal 결합 (핵심 패턴)
|
||||
```typescript
|
||||
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
||||
const combinedSignal = req.signal
|
||||
? AbortSignal.any([req.signal, timeoutSignal]) // 사용자 취소 OR 타임아웃
|
||||
: timeoutSignal;
|
||||
const res = await fetch(apiUrl, { /* ... */ signal: combinedSignal });
|
||||
```
|
||||
이 패턴 덕분에 (1) 응답이 너무 느리면 타임아웃으로, (2) 사용자가 멈추면 외부 signal 로 즉시 중단된다. 긴 multi-turn 경로(dispatcher 등)에는 반드시 `signal` 을 전달하는 것이 규칙 [S1].
|
||||
|
||||
### 직접 만드는 Promise (deferred 패턴)
|
||||
락 매니저는 "다른 코드가 부를 때 풀리는 Promise" 가 필요하다:
|
||||
```typescript
|
||||
let release!: () => void;
|
||||
const newPromise = new Promise<void>((resolve) => { release = resolve; });
|
||||
// ... 작업이 끝나면 호출부가 release() 를 부르면 newPromise 가 fulfilled
|
||||
return () => { release(); /* cleanup */ };
|
||||
```
|
||||
|
||||
### 병렬 vs 순차
|
||||
- 독립 작업은 `Promise.all([a(), b()])` 로 병렬 (provider 모델 목록 동시 조회) [S5].
|
||||
- 의존 작업은 순차 `await a(); await b();`.
|
||||
- 자원 부담이 큰 대량 작업은 `Promise.all` 대신 동시성 제한 큐를 쓴다 [S4].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **`Promise.all` 의 함정:** 하나라도 reject 되면 전체가 reject 되고 나머지 성공 결과를 잃는다. 부분 실패를 허용해야 하면 `Promise.allSettled` 를 쓰거나 각 작업을 try/catch 로 감싸야 한다.
|
||||
- **`await` in loop vs 병렬:** 루프 안 `await` 는 순차 실행이라 느릴 수 있다. 단, AstraAI 의 엔진 폴백 루프는 *의도적으로 순차* (앞 엔진이 성공하면 뒤는 안 부름).
|
||||
- **`forEach` + async 주의:** `array.forEach(async ...)` 는 완료를 기다리지 않는다. 대기하려면 `for...of` + `await` 또는 `Promise.all(array.map(...))`.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/core/services.ts` — AbortSignal 결합 + 엔진 폴백 루프(try/catch 순차) [S1].
|
||||
- `AstraAI/src/core/lock.ts` — deferred Promise + `Promise.race` 타임아웃 [S2].
|
||||
- `AstraAI/src/core/queue.ts` — 동시성 제한 큐 [S4].
|
||||
- `AstraAI/src/features/providers/index.ts` — `Promise.all(tasks)` 로 provider 목록 병렬 조회 [S5].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// 1) 타임아웃 + 외부 취소 결합 (src/core/services.ts)
|
||||
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
||||
const combinedSignal = req.signal ? AbortSignal.any([req.signal, timeoutSignal]) : timeoutSignal;
|
||||
const res = await fetch(apiUrl, { method: 'POST', body: JSON.stringify(payload), signal: combinedSignal });
|
||||
|
||||
// 2) try/catch 폴백 루프 — 한 엔진 실패가 전체 실패가 아님 (src/core/services.ts)
|
||||
let lastError: Error | null = null;
|
||||
for (const engine of engines) {
|
||||
try { const r = await callEngine(engine); if (r) return r; }
|
||||
catch (e: any) { lastError = e instanceof Error ? e : new Error(String(e)); }
|
||||
}
|
||||
throw lastError ?? new Error('All engines failed.');
|
||||
|
||||
// 3) deferred Promise + race 타임아웃 (src/core/lock.ts)
|
||||
let release!: () => void;
|
||||
const newPromise = new Promise<void>((resolve) => { release = resolve; });
|
||||
const timeoutPromise = new Promise<never>((_, reject) =>
|
||||
setTimeout(() => reject(new Error('Lock timed out')), timeoutMs));
|
||||
await Promise.race([previousPromise, timeoutPromise]);
|
||||
|
||||
// 4) fire-and-forget (의도적 비대기) — void 로 명시 (src/extension.ts)
|
||||
void ensureEmbeddingConfigured(context);
|
||||
|
||||
// 5) 병렬 수집 (src/features/providers/index.ts)
|
||||
const tasks: Array<Promise<void>> = [];
|
||||
tasks.push(listOpenRouterModels(ctx).then((ids) => ids.forEach(pushModel)));
|
||||
await Promise.all(tasks);
|
||||
```
|
||||
|
||||
## ✅ 검증 상태 및 신뢰도
|
||||
- **상태:** draft
|
||||
- **검증 단계:** applied
|
||||
- **출처 신뢰도:** A
|
||||
- **신뢰 점수:** 0.93
|
||||
- **중복 검사 결과:** 신규 생성 (New discovery)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[TypeScript 기초와 타입 시스템]]
|
||||
- **관련 개념:** [[동시성 제어 Lock Queue Transaction]], [[LLM 프로바이더 추상화]], [[에러 처리와 커스텀 에러]]
|
||||
- **참조 맥락:** 로컬 LLM 이 fetch/취소/타임아웃/병렬 처리를 작성할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/core/services.ts — AbortSignal.any/timeout, 엔진 폴백, void fire-and-forget(extension.ts 포함)
|
||||
- [S2] AstraAI/src/core/lock.ts — deferred Promise, Promise.race 타임아웃
|
||||
- [S3] (general) Promise.all/race 의미론
|
||||
- [S4] AstraAI/src/core/queue.ts — 동시성 제한 큐
|
||||
- [S5] AstraAI/src/features/providers/index.ts — Promise.all 병렬 수집
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.
|
||||
@@ -0,0 +1,150 @@
|
||||
---
|
||||
id: error-handling-custom-errors
|
||||
title: "에러 처리와 커스텀 에러"
|
||||
category: "Programming_Language"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["error handling", "try catch", "커스텀 에러", "graceful degradation", "에러 클래스", "rollback"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.93
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["typescript", "error-handling", "robustness", "astraai"]
|
||||
raw_sources: ["AstraAI/src/core/errors.ts", "AstraAI/src/core/errorHandler.ts", "AstraAI/src/core/transaction.ts", "AstraAI/src/memory/index.ts", "AstraAI/src/core/services.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[에러 처리와 커스텀 에러]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
견고한 코드는 "실패를 *예측해서 분류하고*, 사용자에게는 친절히 번역하며, 부가 작업의 실패가 본류를 망가뜨리지 않게" 만든다 — AstraAI 는 커스텀 에러 계층 + 사용자 친화 번역기 + "절대 본 흐름을 깨지 않는 try/catch" 로 이를 구현한다 [S1][S2][S4].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **`Error` 상속 계층:** 도메인별 에러를 `class XError extends Error` 로 만들어, `instanceof` 로 분기하고 추가 컨텍스트(경로, 엔진, 상태코드)를 담는다 [S1].
|
||||
2. **추상 베이스 클래스:** `abstract class G1Error extends Error` 가 공통 형태(`details`, `getTypeCode()`)를 강제하고, 구체 에러가 타입 코드를 구현 [S1].
|
||||
3. **에러 번역 (Error translation):** 내부 기술 에러 메시지를 *사용자 행동 지침* 으로 변환 (`title`/`message`/`action`) [S2].
|
||||
4. **Graceful degradation:** 부가 기능(메모리 추출, 증류, 텔레메트리)의 실패는 삼키고(`catch {}`) 본 흐름을 계속한다 [S4].
|
||||
5. **트랜잭션/롤백:** 여러 파일 변경을 묶고, 실패 시 백업으로 되돌리는 보상 트랜잭션 [S3].
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **커스텀 에러에 컨텍스트 부착:** `FileSystemError(message, path, details)`, `APICommunicationError(message, engine, status)` — 잡는 쪽이 어디서 왜 실패했는지 알 수 있게 [S1].
|
||||
- **`this.name = this.constructor.name`:** 스택 트레이스에 정확한 클래스명이 찍히도록 베이스에서 설정 [S1].
|
||||
- **"본 흐름을 깨지 않는" catch:** `try { extract(); } catch { /* memory extraction should never break the main flow */ }` — 의도를 주석으로 명시한 의도적 삼킴 [S4].
|
||||
- **에러를 Error 로 정규화:** `error instanceof Error ? error : new Error(String(error))` — catch 의 `unknown`/`any` 를 항상 Error 로 변환 [S5].
|
||||
- **사용자 친화 번역기:** 키워드 매칭(`fetch`/`timeout`/`404`)으로 정형화된 안내 카드를 반환 [S2].
|
||||
- **보상 트랜잭션:** 변경 전 원본을 백업(`record`), 성공 시 `commit`(백업 폐기), 실패 시 `rollback`(원복) [S3].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### 에러 클래스 계층
|
||||
```typescript
|
||||
abstract class G1Error extends Error {
|
||||
constructor(public message: string, public details?: any) {
|
||||
super(message);
|
||||
this.name = this.constructor.name; // 스택에 실제 클래스명
|
||||
}
|
||||
abstract getTypeCode(): string; // 하위가 타입 코드 구현 강제
|
||||
}
|
||||
export class FileSystemError extends G1Error {
|
||||
constructor(message: string, public path: string, details?: any) { super(message, details); }
|
||||
getTypeCode() { return 'FILE_SYSTEM_ERROR'; }
|
||||
}
|
||||
```
|
||||
`abstract` 메서드로 모든 하위 에러가 식별 코드를 갖게 강제 — 로깅/분기에서 문자열 비교 대신 안정적 코드를 쓴다 [S1].
|
||||
|
||||
### "절대 본 흐름을 깨지 않는다"
|
||||
세션 종료 시 메모리 추출·증류는 *부가 작업* 이다. 실패해도 대화 자체는 정상이어야 하므로 빈 catch 로 삼키되 **왜 삼키는지 주석을 단다**:
|
||||
```typescript
|
||||
try { this.extractor.extractFromSession(...); }
|
||||
catch { /* memory extraction should never break the main flow */ }
|
||||
```
|
||||
무분별한 빈 catch 는 안티패턴이지만, "부가 작업 + 의도 주석" 조합은 의도적 견고성이다 [S4].
|
||||
|
||||
### 사용자 친화 번역
|
||||
```typescript
|
||||
if (msg.includes('timeout')) return {
|
||||
title: '⏱️ 응답 시간 초과 (Timeout)',
|
||||
message: 'AI가 답변을 준비하는 데 너무 오래 걸리고 있습니다.',
|
||||
action: '설정에서 Timeout 시간을 늘리거나, 더 작은 범위로 질문해보세요.',
|
||||
};
|
||||
```
|
||||
기술 메시지(`ECONNREFUSED`)를 그대로 노출하지 않고, *무엇을 하면 되는지* 를 알려준다. 마지막에 일반 fallback 카드로 미분류 에러를 처리 [S2].
|
||||
|
||||
### 보상 트랜잭션 (파일 작업의 원자성)
|
||||
DB 트랜잭션이 없는 파일시스템에서 "여러 파일 변경을 전부 성공 또는 전부 취소" 하려면 직접 백업/복원해야 한다. `begin → record(각 파일) → (성공) commit / (실패) rollback`. rollback 은 `created` 파일은 삭제, `modified` 파일은 원본 내용 복원 [S3].
|
||||
|
||||
## ⚖️ 비교 및 선택 기준 (Comparison & decision criteria)
|
||||
|
||||
| 항목 (Option) | 장점 | 단점 | 언제 선택 |
|
||||
|---|---|---|---|
|
||||
| throw + 상위 catch | 흐름 단순 | 어디서 잡을지 추적 필요 | 계약 위반·복구 불가 상황 |
|
||||
| 빈 catch (의도 주석) | 본 흐름 보호 | 남용 시 버그 은폐 | 진짜 부가 작업만 |
|
||||
| 결과 유니온 반환 | 호출부 강제 처리 | 보일러플레이트 | 흔한 실패(파일 append) |
|
||||
| 커스텀 에러 클래스 | instanceof 분기 + 컨텍스트 | 클래스 정의 비용 | 도메인별 처리 분기 필요 |
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **빈 catch 는 기본적으로 위험:** AstraAI 는 "본 흐름을 깨지 않아야 하는 부가 작업"에 한해 의도 주석과 함께만 허용한다. 검증·핵심 로직의 실패는 절대 조용히 삼키지 않는다.
|
||||
- **에러 메시지 키워드 매칭의 취약성:** `ErrorTranslator` 는 메시지 문자열에 의존하므로, 라이브러리가 메시지를 바꾸면 매칭이 깨질 수 있다. 가능하면 `getTypeCode()` 같은 안정 식별자 기반 분기가 더 견고하다.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/core/errors.ts` — G1Error 추상 베이스 + 4개 도메인 에러 [S1].
|
||||
- `AstraAI/src/core/errorHandler.ts` — ErrorTranslator 사용자 친화 번역 [S2].
|
||||
- `AstraAI/src/core/transaction.ts` — begin/record/commit/rollback 보상 트랜잭션 [S3].
|
||||
- `AstraAI/src/memory/index.ts` — "본 흐름 보호" 의도적 빈 catch [S4].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// 1) 컨텍스트를 담는 커스텀 에러 (src/core/errors.ts)
|
||||
export class APICommunicationError extends G1Error {
|
||||
constructor(message: string, public engine: string, public status?: number, details?: any) {
|
||||
super(message, details);
|
||||
}
|
||||
getTypeCode() { return 'API_COMMUNICATION_ERROR'; }
|
||||
}
|
||||
|
||||
// 2) catch 의 unknown 을 Error 로 정규화 (src/core/services.ts)
|
||||
catch (error: any) {
|
||||
lastError = error instanceof Error ? error : new Error(String(error));
|
||||
}
|
||||
|
||||
// 3) 본 흐름을 깨지 않는 의도적 삼킴 (src/memory/index.ts)
|
||||
try { distillStaleEpisodes(...); }
|
||||
catch { /* distillation should never break session end */ }
|
||||
|
||||
// 4) 보상 트랜잭션 (src/core/transaction.ts)
|
||||
tx.begin();
|
||||
try {
|
||||
await tx.record(filePath); // 변경 전 백업
|
||||
fs.writeFileSync(filePath, next);
|
||||
tx.commit(); // 성공 → 백업 폐기
|
||||
} catch (e) {
|
||||
tx.rollback(); // 실패 → 원본 복원
|
||||
throw e;
|
||||
}
|
||||
```
|
||||
|
||||
## ✅ 검증 상태 및 신뢰도
|
||||
- **상태:** draft
|
||||
- **검증 단계:** applied
|
||||
- **출처 신뢰도:** A
|
||||
- **신뢰 점수:** 0.93
|
||||
- **중복 검사 결과:** 신규 생성 (New discovery)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[TypeScript 기초와 타입 시스템]]
|
||||
- **관련 개념:** [[동시성 제어 Lock Queue Transaction]], [[비동기 프로그래밍 Promise async await]], [[코딩 컨벤션과 주석 철학]]
|
||||
- **참조 맥락:** 로컬 LLM 이 실패를 분류·번역·복구하는 코드를 작성할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/core/errors.ts — G1Error 추상 베이스 + 도메인 에러
|
||||
- [S2] AstraAI/src/core/errorHandler.ts — ErrorTranslator
|
||||
- [S3] AstraAI/src/core/transaction.ts — 보상 트랜잭션
|
||||
- [S4] AstraAI/src/memory/index.ts — 의도적 빈 catch
|
||||
- [S5] AstraAI/src/core/services.ts — Error 정규화
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
id: pattern-catalog-index
|
||||
title: "패턴 카탈로그 인덱스"
|
||||
category: "Index"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["pattern catalog", "패턴 카탈로그", "design pattern index", "패턴 라이브러리"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.9
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["index", "pattern", "catalog", "navigation"]
|
||||
raw_sources: ["Pattern_Catalog 전체"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[패턴 카탈로그 인덱스]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
플랫폼이 달라도 개발은 *같은 문제(상태·비동기·데이터·캐싱·오류·분리)* 를 반복한다 — 이 카탈로그는 재사용 가능한 패턴 27종을 (언제·조건·장점·단점·대안·실패사례) 형식으로 정리해 작은 모델이 상황에 맞는 패턴을 고르게 한다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
각 패턴 카드 = 문제/조건/장단점/대안/실패. AstraAI 사례가 있으면 적용 예로 연결, 없으면 일반 지식.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 목록)
|
||||
|
||||
### Cross-cutting (모든 플랫폼 공통 — 최우선 학습)
|
||||
- [[State Management Pattern]] · [[Async Concurrency Pattern]] · [[Data Flow Pattern]] · [[Caching Pattern]] · [[Error Handling Pattern]] · [[Architecture Separation Pattern]]
|
||||
|
||||
### AI
|
||||
- [[RAG Pattern]] · [[Memory Pattern]] · [[Agent Orchestration Pattern]] · [[Reflection Pattern]] · [[Critic Pattern]] · [[Tool Calling Pattern]]
|
||||
|
||||
### Web
|
||||
- [[JWT Authentication Pattern]] · [[Repository Pattern]] · [[API Client Pattern]] · [[React State Pattern]] · [[Infinite Scroll Pattern]] (캐싱은 [[Caching Pattern]])
|
||||
|
||||
### Mobile
|
||||
- [[Offline Sync Pattern]] · [[Local Storage Pattern]] · [[Background Task Pattern]] · [[Push Notification Pattern]] · [[Navigation Pattern]]
|
||||
|
||||
### Desktop
|
||||
- [[IPC Pattern]] · [[Plugin Architecture Pattern]] · [[Command Pattern]] · [[Event Bus Pattern]] · [[Background Worker Pattern]]
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
패턴은 *기본값* 이지 의무가 아니다. 적용 전 [[소프트웨어 실패 라이브러리]] 로 "이 패턴이 어떻게 깨지는가" 를 함께 확인하라.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
RAG/Memory/Agent Orchestration/Critic/Event Bus/Repository/Caching/API Client/IPC/Command/Plugin/Background Worker 는 AstraAI 에 실제 구현되어 있어 코드 근거가 있다.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[Topic Programming 인덱스]]
|
||||
- **관련 개념:** [[소프트웨어 실패 라이브러리]] · [[플랫폼 개발 가이드 인덱스]] · [[프로젝트 독립 설계 원칙]]
|
||||
- **참조 맥락:** 작은 모델이 구현 시 "어떤 패턴을 쓸까" 를 고를 때의 카탈로그.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] Pattern_Catalog 전체 + 일반 소프트웨어 공학 지식 + AstraAI 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 패턴 카탈로그 인덱스 생성.
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
id: pattern-agent-orchestration
|
||||
title: "Agent Orchestration Pattern"
|
||||
category: "Pattern_AI"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["Agent Orchestration", "에이전트 오케스트레이션 패턴", "multi-agent", "pipeline"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.88
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "ai", "agent", "orchestration", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src/agents/*, src/features/company/dispatcher.ts (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Agent Orchestration Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
에이전트 오케스트레이션은 "큰 작업을 단계/역할로 쪼개 LLM 을 여러 번 호출·조율" 하는 패턴이며, *에이전트 수를 늘리는 것 자체가 목적이 되면 실패* 한다 — 정보 손실과 자원을 먼저 따져라.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **분해:** 작업 → 단계(outline/draft/polish) 또는 역할(planner/specialist/reporter).
|
||||
2. **조율:** 흐름 골격이 호출 순서·데이터 전달을 관리.
|
||||
3. **상태 전달:** 앞 단계 출력을 다음에 전달(peer-context), 단 손실 주의.
|
||||
4. **자원 모델:** 병렬 vs 순차는 하드웨어가 결정.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 단일 호출로는 품질/길이/전문성이 부족한 복합 작업.
|
||||
- **사용 조건:** 단계 분해가 명확; 단계 간 인터페이스 정의 가능; 자원이 선택한 동시성 모델을 감당.
|
||||
- **장점:** 단계별 최적화, 긴 산출물, 역할 전문화, 검증 단계 삽입 용이.
|
||||
- **단점:** 지연·비용 증가, hop 마다 컨텍스트 누적/원본 손실, 디버깅 복잡.
|
||||
- **대안:** 단일 프롬프트(짧은 작업), 단일 작성자 다중 역할(자원 제약), 도구 호출.
|
||||
- **실패 사례:** 에이전트 남발로 "방법론만 생성"; 병렬 다중 모델 상주 OOM; orchestrator 재비대.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
# 자원 제약: 순차 + 한 모델 상주
|
||||
plan = planner(prompt)
|
||||
peer = ""
|
||||
for task in plan.tasks:
|
||||
out = specialist(task, peer); persist(out); peer += truncate(out)
|
||||
report = synthesizer(prompt, peer)
|
||||
|
||||
# 단일 작성자 다중 역할 (작은 모델 친화)
|
||||
outline = M("outline", prompt); body = [M("section", o, source) for o in outline]; M("polish", body)
|
||||
```
|
||||
적용 예: [[Agent 오케스트레이터 분해]], [[AITRAIN 에이전트 오케스트레이션]], 결정 [[ADR-0003 단일작성자 다중역할 멀티에이전트]]·[[ADR-0004 순차 디스패치 채택]].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"멀티에이전트가 항상 낫다" 는 자원 제약 하에서 거짓 — 잘 만든 단일 작성자가 어설픈 병렬 파이프라인을 이긴다.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI company dispatcher(순차), ChunkedWriter(단일 다중역할).
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Reflection Pattern]], [[Critic Pattern]], [[Tool Calling Pattern]], [[Background Worker Pattern]]
|
||||
- **참조 맥락:** 작은 모델이 복합 작업을 단계화할 때 과설계 회피와 함께 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 멀티에이전트 지식
|
||||
- [S2] AstraAI/src/agents/*, features/company/dispatcher.ts — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
id: pattern-critic
|
||||
title: "Critic Pattern"
|
||||
category: "Pattern_AI"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["Critic", "LLM judge", "검수자 패턴", "verifier"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.88
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "ai", "critic", "verification", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src/intelligence/criticAgent.ts (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Critic Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
Critic 패턴은 "별도의 검수자(보통 LLM)가 산출물을 비판적으로 평가" 하는 것으로, 생성자와 검수자를 분리하면 환각·누락을 잡지만 *검수 출력도 결국 LLM 이라 강건 파싱·근거 강제가 필수* 다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. 생성자와 검수자 역할 분리. 2. 검수 기준 명시(요구 충족·근거·미결 구분·지어냄 금지). 3. 구조화 출력(JSON) + 강건 파싱. 4. 검수 결과를 보완 카드/재작성 입력으로.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 산출물의 사실성/완결성이 중요하고, 생성자 자체 점검만으론 부족할 때.
|
||||
- **사용 조건:** 검수 기준을 명문화 가능; 검수 호출 비용 감당; 출력 파싱 방어.
|
||||
- **장점:** 독립 시각으로 오류 포착, 근거 없는 단정 차단, 보완 제안.
|
||||
- **단점:** 추가 LLM 비용, 검수자도 환각 가능, JSON 형식 위반.
|
||||
- **대안:** 결정론 규칙 검증, 다수결(여러 검수자), 사람 검수.
|
||||
- **실패 사례:** 검수자가 원문에 없는 내용을 "보완" 으로 지어냄; JSON.parse 직접 호출로 파싱 실패; 무조건 검수로 비용 폭증.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
critique = LLM_critic(system="검수자. 근거 없는 단정/지어냄은 major. JSON만 출력", user=task+draft)
|
||||
result = parseBalancedJson(critique) or heuristicFallback() # 잡설 내성
|
||||
if not result.pass: attach(footer(result.issues, result.supplement))
|
||||
# 규칙: supplement 도 원문 근거 한정, 없으면 "(확인 필요)"
|
||||
```
|
||||
적용 예: [[Intelligence 검증 레이어]] 의 criticAgent(조건부 1-pass + 균형 괄호 파서), 결정 [[ADR-0009 결정론 항상 LLM검증 조건부]].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
검수자가 생성자보다 똑똑하지 않으면 효과가 제한적 — 작은 모델끼리는 *결정론 신호 + 근거 강제* 가 LLM-judge 보다 안정적일 수 있다.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI Critic(조건부), regression LLM-judge.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Reflection Pattern]], [[프롬프트 엔지니어링 패턴]], [[소프트웨어 실패 라이브러리]]
|
||||
- **참조 맥락:** 작은 모델이 산출물 품질 게이트를 둘 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 LLM critic/judge 지식
|
||||
- [S2] AstraAI/src/intelligence/criticAgent.ts — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
id: pattern-memory
|
||||
title: "Memory Pattern"
|
||||
category: "Pattern_AI"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["Memory Pattern", "에이전트 메모리 패턴", "agent memory"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.89
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "ai", "memory", "agent", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src/memory/* (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Memory Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
에이전트 메모리 패턴은 "대화/세션을 넘어 지식을 보존·회수" 하며, 단일 버퍼가 아니라 *수명·용도별 계층* 으로 나누고 관련도로 선별 주입할 때 작은 모델의 일관성이 크게 오른다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **단기:** 현재 대화(FIFO). 2. **장기:** 안정적 사실/선호(만료 가능). 3. **작업/프로젝트:** 작업 종속 지식. 4. **절차:** 반복 작업 방법. 5. **일화:** 과거 세션 요약. 회수 시 관련도순 선별.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 에이전트가 세션을 넘어 사용자/프로젝트를 기억해야 할 때, 컨텍스트 한도가 빠듯할 때.
|
||||
- **사용 조건:** 영속 저장 가능; 관련도 점수화 가능; 무엇을 어느 계층에 넣을지 분류 규칙 존재.
|
||||
- **장점:** 일관성·개인화, 컨텍스트 정밀 선별, 시한부/영구 공존, 자동 정리(증류).
|
||||
- **단점:** 분류 결정 비용, 저장/검색 인프라, 잘못된 회수 시 노이즈.
|
||||
- **대안:** 무상태(매번 새로), 전체 이력 투입(짧을 때), 외부 RAG 로만 대체.
|
||||
- **실패 사례:** 만료 없는 영구 저장으로 옛 사실 재현; 관련도 오선별로 핵심 누락; 계층 경계 모호로 중복.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
buildContext(query):
|
||||
layers = [shortTerm, longTerm(query), project(query), procedural(query), episodic(query)]
|
||||
return sort_by_relevance(layers).join() # 빈 계층 제외
|
||||
onSessionEnd(): extract -> persist -> distill(stale -> longterm digest)
|
||||
```
|
||||
적용 예: [[5계층 메모리 시스템]], [[AITRAIN 메모리 시스템]], 결정 [[ADR-0002 5계층 메모리 분리]].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
계층이 많을수록 표현력↑ 결정 비용↑ — 명확한 분류 규칙이 없으면 단순 3계층(작업/세션/영구)이 낫다.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI MemoryManager.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[RAG Pattern]], [[Local Storage Pattern]], [[Offline Sync Pattern]]
|
||||
- **참조 맥락:** 작은 모델이 기억하는 에이전트를 만들 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 에이전트 메모리 지식
|
||||
- [S2] AstraAI/src/memory/* — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
id: pattern-rag
|
||||
title: "RAG Pattern"
|
||||
category: "Pattern_AI"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["RAG", "Retrieval-Augmented Generation", "검색 증강 생성 패턴"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.9
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "ai", "rag", "retrieval", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src/retrieval/* (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[RAG Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
RAG 는 "모델이 답하기 전에 외부 지식에서 관련 조각을 검색해 프롬프트에 주입" 하는 패턴으로, 모델의 학습되지 않은/최신/사적 지식을 *재학습 없이* 활용하고 환각을 줄인다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **인덱싱:** 문서를 청크로 나눠 검색 인덱스(키워드/임베딩)에 저장.
|
||||
2. **검색:** 질의로 top-k 관련 청크 회수(sparse/dense/하이브리드).
|
||||
3. **증강:** 회수 청크를 컨텍스트로 프롬프트에 삽입(토큰 예산 내).
|
||||
4. **생성:** 모델이 근거를 보고 답하고 출처를 인용.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 모델이 모르는 사적/최신/대용량 지식이 필요하고, 파인튜닝은 비싸거나 자주 바뀔 때. 출처 인용·환각 감소가 필요할 때.
|
||||
- **사용 조건:** 검색 가능한 지식 베이스 존재; 청킹/인덱싱 가능; 컨텍스트 한도 내 주입 가능.
|
||||
- **장점:** 재학습 불필요, 지식 즉시 갱신, 출처 추적, 환각↓, 작은 모델도 강화.
|
||||
- **단점:** 검색 품질에 답이 좌우(garbage in), 인덱싱/저장 비용, 컨텍스트 토큰 소비, 청킹 경계 손실.
|
||||
- **대안:** 파인튜닝(지식이 안정적·대규모일 때), 긴 컨텍스트에 전체 투입(소량일 때), 도구 호출로 실시간 조회.
|
||||
- **실패 사례:** 청크가 너무 커 정밀도↓; 부분 정규화로 하이브리드 편향; 동의어 미확장으로 recall↓; stale 인덱스; 운영 로그를 지식으로 오염.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
index = chunk(docs) -> tokenize/embed -> store
|
||||
query -> expand(synonyms) -> score(sparse + α·dense) -> normalize -> rerank
|
||||
context = selectWithinTokenBudget(top_chunks)
|
||||
answer = LLM(system + context + question) # "근거 없으면 모른다고"
|
||||
```
|
||||
적용 예: AstraAI 의 [[RAG 검색 파이프라인]]·[[TF-IDF 이중언어 스코어링]] (하이브리드+섹션 청킹+토큰 예산).
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"임베딩만 쓰면 된다" 는 가용성·설명가능성을 잃는다 — 결정론(키워드) 바닥선 + 임베딩 가산이 견고([[ADR-0007 하이브리드 검색 결정론 우선]]).
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI 전체 검색이 이 패턴. → [[AITRAIN RAG 검색]].
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Memory Pattern]], [[Caching Pattern]], [[Tool Calling Pattern]], [[소프트웨어 실패 라이브러리]]
|
||||
- **참조 맥락:** 작은 모델이 지식 기반 응답 시스템을 만들 때 1순위 패턴.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 RAG 공학 지식
|
||||
- [S2] AstraAI/src/retrieval/* — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
id: pattern-reflection
|
||||
title: "Reflection Pattern"
|
||||
category: "Pattern_AI"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["Reflection", "자기성찰 패턴", "self-reflection", "self-critique"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.88
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "ai", "reflection", "self-improvement", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src/intelligence/*, src/features/selfReflector/* (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Reflection Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
Reflection 은 "모델이 자기 출력을 다시 점검·수정" 하는 패턴으로, 작은 모델의 1-pass 오류를 줄이지만 *호출이 늘어 비용/지연이 증가* 하므로 조건부로 써야 한다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **생성 → 점검 → (필요시) 재생성** 루프. 2. 점검은 *결정론 신호* 또는 *LLM 자기비판*. 3. 자기검토 지시를 시스템 프롬프트에 주입. 4. 무한 루프 방지(최대 라운드).
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 1-pass 정확도가 부족하고, 오류 비용이 재검토 비용보다 클 때.
|
||||
- **사용 조건:** 점검 신호(규칙/요구사항/근거) 정의 가능; 추가 호출 latency 감당.
|
||||
- **장점:** 정확도·완결성↑, 누락/모순 발견, 불확실성 표면화.
|
||||
- **단점:** 지연·비용↑, 과도하면 헤지 남발, 무한 루프 위험.
|
||||
- **대안:** 결정론 검증만(무LLM), 외부 검증기, 더 큰 모델 1-pass.
|
||||
- **실패 사례:** 매 턴 무조건 reflect 로 latency 폭증; 자기비판이 오히려 정답을 망침; 종료 조건 없어 루프.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
draft = LLM(task)
|
||||
signals = deterministicChecks(draft) # 커버리지/근거/확신도 — 항상(저비용)
|
||||
if signals.risky: # 조건부로만 LLM 점검
|
||||
issues = LLM_critique(task, draft)
|
||||
if issues: draft = revise(draft, issues) # 최대 N라운드
|
||||
emit(draft + confidence_footer)
|
||||
```
|
||||
적용 예: [[Intelligence 검증 레이어]] (사전 자기검토 블록 + 조건부 critic), 결정 [[ADR-0009 결정론 항상 LLM검증 조건부]].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"항상 성찰하면 좋다" 는 비용을 무시한 통념 — *위험 신호가 있을 때만* 깊은 성찰이 비용 대비 효과적.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI selfReflector + 조건부 Critic.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Critic Pattern]], [[Agent Orchestration Pattern]], [[프롬프트 엔지니어링 패턴]]
|
||||
- **참조 맥락:** 작은 모델의 자기개선 루프 설계 시 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 reflection/self-critique 지식
|
||||
- [S2] AstraAI/src/intelligence/*, features/selfReflector/* — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
id: pattern-tool-calling
|
||||
title: "Tool Calling Pattern"
|
||||
category: "Pattern_AI"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["Tool Calling", "function calling", "도구 호출 패턴", "action tag"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.88
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "ai", "tool-calling", "function-calling", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src/agent/actions/* (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Tool Calling Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
Tool Calling 은 "모델이 자연어 대신 구조화된 호출(함수/태그)로 외부 도구를 실행" 하게 해 실제 행동(파일 생성·명령 실행·검색)을 가능케 하며, *모델 출력을 신뢰 경계로 보고 검증·승인* 하는 것이 안전의 핵심이다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. 도구 스키마 정의(이름·인자). 2. 모델이 호출 의도를 구조화 출력(JSON function call 또는 `<action>` 태그). 3. 실행기가 파싱→검증→실행→결과 반환. 4. 위험 동작은 승인 게이트.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 모델이 텍스트를 넘어 *행동* 해야 할 때(파일/명령/API/검색).
|
||||
- **사용 조건:** 도구 인터페이스 명확; 출력 파싱 가능; 권한/검증 체계.
|
||||
- **장점:** 실제 작업 자동화, 결정론 도구로 환각 보완, 확장성(도구 추가).
|
||||
- **단점:** 보안 위험(임의 명령), 파싱 실패, 잘못된 인자, 무한 호출.
|
||||
- **대안:** 사람이 실행, 고정 워크플로(모델 미개입), 제한된 화이트리스트 액션.
|
||||
- **실패 사례:** 모델 출력을 검증 없이 실행(주입 공격); 경로 미검증으로 임의 파일 접근; 승인 없는 파괴적 명령.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
output = LLM(system + tools_schema + task)
|
||||
for call in parseToolCalls(output): # <create_file>, <run_command> ...
|
||||
if !validate(call): skip/log
|
||||
if dangerous(call): await approval() # 승인 게이트
|
||||
result = execute(call) # 실행기로 라우팅
|
||||
feed(result -> next turn)
|
||||
```
|
||||
적용 예: AstraAI 의 action tag 실행기(src/agent/actions/*) + 승인 큐(approval) + 경로 검증(security.validatePath). 라우팅은 [[Agent 오케스트레이터 분해]] 참조.
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"모델이 시키는 대로 실행" 은 위험 — 모델 출력은 *신뢰되지 않은 입력* 으로 다뤄 검증·샌드박스·승인을 거쳐야 한다.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI action tags + approval gate + validatePath/sanitizeCommand.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Agent Orchestration Pattern]], [[API Client Pattern]], [[Command Pattern]], [[소프트웨어 실패 라이브러리]]
|
||||
- **참조 맥락:** 작은 모델이 행동하는 에이전트를 만들 때 안전 경계와 함께 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 function/tool calling 지식
|
||||
- [S2] AstraAI/src/agent/actions/*, security.ts — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
---
|
||||
id: pattern-architecture-separation
|
||||
title: "Architecture Separation Pattern"
|
||||
category: "Pattern_CrossCutting"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["layering", "아키텍처 분리", "관심사 분리", "separation of concerns", "layered architecture", "ports and adapters"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.88
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "cross-cutting", "architecture", "layering", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src 구조 (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Architecture Separation Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
아키텍처 분리는 "**관심사를 계층/모듈로 나누고, 의존은 한 방향(안정적인 쪽으로)으로만 흐르게**" 하는 것으로, 플랫폼이 달라도 UI/도메인/인프라를 섞지 않는 것이 유지보수의 토대다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **계층:** 인프라(core) → 역량(lib/도메인 서비스) → 기능(features) → 조립(entry). 위가 아래에 의존.
|
||||
2. **관심사 분리:** UI / 도메인 로직 / I/O 를 섞지 않는다.
|
||||
3. **의존성 역전:** 도메인이 인프라 *인터페이스* 에 의존, 구현은 주입.
|
||||
4. **경계(ports & adapters):** 외부(DB/API/UI)는 어댑터로, 핵심은 순수.
|
||||
5. **단일 책임:** 한 모듈은 한 가지 변경 이유.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 코드가 커지며 UI/로직/I/O 가 엉켜 변경이 두려울 때.
|
||||
- **사용 조건:** 책임 경계를 식별 가능; 인터페이스로 추상화 가능.
|
||||
- **장점:** 변경 격리, 테스트성(핵심 순수), 교체 용이(어댑터), 병렬 작업.
|
||||
- **단점:** 초기 보일러플레이트, 과한 계층은 오버헤드("얇은 래퍼 지옥").
|
||||
- **대안:** 모놀리식 단순 구조(소규모), 수직 슬라이스(기능별 풀스택), 모듈러 모놀리스.
|
||||
- **실패 사례:** UI 에 비즈니스 로직 혼입; 도메인이 DB/프레임워크에 직접 의존(교체 불가); 순환 의존; 계층 우회(아래가 위 호출).
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
features/ -> lib/도메인서비스 -> core/인프라 # 단방향 의존
|
||||
domain depends on interface (IRepo, IAIService) # 의존성 역전
|
||||
adapter implements interface (FileRepo, AIService)
|
||||
entrypoint wires them (composition root) # 조립은 한 곳
|
||||
```
|
||||
적용 예: AstraAI 계층(core/lib/memory/retrieval/intelligence/features) + 인터페이스 서비스([[AstraAI 아키텍처 개요]], [[의존성 주입과 서비스 인터페이스]], [[모듈 시스템과 프로젝트 구성]]).
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
계층이 많을수록 격리는 좋아지나 단순 변경도 여러 파일을 거친다 — 규모에 맞춰라. 흐름 가독성을 위해 *골격은 한 곳에* 남기는 절충도 유효([[ADR-0010 오케스트레이터 골격 모듈추출]]).
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI 전체 폴더 계층 + DI.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Repository Pattern]], [[Plugin Architecture Pattern]], [[Data Flow Pattern]], [[프로젝트 독립 설계 원칙]]
|
||||
- **참조 맥락:** 작은 모델이 새 프로젝트의 폴더/계층 구조를 잡을 때 1차 원리.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 계층화/관심사 분리 지식(Clean/Hexagonal)
|
||||
- [S2] AstraAI/src 구조 — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
id: pattern-async-concurrency
|
||||
title: "Async Concurrency Pattern"
|
||||
category: "Pattern_CrossCutting"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["async pattern", "비동기 패턴", "concurrency", "cancellation", "debounce", "throttle"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.89
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "cross-cutting", "async", "concurrency", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src/core/* (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Async Concurrency Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
비동기 처리는 모든 플랫폼이 공유하는 핵심이며, 안전의 3축은 "**취소 가능(cancellation) · 자원 폭주 방지(제한) · 경쟁 상태 제어(직렬화)**" 다 — UI 멈춤·메모리 폭주·갱신 손실이 여기서 갈린다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **취소:** AbortSignal/토큰으로 진행 중 작업 중단(타임아웃+사용자 취소 결합).
|
||||
2. **동시성 제한:** 큐/세마포어로 동시 실행 수 상한.
|
||||
3. **직렬화:** 공유 자원은 락/뮤텍스로 한 번에 하나.
|
||||
4. **debounce/throttle:** 빈번 이벤트(입력/스크롤)를 솎아냄.
|
||||
5. **병렬 vs 순차:** 독립이면 병렬(all), 의존이면 순차, 부분실패 허용이면 allSettled.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** I/O·네트워크·장시간 작업이 UI/자원에 영향 줄 때.
|
||||
- **사용 조건:** 취소 신호 전파 가능; 작업 단위 분리 가능.
|
||||
- **장점:** 반응성 유지, 자원 안정, 데이터 일관.
|
||||
- **단점:** 복잡도↑, 콜백/Promise 추론 어려움, 취소 누락 시 좀비 작업.
|
||||
- **대안:** 동기(작은 작업), 워커/스레드(CPU 바운드), 큐 시스템(분산).
|
||||
- **실패 사례:** 취소 미전파로 좀비 fetch; Promise.all 부분 실패로 전체 손실; 무한 병렬 OOM; 락 미해제 데드락; forEach+async 로 미대기.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
signal = combine(userAbort, timeout(ms)) # 취소 = 사용자 OR 타임아웃
|
||||
await fetch(url, { signal })
|
||||
await queue.enqueue(task) # 동시성 상한
|
||||
release = await lock.acquire(id); try{...} finally{ release() } # 직렬화
|
||||
onInput = debounce(handler, 200) # 이벤트 솎기
|
||||
results = await Promise.allSettled(tasks) # 부분 실패 허용
|
||||
```
|
||||
적용 예: [[비동기 프로그래밍 Promise async await]], [[동시성 제어 Lock Queue Transaction]], [[AITRAIN 동시성 제어]].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"병렬이 빠르다" 는 자원 한도 내에서만 참 — 한도를 넘으면 스왑/OOM 으로 더 느려진다([[ADR-0004 순차 디스패치 채택]]).
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI services(AbortSignal), lock/queue.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Background Worker Pattern]], [[Background Task Pattern]], [[Error Handling Pattern]]
|
||||
- **참조 맥락:** 작은 모델이 어떤 플랫폼이든 비동기 코드를 쓸 때 1차 원리.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 비동기/동시성 지식
|
||||
- [S2] AstraAI/src/core/services.ts, lock.ts, queue.ts — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
id: pattern-caching
|
||||
title: "Caching Pattern"
|
||||
category: "Pattern_CrossCutting"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["caching", "캐싱", "memoization", "TTL", "invalidation", "mtime cache"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.88
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "cross-cutting", "caching", "performance", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src/retrieval/scoring.ts, src/lib/mtimeFileCache.ts (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Caching Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
캐싱은 "비싼 계산/조회 결과를 저장해 재사용" 하는 보편 최적화이며, 어려운 것은 캐싱 자체가 아니라 "**언제 무효화(invalidation)하느냐**" 다 — stale 데이터는 성능보다 더 큰 버그를 만든다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **memoization:** 같은 입력→같은 출력을 키로 저장.
|
||||
2. **무효화 전략:** TTL(시간), 버전/해시, 변경 감지(mtime), 수동.
|
||||
3. **캐시 키 설계:** 입력을 정확히 식별(누락 시 잘못된 hit).
|
||||
4. **용량 제한:** LRU/상한으로 무한 증가 방지.
|
||||
5. **계층:** 메모리→디스크→원격, 가까울수록 빠름.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 동일 계산/조회가 반복되고 비용이 클 때, 결과가 자주 안 바뀔 때.
|
||||
- **사용 조건:** 결정적 입력→출력; 무효화 신호 존재; 메모리/디스크 여유.
|
||||
- **장점:** 지연·비용 대폭↓, 부하 완화.
|
||||
- **단점:** stale 위험, 메모리 사용, 무효화 복잡, 캐시 키 버그.
|
||||
- **대안:** 매번 계산(정확성 우선), 사전 계산(배치), 증분 갱신.
|
||||
- **실패 사례:** 무효화 누락으로 옛 데이터 제공; 키 충돌로 잘못된 hit; 무한 증가 OOM; 변경 감지 누락(mtime 미갱신).
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
# memoization + 용량 제한
|
||||
if cache.has(key): return cache.get(key)
|
||||
val = expensive(input); if cache.size >= LIMIT: cache.clear(); cache.set(key, val)
|
||||
|
||||
# 변경 감지 무효화 (파일)
|
||||
if file.mtime != cached.mtime: cached = reindex(file) # 변경된 파일만 재계산
|
||||
```
|
||||
적용 예: AstraAI 의 TOKEN_CACHE(토크나이저 memoization, 상한 시 clear) + mtime 키 brain 인덱스(변경 없는 파일 재토큰화 회피) [S2]. RAG 의 dense/sparse 인덱스도 캐시.
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"캐시하면 빠르다" 의 이면은 "무효화를 틀리면 조용히 틀린 답" — Phil Karlton 의 "캐시 무효화는 컴퓨터 과학의 2대 난제". 변경 감지(mtime/해시)가 TTL 보다 정확할 때가 많다.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI 토큰 캐시 + mtime 인덱스([[TF-IDF 이중언어 스코어링]], [[RAG 검색 파이프라인]]).
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Local Storage Pattern]], [[API Client Pattern]], [[RAG Pattern]], [[소프트웨어 실패 라이브러리]]
|
||||
- **참조 맥락:** 작은 모델이 성능 최적화를 할 때 무효화 전략과 함께 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 캐싱 공학 지식
|
||||
- [S2] AstraAI/src/retrieval/scoring.ts(TOKEN_CACHE), brainIndex/mtimeFileCache — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
id: pattern-data-flow
|
||||
title: "Data Flow Pattern"
|
||||
category: "Pattern_CrossCutting"
|
||||
status: "draft"
|
||||
verification_status: "conceptual"
|
||||
canonical_id: ""
|
||||
aliases: ["data flow", "데이터 흐름", "pipeline", "transform", "boundary normalization"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.86
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "cross-cutting", "data-flow", "pipeline", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src/retrieval/*, src/features/providers/* (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Data Flow Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
데이터 흐름 설계의 핵심은 "**경계에서 정규화하고(입력 검증·형식 통일), 내부는 단일 형태로 다루며, 변환을 작은 순수 단계의 파이프라인으로**" 만드는 것이다 — 그러면 어디서 무엇이 변하는지 추적된다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **경계 정규화:** 외부 입력(API/파일/사용자)을 들어오자마자 내부 표준 형태로 변환·검증.
|
||||
2. **단일 내부 모델:** 내부는 하나의 형태만 — 분기/특수처리를 가장자리로.
|
||||
3. **파이프라인:** 변환을 작은 순수 단계로 연결(test 가능).
|
||||
4. **출력 정규화:** 다양한 백엔드를 같은 출력 형식으로(예: SSE).
|
||||
5. **불변 전달:** 단계 간 데이터를 변형 대신 새 값 생성.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 이질적 소스/싱크가 많고 변환 단계가 여러 개일 때.
|
||||
- **사용 조건:** 표준 내부 모델 정의 가능; 단계 분해 가능.
|
||||
- **장점:** 추적성, 테스트성(순수 단계), 소스/싱크 추가 용이, 버그 격리.
|
||||
- **단점:** 변환 레이어 비용, 과한 추상화는 오버헤드.
|
||||
- **대안:** 직접 결합(소규모), 스트림 처리(대용량), 이벤트 버스(느슨 결합).
|
||||
- **실패 사례:** 경계 검증 누락으로 내부에 오염 전파; 내부에 외부 형식 누수(공급자별 분기 산재); 가변 전달로 단계 간 부작용.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
internal = normalizeAtBoundary(externalInput) # 들어올 때 1회 정규화 + 검증
|
||||
result = stage3(stage2(stage1(internal))) # 작은 순수 단계 파이프라인
|
||||
output = toStandardFormat(result) # 나갈 때 형식 통일 (예: SSE)
|
||||
```
|
||||
적용 예: [[LLM 프로바이더 추상화]](공급자별 입력 정규화→공통 SSE 출력), [[RAG 검색 파이프라인]](tokenize→score→fuse→budget).
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
경계 정규화는 비용이지만, 생략하면 특수처리가 코드 전체로 번진다 — "차이는 가장자리에서 흡수" 원칙([[AITRAIN 프로바이더 추상화]]).
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI provider 어댑터, retrieval 파이프라인.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[State Management Pattern]], [[Repository Pattern]], [[API Client Pattern]], [[Architecture Separation Pattern]]
|
||||
- **참조 맥락:** 작은 모델이 입출력 변환이 많은 코드를 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 데이터 흐름/파이프라인 지식
|
||||
- [S2] AstraAI/src/retrieval/*, features/providers/* — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
id: pattern-error-handling
|
||||
title: "Error Handling Pattern"
|
||||
category: "Pattern_CrossCutting"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["error handling", "오류 처리 패턴", "graceful degradation", "result type", "retry", "fallback"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.89
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "cross-cutting", "error-handling", "resilience", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src/core/* (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Error Handling Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
견고한 오류 처리는 "**실패를 분류하고(복구 가능/불가), 흔한 실패는 결과값으로·예외는 진짜 예외에, 부가 작업 실패는 본류를 막지 않게, 사용자에겐 행동 지침으로 번역**" 하는 것이다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **분류:** 복구 가능(재시도/폴백) vs 불가(즉시 실패) vs 부가(무시).
|
||||
2. **결과 타입 vs 예외:** 흔한 실패는 `{ok,error}` 유니온, 계약 위반은 throw.
|
||||
3. **재시도/폴백:** 일시 오류는 backoff 재시도, 대안 경로 폴백.
|
||||
4. **graceful degradation:** 핵심은 살리고 부가만 끈다(이유 주석 필수).
|
||||
5. **사용자 번역:** 기술 에러→무엇을 하면 되는지.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** I/O·네트워크·외부 의존이 있는 모든 코드.
|
||||
- **사용 조건:** 실패 유형을 구분 가능; 복구/대안 전략 존재.
|
||||
- **장점:** 복원력, 디버깅 용이, UX 개선, 부분 장애 격리.
|
||||
- **단점:** 코드량↑, 잘못된 삼킴은 버그 은폐.
|
||||
- **대안:** 크래시-온리(빠른 실패+재시작), 서킷 브레이커(연속 실패 차단).
|
||||
- **실패 사례:** 무음 빈 catch 로 실패 은폐; `||` 로 0/'' 삼킴; 무한 재시도; 사용자에게 raw 스택 노출; 부가 실패가 본류 중단.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
result = op() -> { ok:true, val } | { ok:false, error } # 흔한 실패는 유니온
|
||||
for engine in engines: try { return call(engine) } catch { last=e } # 폴백
|
||||
try { sideEffect() } catch { /* 부가 — 본류 안 막음(이유 주석) */ }
|
||||
showUser(translate(error)) # 행동 지침으로 번역
|
||||
catch (e) { err = e instanceof Error ? e : new Error(String(e)) } # 정규화
|
||||
```
|
||||
적용 예: [[에러 처리와 커스텀 에러]](G1Error 계층, ErrorTranslator, 보상 트랜잭션), [[LLM 프로바이더 추상화]](엔진 폴백).
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"모든 에러를 잡아라" 와 "빠르게 실패하라" 의 균형 — 복구 불가·계약 위반은 던지고, 일시·부가만 흡수. 빈 catch 는 *부가 작업 + 이유 주석* 일 때만.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI errors/errorHandler/transaction/services.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Async Concurrency Pattern]], [[API Client Pattern]], [[소프트웨어 실패 라이브러리]], [[안티패턴 카탈로그]]
|
||||
- **참조 맥락:** 작은 모델이 어떤 플랫폼이든 실패 경로를 작성할 때 1차 원리.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 오류 처리/복원력 지식
|
||||
- [S2] AstraAI/src/core/errors.ts, errorHandler.ts, transaction.ts, services.ts — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
id: pattern-state-management
|
||||
title: "State Management Pattern"
|
||||
category: "Pattern_CrossCutting"
|
||||
status: "draft"
|
||||
verification_status: "conceptual"
|
||||
canonical_id: ""
|
||||
aliases: ["state management", "상태 관리", "single source of truth", "unidirectional data flow"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.88
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "cross-cutting", "state", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src/sidebar/managers/* (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[State Management Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
상태 관리의 본질은 플랫폼(웹/모바일/데스크탑)을 막론하고 "**단일 진실 원천(Single Source of Truth) + 단방향 데이터 흐름 + 명시적 변경**" 으로, 상태가 흩어지고 양방향으로 얽힐수록 버그가 기하급수로 는다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **Single Source of Truth:** 같은 데이터를 한 곳에만 둔다(중복 상태 = 동기화 버그).
|
||||
2. **단방향 흐름:** 상태→뷰 렌더, 이벤트→상태 변경(역류 금지).
|
||||
3. **파생 상태 vs 원천 상태:** 계산 가능한 건 저장하지 말고 derive.
|
||||
4. **로컬 vs 전역:** 한 컴포넌트만 쓰면 로컬, 여러 곳이 공유하면 전역(끌어올림).
|
||||
5. **불변 업데이트:** 상태를 *교체* 로 갱신해 변경 추적/되돌리기 용이.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** UI/세션/도메인 상태가 여러 곳에서 읽고 쓰일 때.
|
||||
- **사용 조건:** 상태 소유자를 정할 수 있을 때; 변경 경로를 한정할 수 있을 때.
|
||||
- **장점:** 예측 가능, 디버깅 용이(변경 추적), 동기화 버그↓, 테스트 용이.
|
||||
- **단점:** 보일러플레이트, 과한 전역화는 결합↑, 작은 앱엔 과설계.
|
||||
- **대안:** 로컬 상태만(소규모), 서버 상태를 진실로(react-query류), 이벤트 소싱(이력 필요 시).
|
||||
- **실패 사례:** 같은 데이터를 두 곳에 저장→불일치; 파생값을 저장→stale; 컴포넌트가 부모 상태 직접 변경(역류); 전역 store 에 모든 걸 넣어 결합 폭증.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
state = SingleStore(initial)
|
||||
view = render(state) # 상태 → 뷰
|
||||
onEvent(e): state = reducer(state, e) # 이벤트 → 새 상태(불변 교체) → 재렌더
|
||||
derived = useMemo(() => compute(state))# 파생은 저장 말고 계산
|
||||
```
|
||||
적용 예: AstraAI 의 sessionStateStore/chatSessionStore 등 manager 가 상태 소유, webview 는 메시지로만 변경 요청([[VSCode 확장 구조와 생명주기]]).
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
전역 상태 라이브러리(Redux 등)가 항상 답은 아니다 — 서버 상태는 캐시 라이브러리에, UI 지역 상태는 로컬에, 진짜 공유 도메인 상태만 전역에.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI sidebar managers(상태 소유 + 메시지 변경).
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Data Flow Pattern]], [[React State Pattern]], [[Caching Pattern]], [[프로젝트 독립 설계 원칙]]
|
||||
- **참조 맥락:** 작은 모델이 어떤 플랫폼이든 UI/앱 상태를 설계할 때 1차 원리.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 상태 관리 공학 지식
|
||||
- [S2] AstraAI/src/sidebar/managers/* — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
id: pattern-background-worker
|
||||
title: "Background Worker Pattern"
|
||||
category: "Pattern_Desktop"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["background worker", "백그라운드 워커", "worker thread", "job queue", "concurrency limit"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.86
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "desktop", "worker", "queue", "concurrency", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src/core/queue.ts (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Background Worker Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
Background Worker 는 "무거운/장시간 작업을 메인(UI) 흐름 밖에서, *동시성 상한이 있는 큐* 로 처리" 해 UI 멈춤과 자원 폭주를 동시에 막는 패턴이다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **작업 큐:** 작업을 enqueue, 워커가 꺼내 실행.
|
||||
2. **동시성 상한:** 동시에 N개만(CPU/메모리 보호).
|
||||
3. **UI 분리:** CPU 바운드는 워커 스레드, I/O 는 비동기.
|
||||
4. **결과 반환:** 작업별 Promise/콜백으로 결과 전달.
|
||||
5. **백프레셔:** 큐가 넘치면 거부/지연.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **언제 쓰나:** 대량/무거운 작업이 UI 반응성·자원을 위협할 때.
|
||||
- **사용 조건:** 작업 단위 분리; 동시성 정책; 결과 전달 경로.
|
||||
- **장점:** UI 반응성, 자원 안정(상한), 처리량 제어.
|
||||
- **단점:** 복잡도, 결과 동기화, 스레드 통신 비용(CPU 바운드 시).
|
||||
- **대안:** 동기 처리(소규모), 외부 잡 시스템(분산), OS 스케줄러.
|
||||
- **실패 사례:** 무한 병렬 OOM; 큐 무한 증가(백프레셔 없음); 워커 예외 미처리로 멈춤; UI 스레드에서 무거운 작업.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
class Queue {
|
||||
enqueue(task): Promise = new Promise((res,rej)=>{ this.q.push(()=>task().then(res,rej)); this.next() })
|
||||
next(): if (active < limit && q.length) { active++; run(q.shift()).finally(()=>{active--; next()}) }
|
||||
}
|
||||
limit = max(2, cpus-1) # UI 코어 여유
|
||||
```
|
||||
적용 예: AstraAI 의 ActionQueueManager(동시성 `max(2,cpus-1)`, micro-delay 로 숨통) [S2]. 무거운 LLM 작업은 큐 대신 missionId 락으로 직렬화([[동시성 제어 Lock Queue Transaction]]).
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
동시성은 처리량을 올리지만 자원을 넘으면 역효과 — 상한은 *하드웨어 기준*([[ADR-0004 순차 디스패치 채택]]). 메모리 큰 작업(모델)은 병렬보다 순차가 안전.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI actionQueue + 워처.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Async Concurrency Pattern]], [[Background Task Pattern]], [[AITRAIN 동시성 제어]], [[데스크탑 앱 개발 가이드]]
|
||||
- **참조 맥락:** 작은 모델이 무거운 작업을 백그라운드로 뺄 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 워커/잡 큐 지식
|
||||
- [S2] AstraAI/src/core/queue.ts — ActionQueueManager
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
id: pattern-command
|
||||
title: "Command Pattern"
|
||||
category: "Pattern_Desktop"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["command pattern", "커맨드 패턴", "command registry", "undo redo", "action"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.86
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "desktop", "command", "behavioral", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src/extension.ts(registerCommand), src/agent/actions/* (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Command Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
Command 패턴은 "요청(동작)을 객체/등록 항목으로 캡슐화" 해 실행을 호출자와 분리하고, 등록·취소(undo)·큐잉·로깅·단축키 매핑을 일관되게 만든다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **명령 캡슐화:** 동작을 id+핸들러로 등록.
|
||||
2. **레지스트리:** id→핸들러 매핑(중앙 디스패치).
|
||||
3. **undo/redo:** 명령에 역연산 정의(선택).
|
||||
4. **메타데이터:** 단축키·메뉴·가시성 조건.
|
||||
5. **분리:** UI(버튼/메뉴)는 명령 id 만 알면 됨.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **언제 쓰나:** 여러 진입점(메뉴/단축키/팔레트)이 같은 동작을 부를 때, undo/매크로/큐가 필요할 때.
|
||||
- **사용 조건:** 동작을 id 로 표현; 핸들러 등록 메커니즘.
|
||||
- **장점:** 호출자-실행자 분리, 재사용, undo/큐/로깅 일관, 확장 용이.
|
||||
- **단점:** 명령 폭증, 단순 동작엔 과설계, 상태 전달 설계 필요.
|
||||
- **대안:** 직접 함수 호출(소규모), 이벤트(반응형).
|
||||
- **실패 사례:** 명령에 무거운 상태 결합; undo 불완전(부분 복원); id 충돌; 등록 해제 누락.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
registry.register('app.save', () => save()) # 명령 = id + 핸들러
|
||||
ui.button(onClick = () => exec('app.save')) # UI 는 id 만
|
||||
shortcut('Ctrl+S' -> 'app.save') # 매핑 일관
|
||||
# undo 지원 시: command = { do(), undo() }; history.push(command)
|
||||
```
|
||||
적용 예: AstraAI 의 `vscode.commands.registerCommand('g1nation.openChat', ...)` (명령 레지스트리)와 action tag 실행기(`<create_file>` 등을 명령처럼 라우팅) [S2]. → [[Tool Calling Pattern]].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
진입점이 하나면 함수 호출이 단순 — 다중 진입점/undo/큐가 필요할 때 Command 가 값을 한다.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI VS Code 명령 등록 + action 실행기.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Event Bus Pattern]], [[Tool Calling Pattern]], [[Plugin Architecture Pattern]], [[데스크탑 앱 개발 가이드]]
|
||||
- **참조 맥락:** 작은 모델이 다중 진입점/undo 동작을 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 Command 패턴(GoF) 지식
|
||||
- [S2] AstraAI/src/extension.ts(registerCommand), agent/actions/* — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
id: pattern-event-bus
|
||||
title: "Event Bus Pattern"
|
||||
category: "Pattern_Desktop"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["event bus", "이벤트 버스", "observer", "pub-sub", "EventEmitter", "발행 구독"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.88
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "desktop", "event-bus", "pub-sub", "decoupling", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src/core/events.ts (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Event Bus Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
Event Bus(발행-구독)는 "발신자와 수신자가 서로를 모른 채 이벤트로 소통" 해 모듈 결합을 낮추는 패턴 — 단, 흐름이 *암묵적* 이 되어 추적이 어려워지므로 이벤트 종류와 계약을 명시해야 한다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **발행/구독:** emit(event) / on(event, handler).
|
||||
2. **느슨한 결합:** 발신자는 누가 듣는지 모름.
|
||||
3. **이벤트 타입 명시:** enum/상수로 이벤트 카탈로그.
|
||||
4. **리스너 수명:** 등록 해제(누수 방지), 최대 리스너 한도.
|
||||
5. **동기 vs 비동기:** 핸들러 예외가 발신자에 새지 않게.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **언제 쓰나:** 한 사건에 여러 관심사가 반응(로깅·UI·기록), 모듈을 직접 의존시키고 싶지 않을 때.
|
||||
- **사용 조건:** 이벤트 카탈로그 정의; 리스너 수명 관리.
|
||||
- **장점:** 결합도↓, 확장 용이(구독 추가), 관심사 분리.
|
||||
- **단점:** 흐름 암묵적(추적 난해), 디버깅 어려움, 이벤트 폭발, 순서 보장 약함.
|
||||
- **대안:** 직접 호출(흐름 명확, 결합↑), 콜백 주입, 상태 구독(reactive).
|
||||
- **실패 사례:** 리스너 해제 누락→누수·중복 실행; 이벤트 이름 오타(문자열); 핸들러 예외가 발신자 중단; "누가 이 이벤트를 듣나" 추적 불가; 이벤트 순환.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
enum E { TASK_STARTED='task:started', ERROR='error:occurred' } # 카탈로그
|
||||
bus.emit(E.TASK_STARTED, payload) # 발신자: 누가 듣는지 모름
|
||||
bus.on(E.TASK_STARTED, h); // ... bus.off(E.TASK_STARTED, h) # 해제로 누수 방지
|
||||
bus.setMaxListeners(20) # 폭발 방지
|
||||
```
|
||||
적용 예: AstraAI 의 `agentEvents`(싱글톤 EventEmitter)와 `AgentEventTypes` enum — 트랜잭션 commit/rollback, task 시작/완료 등을 발행해 모듈 결합을 낮춤 [S2].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
이벤트 버스는 결합을 낮추지만 *흐름을 숨긴다* — 핵심 제어 흐름은 명시 호출이 낫고, 부가/횡단 반응(로깅·기록)에 이벤트가 적합.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI agentEvents(Observer 허브).
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Command Pattern]], [[IPC Pattern]], [[Architecture Separation Pattern]], [[데스크탑 앱 개발 가이드]]
|
||||
- **참조 맥락:** 작은 모델이 모듈 간 느슨한 통신을 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 pub-sub/observer 지식
|
||||
- [S2] AstraAI/src/core/events.ts — agentEvents/AgentEventTypes
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
id: pattern-ipc
|
||||
title: "IPC Pattern"
|
||||
category: "Pattern_Desktop"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["IPC", "프로세스 간 통신", "inter-process communication", "message passing", "bridge"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.86
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "desktop", "ipc", "messaging", "platform-independent"]
|
||||
raw_sources: ["일반 데스크탑 공학 지식", "AstraAI/src/bridge.ts, sidebarProvider.ts (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[IPC Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
IPC 는 "서로 다른 프로세스(메인↔렌더러, 앱↔외부 도구)가 메시지로 소통" 하는 패턴으로, *직렬화 가능한 메시지 계약 + 신뢰 경계 검증* 이 핵심 — 다른 프로세스의 입력은 신뢰되지 않은 입력이다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **메시지 패싱:** 객체 직접 공유 불가 → 직렬화(JSON)해 전달.
|
||||
2. **채널/타입:** 메시지에 type 을 두고 핸들러로 라우팅.
|
||||
3. **요청-응답 vs 단방향:** 명령은 응답, 알림은 단방향.
|
||||
4. **신뢰 경계:** 상대 프로세스 입력을 검증(특히 외부 도구).
|
||||
5. **전송 매체:** Electron ipcMain/Renderer, 웹뷰 postMessage, 로컬 HTTP/소켓.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **언제 쓰나:** UI 프로세스↔백그라운드, 앱↔외부 프로그램 통신.
|
||||
- **사용 조건:** 직렬화 가능 메시지; 채널 정의; 보안 검증.
|
||||
- **장점:** 프로세스 격리(크래시 격리·보안), 언어/도구 무관 연동.
|
||||
- **단점:** 직렬화 비용, 객체 공유 불가, 비동기 복잡, 보안 표면.
|
||||
- **대안:** 단일 프로세스(스레드/공유 메모리), 파일 교환, 메시지 큐.
|
||||
- **실패 사례:** 외부 입력 미검증→임의 명령 실행; 함수/순환 객체 직렬화 실패; 채널 타입 오타; 응답 누락으로 행; 포트 충돌.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
# 웹뷰(렌더러) ↔ 확장(메인): postMessage 프로토콜
|
||||
webview.postMessage({ type:'streamChunk', value }) # 확장 → UI
|
||||
onMessage(msg): route(msg.type, validate(msg)) # UI → 확장
|
||||
|
||||
# 앱 ↔ 외부 도구: 로컬 HTTP 브리지
|
||||
http.createServer((req,res) => { body=validate(parse(req)); res.end(handle(body)) })
|
||||
```
|
||||
적용 예: AstraAI 의 BridgeServer(로컬 HTTP 포트 4825 로 외부 도구↔확장 연결, 서비스 레이어로 로직 분리) + 웹뷰 postMessage 프로토콜([[VSCode 확장 구조와 생명주기]], [[Agent 오케스트레이터 분해]]) [S2].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
프로세스 분리는 격리·보안 이득이 있으나 직렬화·복잡도 비용 — 같은 신뢰 영역의 작은 작업이면 단일 프로세스가 단순. 외부 IPC 는 *항상* 입력 검증.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI BridgeServer + 웹뷰 메시지.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Event Bus Pattern]], [[Tool Calling Pattern]], [[API Client Pattern]], [[데스크탑 앱 개발 가이드]]
|
||||
- **참조 맥락:** 작은 모델이 데스크탑(Electron/확장) 프로세스 통신을 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 IPC 지식(Electron, message passing)
|
||||
- [S2] AstraAI/src/bridge.ts, sidebarProvider.ts — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
id: pattern-plugin-architecture
|
||||
title: "Plugin Architecture Pattern"
|
||||
category: "Pattern_Desktop"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["plugin architecture", "플러그인 아키텍처", "extension point", "self-registration", "skill loader"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.85
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "desktop", "plugin", "extensibility", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src/skills/externalSkillLoader.ts, src/features/*/handlers.ts (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Plugin Architecture Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
플러그인 아키텍처는 "코어를 안정적으로 두고 기능을 *확장 지점(extension point)* 으로 끼워 넣게" 해 코어 수정 없이 능력을 늘리는 패턴 — 핵심은 *안정된 계약(인터페이스)* 과 *자기 등록* 이다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **확장 지점:** 코어가 정의한 인터페이스/훅.
|
||||
2. **자기 등록:** 플러그인 로드 시 레지스트리에 자기를 등록(side-effect import).
|
||||
3. **발견(discovery):** 디렉터리/매니페스트 스캔으로 동적 로드.
|
||||
4. **격리/검증:** 플러그인 실패가 코어를 죽이지 않게.
|
||||
5. **버전 계약:** 코어 API 버전 호환.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **언제 쓰나:** 서드파티/도메인 기능을 코어 변경 없이 추가, 기능 on/off, 생태계 구축.
|
||||
- **사용 조건:** 안정된 확장 인터페이스; 로딩/등록 메커니즘; 격리.
|
||||
- **장점:** 확장성, 코어 안정, 병렬 개발, 선택적 기능.
|
||||
- **단점:** 인터페이스 설계 어려움, 버전 호환 부담, 플러그인 품질/보안 위험.
|
||||
- **대안:** 모놀리식(소규모), 설정 플래그, 마이크로서비스.
|
||||
- **실패 사례:** 플러그인 예외가 코어 크래시(격리 부재); 안정 안 된 API 로 잦은 호환 깨짐; 등록 순서 의존; 신뢰 안 된 플러그인 권한 과다.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
# 자기 등록 (side-effect import)
|
||||
import './features/system/handlers' # 로드되며 registry.register(...) 실행
|
||||
registry.register('cmd:foo', handler)
|
||||
|
||||
# 동적 발견
|
||||
for file in scan(pluginsDir): plugin = load(file); if validate(plugin): register(plugin)
|
||||
try { plugin.run() } catch { /* 격리 — 코어 보호 */ logError() }
|
||||
```
|
||||
적용 예: AstraAI 의 핸들러 자기등록(`import './features/.../handlers'` 가 slashRouter 에 등록)과 externalSkillLoader(외부 스킬 동적 로드) [S2]. → [[모듈 시스템과 프로젝트 구성]].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
플러그인은 유연하나 *안정된 계약* 없이는 버전 지옥. 확장 지점을 최소·신중히 설계하고, 신뢰 안 된 플러그인은 샌드박스/권한 제한.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI 핸들러 자기등록 + 스킬 로더.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Command Pattern]], [[Event Bus Pattern]], [[Architecture Separation Pattern]], [[데스크탑 앱 개발 가이드]]
|
||||
- **참조 맥락:** 작은 모델이 확장 가능한 앱(에디터/IDE/툴)을 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 플러그인/확장 아키텍처 지식
|
||||
- [S2] AstraAI/src/skills/externalSkillLoader.ts, features/*/handlers.ts — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
id: pattern-background-task
|
||||
title: "Background Task Pattern"
|
||||
category: "Pattern_Mobile"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["background task", "백그라운드 작업", "scheduled job", "watcher", "cron", "WorkManager"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.86
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "mobile", "background", "scheduling", "platform-independent"]
|
||||
raw_sources: ["일반 모바일/클라이언트 공학 지식", "AstraAI/src/features/*/watcher, src/extension.ts (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Background Task Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
백그라운드 작업은 "사용자 상호작용 밖에서 주기적/지연 작업을 실행" 하는 패턴으로, OS 제약(배터리/킬)과 *재진입·중복 실행 방지*를 고려하지 않으면 자원을 낭비하거나 데이터를 손상시킨다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **스케줄링:** interval/cron/조건(충전 중·Wi-Fi) 트리거.
|
||||
2. **수명관리:** 등록한 작업은 dispose 가능해야(누수 방지).
|
||||
3. **재진입 방지:** 이전 실행이 안 끝났으면 skip/큐.
|
||||
4. **멱등성:** 중복 실행에도 안전.
|
||||
5. **OS 제약:** 모바일은 OS 가 백그라운드를 제한(WorkManager/BGTask).
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 동기화/정리/알림/사전계산을 사용자 흐름 밖에서.
|
||||
- **사용 조건:** 스케줄러; 작업을 작게 분할; 취소/정리 가능.
|
||||
- **장점:** 응답성(무거운 일을 뒤로), 자동화, 유휴 활용.
|
||||
- **단점:** 디버깅 난해, OS 킬/제약, 중복/경쟁 위험.
|
||||
- **대안:** 포그라운드 처리, 서버측 작업(클라 부담↓), 푸시 트리거.
|
||||
- **실패 사례:** dispose 누락으로 타이머 누수; 재진입으로 중복 실행; 무거운 작업을 메인 스레드; OS 제약 무시로 실행 안 됨; 실패 무한 재시도.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
const handle = scheduleInterval(ms, async () => {
|
||||
if (running) return; running = true # 재진입 방지
|
||||
try { await doWork() /*멱등, 작게*/ } finally { running = false }
|
||||
})
|
||||
register(handle) # dispose 가능하게 등록 → 종료 시 정리
|
||||
```
|
||||
적용 예: AstraAI 의 stocksWatcher/dailyBriefing/growthCycle/sleepDigest 워처가 interval 로 돌고 disposable 을 `context.subscriptions` 에 등록해 종료 시 정리([[VSCode 확장 구조와 생명주기]]).
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
모바일에선 OS 가 백그라운드를 강하게 제한 — "정확한 시각 보장" 을 가정하면 깨진다. 중요 작업은 서버 푸시로 트리거하는 것이 안전.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI 워처들(KST 스케줄, dispose 등록).
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Background Worker Pattern]], [[Async Concurrency Pattern]], [[Push Notification Pattern]], [[모바일 개발 가이드]]
|
||||
- **참조 맥락:** 작은 모델이 주기/지연 작업을 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 백그라운드 작업 지식(WorkManager/BGTaskScheduler)
|
||||
- [S2] AstraAI/src/features/*/watcher, extension.ts — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
id: pattern-local-storage
|
||||
title: "Local Storage Pattern"
|
||||
category: "Pattern_Mobile"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["local storage", "로컬 저장 패턴", "key-value", "sqlite", "secure storage"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.86
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "mobile", "storage", "persistence", "platform-independent"]
|
||||
raw_sources: ["일반 모바일/클라이언트 공학 지식", "AstraAI/src/core/services.ts, eventSourcedStore.ts (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Local Storage Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
로컬 저장은 "데이터 성격에 맞는 매체를 고르는 것" 이 핵심 — 소량 설정은 key-value, 구조화 데이터는 SQLite, 민감정보는 보안 저장소, 대용량 파일은 파일시스템. 한 매체에 다 넣으면 성능·보안이 무너진다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **key-value(prefs):** 작은 설정/플래그.
|
||||
2. **임베디드 DB(SQLite/Realm):** 구조화/쿼리 데이터.
|
||||
3. **보안 저장소(Keychain/Keystore):** 토큰/비밀.
|
||||
4. **파일시스템:** 이미지/대용량/캐시.
|
||||
5. **마이그레이션:** 스키마 버전 관리.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 앱이 디바이스에 데이터를 보존해야 할 때.
|
||||
- **사용 조건:** 데이터 성격 분류; 용량/보안 요구 파악.
|
||||
- **장점:** 오프라인, 빠른 접근, 네트워크 절약.
|
||||
- **단점:** 디바이스 한정, 백업/동기화 별도, 보안 책임.
|
||||
- **대안:** 서버 저장(동기화 필요), 캐시만(휘발).
|
||||
- **실패 사례:** 토큰을 평문 prefs 에(보안 사고); 대용량을 key-value 에(성능); 마이그레이션 없어 업데이트 시 크래시; 캐시와 영구 데이터 혼동.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
prefs.set('theme', v) # 소량 설정
|
||||
secureStore.set('token', t) # 민감정보 (Keychain/Keystore)
|
||||
db.exec('INSERT ...') # 구조화 데이터
|
||||
fs.write(path, blob) # 대용량
|
||||
onUpgrade(old, new): migrate(old→new) # 스키마 버전
|
||||
```
|
||||
적용 예: AstraAI 는 설정=VS Code config/secrets, 지식=Markdown 파일, 이벤트=JSONL — *데이터 성격별 매체 분리* 원칙을 그대로([[ADR-0005 파일 기반 저장 채택]]).
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"전부 SQLite" 나 "전부 key-value" 는 안티패턴 — 성격별 분리가 원칙. 민감정보는 *반드시* 보안 저장소.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI secrets(토큰) + 파일(지식) + JSONL(이벤트).
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Offline Sync Pattern]], [[Caching Pattern]], [[이벤트 소싱 스토어 패턴]], [[모바일 개발 가이드]]
|
||||
- **참조 맥락:** 작은 모델이 클라이언트 저장을 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 모바일 저장 지식
|
||||
- [S2] AstraAI/src/core/services.ts, extension.ts(secrets), eventSourcedStore.ts — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
id: pattern-navigation
|
||||
title: "Navigation Pattern"
|
||||
category: "Pattern_Mobile"
|
||||
status: "draft"
|
||||
verification_status: "conceptual"
|
||||
canonical_id: ""
|
||||
aliases: ["navigation", "내비게이션 패턴", "routing", "deep link", "navigation stack"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.83
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "mobile", "navigation", "routing", "platform-independent"]
|
||||
raw_sources: ["일반 모바일/프런트엔드 공학 지식"]
|
||||
applied_in: []
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Navigation Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
내비게이션은 "화면 간 이동과 스택/상태를 관리" 하는 패턴으로, *경로를 선언적·직렬화 가능*하게 두고 딥링크/뒤로가기/상태 복원을 1급으로 다뤄야 한다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **선언적 라우트:** URL/route 로 화면을 표현(직렬화 가능).
|
||||
2. **스택/탭/드로어:** 내비 구조 유형.
|
||||
3. **딥링크:** 외부에서 특정 화면 직접 진입.
|
||||
4. **파라미터 전달:** 라우트 인자 + 타입 안전.
|
||||
5. **상태 복원:** 프로세스 죽어도 내비 상태 복구.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 다화면 앱의 이동/히스토리/딥링크 관리.
|
||||
- **사용 조건:** 라우트 정의; 화면 식별자; 인자 직렬화.
|
||||
- **장점:** 일관된 이동, 딥링크, 뒤로가기, 테스트성.
|
||||
- **단점:** 설정 복잡, 깊은 스택 메모리, 타입 안전 관리.
|
||||
- **대안:** 단일 화면(소규모), 조건부 렌더(상태 기반), 코디네이터 패턴.
|
||||
- **실패 사례:** 객체를 라우트 인자로 직접(직렬화 불가/딥링크 깨짐); 스택 누수(화면 안 떼어냄); 뒤로가기 상태 불일치; 딥링크 시 부모 스택 없어 길 잃음.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
routes = { '/home': Home, '/item/:id': ItemDetail } # 선언적 + 직렬화 가능 인자
|
||||
navigate('/item/42') # id 만 전달(객체 X)
|
||||
deepLink('myapp://item/42') -> rebuild stack [Home, ItemDetail]
|
||||
restore(savedNavState) # 프로세스 복원
|
||||
```
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"상태로 화면 전환" vs "라우터" — 작은 앱은 상태 조건부가 단순하나, 딥링크/히스토리가 필요하면 선언적 라우터가 필수.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
일반 모바일/SPA. (AstraAI 는 패널 기반이라 직접 사례 없음 — 화면 식별/복원 원리는 동일.)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[State Management Pattern]], [[React State Pattern]], [[모바일 개발 가이드]]
|
||||
- **참조 맥락:** 작은 모델이 다화면 앱의 이동을 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 내비게이션/라우팅 지식
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
id: pattern-offline-sync
|
||||
title: "Offline Sync Pattern"
|
||||
category: "Pattern_Mobile"
|
||||
status: "draft"
|
||||
verification_status: "conceptual"
|
||||
canonical_id: ""
|
||||
aliases: ["offline sync", "오프라인 동기화", "optimistic update", "conflict resolution", "outbox"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.85
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "mobile", "offline", "sync", "platform-independent"]
|
||||
raw_sources: ["일반 모바일 공학 지식", "AstraAI/src/features/_shared/eventSourcedStore.ts (개념 유사)"]
|
||||
applied_in: []
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Offline Sync Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
오프라인 동기화는 "네트워크 없이도 로컬에서 동작하고, 연결되면 변경을 *큐로 모아 동기화*하며 충돌을 해소" 하는 패턴으로, 핵심 난제는 동기화 자체가 아니라 **충돌 해소(conflict resolution)** 다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **로컬 우선 저장:** 모든 쓰기를 먼저 로컬에.
|
||||
2. **outbox(변경 큐):** 미동기 변경을 append-only 로 쌓아 연결 시 전송.
|
||||
3. **낙관적 업데이트:** UI 는 즉시 반영, 실패 시 롤백.
|
||||
4. **충돌 해소:** last-write-wins / 버전 벡터 / 병합 / 사용자 선택.
|
||||
5. **멱등성:** 재전송에도 안전하도록 변경에 고유 id.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 불안정/없는 네트워크에서도 앱이 동작해야 할 때.
|
||||
- **사용 조건:** 로컬 저장소; 변경을 식별/순서화 가능; 서버 동기 API.
|
||||
- **장점:** 오프라인 사용성, 빠른 반응(낙관적), 복원력.
|
||||
- **단점:** 충돌 해소 복잡, 데이터 일관성 약화, 디버깅 난해.
|
||||
- **대안:** 온라인 전용(단순), CRDT(자동 병합, 복잡), 서버 권위(충돌 시 서버 우선).
|
||||
- **실패 사례:** 멱등 키 없어 중복 적용; LWW 로 사용자 데이터 유실; outbox 순서 꼬임; 낙관적 업데이트 롤백 누락으로 유령 데이터.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
write(op): localDB.apply(op); outbox.append({id:uuid, op, ts}) # 로컬 우선 + 큐
|
||||
onOnline: for op in outbox: try{ server.apply(op) /*멱등*/; outbox.remove(op) } catch{ retry }
|
||||
onPull: merge(serverChanges, local, resolve=versionVector|userChoice)
|
||||
```
|
||||
개념 유사: AstraAI 의 append-only 이벤트([[이벤트 소싱 스토어 패턴]])가 outbox 와 같은 구조 — 변경을 줄로 쌓고 재생/전송.
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
LWW 는 간단하지만 데이터 손실 위험 — 협업/중요 데이터엔 버전 벡터/CRDT 또는 사용자 충돌 해소가 안전.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
일반 모바일 앱(노트/메신저). AstraAI 는 단일 로컬이라 동기화는 불필요하나 outbox 구조는 동일.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Local Storage Pattern]], [[Background Task Pattern]], [[이벤트 소싱 스토어 패턴]], [[모바일 개발 가이드]]
|
||||
- **참조 맥락:** 작은 모델이 오프라인 가능 앱을 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 오프라인 동기화 지식(outbox, CRDT)
|
||||
- [S2] AstraAI/src/features/_shared/eventSourcedStore.ts — 구조 유사
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
id: pattern-push-notification
|
||||
title: "Push Notification Pattern"
|
||||
category: "Pattern_Mobile"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["push notification", "푸시 알림", "FCM", "APNs", "notification"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.84
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "mobile", "push", "notification", "platform-independent"]
|
||||
raw_sources: ["일반 모바일 공학 지식", "AstraAI/src/integrations/telegram/*, src/features/briefing/* (유사 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Push Notification Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
푸시 알림은 "서버가 디바이스로 비동기 메시지를 밀어 넣는" 패턴으로, 토큰 수명 관리·전달 보장 없음·사용자 동의·과알림 피로를 다루지 못하면 오히려 이탈을 부른다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **디바이스 토큰:** 앱이 FCM/APNs 토큰 등록, 서버 저장(만료/갱신).
|
||||
2. **전송:** 서버→게이트웨이(FCM/APNs)→디바이스.
|
||||
3. **전달 비보장:** best-effort — 중요 데이터는 알림 본문 말고 동기화로.
|
||||
4. **동의/채널:** 권한 요청, 카테고리별 on/off.
|
||||
5. **딥링크:** 탭 시 해당 화면으로.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 서버 이벤트를 사용자에게 즉시 알릴 때.
|
||||
- **사용 조건:** 게이트웨이 연동; 토큰 저장; 사용자 동의.
|
||||
- **장점:** 재참여, 실시간 알림, 백그라운드 트리거.
|
||||
- **단점:** 전달 비보장, 토큰 만료, 권한 거부 시 무력, 과알림 피로.
|
||||
- **대안:** 인앱 알림, 폴링(배터리↑), 이메일/SMS.
|
||||
- **실패 사례:** 만료 토큰으로 전송 실패; 알림 본문에만 중요 데이터(미수신 시 유실); 과알림으로 권한 철회; 딥링크 없어 탭 후 길 잃음.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
onAppStart: token = registerForPush(); server.saveToken(userId, token)
|
||||
server.onEvent: send(FCM/APNs, token, { title, body, data:{deeplink} }) # best-effort
|
||||
onReceive: showNotification ; onTap: navigate(data.deeplink)
|
||||
onTokenRefresh: server.updateToken(...)
|
||||
```
|
||||
유사 예: AstraAI 의 Telegram 리포트/daily briefing 이 "서버측 이벤트→사용자 채널 푸시" 구조([[Background Task Pattern]] 워처가 트리거). 전달 비보장 가정도 동일.
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
알림을 "전달된다" 고 가정하면 안 된다 — 중요 상태는 서버에 두고 알림은 *유도* 만. 과알림은 가장 흔한 이탈 원인.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI Telegram 알림(리포트/브리핑).
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Background Task Pattern]], [[API Client Pattern]], [[모바일 개발 가이드]]
|
||||
- **참조 맥락:** 작은 모델이 알림 기능을 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 푸시(FCM/APNs) 지식
|
||||
- [S2] AstraAI/src/integrations/telegram/*, features/briefing/* — 유사 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,72 @@
|
||||
---
|
||||
id: pattern-api-client
|
||||
title: "API Client Pattern"
|
||||
category: "Pattern_Web"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["API client", "HTTP client", "API 클라이언트 패턴", "adapter", "SDK wrapper"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.88
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "web", "api", "http", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src/features/providers/*, src/integrations/telegram/telegramClient.ts (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[API Client Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
API Client 패턴은 "외부 HTTP/SDK 호출을 한 모듈로 캡슐화" 해 인증·재시도·타임아웃·에러 정규화·취소를 한 곳에서 관리하고, 호출부는 깨끗한 메서드만 보게 한다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **단일 클라이언트:** baseURL/헤더/인증을 한 곳에.
|
||||
2. **횡단 관심사:** 재시도·타임아웃·취소(AbortSignal)·로깅·에러 변환을 내장.
|
||||
3. **응답 정규화:** 다양한 응답을 내부 표준 형태로.
|
||||
4. **인증 주입:** 토큰을 getter 로(갱신 반영).
|
||||
5. **에러 passthrough/translate:** 실패를 호출부가 쓸 수 있는 형태로.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 외부 API/SDK 를 여러 곳에서 호출, 인증·재시도·에러 처리가 반복될 때.
|
||||
- **사용 조건:** 호출 인터페이스 정의 가능; 인증/설정 중앙화 가능.
|
||||
- **장점:** 중복 제거, 일관된 에러/재시도/취소, 교체·모킹 용이, 테스트성.
|
||||
- **단점:** 추상화 비용, 만능 클라이언트화 위험.
|
||||
- **대안:** fetch 직접(소규모), 생성된 SDK, GraphQL 클라이언트.
|
||||
- **실패 사례:** 타임아웃/취소 누락으로 멈춤; 토큰 하드코딩(갱신 안 됨); 에러 삼킴; 재시도에 backoff 없어 폭주; 응답 형식 호출부 산재.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
class Client {
|
||||
constructor({ getToken, baseUrl }) # 인증은 getter 주입
|
||||
async call(path, body, { signal }) {
|
||||
const s = combine(signal, timeout(ms)) # 취소+타임아웃
|
||||
res = await fetch(baseUrl+path, { headers:{Authorization:getToken()}, signal:s })
|
||||
if (!res.ok) return normalizeError(res) # 에러 정규화/passthrough
|
||||
return parse(res) # 응답 정규화
|
||||
}
|
||||
}
|
||||
```
|
||||
적용 예: AstraAI 의 provider 어댑터(공급자별 차이 흡수→공통 SSE)와 TelegramHttpClient(getToken 게터). → [[LLM 프로바이더 추상화]], [[AITRAIN 프로바이더 추상화]].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
얇은 호출이면 fetch 직접이 낫다 — 인증/재시도/에러가 반복될 때만 클라이언트 추상화가 이득.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI providers + telegramClient.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[Async Concurrency Pattern]], [[Error Handling Pattern]], [[Caching Pattern]], [[Tool Calling Pattern]]
|
||||
- **참조 맥락:** 작은 모델이 외부 API 통합 코드를 작성할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 API 클라이언트 지식
|
||||
- [S2] AstraAI/src/features/providers/*, integrations/telegram/telegramClient.ts — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
id: pattern-infinite-scroll
|
||||
title: "Infinite Scroll Pattern"
|
||||
category: "Pattern_Web"
|
||||
status: "draft"
|
||||
verification_status: "conceptual"
|
||||
canonical_id: ""
|
||||
aliases: ["infinite scroll", "무한 스크롤", "pagination", "cursor pagination", "virtualization"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.85
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "web", "frontend", "pagination", "platform-independent"]
|
||||
raw_sources: ["일반 프런트엔드 공학 지식"]
|
||||
applied_in: []
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Infinite Scroll Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
무한 스크롤은 "사용자가 끝에 도달하면 다음 페이지를 자동 로드" 하는 패턴으로, *커서 기반 페이징 + DOM 가상화 + 중복/경쟁 요청 방지* 가 없으면 성능과 정확성이 무너진다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **트리거:** IntersectionObserver 로 sentinel 가시화 감지.
|
||||
2. **커서 페이징:** offset 대신 cursor(마지막 항목 키) — 삽입/삭제에 안정.
|
||||
3. **가상화:** 화면 밖 항목은 DOM 에서 제거(react-window 등).
|
||||
4. **중복/경쟁 방지:** 진행 중 로드 잠금, 이전 요청 취소.
|
||||
5. **상태:** 로딩/끝(hasMore)/에러 표시.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 큰 목록(피드/검색결과)을 점진 로드해 초기 부하를 줄일 때.
|
||||
- **사용 조건:** 페이징 API(가급적 커서); 항목 높이 처리.
|
||||
- **장점:** 빠른 초기 로드, 자연스러운 UX, 대용량 처리.
|
||||
- **단점:** 푸터 도달 불가, 딥링크/뒤로가기 어려움, 접근성/SEO 약함, 구현 복잡.
|
||||
- **대안:** 일반 페이지네이션(점프/SEO 좋음), "더 보기" 버튼(제어 명확).
|
||||
- **실패 사례:** offset 페이징 중 삽입→항목 중복/누락; 가상화 없이 DOM 폭증 렉; 중복 트리거로 같은 페이지 N번; 경쟁 요청 순서 꼬임; hasMore 미처리로 무한 호출.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
observer.observe(sentinel)
|
||||
onIntersect: if (!loading && hasMore) { loading=true; signal=abortPrev()
|
||||
page = await api.list({ cursor, signal }); items.push(...page.items)
|
||||
cursor = page.nextCursor; hasMore = !!cursor; loading=false }
|
||||
render: virtualize(items) # 화면 밖 제거
|
||||
```
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
무한 스크롤이 항상 옳지 않다 — 작업형 목록(테이블/검색)엔 페이지네이션이 제어·딥링크 면에서 낫다. 피드형에만 적합.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
일반 웹/모바일 피드. (AstraAI 직접 사례 없음.)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[React State Pattern]], [[Async Concurrency Pattern]], [[Caching Pattern]], [[웹 개발 가이드]]
|
||||
- **참조 맥락:** 작은 모델이 큰 목록 UI 를 구현할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 프런트엔드 페이징/가상화 지식
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
id: pattern-jwt-authentication
|
||||
title: "JWT Authentication Pattern"
|
||||
category: "Pattern_Web"
|
||||
status: "draft"
|
||||
verification_status: "conceptual"
|
||||
canonical_id: ""
|
||||
aliases: ["JWT", "토큰 인증", "access token", "refresh token", "stateless auth"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.86
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "web", "auth", "jwt", "security", "platform-independent"]
|
||||
raw_sources: ["일반 웹 보안 공학 지식"]
|
||||
applied_in: []
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[JWT Authentication Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
JWT 인증은 "서명된 토큰에 사용자 정보를 담아 *서버 세션 없이* 상태 무관(stateless) 인증" 을 하는 패턴으로, 확장성은 좋지만 *토큰을 즉시 무효화하기 어렵다* 는 본질적 약점이 있다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **access token(짧은 수명) + refresh token(긴 수명):** 짧은 access 로 노출 위험↓, refresh 로 재발급.
|
||||
2. **서명 검증:** 서버 비밀키로 서명, 변조 시 검증 실패(저장 불필요).
|
||||
3. **claims:** sub/exp/role 등 페이로드(민감정보 금지 — base64 는 암호화 아님).
|
||||
4. **저장 위치:** httpOnly 쿠키(XSS 안전) vs localStorage(XSS 취약).
|
||||
5. **무효화:** 블랙리스트/짧은 만료/회전으로 보완.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 분산/무상태 API, 여러 서비스가 같은 토큰 검증(SSO), 모바일+웹 공용.
|
||||
- **사용 조건:** 비밀키 안전 보관; HTTPS; 토큰 수명 정책.
|
||||
- **장점:** 무상태(수평 확장), 서비스 간 공유, DB 조회 없이 검증.
|
||||
- **단점:** 즉시 무효화 어려움(로그아웃/탈취), 페이로드 노출, 토큰 비대.
|
||||
- **대안:** 서버 세션(즉시 무효화 쉬움, 상태 필요), OAuth/OIDC(위임), API key(머신).
|
||||
- **실패 사례:** localStorage 저장→XSS 탈취; refresh 회전 없이 탈취 지속; 민감정보를 claims 에; 만료 너무 길어 탈취 피해 확대; 서명 알고리즘 `none` 허용.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
login: verify(creds) -> access=sign({sub,exp:15m}), refresh=sign({sub,exp:7d}); setHttpOnlyCookie
|
||||
request: verifySignature(access) && !expired -> allow ; else 401
|
||||
refresh: verify(refresh) && !revoked -> rotate(new access+refresh), invalidate old
|
||||
logout: revoke(refresh) # 블랙리스트/회전
|
||||
```
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"JWT 가 세션보다 낫다" 는 과장 — 즉시 무효화·서버측 제어가 중요하면 세션이 낫다. JWT 는 *무상태 확장* 이 목적일 때.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
일반 웹/모바일 API 인증. (AstraAI 는 로컬 도구라 직접 사례 없음 — provider API key 는 [[API Client Pattern]] 참조.)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[API Client Pattern]], [[웹 개발 가이드]], [[소프트웨어 실패 라이브러리]]
|
||||
- **참조 맥락:** 작은 모델이 웹/모바일 인증을 구현할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 웹 보안/JWT 지식(RFC 7519, OWASP)
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
id: pattern-react-state
|
||||
title: "React State Pattern"
|
||||
category: "Pattern_Web"
|
||||
status: "draft"
|
||||
verification_status: "conceptual"
|
||||
canonical_id: ""
|
||||
aliases: ["React state", "리액트 상태 패턴", "hooks", "lifting state up", "server state"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.85
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "web", "react", "frontend", "state", "platform-independent"]
|
||||
raw_sources: ["일반 프런트엔드 공학 지식"]
|
||||
applied_in: []
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[React State Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
React(및 유사 선언형 UI) 상태의 핵심 규칙은 "**상태를 필요한 가장 낮은 곳에 두되, 공유되면 끌어올리고, 서버 데이터는 UI 상태와 분리**" 하는 것 — 이는 [[State Management Pattern]] 의 프런트엔드 구체화다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **로컬 상태(useState):** 한 컴포넌트만 쓰는 상태.
|
||||
2. **lifting state up:** 두 형제가 공유하면 공통 부모로.
|
||||
3. **전역 상태(Context/Zustand/Redux):** 앱 전반 공유(과용 금지).
|
||||
4. **서버 상태(react-query/SWR):** 원격 데이터는 캐시·동기화 라이브러리로 분리.
|
||||
5. **파생 상태:** useMemo 로 계산, 저장하지 않음.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 컴포넌트 트리에서 상태 위치·공유 범위를 정할 때.
|
||||
- **사용 조건:** 선언형 UI; 단방향 데이터.
|
||||
- **장점:** 예측 가능 렌더, 재사용, 테스트성.
|
||||
- **단점:** prop drilling(전역 미사용 시), 과한 전역화는 리렌더·결합, 서버/클라 상태 혼동.
|
||||
- **대안:** 전역 store(공유 많을 때), 서버 상태 라이브러리, URL 상태(공유 가능 상태).
|
||||
- **실패 사례:** 서버 데이터를 useState 에 복사→stale·동기화 버그; 모든 걸 전역 store 에→불필요 리렌더·결합; 파생값 저장; 깊은 prop drilling.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
const [v, setV] = useState(init) # 로컬
|
||||
// 공유되면 부모로 올리고 props/context 로 전달
|
||||
const data = useQuery('key', fetcher) # 서버 상태는 분리(캐시/리페치)
|
||||
const total = useMemo(() => sum(items), [items]) # 파생은 계산
|
||||
```
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"Redux 가 정석" 은 옛말 — 서버 상태는 react-query, 지역은 useState, 진짜 전역만 가벼운 store. 도구보다 *상태의 출처/수명* 으로 위치를 정하라.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
일반 React 앱. (AstraAI 웹뷰는 메시지 기반 — 원리는 [[State Management Pattern]] 와 동일.)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[State Management Pattern]], [[Data Flow Pattern]], [[Infinite Scroll Pattern]], [[웹 개발 가이드]]
|
||||
- **참조 맥락:** 작은 모델이 프런트엔드 상태를 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 React/프런트엔드 상태 지식
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
id: pattern-repository
|
||||
title: "Repository Pattern"
|
||||
category: "Pattern_Web"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["Repository", "리포지토리 패턴", "data access layer", "DAO"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.88
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["pattern", "web", "backend", "data-access", "platform-independent"]
|
||||
raw_sources: ["일반 소프트웨어 공학 지식", "AstraAI/src/features/_shared/eventSourcedStore.ts (적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Repository Pattern]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
Repository 는 "도메인 코드와 데이터 저장 방식 사이에 *컬렉션처럼 보이는* 인터페이스를 두어, 비즈니스 로직이 DB/파일/API 의 세부를 모르게" 하는 패턴이다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **인터페이스로 저장 추상화:** `find/save/delete` 같은 도메인 언어 메서드.
|
||||
2. **구현 교체:** 같은 인터페이스로 메모리/파일/SQL/원격 구현.
|
||||
3. **도메인 모델 반환:** raw 행이 아니라 도메인 객체.
|
||||
4. **쿼리 캡슐화:** 복잡 쿼리를 repository 안에.
|
||||
|
||||
## 📖 세부 내용 (Details · 패턴 명세)
|
||||
- **Problem (언제 쓰나):** 도메인 로직을 저장 기술과 분리하고 테스트(가짜 repo)하고 싶을 때.
|
||||
- **사용 조건:** 도메인 모델 정의; 저장 연산을 인터페이스로 표현 가능.
|
||||
- **장점:** 저장 교체 용이, 테스트성(in-memory repo), 도메인 순수, 쿼리 한 곳.
|
||||
- **단점:** 추상화 비용, 단순 CRUD 엔 과설계, leaky abstraction 위험.
|
||||
- **대안:** ORM 직접 사용(소규모), Active Record, 쿼리 빌더 직접.
|
||||
- **실패 사례:** repository 가 DB 세부를 누수(IQueryable 노출); 만능 repository(God repo); 도메인이 SQL 을 알게 됨.
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```text
|
||||
interface UserRepo { findById(id): User?; save(u: User): Result; list(): User[] }
|
||||
class FileUserRepo implements UserRepo { ... } # 교체 가능 구현
|
||||
class SqlUserRepo implements UserRepo { ... }
|
||||
service(repo: UserRepo) # 도메인은 인터페이스만 의존(주입)
|
||||
```
|
||||
적용 예: AstraAI 의 `createEventStore<E>` 가 read/append/count 로 저장을 추상화하고 도메인은 인터페이스만 사용([[이벤트 소싱 스토어 패턴]], [[AITRAIN 이벤트소싱 저장]]).
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
ORM 이 이미 repository 유사 추상을 주므로, 그 위에 또 repository 를 얹으면 중복일 수 있다 — 교체/테스트 필요가 명확할 때만.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI eventSourcedStore(도메인별 store 인스턴스화).
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[패턴 카탈로그 인덱스]]
|
||||
- **관련 개념:** [[의존성 주입과 서비스 인터페이스]], [[Architecture Separation Pattern]], [[Local Storage Pattern]], [[백엔드 API 개발 가이드]]
|
||||
- **참조 맥락:** 작은 모델이 데이터 접근 계층을 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 DDD/Repository 지식
|
||||
- [S2] AstraAI/src/features/_shared/eventSourcedStore.ts — 적용 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 프로젝트 독립 패턴 카드 작성.
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
id: platform-guides-index
|
||||
title: "플랫폼 개발 가이드 인덱스"
|
||||
category: "Index"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["platform guides", "플랫폼 가이드", "플랫폼별 개발 패턴", "platform development index"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.9
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["index", "platform", "guide", "navigation"]
|
||||
raw_sources: ["Platform_Guides 전체"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[플랫폼 개발 가이드 인덱스]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
플랫폼별 가이드는 [[프로젝트 독립 설계 원칙]] 과 [[패턴 카탈로그 인덱스]] 를 *각 플랫폼의 구체적 폴더 구조·핵심 컴포넌트·테스트·확장 전략* 으로 구체화한 것 — 경험 많은 엔지니어가 플랫폼을 가로질러 어떻게 설계하는지를 작은 모델에 가르친다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
각 가이드 12-field: Problem / Recommended Architecture / Folder Structure / Core Components / State Management / Error Handling / Testing / Scaling / Common Mistakes / Refactoring / Tradeoffs / Heuristics.
|
||||
|
||||
## 📖 세부 내용 (Details · 가이드 목록)
|
||||
- [[웹 개발 가이드]]
|
||||
- [[데스크탑 앱 개발 가이드]] (AstraAI 실증)
|
||||
- [[모바일 개발 가이드]]
|
||||
- [[백엔드 API 개발 가이드]]
|
||||
- [[AI 에이전트 개발 가이드]] (AstraAI 실증)
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
가이드의 "Recommended" 는 *기본값* 이며, 프레임워크/스택 선택은 팀·생태계·규모로 조정. 공통 원리는 [[프로젝트 독립 설계 원칙]] 으로 수렴.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
데스크탑·AI 에이전트 가이드는 AstraAI 가 실제 구현한 사례로 뒷받침된다.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[Topic Programming 인덱스]]
|
||||
- **관련 개념:** [[패턴 카탈로그 인덱스]] · [[프로젝트 독립 설계 원칙]] · [[소프트웨어 실패 라이브러리]]
|
||||
- **참조 맥락:** 작은 모델이 특정 플랫폼 프로젝트를 시작할 때의 상위 설계 가이드.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] Platform_Guides 전체 + 일반 공학 지식 + AstraAI 실증
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 플랫폼 개발 가이드 인덱스 생성.
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
id: platform-ai-agent-development
|
||||
title: "AI 에이전트 개발 가이드"
|
||||
category: "Platform_Engineering"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["AI agent development", "AI 에이전트 개발", "LLM app", "agent architecture", "RAG agent"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.89
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["platform", "ai", "agent", "llm", "guide", "platform-independent"]
|
||||
raw_sources: ["일반 AI 에이전트 공학 지식", "AstraAI 전체 (실증 사례)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[AI 에이전트 개발 가이드]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
AI 에이전트 개발의 핵심은 "**검색(RAG)·기억(Memory)·도구(Tool)·검증(Critic)·오케스트레이션**" 을 자원 제약에 맞게 조합하는 것 — 특히 작은 로컬 모델에선 *결정론 우선·강한 grounding·자기검증* 이 품질을 가른다. AstraAI 전체가 이 가이드의 실증이다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
컨텍스트 조립, RAG, 다계층 메모리, 도구 호출, 자기검증/critic, 프롬프트 엔지니어링, 멀티에이전트 오케스트레이션, 모델 라우팅/폴백.
|
||||
|
||||
## 📖 세부 내용 (Details · 12-field)
|
||||
- **Problem:** LLM(특히 작은 모델)으로 신뢰 가능·근거 있는·행동하는 시스템을 만들기.
|
||||
- **Recommended Architecture:** 턴 파이프라인(컨텍스트 조립 → 라우팅 → 생성 → 후처리/검증 → 학습) + RAG + 메모리 + 도구 + 검증 레이어. 흐름 골격은 한 곳([[Agent 오케스트레이터 분해]]).
|
||||
- **Folder Structure:** `src/{retrieval/, memory/, intelligence/(검증), agent/(handlePrompt,llm,actions), providers/, lib/contextBuilders/}` — AstraAI 구조.
|
||||
- **Core Components:** RAG([[RAG Pattern]]), 메모리([[Memory Pattern]]), 도구 실행([[Tool Calling Pattern]]), 검증([[Critic Pattern]]/[[Reflection Pattern]]), 프롬프트 빌더([[프롬프트 엔지니어링 패턴]]), 프로바이더([[LLM 프로바이더 추상화]]).
|
||||
- **State Management:** 대화=단기 메모리, 지식=RAG/장기, 작업 상태=세션 store. 컨텍스트는 토큰 예산 내 선별.
|
||||
- **Error Handling:** 엔진 폴백, 빈 응답 soft failure, JSON 강건 파싱, 환각 가드([[Error Handling Pattern]], [[Intelligence 검증 레이어]]).
|
||||
- **Testing Strategy:** 순수 함수 단위(토크나이저/스코어/파서), 검색 평가 하니스(recall@k/MRR), 회귀 케이스(정정 재검사), 프롬프트 골든셋.
|
||||
- **Scaling Strategy:** 인덱스 캐시(mtime), 토큰 예산, 순차/자원 인지 동시성, sleep-time 사전소화, 클라우드 폴백.
|
||||
- **Common Mistakes:** 에이전트 남발(hop 손실), 임베딩 단독 의존, 매 턴 LLM 검수(비용), JSON 직접 파싱, 모델 출력 무검증 실행, system 없는 호출(작은 모델 거절).
|
||||
- **Refactoring Patterns:** 5-persona→단일 작성자([[ADR-0003 단일작성자 다중역할 멀티에이전트]]), 동적→정적, 휴리스틱→골든셋 보정, 프롬프트 블록화.
|
||||
- **Real-world Tradeoffs:** 로컬(프라이버시/비용 ↔ 품질) vs 클라우드, 결정론(가용/설명 ↔ 의미) vs 임베딩, 검증 깊이(정확 ↔ latency), 멀티에이전트(다양성 ↔ 자원/손실).
|
||||
- **Design Heuristics:** "결정론 우선, 의미는 가산", "작은 모델엔 강한 system+명시 규칙", "근거 없으면 모른다", "검증 비용은 위험에 비례", "에이전트 추가 전 정보 손실 점검", "동시성은 하드웨어가 결정".
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
"더 큰 모델·더 많은 에이전트" 가 답이 아니다 — 자원 제약 하에선 *잘 설계된 RAG+메모리+검증* 이 작은 모델을 크게 끌어올린다. 이 위키 자체가 그 전략(제2뇌)의 산물.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI(Astra) — RAG/메모리/검증/멀티에이전트의 통합 실증. 본 위키 [[AstraAI 아키텍처 개요]] 및 AI_Training 시리즈.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[플랫폼 개발 가이드 인덱스]]
|
||||
- **관련 개념:** [[RAG Pattern]], [[Memory Pattern]], [[Agent Orchestration Pattern]], [[Critic Pattern]], [[Tool Calling Pattern]], [[Intelligence 검증 레이어]]
|
||||
- **참조 맥락:** 작은 모델이 *자기 같은* AI 에이전트 시스템을 설계할 때 최상위 가이드로 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 AI 에이전트/LLM 앱 공학 지식
|
||||
- [S2] AstraAI 전체 — 실증 사례
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 플랫폼 독립 AI 에이전트 개발 가이드 초안.
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
id: platform-desktop-development
|
||||
title: "데스크탑 앱 개발 가이드"
|
||||
category: "Platform_Engineering"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["desktop development", "데스크탑 개발", "Electron", "VS Code extension", "native app"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.87
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["platform", "desktop", "electron", "guide", "platform-independent"]
|
||||
raw_sources: ["일반 데스크탑 공학 지식", "AstraAI(VS Code 확장) 적용 예"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[데스크탑 앱 개발 가이드]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
데스크탑 앱의 핵심은 "**프로세스 분리(UI↔백그라운드)·생명주기/자원 관리·확장성·로컬 저장**" 이며, AstraAI(VS Code 확장)가 이 원리들의 실증 사례다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
메인/렌더러 프로세스, IPC, 생명주기(activate/dispose), 로컬 파일/설정/시크릿, 플러그인 확장, 백그라운드 워커.
|
||||
|
||||
## 📖 세부 내용 (Details · 12-field)
|
||||
- **Problem:** OS 자원 접근·장시간 실행·로컬 데이터·반응적 UI 를 안정적으로.
|
||||
- **Recommended Architecture:** 얇은 entry(조립) + 계층 분리(인프라/도메인/기능) + IPC 로 UI 분리 + 플러그인 확장 지점. ([[AstraAI 아키텍처 개요]])
|
||||
- **Folder Structure:** `src/{core/(인프라), lib/도메인, features/<기능>, ui|webview, integrations}` + entry(activate/main).
|
||||
- **Core Components:** entry point, IPC 브리지([[IPC Pattern]]), 명령 레지스트리([[Command Pattern]]), 이벤트 버스([[Event Bus Pattern]]), 워커 큐([[Background Worker Pattern]]), 로컬 저장([[Local Storage Pattern]]).
|
||||
- **State Management:** 메인 프로세스가 진실 소유, UI 는 메시지로 변경 요청([[State Management Pattern]]). 설정은 단일 getConfig.
|
||||
- **Error Handling:** 사용자 친화 번역, 부가 작업 격리(빈 catch+이유), 보상 트랜잭션([[Error Handling Pattern]]).
|
||||
- **Testing Strategy:** 순수 도메인 단위 테스트(핵심), IPC/통합 테스트, UI 스모크. (AstraAI: jest + 순수 함수 격리)
|
||||
- **Scaling Strategy:** 무거운 작업 워커/순차([[ADR-0004 순차 디스패치 채택]]), 지연 로드(동적 import), 인덱스 캐시([[Caching Pattern]]).
|
||||
- **Common Mistakes:** disposable 미등록(누수), UI 스레드 무거운 작업, 외부 IPC 입력 미검증, 동적 import 남발, 전역 상태 산재.
|
||||
- **Refactoring Patterns:** entry 얇게(조립만), god-class 골격+추출([[ADR-0010 오케스트레이터 골격 모듈추출]]), 동적→정적 import, 중복→공통 모듈.
|
||||
- **Real-world Tradeoffs:** Electron(생산성·크로스플랫폼 ↔ 메모리·번들 크기), 네이티브(성능 ↔ 플랫폼별 코드), 프로세스 분리(격리·보안 ↔ 직렬화 비용).
|
||||
- **Design Heuristics:** "모든 자원은 dispose 등록", "한 번에 한 모델/무거운 자원", "외부 입력은 신뢰 안 함", "흐름 골격은 한 곳".
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
Electron 은 편하지만 무겁다 — 경량이 중요하면 Tauri/네이티브. 자원 제약(메모리/GPU)이 동시성·아키텍처를 좌우한다(AstraAI 의 핵심 교훈).
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI(Astra) VS Code 확장 — 본 위키 [[AstraAI 아키텍처 개요]] 전체가 실증.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[플랫폼 개발 가이드 인덱스]]
|
||||
- **관련 개념:** [[IPC Pattern]], [[Event Bus Pattern]], [[Command Pattern]], [[Plugin Architecture Pattern]], [[Background Worker Pattern]], [[VSCode 확장 구조와 생명주기]]
|
||||
- **참조 맥락:** 작은 모델이 데스크탑/확장 앱을 설계할 때 상위 가이드로 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 데스크탑(Electron/확장) 공학 지식
|
||||
- [S2] AstraAI — 실증 사례
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 플랫폼 독립 데스크탑 개발 가이드 초안.
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
id: platform-mobile-development
|
||||
title: "모바일 개발 가이드"
|
||||
category: "Platform_Engineering"
|
||||
status: "draft"
|
||||
verification_status: "conceptual"
|
||||
canonical_id: ""
|
||||
aliases: ["mobile development", "모바일 개발", "iOS", "Android", "React Native", "Flutter"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.85
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["platform", "mobile", "guide", "platform-independent"]
|
||||
raw_sources: ["일반 모바일 공학 지식"]
|
||||
applied_in: []
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[모바일 개발 가이드]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
모바일 개발의 고유 제약은 "**불안정 네트워크·제한된 자원·OS 백그라운드 제약·생명주기**" 이며, 이를 *오프라인 우선·로컬 저장·백그라운드 작업·내비게이션* 패턴으로 다루는 것이 핵심이다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
앱 생명주기(foreground/background), 오프라인 우선, 로컬 저장, 푸시, 내비게이션 스택, 권한.
|
||||
|
||||
## 📖 세부 내용 (Details · 12-field)
|
||||
- **Problem:** 끊기는 네트워크·제한 메모리/배터리·OS 제약 하에서 반응적이고 신뢰 가능한 앱.
|
||||
- **Recommended Architecture:** 오프라인 우선(로컬 저장이 진실) + 동기화 계층 + 화면/도메인 분리(MVVM/Clean) + 내비게이션 라우터.
|
||||
- **Folder Structure:** `lib|src/{features/<feature>/{ui,viewmodel,data}, core/(network,storage,di), navigation}`.
|
||||
- **Core Components:** 로컬 DB([[Local Storage Pattern]]), 동기화([[Offline Sync Pattern]]), API 클라이언트([[API Client Pattern]]), 푸시([[Push Notification Pattern]]), 내비게이션([[Navigation Pattern]]), 백그라운드([[Background Task Pattern]]).
|
||||
- **State Management:** ViewModel/store(Bloc/Riverpod/Redux) + 서버 상태 분리 + 화면 상태 복원([[State Management Pattern]]).
|
||||
- **Error Handling:** 네트워크 실패 우아 처리(오프라인 표시·재시도), 낙관적 업데이트 롤백([[Error Handling Pattern]]).
|
||||
- **Testing Strategy:** 단위(ViewModel/로직), 위젯/컴포넌트, 통합/E2E(Detox/Espresso). 디바이스 매트릭스.
|
||||
- **Scaling Strategy:** 이미지/리스트 가상화, 지연 로드, 배터리/네트워크 인지 동기화, 모듈화.
|
||||
- **Common Mistakes:** 메인 스레드 무거운 작업(jank), 토큰 평문 저장, 알림 전달 가정, 생명주기 무시(누수), offset 페이징.
|
||||
- **Refactoring Patterns:** UI-로직 분리(ViewModel 추출), 동기화 계층 분리, 거대 위젯 분해, 네트워크 클라이언트 통합.
|
||||
- **Real-world Tradeoffs:** 크로스플랫폼(RN/Flutter: 생산성 ↔ 네이티브 한계), 네이티브(성능/플랫폼 기능 ↔ 2벌 개발), 오프라인(UX ↔ 충돌 복잡도).
|
||||
- **Design Heuristics:** "로컬을 진실로, 서버는 동기화", "메인 스레드를 비워라", "민감정보는 보안 저장소", "알림은 유도, 데이터는 동기화".
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
크로스플랫폼이 항상 답은 아니다 — 고성능/플랫폼 특화 기능이 중요하면 네이티브. OS 백그라운드 제약은 "정시 실행" 가정을 깬다.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
일반 모바일 앱. AstraAI 직접 사례 없으나 오프라인/저장/백그라운드 원리는 [[패턴 카탈로그 인덱스]] 공유.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[플랫폼 개발 가이드 인덱스]]
|
||||
- **관련 개념:** [[Offline Sync Pattern]], [[Local Storage Pattern]], [[Background Task Pattern]], [[Push Notification Pattern]], [[Navigation Pattern]]
|
||||
- **참조 맥락:** 작은 모델이 모바일 앱을 설계할 때 상위 가이드로 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 모바일(iOS/Android/RN/Flutter) 공학 지식
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 플랫폼 독립 모바일 개발 가이드 초안.
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
id: platform-backend-api-development
|
||||
title: "백엔드 API 개발 가이드"
|
||||
category: "Platform_Engineering"
|
||||
status: "draft"
|
||||
verification_status: "conceptual"
|
||||
canonical_id: ""
|
||||
aliases: ["backend development", "백엔드 개발", "API design", "REST", "서버 아키텍처", "microservices"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.86
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["platform", "backend", "api", "guide", "platform-independent"]
|
||||
raw_sources: ["일반 백엔드 공학 지식", "AstraAI/src/bridge.ts (소규모 서버 적용 예)"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[백엔드 API 개발 가이드]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
백엔드의 핵심은 "**계층 분리·명확한 API 계약·데이터 일관성·복원력(재시도/멱등/한도)·관측성**" 이며, 화려한 프레임워크보다 이 기본기가 신뢰성을 만든다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
계층(라우터→서비스→리포지토리), API 계약(REST/GraphQL/RPC), 트랜잭션, 인증/인가, 멱등성, 레이트 리밋, 로깅/메트릭.
|
||||
|
||||
## 📖 세부 내용 (Details · 12-field)
|
||||
- **Problem:** 동시 다수 클라이언트에 일관·안전·확장 가능한 데이터/로직 제공.
|
||||
- **Recommended Architecture:** 계층형(라우터/컨트롤러 → 서비스(도메인) → 리포지토리(데이터)) + DTO 경계 + 의존성 주입. ([[Architecture Separation Pattern]])
|
||||
- **Folder Structure:** `src/{routes|controllers, services, repositories, domain/models, middleware, infra(db,cache,queue), config}`.
|
||||
- **Core Components:** 라우터/미들웨어, 서비스, 리포지토리([[Repository Pattern]]), 인증([[JWT Authentication Pattern]]), 캐시([[Caching Pattern]]), 큐/워커([[Background Worker Pattern]]), 에러 핸들러.
|
||||
- **State Management:** 상태는 DB/캐시(서버는 가급적 무상태), 세션/토큰, 분산 락. SSOT.
|
||||
- **Error Handling:** 표준 에러 응답(코드/메시지), 재시도(backoff)/서킷 브레이커, 멱등 키, 트랜잭션 롤백([[Error Handling Pattern]]).
|
||||
- **Testing Strategy:** 단위(서비스/도메인), 통합(DB/리포), 계약 테스트(API), 부하 테스트.
|
||||
- **Scaling Strategy:** 수평 확장(무상태), 캐시 계층, 읽기 복제/샤딩, 비동기 큐, 레이트 리밋, CDN.
|
||||
- **Common Mistakes:** 컨트롤러에 비즈니스 로직, N+1 쿼리, 멱등성 부재(중복 처리), 트랜잭션 경계 오류, 검증 누락, 무한 재시도.
|
||||
- **Refactoring Patterns:** 컨트롤러→서비스 로직 이동, 쿼리→리포지토리 캡슐화, 공통→미들웨어, 동기→큐 비동기화.
|
||||
- **Real-world Tradeoffs:** 모놀리스(단순·일관 ↔ 확장/배포 결합) vs 마이크로서비스(독립 확장 ↔ 분산 복잡도/일관성), SQL(일관성 ↔ 확장) vs NoSQL(확장 ↔ 일관성), REST vs GraphQL.
|
||||
- **Design Heuristics:** "서버 무상태로", "쓰기는 멱등하게", "경계에서 검증", "느린 작업은 큐로", "관측 가능하게(로그/메트릭/트레이스)".
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
마이크로서비스가 기본값은 아니다 — 대부분 모놀리스(또는 모듈러 모놀리스)로 시작해 *필요할 때* 분리하는 것이 안전(분산은 비싸다).
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
AstraAI BridgeServer(로컬 HTTP, 서비스 레이어로 로직 분리 — 소규모 백엔드의 계층 분리 예) [S2].
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[플랫폼 개발 가이드 인덱스]]
|
||||
- **관련 개념:** [[Repository Pattern]], [[API Client Pattern]], [[JWT Authentication Pattern]], [[Caching Pattern]], [[Event Bus Pattern]], [[이벤트 소싱 스토어 패턴]]
|
||||
- **참조 맥락:** 작은 모델이 서버/API 를 설계할 때 상위 가이드로 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 백엔드/API 공학 지식
|
||||
- [S2] AstraAI/src/bridge.ts — 소규모 서버 계층 분리 예
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 플랫폼 독립 백엔드 개발 가이드 초안.
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
id: platform-web-development
|
||||
title: "웹 개발 가이드"
|
||||
category: "Platform_Engineering"
|
||||
status: "draft"
|
||||
verification_status: "conceptual"
|
||||
canonical_id: ""
|
||||
aliases: ["web development", "웹 개발", "frontend", "SPA", "프런트엔드 아키텍처"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.86
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["platform", "web", "frontend", "guide", "platform-independent"]
|
||||
raw_sources: ["일반 웹 공학 지식"]
|
||||
applied_in: []
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[웹 개발 가이드]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
웹 개발의 본질은 프레임워크가 아니라 "**상태·비동기·데이터 흐름·에러·계층 분리**" 라는 반복 문제를 푸는 것 — 도구는 바뀌어도 원리는 [[패턴 카탈로그 인덱스]] 의 cross-cutting 패턴으로 수렴한다.
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
선언형 UI, 컴포넌트, 단방향 데이터, 서버/클라 상태 분리, 라우팅, 번들링/코드 분할.
|
||||
|
||||
## 📖 세부 내용 (Details · 12-field)
|
||||
- **Problem:** 다양한 디바이스/브라우저에서 반응적이고 유지보수 가능한 UI 와 데이터 동기화.
|
||||
- **Recommended Architecture:** 컴포넌트 기반 + 단방향 데이터 + 서버 상태 라이브러리(react-query) + 기능별 폴더(feature-sliced). 무거운 로직은 도메인 계층으로 분리.
|
||||
- **Folder Structure:** `src/{features/<feature>/{ui,api,model}, shared/{ui,lib,api}, app/(라우팅·프로바이더)}`. 기능 슬라이스 + 공유 계층.
|
||||
- **Core Components:** 라우터, 데이터 페칭 계층([[API Client Pattern]]), 상태 store([[State Management Pattern]]/[[React State Pattern]]), 디자인 시스템, 에러 바운더리.
|
||||
- **State Management:** 지역=useState, 서버=쿼리 캐시, 공유 도메인=가벼운 store, 공유 가능 상태=URL. (SSOT·단방향)
|
||||
- **Error Handling:** 에러 바운더리(렌더 에러), 쿼리 에러/리트라이, 사용자 친화 메시지([[Error Handling Pattern]]).
|
||||
- **Testing Strategy:** 단위(순수 로직)·컴포넌트(Testing Library)·E2E(Playwright). 피라미드(단위 多, E2E 少).
|
||||
- **Scaling Strategy:** 코드 분할/지연 로드, 가상화([[Infinite Scroll Pattern]]), CDN/캐시, SSR/SSG(초기 로드·SEO), 이미지 최적화.
|
||||
- **Common Mistakes:** 서버 데이터를 로컬 상태에 복사(stale), 전역 store 남용(리렌더), prop drilling, 거대 컴포넌트, 무분별 useEffect.
|
||||
- **Refactoring Patterns:** 거대 컴포넌트 분해, 로직→커스텀 훅 추출, 페칭→쿼리 계층 이동, prop drilling→context/store.
|
||||
- **Real-world Tradeoffs:** SSR(성능·SEO ↔ 복잡도), 전역 상태(편의 ↔ 결합), 마이크로프런트엔드(독립 배포 ↔ 운영 부담).
|
||||
- **Design Heuristics:** "상태는 가장 낮은 곳, 공유되면 올린다", "서버 상태와 UI 상태 분리", "파생은 계산", "경계에서 검증".
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
프레임워크(React/Vue/Svelte)는 수단 — 채용/생태계로 고르되, 위 원리는 공통. "최신 프레임워크" 추종보다 상태/데이터 흐름 설계가 품질을 가른다.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
일반 SPA/웹앱. AstraAI 웹뷰 UI 도 상태/메시지 원리는 동일.
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[플랫폼 개발 가이드 인덱스]]
|
||||
- **관련 개념:** [[State Management Pattern]], [[React State Pattern]], [[API Client Pattern]], [[JWT Authentication Pattern]], [[Infinite Scroll Pattern]]
|
||||
- **참조 맥락:** 작은 모델이 웹 프로젝트를 설계/구현할 때 상위 가이드로 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] 일반 웹/프런트엔드 공학 지식
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: 플랫폼 독립 웹 개발 가이드 초안.
|
||||
@@ -0,0 +1,110 @@
|
||||
---
|
||||
id: five-layer-memory-system
|
||||
title: "5계층 메모리 시스템"
|
||||
category: "AI_and_ML"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["cognitive memory", "메모리 시스템", "short-term", "long-term", "episodic", "procedural", "distillation", "memory layers"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.93
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["memory", "ai", "agent", "cognitive-architecture", "astraai"]
|
||||
raw_sources: ["AstraAI/src/memory/index.ts", "AstraAI/src/memory/types.ts", "AstraAI/src/retrieval/index.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[5계층 메모리 시스템]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
LLM 에이전트의 "기억"은 인간 인지처럼 **시간 범위·용도가 다른 5개 계층(단기·장기·프로젝트·절차·일화)** 으로 나누고, 각 계층이 질의에 대해 관련도 점수를 매겨 컨텍스트에 합치는 것이 AstraAI 의 설계다 [S1][S2].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **① 단기(Short-Term):** 현재 대화 흐름. 최근 N개 메시지를 FIFO 로 유지(`shortTermLimit: 8`) [S1].
|
||||
2. **② 장기(Long-Term):** 사용자 취향·규칙·결정·목표. category(`preference`/`rule`/`decision`/`goal`/`episode-digest`)와 confidence, 참조 횟수, 만료시각(`expiresAt`)을 가진 엔트리 [S2].
|
||||
3. **③ 프로젝트(Project):** 워크스페이스별 지식 — 아키텍처 결정(ADR), 버그 기록, 요구사항, 기술스택, 코드 컨벤션. workspace 경로 hash 로 식별 [S2].
|
||||
4. **④ 절차(Procedural):** 반복 작업의 절차서(skill.md). triggerPatterns 로 매칭(`["wiki화","위키","wikify"]`)해 steps 를 제공 [S2].
|
||||
5. **⑤ 일화(Episodic):** 과거 세션의 요약·주요 결정·토픽. 시간이 지나면 distillation 으로 장기 digest 로 승급 [S2].
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **통합 매니저 + 계층 위임:** `MemoryManager` 가 5개 계층 객체를 보유하고 `buildContext()` 에서 각 계층의 `buildContext(query)` 를 호출해 결과를 모은다 — 계층은 독립, 매니저는 조립 [S1].
|
||||
- **관련도 점수 + 정렬:** 각 계층이 `MemoryContextResult { layer, label, content, relevance }` 를 반환, 매니저가 `relevance` 내림차순 정렬 후 합침 [S1].
|
||||
- **lazy 프로젝트 메모리:** `projectMemories: Map<string, ProjectMemory>` 로 워크스페이스별 지연 생성·캐시 [S1].
|
||||
- **temporal marker 로 자동 만료:** `expiresAt < now` 인 엔트리는 검색·컨텍스트 구성에서 자동 제외 — "Q3 계획은 9/30까지만 유효" 같은 시한부 지식 [S2].
|
||||
- **증류(Distillation) 폐루프:** 세션 종료 시 stale 일화를 장기 digest 로 승급하고 `promoted=true` 로 표시해 이후 검색에서 제외(중복 방지) [S1].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### 컨텍스트 조립 (핵심 API)
|
||||
`buildContext(currentPrompt, visibleHistory, summarize, workspacePath)` 가 5계층에서 관련 컨텍스트를 모아 하나의 `[MEMORY CONTEXT]` 블록으로 만든다. 각 계층은 자기 데이터를 query 와 비교해 relevance 를 매기고, 빈 결과면 제외된다. 마지막에 "관련될 때만 사용하고, 충돌 시 현재 요청을 우선하라"는 지침을 덧붙인다 [S1].
|
||||
|
||||
### 세션 종료 시 추출·영속화
|
||||
`onSessionEnd(sessionId, messages, workspacePath, distillationOpts)`:
|
||||
1. `MemoryExtractor` 가 대화에서 장기/일화/프로젝트 메모리를 추출 (실패해도 본 흐름 안 깨짐 — 빈 catch).
|
||||
2. 장기 메모리 `save()`.
|
||||
3. distillation 이 enabled 이고 interval 충족 시 stale 일화를 장기 digest 로 승급 [S1].
|
||||
|
||||
### RAG 와의 결합
|
||||
검색 오케스트레이터는 메모리 계층을 RAG 소스 중 하나로 끌어온다 — 장기/프로젝트/절차/일화 각각을 `RetrievalChunk` 로 변환하고, source 별 가중치(procedural 0.95, project 0.85, episodic 0.7)로 정규화한다 [S3]. → [[RAG 검색 파이프라인]].
|
||||
|
||||
### 설정 가능성
|
||||
`MemoryConfig` 로 계층별 on/off 와 한도(`longTermMaxEntries: 100`, `episodicMaxEpisodes: 50`)를 조절. 생성자에서 `{ ...defaults, ...config }` 로 부분 오버라이드 [S1].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **계층 경계의 모호성:** "프로젝트 결정"이 장기 메모리(decision)인지 프로젝트 메모리(ADR)인지 겹칠 수 있다. AstraAI 는 워크스페이스 종속성 유무로 가른다(프로젝트 종속이면 ③, 사용자 보편이면 ②).
|
||||
- **만료 vs 보존:** `expiresAt` 로 시한부 지식을 자동 제외하지만, 만료된 지식이 "역사적 맥락"으로 필요할 때도 있다 — 검색은 제외하되 distillation 이 digest 로 보존하는 식으로 절충.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/memory/index.ts` — MemoryManager 의 buildContext/onSessionEnd 전체 흐름 [S1].
|
||||
- `AstraAI/src/memory/types.ts` — 5계층 데이터 형태, temporal marker, distillation 승급 필드 [S2].
|
||||
- `AstraAI/src/retrieval/index.ts` — `searchMemoryLayers` 가 계층을 RAG 청크로 변환 [S3].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// 1) 통합 매니저가 계층에 위임 + 관련도 정렬 (src/memory/index.ts)
|
||||
public buildContext(prompt, history, summarize, workspacePath?): string {
|
||||
const layers: MemoryContextResult[] = [];
|
||||
const stm = this.shortTerm.buildContext(history, this.config.shortTermLimit, summarize);
|
||||
if (stm) layers.push(stm);
|
||||
const ltm = this.longTerm.buildContext(prompt);
|
||||
if (ltm) layers.push(ltm);
|
||||
// ... project / procedural / episodic 동일 패턴
|
||||
if (!layers.length) return '';
|
||||
layers.sort((a, b) => b.relevance - a.relevance); // 관련도 내림차순
|
||||
return ['', '[MEMORY CONTEXT]', /* 지침 */, layers.map(l => `### ${l.label}\n${l.content}`).join('\n\n')].join('\n');
|
||||
}
|
||||
|
||||
// 2) lazy 프로젝트 메모리 (src/memory/index.ts)
|
||||
public getProjectMemory(workspacePath: string): ProjectMemory {
|
||||
if (!this.projectMemories.has(workspacePath))
|
||||
this.projectMemories.set(workspacePath, new ProjectMemory(workspacePath));
|
||||
return this.projectMemories.get(workspacePath)!;
|
||||
}
|
||||
|
||||
// 3) 부가 작업은 본 흐름을 깨지 않음 (src/memory/index.ts)
|
||||
try { this.extractor.extractFromSession(...); } catch { /* never break main flow */ }
|
||||
```
|
||||
|
||||
## ✅ 검증 상태 및 신뢰도
|
||||
- **상태:** draft
|
||||
- **검증 단계:** applied
|
||||
- **출처 신뢰도:** A
|
||||
- **신뢰 점수:** 0.93
|
||||
- **중복 검사 결과:** 신규 생성 (New discovery)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[RAG 검색 파이프라인]], [[이벤트 소싱 스토어 패턴]], [[Agent 오케스트레이터 분해]]
|
||||
- **참조 맥락:** 로컬 LLM 이 에이전트의 기억/컨텍스트 시스템을 설계하거나 메모리 계층 코드를 다룰 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/memory/index.ts — MemoryManager, buildContext, onSessionEnd, distillation 호출
|
||||
- [S2] AstraAI/src/memory/types.ts — 5계층 타입, temporal marker, 승급 필드
|
||||
- [S3] AstraAI/src/retrieval/index.ts — searchMemoryLayers(메모리→RAG 청크)
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.
|
||||
@@ -0,0 +1,113 @@
|
||||
---
|
||||
id: agent-orchestrator-decomposition
|
||||
title: "Agent 오케스트레이터 분해"
|
||||
category: "AI_and_ML"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["agent executor", "orchestrator", "god class 분해", "multi-agent", "ChunkedWriter", "sequential dispatch", "에이전트 파이프라인"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.9
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["agent", "orchestrator", "multi-agent", "architecture", "ai", "astraai"]
|
||||
raw_sources: ["AstraAI/src/agent.ts", "AstraAI/src/agents/AgentWorkflowManager.ts", "AstraAI/src/agent/multiAgent/workflow.ts", "AstraAI/src/features/company/dispatcher.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Agent 오케스트레이터 분해]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
한 턴의 복잡한 처리(컨텍스트 조립→라우팅→스트리밍→후처리→학습)는 거대 orchestrator 하나가 *흐름의 골격만 쥐고 세부는 추출된 모듈에 위임*하는 구조가 유지보수에 유리하며, 멀티에이전트는 "병렬 persona 줄세우기"보다 **자원 제약에 맞춘 순차 실행 + 단일 작성자 다중 역할**이 로컬 환경에서 더 견고하다 [S1][S2][S4].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **얇은 골격 + 추출 위임:** `agent.ts`(orchestrator)는 한 턴의 흐름을 읽을 수 있게 유지하고, 세부는 `handlePrompt/`, `llm/`, `actions/`, `sessions/`, `multiAgent/` 로 추출 [S1].
|
||||
2. **Action tag 실행:** 모델 출력의 `<create_file>`, `<run_command>` 등 태그를 액션 실행기로 라우팅해 도구를 수행 [S1][S4].
|
||||
3. **단일 작성자 다중 역할(ChunkedWriter):** outline → section[N] → polish 를 같은 모델이 번갈아 수행 — hop 마다 컨텍스트 폭증·본문 손실을 피함 [S2].
|
||||
4. **순차 디스패치(company):** CEO 플래너 → 전문가들 순차 실행(peer-context 전달) → CEO 리포터 합성 [S4].
|
||||
5. **mission 락:** 무거운 LLM 작업은 `missionId` 단위로 직렬화 [S2][참조: [[동시성 제어 Lock Queue Transaction]]].
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **God-class 분해:** orchestrator 의 import 가 100줄을 넘지만, 이는 "기능을 작은 모듈로 추출하고 흐름에서 다시 끌어모은" 결과 — 흐름은 한 곳, 구현은 분산 [S1].
|
||||
- **메시지 프로토콜 UI:** webview 와 `streamStart`/`streamChunk`/`streamEnd`/`workflowStage` 메시지로 통신 — 진행 단계는 본문이 아니라 상단 인디케이터로 [S3].
|
||||
- **모든 종료 경로에서 인디케이터 닫기:** 성공·취소·에러 어디서든 `workflowStage{done:true}` 를 보내 "영원히 도는 스피너" 방지 [S3].
|
||||
- **peer-context 버퍼:** 앞 에이전트 출력을 잘라(`PEER_OUTPUT_BUDGET 1500`) 다음 에이전트 프롬프트에 전달 [S4].
|
||||
- **raw 출력 → 공용 액션 실행기 재사용:** 전문가도 action tag 를 낼 수 있고, 채팅과 같은 실행기를 통과시켜 도구 동작 일관성 유지 [S4].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### 멀티에이전트 설계의 진화 (post-mortem)
|
||||
초기엔 planner/researcher/reflector/writer/synthesizer 5개 persona 를 줄세웠다. 문제: 각 hop 마다 컨텍스트가 누적되고 *원본 본문이 추상화로 손실* 돼, 사용자가 본문 분석을 요청해도 "분석 방법론" 만 만들어내는 사고가 났다. → 현재는 단일 `ChunkedWriter` 가 outline/section/polish 세 역할을 같은 모델에서 번갈아 수행 — 각 호출이 작고 본문은 매 호출에 직접 전달돼 손실이 없다 [S2].
|
||||
|
||||
### 왜 순차 디스패치인가 (company 모드)
|
||||
사용자는 단일 GPU/제한된 RAM 에서 Astra 를 돌린다. 병렬 에이전트는 여러 모델을 동시에 메모리에 상주시켜야 한다. 순차 실행은 "정확히 한 번에 하나의 모델만 상주" 를 보장하고, LM Studio lifecycle 매니저가 이전 모델을 unload 하고 다음을 load 한다 [S4]. → 이 위키의 sub-agent 제약(병렬 fanout 금지)과도 같은 원리.
|
||||
|
||||
### 왜 handlePrompt 를 재사용하지 않는가
|
||||
`handlePrompt` 는 *대화형* 경로용이라 대화 이력·스트리밍 UI·에이전트 모드 주입 등 12가지를 떠안는다. company 턴은 "system 1개 + user 1개 → 문자열 1개" 의 깨끗한 primitive 가 필요하므로 `AIService.chat()` 을 쓴다 — 책임이 다른 경로는 다른 primitive [S4].
|
||||
|
||||
## ⚖️ 비교 및 선택 기준 (Comparison & decision criteria)
|
||||
|
||||
| 멀티에이전트 방식 | 장점 | 단점 | 언제 |
|
||||
|---|---|---|---|
|
||||
| 병렬 persona N개 | 빠름(자원 충분 시) | 모델 다중 상주, 컨텍스트 누적/본문 손실 | RAM/GPU 넉넉한 서버 |
|
||||
| 단일 작성자 다중 역할 | 컨텍스트 작고 본문 보존 | 한 모델 품질에 의존 | 로컬 단일 모델 |
|
||||
| 순차 디스패치 | 한 번에 한 모델, 자원 안전 | 총 시간 김 | 단일 GPU/제한 RAM |
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **orchestrator 크기:** 분해했어도 agent.ts 가 크다 — "흐름 가독성" 을 위해 의도적으로 골격을 남긴 트레이드오프(완전 분해 시 흐름 추적이 파일 사이를 떠돈다).
|
||||
- **순차의 비용:** 응답이 느리다. 사용자 경험을 위해 진행 단계를 webview 인디케이터로 보여 체감 지연을 완화한다.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/agent.ts` — orchestrator 골격 + 추출 모듈 import [S1].
|
||||
- `AstraAI/src/agents/AgentWorkflowManager.ts` — ChunkedWriter 단일 작성자 다중 역할 [S2].
|
||||
- `AstraAI/src/agent/multiAgent/workflow.ts` — webview 메시지 프로토콜, 모든 경로 인디케이터 닫기 [S3].
|
||||
- `AstraAI/src/features/company/dispatcher.ts` — 순차 디스패치, peer-context, 설계 근거 주석 [S4].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// 1) 단일 작성자 다중 역할 — 스테이지를 UI 라벨로 (src/agents/AgentWorkflowManager.ts)
|
||||
const writer = new ChunkedWriter(modelName, overrides); // outline → section → polish
|
||||
const engine = new AgentEngine(writer);
|
||||
return await engine.runMission(missionId, prompt, brainContext, signal,
|
||||
(stage, msg) => onProgress(this.mapStageToUI(stage), msg)); // ① 구조 → ② 본문 → ③ 다듬기
|
||||
|
||||
// 2) 모든 종료 경로에서 인디케이터 닫기 (src/agent/multiAgent/workflow.ts)
|
||||
} catch (error: any) {
|
||||
deps.getWebview()?.postMessage({ type: 'workflowStage', value: { step: '완료', done: true } });
|
||||
if (error.name === 'AbortError') { /* 취소 */ return; }
|
||||
// ... 에러 카드
|
||||
} finally { deps.options.onStreamLifecycle?.end(); }
|
||||
|
||||
// 3) 순차 디스패치 + peer-context 버퍼 (src/features/company/dispatcher.ts, 개념)
|
||||
let peerContext = '';
|
||||
for (const task of plan.tasks) {
|
||||
const prompt = buildSpecialistPrompt(task, peerContext); // 앞 에이전트 맥락 포함
|
||||
const out = await aiService.chat({ system, user: prompt }); // 한 번에 한 모델만 상주
|
||||
writeAgentOutput(sessionDir, task, out.content);
|
||||
peerContext += '\n' + out.content.slice(0, PEER_OUTPUT_BUDGET); // 다음 에이전트에 전달
|
||||
}
|
||||
```
|
||||
|
||||
## ✅ 검증 상태 및 신뢰도
|
||||
- **상태:** draft
|
||||
- **검증 단계:** applied
|
||||
- **출처 신뢰도:** A
|
||||
- **신뢰 점수:** 0.90
|
||||
- **중복 검사 결과:** 신규 생성 (New discovery)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[Intelligence 검증 레이어]], [[LLM 프로바이더 추상화]], [[동시성 제어 Lock Queue Transaction]], [[Agent Orchestration Pattern]]
|
||||
- **참조 맥락:** 로컬 LLM 이 에이전트 실행 파이프라인·멀티에이전트 구조를 자원 제약 하에서 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/agent.ts — orchestrator 골격, 추출 모듈 import 구조
|
||||
- [S2] AstraAI/src/agents/AgentWorkflowManager.ts — ChunkedWriter, 멀티에이전트 진화 post-mortem
|
||||
- [S3] AstraAI/src/agent/multiAgent/workflow.ts — 메시지 프로토콜, 인디케이터 닫기
|
||||
- [S4] AstraAI/src/features/company/dispatcher.ts — 순차 디스패치 근거, peer-context, primitive 분리
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.
|
||||
@@ -0,0 +1,127 @@
|
||||
---
|
||||
id: intelligence-verification-layer
|
||||
title: "Intelligence 검증 레이어"
|
||||
category: "AI_and_ML"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["self-evolving", "critic", "confidence engine", "epistemic guard", "correction loop", "anti-hallucination", "자기검증", "환각 방지"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.93
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["intelligence", "verification", "hallucination", "self-evolving", "ai", "astraai"]
|
||||
raw_sources: ["AstraAI/src/intelligence/criticAgent.ts", "AstraAI/src/intelligence/confidenceEngine.ts", "AstraAI/src/intelligence/epistemicGuardBlock.ts", "AstraAI/src/intelligence/correctionLoop.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[Intelligence 검증 레이어]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
작은 로컬 LLM 의 환각·오류를 시스템이 잡으려면 "**저렴한 결정론적 검사를 항상, 비싼 LLM 검사는 조건부로**" 돌리고, 사용자 정정 한 번을 시스템 성장으로 환원하는 폐루프가 핵심이며, AstraAI 는 Epistemic Guard(사전 억제)·Confidence Engine(측정)·Critic(사후 검수)·Correction Loop(학습)로 이를 계층화한다 [S1][S2][S3][S4].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **Epistemic Guard (사전):** 시스템 프롬프트에 "확실/추정/모름 3등급" 을 강제하는 블록을 주입. 검색 근거가 없을수록 지시가 강해진다("지어내지 말고 질문하라") [S3].
|
||||
2. **Confidence Engine (측정):** LLM 호출 없이 검색 그라운딩 신호 + 답변 텍스트 신호(정규식)만으로 0~100 확신도를 *결정론적* 산출. latency 0 [S2].
|
||||
3. **Critic Agent (사후):** 결정론적 검사가 문제를 신호할 때만 LLM 검수 1회 — 조건부 1-pass. 누락·근거 없는 단정·미결 구분을 검사 [S1].
|
||||
4. **Correction Loop (학습):** 사용자 정정을 Ground Truth 로 보고 레슨 저장 + 회귀 케이스 적립 + 약점 프로필 → 다음 턴 프롬프트에 자동 주입 [S4].
|
||||
5. **CoVe vs Epistemic Guard 분업:** CoVe 는 출처가 *있을 때* 주장-출처 매핑 검증, Epistemic Guard 는 출처 *유무 무관* 등급 표시 강제 [S3].
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **저렴한 것 항상, 비싼 것 조건부:** 결정론적(정규식/카운트) 검사는 매 턴, LLM 검수는 신호가 있을 때만 — 로컬 모델 latency 비용 통제 [S1][S2].
|
||||
- **"확신도는 모델 자신감이 아니라 검증 가능성":** 모델이 솔직히 "(확인 필요)" 를 쓰면 점수가 *내려가는* 게 올바른 동작 — 사용자 검토를 유도해야 하므로 [S2].
|
||||
- **가중치 합산 + factor 기록:** 확신도를 요인별 delta 합으로 계산하고 각 factor 를 footer 에 노출 — 점수가 왜 그렇게 나왔는지 설명가능 [S2].
|
||||
- **정답지를 사람이 안 만든다:** 정정 발화 자체가 Ground Truth. 회귀 테스트가 "같은 실수 반복?" 을 LLM-judge 로 판정 [S4].
|
||||
- **통찰→행동의 기계화:** 태그 통계가 리포트에 머물지 않고 `buildSelfReviewBlock` 으로 다음 턴 시스템 프롬프트를 바꾼다(같은 태그 2회+일 때만) [S4].
|
||||
- **JSON 강건 파싱:** LLM 의 JSON 출력에 잡설이 섞여도 첫 균형 `{}` 블록을 스캔해 추출 [S1].
|
||||
- **fire-and-forget 캡처:** 정정 캡처는 비동기로 흘려 응답 속도에 영향 없음 [S4].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### Confidence Engine — 결정론적 가중 합산
|
||||
중립 출발점 55에서 시작해 요인별로 가감한다 [S2]:
|
||||
- 그라운딩: 청크 3건+ & topScore 0.5+ → +25, 1건+ → +12, 없음 → -15.
|
||||
- 출처 인용 +8 / 모델 지식만 -5.
|
||||
- 출처 충돌 건당 -8(최대 -16), 요청 모호성 -10.
|
||||
- Requirement 커버리지 전부 충족 +10 / 누락당 -6(최대 -18).
|
||||
- 헤지 표현 개당 -4(최대 -12).
|
||||
구간: 90+ 높음 / 70-89 보통 / 50-69 낮음 / <50 매우 낮음(에스컬레이션).
|
||||
|
||||
### Critic — 조건부 1-pass 검수
|
||||
완전한 작성→비판→재작성 debate 는 로컬 Gemma latency 때문에 미룬다. v1 은 "커버리지 누락 또는 확신도 <70" 일 때만 Critic LLM 1회 호출, 결과를 답변 아래 보완 카드로 표시. `maxRounds` knob 만 준비해 두고 다회전은 후속 [S1].
|
||||
|
||||
### Correction Loop — 정정 1회가 3곳을 성장
|
||||
```
|
||||
사용자 정정 → ① 감지(보수적 정규식) + LLM 분류(6개 오류 태그)
|
||||
├→ 태깅된 레슨 저장 (lessons/)
|
||||
└→ 회귀 케이스 적립 (.astra/eval/corrections.jsonl)
|
||||
② 주간 성장 사이클: 회귀 재검사 + 태그 통계 → 약점 프로필
|
||||
③ 약점 프로필 → 시스템 프롬프트 자기검토 블록 자동 주입
|
||||
```
|
||||
설계 원칙: 정답지는 정정 자체, 통찰→행동은 기계적, 모든 산출물은 사람이 열어 수정/삭제 가능(Permission Based Learning), 캡처는 fire-and-forget [S4].
|
||||
|
||||
### 폭주 방지 장치들
|
||||
- 자기검토 블록은 같은 태그 2회+일 때만(1회성 실수로 프롬프트 어지럽힘 방지) [S4].
|
||||
- 지식 공백 학습 큐는 같은 질문 1회만 등록(해시 id) + proposed 20건 쌓이면 사람이 정리할 때까지 중단 [S4].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **휴리스틱 가중치의 임시성:** Confidence 가중치는 "휴리스틱 v1" 으로, 골든셋이 쌓이면 사람 평가와의 상관으로 보정 예정 — 현재 절대 점수보다 *상대 비교* 와 추세에 의미가 있다.
|
||||
- **정규식 정정 감지의 한계:** 보수적이라 미묘한 정정("음 그건 좀…")은 놓친다. 오탐이 레슨 노이즈를 만들기에 의도적으로 보수적.
|
||||
- **Critic 의 1-pass 한계:** 다회전 debate 가 더 정확하지만 비용 때문에 보류 — 정확도 vs latency 트레이드오프의 현실적 타협.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/intelligence/confidenceEngine.ts` — 결정론적 확신도 + footer [S2].
|
||||
- `AstraAI/src/intelligence/criticAgent.ts` — 조건부 검수 + 균형 JSON 파싱 [S1].
|
||||
- `AstraAI/src/intelligence/epistemicGuardBlock.ts` — 사전 억제 프롬프트 [S3].
|
||||
- `AstraAI/src/intelligence/correctionLoop.ts` — 정정→레슨→약점프로필→프롬프트 폐루프 [S4].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// 1) 결정론적 확신도 — 요인별 delta 합산 + 설명가능 (src/intelligence/confidenceEngine.ts)
|
||||
let score = 55; // 중립 출발점
|
||||
if (retrieval.chunkCount >= 3 && retrieval.topScore >= 0.5) factors.push({ label: '검색 근거 강', delta: +25 });
|
||||
else if (retrieval.chunkCount >= 1) factors.push({ label: '검색 근거 있음', delta: +12 });
|
||||
else factors.push({ label: '검색 근거 없음', delta: -15 });
|
||||
if (answer.hedgeCount > 0) factors.push({ label: '불확실 표시', delta: -Math.min(12, answer.hedgeCount * 4) });
|
||||
for (const f of factors) score += f.delta;
|
||||
score = Math.max(0, Math.min(100, Math.round(score))); // 0~100 clamp
|
||||
|
||||
// 2) 균형 괄호 JSON 추출 — LLM 잡설 내성 (src/intelligence/criticAgent.ts)
|
||||
let depth = 0, end = -1, inString = false, escaped = false;
|
||||
for (let i = start; i < raw.length; i++) {
|
||||
const ch = raw[i];
|
||||
if (escaped) { escaped = false; continue; }
|
||||
if (ch === '\\') { escaped = true; continue; }
|
||||
if (ch === '"') { inString = !inString; continue; }
|
||||
if (inString) continue;
|
||||
if (ch === '{') depth++; else if (ch === '}' && --depth === 0) { end = i; break; }
|
||||
}
|
||||
|
||||
// 3) 통찰→행동 — 약점 통계를 다음 턴 프롬프트로 (src/intelligence/correctionLoop.ts)
|
||||
const significant = profile.tagCounts.filter(t => t.count >= 2).slice(0, 2); // 2회+만
|
||||
// → "너는 최근 '사실오류' 정정을 N회 받았다. 수치·날짜는 근거 없으면 '확인 필요'로 표시하라."
|
||||
```
|
||||
|
||||
## ✅ 검증 상태 및 신뢰도
|
||||
- **상태:** draft
|
||||
- **검증 단계:** applied
|
||||
- **출처 신뢰도:** A
|
||||
- **신뢰 점수:** 0.93
|
||||
- **중복 검사 결과:** 신규 생성 (New discovery)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[의존성 주입과 서비스 인터페이스]], [[프롬프트 엔지니어링 패턴]], [[Agent 오케스트레이터 분해]]
|
||||
- **참조 맥락:** 로컬 LLM 이 자기검증·환각 억제·피드백 학습 루프를 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/intelligence/criticAgent.ts — 조건부 검수, 균형 JSON 파싱, 함수 주입
|
||||
- [S2] AstraAI/src/intelligence/confidenceEngine.ts — 결정론적 확신도 산출
|
||||
- [S3] AstraAI/src/intelligence/epistemicGuardBlock.ts — 3등급 인식론 가드
|
||||
- [S4] AstraAI/src/intelligence/correctionLoop.ts — 정정 폐루프, 약점 프로필, 폭주 방지
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.
|
||||
@@ -0,0 +1,124 @@
|
||||
---
|
||||
id: llm-provider-abstraction
|
||||
title: "LLM 프로바이더 추상화"
|
||||
category: "AI_and_ML"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["provider abstraction", "adapter pattern", "LLM 라우팅", "prefix routing", "SSE", "스트리밍", "엔진 폴백"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.92
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["llm", "provider", "adapter", "streaming", "sse", "astraai"]
|
||||
raw_sources: ["AstraAI/src/features/providers/types.ts", "AstraAI/src/features/providers/index.ts", "AstraAI/src/features/providers/anthropic.ts", "AstraAI/src/core/services.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[LLM 프로바이더 추상화]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
여러 LLM 공급자(로컬 LM Studio/Ollama, 클라우드 OpenRouter/Anthropic/Gemini)를 한 코드에서 쓰려면 "**model id prefix 로 라우팅 + 공급자별 어댑터가 차이를 흡수 + 모두 같은 SSE 포맷으로 정규화**"가 핵심이며, AstraAI 는 이 어댑터 패턴으로 호출부를 공급자 무관하게 유지한다 [S1][S2].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **Prefix 라우팅:** `anthropic:claude-...`, `gemini:...`, `openrouter:...` 처럼 model id 의 접두사로 공급자를 결정. 접두사 없으면 로컬 엔진 [S1].
|
||||
2. **어댑터 패턴:** 공급자마다 `streamX(context, params)` 함수가 그 API 의 차이(인증·바디·스트림 형식)를 흡수하고 표준 인터페이스(`StreamParams`)를 받는다 [S2][S3].
|
||||
3. **출력 정규화(SSE):** 각 어댑터가 응답 스트림을 *OpenAI 호환 SSE* 로 변환해 반환 → 기존 SSE 파서 하나로 모두 소비 [S2][S3].
|
||||
4. **로컬 엔진 폴백:** 로컬은 LM Studio↔Ollama 간 자동 폴백(전송 오류/5xx/빈 응답 시) [S4].
|
||||
5. **에러 응답 passthrough:** 인증 실패·4xx·5xx 는 `.ok=false` Response 로 그대로 반환, 호출부가 `.text()` 로 메시지 추출 [S2][S3].
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **양방향 prefix 변환:** `parseModelPrefix(id)`(분해) ↔ `makeModelId(provider, model)`(조립) — UI/config 저장과 라우팅이 1:1 [S1].
|
||||
- **switch dispatch:** `streamCloudCompletion` 이 `switch (hit.provider)` 로 어댑터 선택 — 공급자 추가는 case 하나 [S2].
|
||||
- **입력 정규화(공급자 제약 흡수):** Anthropic 어댑터는 (1) system 을 top-level 로 분리, (2) 연속 같은 role 병합(교대 강제), (3) 첫 메시지 user 강제(dummy 삽입) [S3].
|
||||
- **활성 공급자만 병렬 조회:** `listAllCloudModels` 가 enabled+apiKey 인 공급자만 `Promise.all` 로 모델 목록 수집 [S2].
|
||||
- **하드코딩 fallback 목록:** 모델 list API 가 없는 공급자(Anthropic)는 알려진 모델 목록을 반환하되 사용자 직접 입력도 허용(validate 안 함) [S3].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### prefix 를 왜 쓰는가
|
||||
같은 model name 이 OpenRouter 와 직통에 동시 존재할 수 있어 출처를 명시해야 라우팅이 모호하지 않다. 또 UI 드롭다운 그룹화('OpenRouter · ...')와, 접두사 없는 옛 설정('gemma4:e2b')의 자동 로컬 경로 처리에 유리하다 [S1].
|
||||
|
||||
### 어댑터가 흡수하는 차이 (Anthropic 예)
|
||||
- base URL `https://api.anthropic.com/v1`, 인증 `x-api-key` + `anthropic-version` 헤더.
|
||||
- system 은 messages 가 아니라 top-level `system` 필드 → 어댑터가 분리·병합.
|
||||
- role 교대 강제 → 연속 같은 role 병합.
|
||||
- 응답 스트림이 OpenAI 와 다른 event 형식 → `transformAnthropicStream` 으로 변환 후 새 `Response` 로 wrap [S3].
|
||||
|
||||
이 정규화 덕분에 상위 `agent.ts` 의 스트림 파서는 공급자를 전혀 모른다 — "차이는 가장자리(어댑터)에서 흡수, 중심은 단일 포맷".
|
||||
|
||||
### 로컬 엔진 폴백 (services.ts)
|
||||
`AIService.chat` 은 사용자 설정 엔진을 먼저 시도하고, 전송 오류/HTTP 실패/빈 응답이면 다른 엔진으로 폴백한다. 빈 응답은 soft failure 로 취급해 재시도, 두 엔진 모두 빈 응답이면 `empty: true` 결과를 반환해 호출부가 사용자에게 안내하게 한다(예외 삼키지 않음) [S4].
|
||||
|
||||
## ⚖️ 비교 및 선택 기준 (Comparison & decision criteria)
|
||||
|
||||
| 접근 | 장점 | 단점 | 언제 |
|
||||
|---|---|---|---|
|
||||
| prefix 라우팅 | 모호성 없음, UI 그룹화 | id 규칙 학습 필요 | 다중 공급자/중복 모델명 |
|
||||
| 어댑터별 함수 | 차이 격리, 추가 쉬움 | 공급자마다 구현 | 공급자 API 가 제각각일 때 |
|
||||
| 공통 SSE 정규화 | 파서 1개로 통일 | 변환 레이어 비용 | 스트리밍 다공급자 |
|
||||
| 로컬↔로컬 폴백 | 가용성↑ | 지연 증가 가능 | 로컬 엔진 불안정 환경 |
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **하드코딩 모델 목록의 노후화:** Anthropic 어댑터의 모델 목록은 작성 시점 기준이라 시간이 지나면 낡는다. 사용자 직접 입력을 허용해 완화하지만, 최신 모델 사용 시 id 를 직접 넣어야 한다.
|
||||
- **prompt caching/tool use 미구현:** 어댑터 주석이 "향후 확장 여지(prompt caching, tool use)"를 명시 — 현재는 단순 streaming 만. 비용 최적화·구조화 호출은 후속 과제.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/features/providers/index.ts` — streamCloudCompletion switch dispatch, listAllCloudModels 병렬 [S2].
|
||||
- `AstraAI/src/features/providers/anthropic.ts` — 입력 정규화 + SSE 변환 + 에러 passthrough [S3].
|
||||
- `AstraAI/src/features/providers/types.ts` — parseModelPrefix/makeModelId [S1].
|
||||
- `AstraAI/src/core/services.ts` — 로컬 엔진 폴백 [S4].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// 1) prefix 라우팅 (src/features/providers/types.ts)
|
||||
export function parseModelPrefix(id: string): { provider: ProviderId; model: string } | null {
|
||||
for (const { prefix, id: pid } of PROVIDER_PREFIXES)
|
||||
if (id.startsWith(prefix)) return { provider: pid, model: id.slice(prefix.length) };
|
||||
return null; // null = 로컬 엔진 경로
|
||||
}
|
||||
|
||||
// 2) switch dispatch — 공급자 추가는 case 하나 (src/features/providers/index.ts)
|
||||
switch (hit.provider) {
|
||||
case 'openrouter': return streamOpenRouter(context, fullParams);
|
||||
case 'anthropic': return streamAnthropic(context, fullParams);
|
||||
case 'gemini': return streamGemini(context, fullParams);
|
||||
}
|
||||
|
||||
// 3) 입력 정규화로 공급자 제약 흡수 (src/features/providers/anthropic.ts)
|
||||
for (const m of params.messages) {
|
||||
if (m.role === 'system') systemPrompt += (systemPrompt ? '\n\n' : '') + m.content; // top-level 분리
|
||||
else { const last = messages.at(-1);
|
||||
if (last?.role === m.role) last.content += '\n\n' + m.content; // 같은 role 병합
|
||||
else messages.push({ role: m.role, content: m.content }); }
|
||||
}
|
||||
if (messages[0]?.role !== 'user') messages.unshift({ role: 'user', content: '(continue)' }); // 첫 user 강제
|
||||
|
||||
// 4) 응답 스트림을 공통 SSE 로 정규화
|
||||
const transformed = transformAnthropicStream(upstream.body);
|
||||
return new Response(transformed, { status: 200, headers: { 'Content-Type': 'text/event-stream' } });
|
||||
```
|
||||
|
||||
## ✅ 검증 상태 및 신뢰도
|
||||
- **상태:** draft
|
||||
- **검증 단계:** applied
|
||||
- **출처 신뢰도:** A
|
||||
- **신뢰 점수:** 0.92
|
||||
- **중복 검사 결과:** 신규 생성 (New discovery)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[비동기 프로그래밍 Promise async await]], [[의존성 주입과 서비스 인터페이스]], [[Agent 오케스트레이터 분해]]
|
||||
- **참조 맥락:** 로컬 LLM 이 다중 LLM 공급자/외부 API 를 어댑터로 통합하는 코드를 작성할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/features/providers/types.ts — prefix 라우팅, makeModelId
|
||||
- [S2] AstraAI/src/features/providers/index.ts — switch dispatch, 병렬 모델 조회
|
||||
- [S3] AstraAI/src/features/providers/anthropic.ts — 입력 정규화, SSE 변환, 에러 passthrough
|
||||
- [S4] AstraAI/src/core/services.ts — 로컬 엔진 폴백
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
id: rag-retrieval-pipeline
|
||||
title: "RAG 검색 파이프라인"
|
||||
category: "AI_and_ML"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["RAG", "retrieval", "검색 증강 생성", "하이브리드 검색", "context budget", "rerank", "chunking", "orchestrator"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.92
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["rag", "retrieval", "ai", "search", "embedding", "astraai"]
|
||||
raw_sources: ["AstraAI/src/retrieval/index.ts", "AstraAI/src/retrieval/chunker.ts", "AstraAI/src/retrieval/scoring.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[RAG 검색 파이프라인]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
RAG 는 "질문에 답하기 전에 관련 지식을 찾아 컨텍스트에 넣는" 기법이며, AstraAI 의 오케스트레이터는 **질의 계획 → 다중 소스 병렬 검색 → 점수 정규화·재가중 → 토큰 예산 내 선택** 의 4단계로 brain 파일·5계층 메모리·최근 세션을 하나의 컨텍스트로 융합한다 [S1].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **소스 융합(Fusion):** brain 파일(TF-IDF/하이브리드), 메모리 계층, 중기(최근 세션)를 각각 검색해 `RetrievalChunk[]` 로 모은다 [S1].
|
||||
2. **점수 정규화:** 소스마다 점수 스케일이 달라, 소스별로 0~1 정규화 후 source 우선순위 가중치를 곱한다 [S1].
|
||||
3. **재가중(Re-rank):** Actionability(현재 작업 상태 신호)와 Hierarchical(질의·문서 추상도 매칭)로 점수를 조정 [S1].
|
||||
4. **토큰 예산(Context budget):** 모델 컨텍스트 한도 내에서 점수 높은 청크만 선택, 나머지는 drop [S1].
|
||||
5. **섹션 청킹:** 긴 문서를 헤딩 경계로 쪼개 정밀도를 높이는 선택적 경로 [S2]. → [[TF-IDF 이중언어 스코어링]].
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **단계별 fusionLog:** 각 단계가 `fusionLog.push(...)` 로 무엇을 했는지 기록 — 검색이 왜 그 결과를 냈는지 추적·디버깅 가능 [S1].
|
||||
- **`??` 로 의미 있는 0 보존:** `brainFileLimit ?? 8` — Knowledge Mix "모델 지식만" 모드가 명시적 0 을 보내면 검색을 건너뛴다(`|| 8` 이면 0이 8로 둔갑) [S1].
|
||||
- **하이브리드 blend(sparse+dense):** TF-IDF 점수를 top 값으로 정규화하고 임베딩 cosine 과 `(1-α)·sparse + α·dense` 로 혼합. 벡터 없는 문서는 순수 TF-IDF 유지 [S1].
|
||||
- **per-file cap:** 한 문서가 상위 슬롯을 독식하지 않게 파일당 청크 수를 3개로 제한 [S1].
|
||||
- **운영 로그 제외:** 세션/메모리/회사 로그 폴더는 "지식"이 아니므로 검색에서 제외(`isOperationalPath`) — 노이즈·토큰 낭비 차단 [S1].
|
||||
- **레슨 카드 가산:** 짧고 신호 강한 레슨 카드는 top-limit 밖이어도 추가로 끌어오고 1.4× 가중 [S1].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### 4단계 흐름 (`retrieve`)
|
||||
```
|
||||
① Query Planning : tokenize → expandQuery(동의어 확장)
|
||||
② Parallel Search : Brain(TF-IDF/하이브리드) + Memory 계층 + Medium-term(최근 세션)
|
||||
③ Result Fusion : normalizeScores(소스별 0~1 + source boost) → actionability/hierarchical re-rank
|
||||
④ Context Budget : selectWithinBudget(점수순, 토큰 한도 내) → lesson 청크 분리 추출
|
||||
```
|
||||
반환에는 선택/탈락 청크, 레슨 청크, 사용 토큰, fusionLog 가 포함된다 [S1].
|
||||
|
||||
### 하이브리드 검색의 스케일 함정 (주석에 기록된 실측 버그)
|
||||
1. *모든* 후보를 maxTfidf 로 정규화해야 한다 — 벡터 있는 것만 0..1 로 줄이면 벡터 없는 후보의 raw 점수(≫1)가 상위를 독식해 blend 가 무효가 된다.
|
||||
2. cosine 은 후보군 내 min-max 정규화 — 임베딩 모델은 무관 문서끼리도 cos 0.5~0.7 이 나와, 절대값 가산이 균일 노이즈로 sparse 정밀도를 흐린다 [S1].
|
||||
|
||||
### 성능 — mtime 인덱스
|
||||
`getBrainTokenIndex` 는 파일 mtime 기준 영속 인덱스라, 변경 없는 파일은 재읽기·재토큰화하지 않는다. 큰 brain 에서 질의당 작업량이 O(전체 내용) → O(파일 수)로 떨어진다. 실제 디스크 읽기는 *선택된 파일* 의 발췌 추출 때만 발생 [S1].
|
||||
|
||||
### 평가 무결성
|
||||
`rankBrainForEval` 은 프로덕션 `retrieve` 와 *동일한 scoring 경로*(`searchBrainFiles`)를 재사용한다 — recall@k/MRR 측정이 실제 검색 동작을 반영하도록 [S1].
|
||||
|
||||
## ⚖️ 비교 및 선택 기준 (Comparison & decision criteria)
|
||||
|
||||
| 검색 방식 | 장점 | 단점 | 언제 |
|
||||
|---|---|---|---|
|
||||
| TF-IDF (sparse) | 키워드 정확, 인덱스 가벼움, 설명가능 | 의미 유사 놓침 | 임베딩 엔진 없을 때 기본 |
|
||||
| 임베딩 (dense) | 의미 유사 포착 | 무관 문서도 높은 cos, 비용 | 동의·환언 많은 질의 |
|
||||
| 하이브리드 blend | 둘의 장점 결합 | 스케일 정규화 까다로움 | 임베딩 가용 시 권장 |
|
||||
| 섹션 청크 | 긴 문서 정밀도↑ | 인덱스 크기↑ | 다주제 장문 brain |
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **청크 vs 파일 단위:** 섹션 청킹은 정밀도를 높이지만 회귀 위험이 있어 파일 단위 경로와 분리(`chunkLevelRetrieval` 플래그)해 격리했다 — 점진 도입 전략.
|
||||
- **재가중의 위험:** actionability/hierarchical 가중이 과하면 키워드 정합이 약한 문서가 떠오를 수 있다. 그래서 정규화 *후, 예산 선택 전* 에 적용해 영향 범위를 통제한다.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/retrieval/index.ts` — RetrievalOrchestrator 의 retrieve/searchBrainFiles/searchBrainChunks/normalizeScores 전체 [S1].
|
||||
- `AstraAI/src/retrieval/chunker.ts` — 헤딩 경계 섹션 청킹(순수 함수) [S2].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// 1) 의미 있는 0 보존 — Knowledge Mix "모델 지식만" 모드 (src/retrieval/index.ts)
|
||||
const brainFileLimit = options.brainFileLimit ?? 8; // ?? : 명시적 0 을 0으로 존중
|
||||
const brainChunks = brainFileLimit > 0 ? this.searchBrainFiles(...) : [];
|
||||
|
||||
// 2) 소스별 정규화 + 우선순위 가중 (src/retrieval/index.ts)
|
||||
for (const [, group] of groups) {
|
||||
const maxScore = Math.max(...group.map(c => c.score), 0.001);
|
||||
for (const c of group) c.score /= maxScore; // 소스 내 0~1 정규화
|
||||
}
|
||||
const sourceBoost = { 'procedural-memory': 0.95, 'brain-memory': 0.9, 'episodic-memory': 0.7 /* ... */ };
|
||||
for (const c of chunks) { c.score *= (sourceBoost[c.source] ?? 0.5); if (c.metadata.isLesson) c.score *= 1.4; }
|
||||
|
||||
// 3) 하이브리드 blend — 모든 후보를 같은 스케일로 (src/retrieval/index.ts)
|
||||
const sparse = s.score / maxTfidf;
|
||||
s.score = cos === null ? sparse : (1 - alpha) * sparse + alpha * ((cos - minCos) / span);
|
||||
```
|
||||
|
||||
## ✅ 검증 상태 및 신뢰도
|
||||
- **상태:** draft
|
||||
- **검증 단계:** applied
|
||||
- **출처 신뢰도:** A
|
||||
- **신뢰 점수:** 0.92
|
||||
- **중복 검사 결과:** 신규 생성 (New discovery)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[TF-IDF 이중언어 스코어링]], [[5계층 메모리 시스템]], [[Agent 오케스트레이터 분해]]
|
||||
- **참조 맥락:** 로컬 LLM 이 검색 증강·컨텍스트 조립·점수 융합 코드를 설계할 때 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/retrieval/index.ts — RetrievalOrchestrator(4단계, fusion, 하이브리드, 예산, 평가)
|
||||
- [S2] AstraAI/src/retrieval/chunker.ts — 섹션 청킹 순수 함수
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
id: tfidf-bilingual-scoring
|
||||
title: "TF-IDF 이중언어 스코어링"
|
||||
category: "AI_and_ML"
|
||||
status: "draft"
|
||||
verification_status: "applied"
|
||||
canonical_id: ""
|
||||
aliases: ["TF-IDF", "토크나이저", "tokenizer", "한국어 영어 토큰화", "동의어 확장", "검색 점수", "stop words", "섹션 청킹"]
|
||||
duplicate_of: ""
|
||||
source_trust_level: "A"
|
||||
confidence_score: 0.92
|
||||
created_at: 2026-06-13
|
||||
updated_at: 2026-06-13
|
||||
review_reason: ""
|
||||
merge_history: []
|
||||
tags: ["tfidf", "tokenizer", "search", "nlp", "korean", "astraai"]
|
||||
raw_sources: ["AstraAI/src/retrieval/scoring.ts", "AstraAI/src/retrieval/chunker.ts"]
|
||||
applied_in: ["AstraAI"]
|
||||
github_commit: ""
|
||||
---
|
||||
|
||||
# [[TF-IDF 이중언어 스코어링]]
|
||||
|
||||
## 🎯 한 줄 통찰 (One-line insight)
|
||||
임베딩 엔진 없이도 쓸 수 있는 가벼운 검색의 핵심은 "좋은 토크나이저 + TF-IDF 가중"이며, AstraAI 는 **한국어/영어 혼합 토크나이저·불용어·동의어 확장·제목 가중·충돌 신호** 를 더해 단순 `includes()` 매칭을 넘어선 점수를 낸다 [S1].
|
||||
|
||||
## 🧠 핵심 개념 (Core concepts)
|
||||
1. **TF-IDF:** 용어 빈도(TF, 문서 내 흔함) × 역문서빈도(IDF, 전체에서 희소함). 흔하면서 그 문서에만 자주 나오는 단어가 고득점 [S1].
|
||||
2. **이중언어 토큰화:** 한글-영문 경계를 분리(`성능optimization` → `성능` `optimization`), 특수기호 보존(C++, C#, .net) [S1].
|
||||
3. **불용어(Stop words):** 검색에 무의미한 단어(영/한 각각 집합)를 제거 [S1].
|
||||
4. **동의어 확장:** 질의 토큰을 관련어로 확장(`성능` → `performance`, `optimization`, `최적화`) [S1].
|
||||
5. **제목 가중:** 제목 일치는 본문보다 3배 가중(`TITLE_MULTIPLIER: 3.0`) [S1].
|
||||
6. **토큰 캐시:** 같은 텍스트의 토큰화를 Map 으로 캐시(한도 초과 시 전체 clear) [S1].
|
||||
|
||||
## 🧩 추출된 패턴 (Extracted patterns)
|
||||
- **중앙 설정 객체:** `SCORING_CONFIG` 에 불용어·동의어·임계값·가중치를 모아 한 곳에서 조정 [S1].
|
||||
- **경계 분리 정규식:** `replace(/([a-z0-9]+)([가-힣]+)/gi, '$1 $2')` 로 언어 경계 분할, `split(/[^a-z0-9가-힣+#.-]+/g)` 로 특수기호(C++) 보존 [S1].
|
||||
- **TF 계산 1회화:** `buildTermCounts` 로 문서당 용어 빈도 맵을 한 번 만들고 질의 용어마다 재사용 — O(질의×문서) 재스캔 회피 [S1].
|
||||
- **IDF smoothing:** 문서 수가 적을 때도 안정적이도록 평활화 적용 [S1].
|
||||
- **충돌 신호 탐지:** "반대/충돌/conflict/vs" 등 지표 단어 수로 conflictSeverity 산출 — 지식 충돌 가능 문서를 표시 [S1].
|
||||
- **순수 함수 분리:** chunker/scoring 은 fs·네트워크 의존 없는 순수 함수라 단위 테스트·재현이 쉽다 [S2].
|
||||
|
||||
## 📖 세부 내용 (Details)
|
||||
### 토크나이저 (가장 중요한 부품)
|
||||
```typescript
|
||||
const normalized = text.toLowerCase()
|
||||
.replace(/[-]/g, '') // zero-width 제거
|
||||
.replace(/[^\w\s가-힣_+#.-]/g, ' '); // 의미 없는 기호 → 공백
|
||||
const splitText = normalized
|
||||
.replace(/([a-z0-9]+)([가-힣]+)/gi, '$1 $2') // 영→한 경계 분리
|
||||
.replace(/([가-힣]+)([a-z0-9]+)/gi, '$1 $2');// 한→영 경계 분리
|
||||
const tokens = splitText.split(/[^a-z0-9가-힣+#.-]+/g) // C++, C#, .net 보존
|
||||
.map(t => t.trim().replace(/[.,]$/g, ''))
|
||||
.filter(t => /[가-힣]/.test(t) ? t.length >= 1 : t.length >= 2) // 한글 1자+, 영문 2자+
|
||||
.filter(t => !STOP_EN.has(t) && !STOP_KO.has(t));
|
||||
```
|
||||
한국어는 한 글자도 의미를 가질 수 있어 1자 이상 허용, 영문은 2자 이상으로 노이즈를 줄인다 [S1].
|
||||
|
||||
### 동의어 확장
|
||||
질의 `[성능]` → `[성능, performance, optimization, 최적화, speed]`. Set 으로 중복 제거 후 반환. brain 문서가 영어로, 질의가 한국어로 와도(또는 반대) 매칭되게 하는 양국어 다리 [S1].
|
||||
|
||||
### 섹션 청킹과의 결합
|
||||
긴 문서를 통째 색인하면 5000자 다주제 문서가 흐릿한 한 단위가 되어 정밀도가 떨어진다. `chunker.ts` 가 헤딩(`#`~`######`) 경계로 섹션을 나누고, 짧은 섹션은 병합·긴 섹션은 문단 경계로 재분할한다. fenced code block(```) 안의 `#` 는 헤딩으로 보지 않는다. 헤딩 breadcrumb 을 보존해 청크가 문맥을 잃지 않게 한다 [S2].
|
||||
|
||||
## ⚖️ 모순 및 업데이트 (Contradictions & updates)
|
||||
- **TF-IDF 의 한계:** 어휘가 다르면(동의어 사전에 없는 환언) 못 잡는다. 그래서 임베딩 하이브리드로 보완한다 → [[RAG 검색 파이프라인]].
|
||||
- **동의어 사전의 유지보수:** 수작업 사전이라 도메인이 늘면 누락이 생긴다. 핵심 도메인 용어 위주로 관리하는 절충.
|
||||
- **형태소 분석 부재:** 한국어 조사/어미를 정밀 분해하지 않는다(경량 우선). 정밀도가 더 필요하면 형태소 분석기 도입 여지.
|
||||
|
||||
## 🛠️ 적용 사례 (Applied in summary)
|
||||
- `AstraAI/src/retrieval/scoring.ts` — tokenize/expandQuery/TF-IDF/충돌 탐지 [S1].
|
||||
- `AstraAI/src/retrieval/chunker.ts` — splitIntoSections 섹션 청킹 [S2].
|
||||
|
||||
## 💻 코드 패턴 (Code patterns)
|
||||
```typescript
|
||||
// 1) 중앙 설정 객체 — 가중치/임계값 한 곳에서 (src/retrieval/scoring.ts)
|
||||
const SCORING_CONFIG = {
|
||||
STOP_WORDS_EN: new Set(['the','a','and',/* ... */]),
|
||||
STOP_WORDS_KO: new Set(['그리고','그런데',/* ... */]),
|
||||
SYNONYM_DATA: [['성능', ['performance','optimization','최적화','speed']], /* ... */],
|
||||
TITLE_MULTIPLIER: 3.0,
|
||||
GLOBAL_CACHE_LIMIT: 2000,
|
||||
};
|
||||
|
||||
// 2) TF 계산 1회화 (src/retrieval/scoring.ts)
|
||||
function buildTermCounts(tokens: string[]): Map<string, number> {
|
||||
const counts = new Map<string, number>();
|
||||
for (const t of tokens) counts.set(t, (counts.get(t) || 0) + 1);
|
||||
return counts; // 질의 용어마다 재스캔 대신 이 맵을 조회
|
||||
}
|
||||
|
||||
// 3) 동의어 확장 (src/retrieval/scoring.ts)
|
||||
export function expandQuery(tokens: string[]): string[] {
|
||||
const expanded = new Set(tokens);
|
||||
for (const t of tokens) (synonymMap.get(t) ?? []).forEach(s => expanded.add(s));
|
||||
return Array.from(expanded);
|
||||
}
|
||||
|
||||
// 4) 헤딩 경계 섹션 청킹 — fence 안의 # 무시 (src/retrieval/chunker.ts)
|
||||
const fence = line.trimStart().startsWith('```'); if (fence) inFence = !inFence;
|
||||
const m = !inFence ? line.match(HEADING_RE) : null; // 코드블록 내 #는 헤딩 아님
|
||||
```
|
||||
|
||||
## ✅ 검증 상태 및 신뢰도
|
||||
- **상태:** draft
|
||||
- **검증 단계:** applied
|
||||
- **출처 신뢰도:** A
|
||||
- **신뢰 점수:** 0.92
|
||||
- **중복 검사 결과:** 신규 생성 (New discovery)
|
||||
|
||||
## 🔗 지식 그래프 (Knowledge Graph)
|
||||
- **상위/루트:** [[AstraAI 아키텍처 개요]]
|
||||
- **관련 개념:** [[RAG 검색 파이프라인]], [[5계층 메모리 시스템]], [[TypeScript 기초와 타입 시스템]]
|
||||
- **참조 맥락:** 로컬 LLM 이 가벼운 텍스트 검색·토큰화·점수 함수를 작성할 때(특히 한/영 혼용) 참조.
|
||||
|
||||
## 📚 출처 (Sources)
|
||||
- [S1] AstraAI/src/retrieval/scoring.ts — 토크나이저, TF-IDF, 동의어, 불용어, 충돌 탐지, 캐시
|
||||
- [S2] AstraAI/src/retrieval/chunker.ts — 섹션 청킹(순수 함수)
|
||||
|
||||
## 📝 변경 이력 (Change history)
|
||||
- 2026-06-13: AstraAI 코드 분석 기반 초안 생성.
|
||||
@@ -0,0 +1,18 @@
|
||||
# Topic_Programming Chronicle Records
|
||||
|
||||
## Project
|
||||
- ID: topic-programming
|
||||
- Root: /Volumes/Data/project/Antigravity/Wiki/10_Wiki/Topic_Programming
|
||||
- Record root: /Volumes/Data/project/Antigravity/Wiki/10_Wiki/Topic_Programming/docs/records/Topic_Programming
|
||||
- Detail level: standard
|
||||
|
||||
## Purpose
|
||||
Auto-created by Project Architecture activation.
|
||||
|
||||
## Folders
|
||||
- `planning/`
|
||||
- `discussions/`
|
||||
- `decisions/`
|
||||
- `development/`
|
||||
- `bugs/`
|
||||
- `retrospectives/`
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"projectId": "topic-programming",
|
||||
"projectName": "Topic_Programming",
|
||||
"projectRoot": "/Volumes/Data/project/Antigravity/Wiki/10_Wiki/Topic_Programming",
|
||||
"recordRoot": "/Volumes/Data/project/Antigravity/Wiki/10_Wiki/Topic_Programming/docs/records/Topic_Programming",
|
||||
"description": "Auto-created by Project Architecture activation.",
|
||||
"corePurpose": "",
|
||||
"detailLevel": "standard",
|
||||
"createdAt": "2026-06-13T05:17:27.365Z",
|
||||
"updatedAt": "2026-06-14T09:54:16.959Z"
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
# Project Profile
|
||||
|
||||
## Project Name
|
||||
Topic_Programming
|
||||
|
||||
## Description
|
||||
Auto-created by Project Architecture activation.
|
||||
|
||||
## Project Root
|
||||
/Volumes/Data/project/Antigravity/Wiki/10_Wiki/Topic_Programming
|
||||
|
||||
## Record Root
|
||||
/Volumes/Data/project/Antigravity/Wiki/10_Wiki/Topic_Programming/docs/records/Topic_Programming
|
||||
|
||||
## Core Purpose
|
||||
Not captured yet.
|
||||
|
||||
## Target Users
|
||||
Not captured yet.
|
||||
|
||||
## Avoid Directions
|
||||
Not captured yet.
|
||||
|
||||
## Record Detail Level
|
||||
standard
|
||||
|
||||
## Created
|
||||
2026-06-13T05:17:27.365Z
|
||||
|
||||
## Updated
|
||||
2026-06-13T05:17:27.378Z
|
||||
@@ -0,0 +1,4 @@
|
||||
# Project Timeline
|
||||
|
||||
## 2026-06-13
|
||||
- Project Chronicle record folder initialized for Topic_Programming.
|
||||
Reference in New Issue
Block a user