@@ -212,7 +212,76 @@ retriever = VectorRetriever.from_sources(
212212
213213---
214214
215- ## 5) Hook — 관측성과 디버깅
215+ ## 5) DataHub 카탈로그 로더
216+
217+ DataHub GMS 서버에서 테이블 메타데이터를 가져와 ` CatalogEntry ` 목록으로 변환합니다.
218+ 수동으로 카탈로그를 작성하지 않아도 DataHub에 등록된 스키마 정보를 바로 사용할 수 있습니다.
219+
220+ ``` bash
221+ pip install acryl-datahub
222+ ```
223+
224+ ``` python
225+ from lang2sql.integrations.catalog import DataHubCatalogLoader
226+
227+ loader = DataHubCatalogLoader(
228+ gms_server = " http://localhost:8080" ,
229+ extra_headers = {" Authorization" : " Bearer <token>" },
230+ )
231+
232+ # 전체 URN 조회
233+ catalog = loader.load()
234+
235+ # 특정 URN만 조회
236+ catalog = loader.load(urns = [
237+ " urn:li:dataset:(urn:li:dataPlatform:postgres,mydb.public.orders,PROD)" ,
238+ " urn:li:dataset:(urn:li:dataPlatform:postgres,mydb.public.customers,PROD)" ,
239+ ])
240+
241+ # 바로 파이프라인에 연결
242+ from lang2sql import BaselineNL2SQL
243+ from lang2sql.integrations.db import SQLAlchemyDB
244+ from lang2sql.integrations.llm import OpenAILLM
245+
246+ pipeline = BaselineNL2SQL(
247+ catalog = catalog,
248+ llm = OpenAILLM(model = " gpt-4o-mini" ),
249+ db = SQLAlchemyDB(" postgresql://user:pass@localhost:5432/mydb" ),
250+ db_dialect = " postgresql" ,
251+ )
252+ ```
253+
254+ > ` DataHubCatalogLoader ` 는 ` CatalogLoaderPort ` 를 구현합니다.
255+ > DataHub 없이도 ` SQLAlchemyExplorer ` 로 DDL을 직접 조회하거나 CSV/수동 카탈로그를 사용할 수 있습니다.
256+
257+ ---
258+
259+ ## 6) Port 프로토콜 레퍼런스
260+
261+ 커스텀 어댑터를 작성할 때 구현해야 하는 메서드 목록입니다.
262+
263+ | Port | 메서드 | 시그니처 | 용도 |
264+ | ------| --------| ----------| ------|
265+ | ` LLMPort ` | ` invoke ` | ` (messages: list[dict]) -> str ` | LLM 백엔드 교체 |
266+ | ` DBPort ` | ` execute ` | ` (sql: str) -> list[dict] ` | DB 백엔드 교체 |
267+ | ` EmbeddingPort ` | ` embed_query ` | ` (text: str) -> list[float] ` | 단일 텍스트 임베딩 |
268+ | | ` embed_texts ` | ` (texts: list[str]) -> list[list[float]] ` | 배치 임베딩 |
269+ | ` VectorStorePort ` | ` upsert ` | ` (ids: list[str], vectors: list[list[float]]) -> None ` | 벡터 저장 |
270+ | | ` search ` | ` (vector: list[float], k: int) -> list[tuple[str, float]] ` | 유사도 검색 (id, score) |
271+ | ` DocumentLoaderPort ` | ` load ` | ` () -> list[TextDocument] ` | 문서 로드 |
272+ | ` DocumentChunkerPort ` | ` chunk ` | ` (doc: TextDocument) -> list[IndexedChunk] ` | 문서 분할 |
273+ | ` CatalogLoaderPort ` | ` load ` | ` (urns: list[str] \| None) -> list[CatalogEntry] ` | 외부 카탈로그 로드 |
274+ | ` DBExplorerPort ` | ` list_tables ` | ` () -> list[str] ` | 테이블 목록 |
275+ | | ` get_ddl ` | ` (table: str) -> str ` | DDL 조회 |
276+ | | ` sample_data ` | ` (table: str, limit: int) -> list[dict] ` | 샘플 데이터 |
277+ | | ` execute_read_only ` | ` (sql: str) -> list[dict] ` | 읽기 전용 쿼리 |
278+
279+ 모든 Port는 ` src/lang2sql/core/ports.py ` 에 ` Protocol ` 로 정의되어 있습니다.
280+ 클래스 상속 없이 ** 메서드 시그니처만 맞추면** 어떤 객체든 연결할 수 있습니다 (structural subtyping).
281+
282+ ---
283+
284+ ## 7) Hook — 관측성과 디버깅
216285
217286` MemoryHook ` 으로 컴포넌트 단위 실행 이벤트를 수집합니다.
218287
@@ -254,7 +323,7 @@ SQLExecutor end 1.2ms error=None
254323
255324---
256325
257- ## 6 ) Best Practices 체크리스트
326+ ## 8 ) Best Practices 체크리스트
258327
259328### 카탈로그 작성
260329
@@ -285,7 +354,7 @@ SQLExecutor end 1.2ms error=None
285354
286355---
287356
288- ## 7 ) 트러블슈팅
357+ ## 9 ) 트러블슈팅
289358
290359### ` IntegrationMissingError: openai `
291360
0 commit comments