一键导入
grpc-service
gRPC 서비스 통합 가이드. Port/Adapter 패턴, Proto 정의, Async Client 구현 시 참조. "grpc", "proto", "subagent", "character", "location", "rpc" 키워드로 트리거.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
gRPC 서비스 통합 가이드. Port/Adapter 패턴, Proto 정의, Async Client 구현 시 참조. "grpc", "proto", "subagent", "character", "location", "rpc" 키워드로 트리거.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Chat Eval Pipeline 코드에 대한 5-expert 피드백 루프 리뷰 가이드
Agent 시스템 프로비저닝 가이드. Dependencies 싱글톤, HTTP 클라이언트 풀링, LLM 클라이언트 설정, 환경변수 관리, Worker 초기화 패턴. "dependencies", "provisioning", "http client", "connection pool", "worker setup" 키워드로 트리거.
Google Gemini SDK (google-genai) 활용 가이드. Gemini 3/2 모델, Structured Output, Function Calling, Google Search Grounding, 이미지 생성 구현 시 참조. "gemini", "google ai", "genai", "google search", "imagen" 키워드로 트리거.
LangGraph 1.0+ 파이프라인 구축 가이드. Intent-Routed Workflow, Subagent 패턴, Checkpointing, Conditional Routing 구현 시 참조. "langgraph", "pipeline", "graph", "workflow", "subagent", "checkpointer" 키워드로 트리거.
LangSmith 통합 및 LLM Observability 가이드. 토큰 추적, 비용 계산, Run Tree, Tracing 데코레이터, OTEL 연동 구현 시 참조. "langsmith", "tracing", "observability", "token usage", "cost tracking" 키워드로 트리거.
OpenAI Agents SDK (2025~) 활용 가이드. Agent + Runner + WebSearchTool + RunContextWrapper 패턴. Structured Output, Function Tool, Handoff 구현 시 참조. "agents sdk", "openai agent", "runner", "web_search", "function_tool", "handoff" 키워드로 트리거.
| name | grpc-service |
| description | gRPC 서비스 통합 가이드. Port/Adapter 패턴, Proto 정의, Async Client 구현 시 참조. "grpc", "proto", "subagent", "character", "location", "rpc" 키워드로 트리거. |
┌─────────────────────────────────────────────────────────────────────────┐
│ gRPC Integration (Clean Architecture) │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Application Layer (Ports) │
│ ├─ CharacterClientPort (Protocol) │
│ ├─ LocationClientPort (Protocol) │
│ └─ DTOs: CharacterDTO, LocationDTO │
│ │ │
│ ▼ │
│ Infrastructure Layer (Adapters) │
│ ├─ CharacterGrpcClient ──→ character-api:50051 │
│ └─ LocationGrpcClient ──→ location-api:50051 │
│ │ │
│ ▼ │
│ Proto Files (Contract) │
│ ├─ character.proto → character_pb2.py, character_pb2_grpc.py │
│ └─ location.proto → location_pb2.py, location_pb2_grpc.py │
│ │
└─────────────────────────────────────────────────────────────────────────┘
| Aspect | HTTP | Celery | gRPC |
|---|---|---|---|
| Latency | ~10ms | ~50ms+ | ~1-3ms |
| Type Safety | 런타임 | 없음 | 컴파일타임 |
| Asyncio | 제한적 | 미지원 | 네이티브 |
| Streaming | 복잡 | 미지원 | 기본 지원 |
| LangGraph 통합 | OK | await 불가 | 최적 |
# application/ports/character_client.py
from abc import ABC, abstractmethod
from dataclasses import dataclass
@dataclass(frozen=True)
class CharacterDTO:
"""캐릭터 정보 DTO"""
name: str
character_type: str
dialog: str
match_label: str
class CharacterClientPort(ABC):
"""캐릭터 서비스 클라이언트 Port"""
@abstractmethod
async def get_character_by_waste_category(
self,
waste_category: str,
) -> CharacterDTO | None:
"""폐기물 카테고리로 캐릭터 조회"""
...
@abstractmethod
async def get_catalog(self) -> list[CharacterDTO]:
"""전체 캐릭터 목록 조회"""
...
# infrastructure/integrations/character/grpc_client.py
import grpc.aio
from .proto import character_pb2, character_pb2_grpc
class CharacterGrpcClient(CharacterClientPort):
"""gRPC 기반 캐릭터 클라이언트"""
def __init__(self, host: str = "character-api", port: int = 50051):
self._host = host
self._port = port
self._channel: grpc.aio.Channel | None = None
self._stub: character_pb2_grpc.CharacterServiceStub | None = None
async def _get_stub(self) -> character_pb2_grpc.CharacterServiceStub:
"""Lazy 연결 (첫 호출 시 채널 생성)"""
if self._stub is None:
self._channel = grpc.aio.insecure_channel(
f"{self._host}:{self._port}"
)
self._stub = character_pb2_grpc.CharacterServiceStub(self._channel)
return self._stub
async def get_character_by_waste_category(
self,
waste_category: str,
) -> CharacterDTO | None:
try:
stub = await self._get_stub()
request = character_pb2.GetByMatchRequest(
match_label=waste_category
)
response = await stub.GetCharacterByMatch(request)
if not response.found:
return None
return CharacterDTO(
name=response.name,
character_type=response.character_type,
dialog=response.dialog,
match_label=response.match_label,
)
except grpc.aio.AioRpcError as e:
logger.error("gRPC error", code=e.code().name, details=e.details())
return None
async def close(self) -> None:
"""채널 종료"""
if self._channel:
await self._channel.close()
self._channel = None
self._stub = None
# infrastructure/orchestration/langgraph/nodes/character_node.py
def create_character_node(
character_client: CharacterClientPort,
llm: LLMClientPort,
) -> Callable:
"""캐릭터 Subagent 노드 생성"""
async def character_node(state: dict) -> dict:
query = state["query"]
# LLM으로 폐기물 카테고리 추출
category = await extract_waste_category(llm, query)
# gRPC 호출
character = await character_client.get_character_by_waste_category(
category
)
return {
"character_context": character.__dict__ if character else None,
}
return character_node
# setup/dependencies.py
from functools import lru_cache
@lru_cache
def get_character_client() -> CharacterClientPort:
settings = get_settings()
return CharacterGrpcClient(
host=settings.character_grpc_host,
port=settings.character_grpc_port,
)
async def cleanup():
"""애플리케이션 종료 시 리소스 정리"""
client = get_character_client()
await client.close()