Skip to content

Latest commit

 

History

History
245 lines (197 loc) · 14.5 KB

File metadata and controls

245 lines (197 loc) · 14.5 KB

Architecture — 기여자용 한눈 가이드

이 문서는 처음 보는 사람도 10분 안에 어디 무엇이 있는지 / 어디를 손대면 좋은지 알 수 있도록 쓰여졌습니다. 상세 설계 의도는 docs/discord_first_redesign_v4_1.md에 있습니다.


1. 한 눈에 보는 아키텍처

   USER (Discord / CLI / 향후 Slack·Web)
       │
       ▼
┌─────────────────────────────────────────────────┐
│  frontends/  ← 입력 받고 출력 보내기 (transport)    │
│   discord/   cli/   slack/(빈)   web/(빈)         │
└──────────────────┬──────────────────────────────┘
                   ▼   (인터랙션 → Identity)
┌─────────────────────────────────────────────────┐
│  tenancy/  ContextConcierge ← *조립점*            │
│   요청마다 HarnessContext를 하나 만들어 넘김         │
└──────────────────┬──────────────────────────────┘
                   ▼   (ctx = LLM+tools+session+...)
┌─────────────────────────────────────────────────┐
│  harness/  agent_loop                            │
│   system prompt → LLM → tool 호출 → 다음 턴/종료   │
└──────────────────┬──────────────────────────────┘
                   ▼   (도구가 ctx의 포트를 호출)
┌──────────────┬───────────┬───────────┬─────────┐
│ semantic/(★④)│safety/(★①)│memory/(★②)│ingest/(★③)│  ← 4기둥
└──────────────┴───────────┴───────────┴─────────┘
                   │
                   ▼   (모두 포트(Protocol)로 외부와 분리)
┌─────────────────────────────────────────────────┐
│  adapters/  외부 시스템과의 마지막 한 줄              │
│   llm/openai_ · llm/fake                          │
│   db/sqlalchemy_explorer · db/d1_explorer · db/postgres_explorer │
│   storage/sqlite_store · storage/sqlite_semantic   │
└─────────────────────────────────────────────────┘

핵심 원칙: 로직은 포트(추상)에만 의존, 어댑터(구체)는 가장자리에만. 그래서 새 LLM·새 DB·새 frontend를 기존 코드 안 건드리고 끼울 수 있습니다.


2. 왜 이런 구조? — 4기둥 (해결하려는 문제)

이름 풀려는 현실 문제 핵심 파일
Safety pipeline SQL이 실수로/악의로 DB를 망치는 일 src/lang2sql/safety/
Memory 3축 봇이 어제 한 얘기·정의를 기억 못 함 src/lang2sql/memory/
Ingestion 매트릭스 비즈니스 정의를 사람이 일일이 입력해야 함 src/lang2sql/ingestion/
Semantic federation 같은 "활성 사용자" 가 팀마다 의미 다름 src/lang2sql/semantic/

자세한 배경은 redesign 문서 §3을 참고.


3. 디렉토리·레이어 가이드

의존 방향: frontends → tenancy → harness → semantic/safety/memory/ingestion/tools → core ← adapters core/는 누구도 의존하지 않는 순수 영역(타입+포트). 새 모듈 추가 시 이 방향을 깨지 않게.

src/lang2sql/core/ — 순수 타입 + 포트 (★ 손대지 마세요)

시스템 전체의 어휘가 모여 있습니다. 외부 의존 0, I/O 0.

  • types.pyMessage, ToolCall, ToolResult, Completion, Role
  • identity.pyIdentity, Scope, federation의 scope_chain() 순서 (narrow→wide)
  • ports/ — 11개 Protocol: LLMPort, ExplorerPort, ToolPort, SafetyLayerPort, SafetyPipelinePort, StorePort, RecallPort, ExtractorPort (memory), SourcePort, DocExtractorPort, ScopeResolverPort, FrontendPort, SecretsPort, SessionStorePort, AuditPort

src/lang2sql/harness/ — 에이전트 한 턴의 엔진

  • context.pyHarnessContext (llm + tools + safety + explorer + scope_resolver + session 한 다발)
  • session.py — 대화 transcript
  • loop.pyagent_loop: system prompt → LLM → tool 호출 → 다음 턴
  • tool_registry.py — 이름→도구 dispatch
  • system_prompt.py — 시멘틱 + 스키마 주입

src/lang2sql/semantic/ — 시멘틱 레이어 + federation (★④)

  • types.pySemanticEntry (METRIC/DIMENSION/RELATIONSHIP/RULE)
  • layer.pySemanticLayer.render() (시스템 프롬프트로 들어감)
  • scoped_layer.py가장 구체적 scope가 승리하는 merge
  • store.py — in-memory store
  • sql_composer.py — metric 이름 → 정의 펼치기 (V1 최소)

src/lang2sql/safety/ — Read-only 게이트 (★①)

src/lang2sql/memory/ — Hermes 3축 (★②)

src/lang2sql/ingestion/ — 문서 → 시멘틱 후보 (★③)

src/lang2sql/tools/ — 에이전트가 부르는 capability

6개 도구 (모두 ctx-aware, async):

src/lang2sql/tenancy/ — 조립점

src/lang2sql/adapters/ — 외부 시스템과의 마지막 줄

  • llm/openai_.py — urllib 기반 OpenAI tool-calling
  • llm/fake.py — 오프라인 테스트용 결정적 LLM
  • db/sqlalchemy_explorer.pyDSN만 바꾸면 Postgres/MySQL/Snowflake/BigQuery/DuckDB 다 커버
  • db/d1_explorer.py — Cloudflare D1 (HTTP API, urllib)
  • db/factory.pybuild_explorer(connection) scheme 라우팅
  • db/postgres_explorer.py — V1 stub (psycopg 미설치 환경용)
  • storage/sqlite_store.pyAuditPort + SessionStorePort + kv
  • storage/sqlite_semantic.py — 시멘틱 정의 영속화

src/lang2sql/frontends/ — 사용자 인터페이스


4. 한 메시지의 lifecycle (디스코드 멘션 한 번 따라가기)

1. 사용자: "@lang2sql-test 이번 달 매출 알려줘"
2. discord/bot.py: on_message → _message_context()로 (guild_id, channel_id, user_id) 뽑음
3. session_router.to_identity()  →  Identity(...)
4. CommandHandlers.query(identity, "이번 달 매출 알려줘")
5. ContextConcierge.build_context(identity)
     - secrets에서 길드별 db_dsn 있나? → 있으면 build_explorer로 그 DB 사용 (캐시)
     - SqliteStore에서 세션 로드 (없으면 새로)
     - build_default_tools()로 ToolRegistry 채움
     - HarnessContext 반환
6. agent_loop(ctx, "이번 달 매출 알려줘")
     - system_prompt: 시멘틱 effective_layer + 스키마 주입
     - LLM(GPT-4.1-mini): "run_sql 도구를 부르세요" 응답
     - tools.dispatch("run_sql", {sql: "SELECT ..."}, ctx)
        → safety.evaluate(sql) → PASS
        → explorer.execute(sql) → 행들 반환
     - 결과 messages에 추가, LLM 다시 호출 → 최종 답변
7. concierge.store.save(session_key, ctx.session)  ← 세션 영속화
8. render_answer(answer) → OutboundMessage
9. interaction.followup.send(...)  → Discord에 답

5. 어디를 수정하면 좋을까 — Extension Points

기여 PR을 받기 가장 쉬운 지점들. 전부 기존 코드 안 건드리고 추가만 하면 됩니다.

LLM 추가 (예: Anthropic Claude, NIM)

  1. src/lang2sql/adapters/llm/<provider>_.py 새로 작성, LLMPort 구현
  2. tenancy/concierge.py: _default_llm()에 분기 추가
  3. tests/ 에 test_<provider>_adapter.py

새 DB 지원

SQLAlchemy 지원 DB라면:

  1. pyproject.toml[project.optional-dependencies]에 extra 추가
  2. 끝. SqlAlchemyExplorer가 DSN으로 알아서 처리

SQLAlchemy 미지원 (예: 자체 HTTP API):

  1. adapters/db/<db>_explorer.pyExplorerPort 구현
  2. adapters/db/factory.pybuild_explorer에 scheme 분기
  3. adapters/db/dsn_builder.pybuild_<db>() + FIELD_SCHEMA[<db>]
  4. tests/

새 safety layer (예: AST 정밀 검증, 함수 차단, EXPLAIN 비용)

  1. safety/layers/<name>.pySafetyLayerPort 구현
  2. safety/pipeline.pySafetyPipeline 기본 layers 목록에 끼우거나, 옵셔널로 노출
  3. tests/test_safety.py에 회귀 케이스 추가

더 똑똑한 memory recall (예: 키워드, 벡터)

  1. memory/recall/<name>.pyRecallPort 구현
  2. concierge에서 옵션으로 선택 가능하게
  3. tests/

새 ingestion source (예: URL, Notion MCP)

  1. ingestion/sources/<name>.pySourcePort 구현
  2. ingestion 도구 흐름이 자동 매트릭스이므로 추가 코드 거의 없음

새 frontend (예: Slack, Web)

  1. frontends/<platform>/ 디렉토리에 transport 작성
  2. commands.py는 그대로 재사용 (discord 비의존이라)
  3. core/ports/frontend.pyFrontendPort 인터페이스 따르기

새 도구 (예: visualize, write_code)

  1. tools/<name>.pyToolPort 구현 (spec + run)
  2. tools/__init__.py: build_default_tools()에 추가
  3. tests/

6. 빠른 기여 시작 (5분)

git clone https://github.com/CausalInferenceLab/Lang2SQL.git
cd Lang2SQL
uv sync                          # 기본 deps
.venv/bin/pytest -q              # 106 테스트 통과 확인
.venv/bin/python bench/ecommerce_demo.py   # federation + safety 로컬 데모

브랜치 → 코드 + 테스트 → PR. CI는 따로 없으니 로컬에서 pytest 확인 후 PR.


7. 코드 컨벤션 (작은 약속)

규칙 이유
포트는 typing.Protocol (runtime_checkable 권장) 덕타이핑 + isinstance 가능
어댑터의 engine/connection은 lazy 라우팅 단계에서 드라이버 미설치여도 OK
blocking 호출은 asyncio.to_thread discord 이벤트 루프 막지 않기
frontends/discord에서 discord.py import는 bot.py·setup_wizard.py 로직층은 유닛테스트 가능해야 함
새 환경변수는 .env.example에도 문서화 신규 컨트리뷰터 친화
테스트는 토큰/네트워크 없이도 통과해야 함 FakeLLM / mock transport 활용
포트(core/ports/)는 거의 frozen 변경은 모든 어댑터/구현에 영향 — 정말 필요한지 한 번 더 고민

8. 더 깊이 보고 싶다면


질문/제안은 Discord 또는 GitHub Issues 환영.