황현동 블로그 개발, 인생, 유우머

기술리서치 종합정리

Tags:

################################################################################

INIT

################################################################################

CONDA_INIT


layout: post
title: 260602 기술 리서치 종합 정리
comments: true
tags:

  • 기술리서치
  • 종합정리
  • 리서치

0. Executive Summary

이번 문서는 여러 기술 키워드를 “실무 설계 판단” 관점에서 묶어 정리한다. 핵심 축은 다음과 같다.

영역 핵심 질문 실무 결론
멀티테넌트 한 시스템에 여러 고객을 어떻게 안전하게 태울 것인가 격리는 스펙트럼이다. Pool, Bridge, Silo를 비용/보안/성능 기준으로 섞어야 한다.
Python 비동기 언제 asyncio를 쓰는가 네트워크 I/O, 스트리밍, 동시 API 호출에는 강력하지만 CPU-bound에는 별도 처리 필요
Agent 프레임워크 LangChain/LangGraph와 PydanticAI 중 무엇을 고를까 복잡한 상태/장기 실행은 LangGraph, 타입 안전한 Python 앱은 PydanticAI가 유리
Vector DB MongoDB/SQL DB에 벡터를 넣어도 되는가 운영 데이터와 함께 검색해야 하면 유리, 초대규모 ANN 최적화만 원하면 전용 DB도 검토
RCPS 보통주 전환이 재무/지분에 미치는 영향은 회계상 부채가 자본으로 바뀔 수 있고, 희석/전환조건/등기/정관 확인이 핵심
저지연 음성 STT → LLM → TTS TTFT를 줄이는 법 스트리밍, endpointing, 작은 청크, 프롬프트 캐시, TTS WebSocket이 핵심
GStreamer 실시간 미디어 파이프라인을 어떻게 만든다 요소/패드/파이프라인 모델이 강력하지만 디버깅 난도와 플러그인 의존성이 있다
Docker/AWS 컨테이너를 어떻게 운영할까 로컬 재현성과 배포 단위로 좋고, AWS에서는 ECR/ECS/Fargate/EKS 선택지가 핵심
멀티플렉싱 하나의 연결에 여러 흐름을 태우는 의미는 지연과 연결 수를 줄이지만 흐름제어/우선순위/Head-of-Line 이슈를 이해해야 한다
Fuzzy Search 오타/부분일치/유사 문자열 검색을 어떻게 구현할까 edit distance, trigram, autocomplete, typo tolerance를 목적별로 조합해야 한다
L2 vs Cosine 벡터 거리 지표를 어떻게 고를까 벡터 크기가 의미 있으면 L2, 방향/의미 유사도가 중요하면 cosine이 보통 더 적합하다
flowchart LR
  A["멀티테넌트 SaaS"] --> B["비동기 Python 서버"]
  B --> C["Agent Framework"]
  C --> D["Vector DB / RAG"]
  B --> E["STT-LLM-TTS 스트리밍"]
  E --> F["GStreamer / 멀티플렉싱"]
  A --> G["Docker on AWS"]
  H["RCPS 보통주 전환"] --> I["재무/지배구조 판단"]

1. 멀티테넌트

1.1 소개

멀티테넌트는 하나의 소프트웨어/인프라가 여러 고객, 조직, 팀, 사용자 그룹을 동시에 서비스하는 구조다. 여기서 tenant는 단순 사용자 하나가 아니라 “격리와 과금, 권한, 데이터 경계가 필요한 단위”로 이해하는 것이 좋다.

Azure Architecture Center는 테넌트 격리를 완전 공유에서 완전 분리까지의 스펙트럼으로 설명한다. AWS SaaS 문서와 보안 블로그에서는 흔히 Pool, Bridge, Silo 모델을 사용한다.

1.2 핵심 모델

모델 구조 장점 단점 적합한 경우
Pool 모든 테넌트가 앱/DB/인프라를 공유하고 tenant_id로 논리 분리 비용 효율, 운영 단순 데이터 유출 위험, noisy neighbor SMB SaaS, 낮은 보안 요구
Bridge 일부는 공유, 일부는 분리 비용과 격리 균형 설계 복잡 엔터프라이즈 등급별 서비스
Silo 테넌트별 전용 인프라 강한 격리, 커스터마이징 비용/운영 부담 금융/의료/대기업 전용 배포
flowchart LR
  P["Pool<br/>공유 앱 + 공유 DB"] --> B["Bridge<br/>공유 앱 + 테넌트별 DB"]
  B --> S["Silo<br/>테넌트별 앱 + DB + 네트워크"]
  P -. "저비용/고밀도" .-> B
  S -. "강격리/고비용" .-> B

1.3 설계 특징

  • 모든 요청에는 신뢰 가능한 tenant_id가 있어야 한다.
  • 인증의 subject와 tenant membership을 분리해서 검증해야 한다.
  • DB Row Level Security, query filter, schema-per-tenant, database-per-tenant 중 하나를 선택한다.
  • 캐시 키, 큐 메시지, 로그, 파일 경로에도 tenant 경계를 넣어야 한다.
  • 운영 지표는 tenant별로 쪼개야 noisy neighbor를 찾을 수 있다.

1.4 장단점

구분 장점 단점
비용 인프라 공유로 단가 절감 고가 테넌트 요구를 맞추려면 예외 구조 증가
운영 배포/패치가 일괄 처리됨 장애가 다수 테넌트로 전파될 수 있음
보안 중앙 정책 적용 가능 애플리케이션 버그가 데이터 유출로 이어질 수 있음
성능 자원 활용률 증가 특정 테넌트 트래픽이 전체 성능을 흔들 수 있음

1.5 실용 패턴

from dataclasses import dataclass

@dataclass(frozen=True)
class TenantContext:
    tenant_id: str
    user_id: str
    roles: set[str]

def build_query(ctx: TenantContext, symbol: str) -> dict:
    return {
        "tenant_id": ctx.tenant_id,
        "symbol": symbol,
    }

실무에서는 이 정도 코드만으로는 부족하다. DB 레벨 제약, API gateway, middleware, 로그 마스킹, 권한 테스트가 함께 들어가야 한다.

1.6 근거 URL

  • Azure 멀티테넌트 격리 모델: https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/considerations/tenancy-models
  • AWS SaaS Lens: https://docs.aws.amazon.com/wellarchitected/latest/saas-lens/saas-lens.html
  • AWS 멀티테넌트 보안 모델: https://aws.amazon.com/blogs/security/security-practices-in-aws-multi-tenant-saas-environments/
  • Kubernetes 멀티테넌시: https://kubernetes.io/docs/concepts/security/multi-tenancy/
  • GKE 엔터프라이즈 멀티테넌시: https://docs.cloud.google.com/kubernetes-engine/docs/best-practices/enterprise-multitenancy

2. Python 비동기 프로그래밍

2.1 소개

Python 비동기 프로그래밍은 async/await 문법과 이벤트 루프를 사용해 I/O 대기 시간을 겹쳐 처리하는 방식이다. asyncio는 네트워크 서버, DB 클라이언트, 분산 큐, 스트리밍 처리의 기반으로 쓰인다.

sequenceDiagram
  participant App
  participant Loop as Event Loop
  participant API1
  participant API2
  App->>Loop: create_task(API1)
  App->>Loop: create_task(API2)
  Loop->>API1: request
  Loop->>API2: request
  API2-->>Loop: response
  API1-->>Loop: response
  Loop-->>App: gather results

2.2 특징

개념 설명
coroutine async def로 만든 실행 가능한 비동기 함수
await 대기 중 이벤트 루프에 제어권을 돌려주는 지점
task coroutine을 이벤트 루프에 스케줄링한 객체
event loop I/O 이벤트와 task 실행을 조율하는 루프
gather 여러 awaitable을 동시에 실행하고 결과 수집
queue producer/consumer 비동기 파이프라인 구성

2.3 장단점

장점 단점
I/O-bound 처리량이 좋다 CPU-bound 작업은 이벤트 루프를 막는다
스레드보다 메모리 비용이 낮다 sync/async 라이브러리 혼용이 까다롭다
스트리밍 서버 구현에 적합하다 cancellation, timeout, backpressure 설계가 필요하다
WebSocket, SSE, LLM streaming과 잘 맞는다 디버깅 스택이 동기 코드보다 낯설다

2.4 간단 예제

import asyncio

async def fetch_price(symbol: str) -> str:
    await asyncio.sleep(0.2)
    return f"{symbol}=100"

async def main() -> None:
    results = await asyncio.gather(
        fetch_price("AAPL"),
        fetch_price("MSFT"),
        fetch_price("NVDA"),
    )
    print(results)

asyncio.run(main())

2.5 실용 예제: 동시 요청 + timeout + 제한

import asyncio
from collections.abc import Awaitable, Callable

async def bounded_map(
    items: list[str],
    worker: Callable[[str], Awaitable[str]],
    concurrency: int = 5,
    timeout: float = 2.0,
) -> list[str]:
    semaphore = asyncio.Semaphore(concurrency)

    async def run_one(item: str) -> str:
        async with semaphore:
            return await asyncio.wait_for(worker(item), timeout=timeout)

    return await asyncio.gather(*(run_one(item) for item in items))

이 패턴은 외부 API 호출, 종목별 데이터 수집, 멀티테넌트 배치 작업에 자주 쓴다.

2.6 근거 URL

  • Python asyncio 공식 문서: https://docs.python.org/3.14/library/asyncio.html
  • Python asyncio 개념 문서: https://docs.python.org/3/howto/a-conceptual-overview-of-asyncio.html
  • Python event loop 문서: https://docs.python.org/3.15/library/asyncio-eventloop.html

3. LangChain, LangGraph

3.1 소개

LangChain은 LLM 애플리케이션과 agent를 빠르게 만들기 위한 고수준 프레임워크다. LangGraph는 장기 실행, 상태 저장, human-in-the-loop, streaming, durable execution에 초점을 맞춘 저수준 orchestration framework다.

LangChain v1 계열의 agent는 내부적으로 LangGraph 기반 runtime을 사용한다. 즉, 간단한 agent는 LangChain으로 시작하고, 상태 전이/복구/분기 제어가 커지면 LangGraph를 직접 쓰는 식의 흐름이 자연스럽다.

3.2 특징

항목 LangChain LangGraph
추상화 수준 높음 낮음
주 용도 agent 빠른 구성, model/tool 통합 상태 기반 agent/workflow orchestration
상태 관리 checkpointer 사용 가능 핵심 기능
스트리밍 지원 핵심 기능
human-in-the-loop middleware/graph 기반 핵심 기능
적합한 팀 빠른 PoC/서비스 앱 복잡한 agent platform
flowchart TD
  U["User Message"] --> A["LangChain create_agent"]
  A --> M["Model Node"]
  M -->|tool call| T["Tool Node"]
  T --> M
  M -->|final| R["Response"]
  A -. "built on" .-> G["LangGraph Runtime"]

3.3 장단점

구분 장점 단점
LangChain 빠른 시작, provider/tool 통합, agent 기본 구조 제공 내부 추상화가 많아 디버깅이 어려울 수 있음
LangGraph 상태 전이 명확, durable execution, 재시작/체크포인트 유리 학습 곡선이 있고 boilerplate가 증가

3.4 LangChain 간단 예제

from langchain.agents import create_agent

def get_weather(city: str) -> str:
    """Get weather for a given city."""
    return f"{city}: sunny"

agent = create_agent(
    model="openai:gpt-5-mini",
    tools=[get_weather],
    system_prompt="You are a concise assistant.",
)

result = agent.invoke({
    "messages": [{"role": "user", "content": "weather in Seoul?"}]
})

3.5 LangGraph 실용 예제: 간단 상태 그래프

from typing import TypedDict
from langgraph.graph import StateGraph, START, END

class State(TypedDict):
    text: str
    route: str

def classify(state: State) -> State:
    route = "finance" if "stock" in state["text"].lower() else "general"
    return {"text": state["text"], "route": route}

def answer(state: State) -> State:
    return {"text": f"[{state['route']}] {state['text']}", "route": state["route"]}

graph = StateGraph(State)
graph.add_node("classify", classify)
graph.add_node("answer", answer)
graph.add_edge(START, "classify")
graph.add_edge("classify", "answer")
graph.add_edge("answer", END)
app = graph.compile()

print(app.invoke({"text": "stock news", "route": ""}))

3.6 근거 URL

  • LangChain overview: https://docs.langchain.com/oss/python/langchain/overview
  • LangChain agents: https://docs.langchain.com/oss/python/langchain/agents
  • LangGraph overview: https://docs.langchain.com/oss/python/langgraph
  • LangGraph persistence: https://langchain-5e9cc07a.mintlify.app/oss/javascript/langgraph/persistence

4. PydanticAI

4.1 소개

PydanticAI는 Pydantic 팀이 만든 Python agent framework다. FastAPI가 타입 힌트와 Pydantic validation으로 웹 API 개발 경험을 단순화한 것처럼, PydanticAI는 GenAI/agent 개발에서 타입, 의존성, structured output, tool validation을 중심에 둔다.

4.2 특징

특징 설명
타입 안전성 agent dependency와 output type을 generic으로 표현
structured output Pydantic schema 기반 검증
tool validation tool 인자와 반환을 타입으로 관리
dependency injection RunContext로 API client, DB session, tenant context 주입
model agnostic OpenAI, Anthropic, Gemini, Bedrock, Ollama 등 다양한 provider 지원
Python 친화성 FastAPI/Pydantic 사용자에게 익숙한 구조
flowchart LR
  A["Agent"] --> B["Instructions"]
  A --> C["Tools"]
  A --> D["Deps via RunContext"]
  A --> E["Structured Output"]
  E --> F["Pydantic Validation"]

4.3 장단점

장점 단점
타입 기반 유지보수성이 좋다 LangChain 생태계보다 통합 예제가 적을 수 있음
structured output 검증이 자연스럽다 매우 복잡한 graph orchestration은 별도 설계 필요
FastAPI와 잘 어울린다 팀이 Pydantic/typing에 익숙해야 효과가 크다
dependency injection이 깔끔하다 provider별 native 기능 차이는 직접 이해해야 한다

4.4 간단 예제

from pydantic_ai import Agent

agent = Agent(
    "openai:gpt-5-mini",
    instructions="Answer in Korean. Be concise.",
)

result = agent.run_sync("PydanticAI가 뭐야?")
print(result.output)

4.5 실용 예제: 멀티테넌트 의존성 + structured output

from dataclasses import dataclass
from pydantic import BaseModel
from pydantic_ai import Agent, RunContext

@dataclass
class Deps:
    tenant_id: str
    plan: str

class StockAnswer(BaseModel):
    summary: str
    risk_level: str
    tickers: list[str]

agent = Agent[Deps, StockAnswer](
    "openai:gpt-5-mini",
    deps_type=Deps,
    output_type=StockAnswer,
)

@agent.instructions
def add_tenant_policy(ctx: RunContext[Deps]) -> str:
    return f"Tenant={ctx.deps.tenant_id}, plan={ctx.deps.plan}. Respect tenant policy."

result = agent.run_sync(
    "NVDA와 MSFT를 짧게 비교해줘.",
    deps=Deps(tenant_id="tenant-a", plan="pro"),
)
print(result.output)

4.6 근거 URL

  • PydanticAI overview: https://pydantic.dev/docs/ai/overview/
  • PydanticAI agent: https://pydantic.dev/docs/ai/core-concepts/agent/
  • PydanticAI output: https://pydantic.dev/docs/ai/core-concepts/output/
  • PydanticAI dependencies: https://pydantic.dev/docs/ai/core-concepts/dependencies/
  • PydanticAI graph: https://pydantic.dev/docs/ai/graph/graph/

5. LangChain/LangGraph vs PydanticAI 비교분석

5.1 핵심 비교

기준 LangChain LangGraph PydanticAI
주 포지션 agent/app 프레임워크 workflow/agent runtime 타입 중심 Python agent
강점 생태계, integrations, 빠른 PoC 상태, 분기, 복구, durable execution 타입, structured output, DI
약점 추상화 복잡성 초기 설계 비용 상대적으로 작은 생태계
추천 LLM 앱 빠른 개발 장기 실행/복잡 workflow FastAPI/Python typed service
멀티테넌트 context/middleware로 구현 graph state/config로 구현 deps_type으로 깔끔하게 구현
streaming 지원 강함 지원
quadrantChart
  title Agent Framework Positioning
  x-axis "간단한 앱" --> "복잡한 orchestration"
  y-axis "느슨한 타입" --> "강한 타입"
  quadrant-1 "Typed Orchestration"
  quadrant-2 "Typed App"
  quadrant-3 "Fast PoC"
  quadrant-4 "Runtime Control"
  "LangChain": [0.35, 0.45]
  "LangGraph": [0.85, 0.55]
  "PydanticAI": [0.45, 0.85]

5.2 선택 가이드

상황 추천
빠르게 RAG chatbot을 만든다 LangChain
agent가 여러 단계에서 멈추고 재개되어야 한다 LangGraph
FastAPI 서비스 안에서 output schema가 중요하다 PydanticAI
human approval, checkpoint, time travel debugging이 필요하다 LangGraph
멀티테넌트 context를 타입으로 강제하고 싶다 PydanticAI
provider/tool integration이 가장 중요하다 LangChain

5.3 실무 조합

PydanticAI와 LangGraph는 경쟁만 하는 관계가 아니다. 예를 들어 LangGraph node 안에서 PydanticAI agent를 호출하면 “상태 orchestration은 LangGraph, typed agent는 PydanticAI”로 역할을 나눌 수 있다.

def pydantic_agent_node(state: dict) -> dict:
    result = agent.run_sync(state["question"], deps=state["deps"])
    return {"answer": result.output.model_dump()}

6. VectorDB in MongoDB

6.1 소개

MongoDB Atlas Vector Search는 MongoDB 문서 컬렉션에 embedding vector를 저장하고, $vectorSearch aggregation stage로 semantic search를 수행하는 기능이다. 운영 데이터와 vector embedding을 같은 document model 안에서 다룰 수 있다는 점이 핵심이다.

6.2 특징

특징 설명
저장 방식 문서 필드에 dense vector 저장
검색 방식 ANN/ENN vector search
통합 검색 vector search + full-text search + metadata filter
RAG 활용 문서/메타데이터/권한 필터를 함께 사용
버전 조건 Atlas cluster MongoDB 6.0.11/7.0.2 이상 등 조건 존재
flowchart LR
  D["Documents"] --> E["Embedding Model"]
  E --> M["MongoDB Collection<br/>text + metadata + embedding"]
  Q["User Query"] --> QE["Query Embedding"]
  QE --> V["$vectorSearch"]
  M --> V
  V --> R["Top-k Documents"]
  R --> L["LLM Answer"]

6.3 장단점

장점 단점
앱 데이터와 벡터를 한 DB에서 관리 전용 vector DB보다 세밀한 ANN 튜닝은 제한될 수 있음
metadata filter와 함께 쓰기 좋음 Atlas 기능 의존성이 있다
RAG 구현 진입장벽이 낮음 embedding 차원/인덱스 변경 시 재색인 필요
JSON document model과 잘 맞음 초대규모/초저지연 검색은 벤치마크 필요

6.4 간단 예제

db.articles.aggregate([
  {
    $vectorSearch: {
      index: "article_embedding_index",
      path: "embedding",
      queryVector: [0.12, 0.34, 0.56],
      numCandidates: 100,
      limit: 5
    }
  },
  {
    $project: {
      title: 1,
      score: { $meta: "vectorSearchScore" }
    }
  }
])

6.5 실용 예제: 멀티테넌트 RAG 검색

db.knowledge.aggregate([
  {
    $vectorSearch: {
      index: "knowledge_vector_index",
      path: "embedding",
      queryVector: queryEmbedding,
      numCandidates: 200,
      limit: 8,
      filter: {
        tenant_id: "tenant-a",
        visibility: "internal"
      }
    }
  },
  {
    $project: {
      _id: 0,
      title: 1,
      content: 1,
      tenant_id: 1,
      score: { $meta: "vectorSearchScore" }
    }
  }
])

6.6 근거 URL

  • MongoDB Vector Search overview: https://www.mongodb.com/docs/vector-search/
  • MongoDB Vector Search index: https://www.mongodb.com/docs/vector-search/index/vector-search-type/
  • MongoDB Vector Search getting started: https://www.mongodb.com/products/platform/atlas-vector-search/getting-started

7. VectorDB in other SQL DB

7.1 소개

SQL DB 안의 vector search는 “정형 데이터와 embedding을 같은 SQL 질의 체계에서 다루는 방식”이다. PostgreSQL pgvector, SQL Server VECTOR, Oracle AI Vector Search, MariaDB Vector, MySQL HeatWave Vector Store, DuckDB VSS 등이 대표적이다.

7.2 주요 선택지

DB 기능 인덱스/검색 실무 포인트
PostgreSQL + pgvector vector type, distance operator HNSW, IVFFlat 오픈소스, RAG 기본 선택지로 인기
SQL Server 2025/Azure SQL native VECTOR type VECTOR_DISTANCE Microsoft stack과 통합
Oracle 23ai native VECTOR, SQL vector search vector indexes 엔터프라이즈 보안/운영 데이터와 결합
MariaDB 11.7 VECTOR(n), VECTOR INDEX modified HNSW 기존 MariaDB 앱에 적합
MySQL HeatWave in-database vector store HeatWave GenAI OCI/HeatWave 중심
DuckDB VSS FLOAT[n] ARRAY + HNSW experimental VSS 로컬 분석/임베디드 분석에 적합
flowchart TD
  A["SQL Vector Search"] --> P["Postgres pgvector"]
  A --> S["SQL Server VECTOR"]
  A --> O["Oracle AI Vector Search"]
  A --> M["MariaDB Vector"]
  A --> H["MySQL HeatWave"]
  A --> D["DuckDB VSS"]

7.3 장단점

장점 단점
기존 트랜잭션/권한/백업 체계 재사용 전용 vector DB 대비 scale-out 검색 기능 제한 가능
SQL filter와 vector distance 결합 인덱스별 recall/latency 튜닝 필요
데이터 이동 감소 DB별 기능 성숙도가 다름
운영 단순화 대규모 embedding 업데이트 시 부하 관리 필요

7.4 PostgreSQL + pgvector 간단 예제

CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE documents (
  id bigserial PRIMARY KEY,
  tenant_id text NOT NULL,
  content text NOT NULL,
  embedding vector(3) NOT NULL
);

CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops);

SELECT id, content
FROM documents
WHERE tenant_id = 'tenant-a'
ORDER BY embedding <=> '[0.1,0.2,0.3]'
LIMIT 5;

7.5 실용 예제: hybrid SQL + vector

SELECT id, title, published_at
FROM articles
WHERE tenant_id = $1
  AND published_at >= now() - interval '90 days'
ORDER BY embedding <=> $2
LIMIT 10;

실무에서는 tenant_id, published_at, category 같은 정형 필터를 먼저 좁히고 vector search를 수행하는 구조가 비용과 품질 면에서 유리하다.

7.6 근거 URL

  • pgvector GitHub: https://github.com/pgvector/pgvector
  • SQL Server vector type: https://learn.microsoft.com/en-us/sql/t-sql/data-types/vector-data-type
  • Oracle AI Vector Search: https://blogs.oracle.com/database/oracle-announces-general-availability-of-ai-vector-search-in-oracle-database-23ai
  • MariaDB Vector: https://mariadb.com/docs/server/reference/sql-structure/vectors/vector-overview
  • MySQL HeatWave Vector Store: https://dev.mysql.com/doc/heatwave/en/mys-hw-genai-vector-store-overview.html
  • DuckDB VSS: https://duckdb.org/docs/current/core_extensions/vss.html

8. L2 Distance vs Cosine Distance

8.1 소개

L2 distance와 cosine distance는 vector search, embedding retrieval, clustering, recommendation에서 가장 자주 비교되는 거리 지표다. 둘 다 “가까운 벡터”를 찾지만, 무엇을 가깝다고 보는지가 다르다.

지표 무엇을 본다 직관
L2 distance 좌표 공간에서의 실제 거리 두 점이 공간에서 얼마나 떨어져 있는가
Cosine distance 벡터 방향의 차이 두 벡터가 같은 방향을 바라보는가
flowchart LR
  A["Embedding Vectors"] --> N{"Normalize?"}
  N -->|Yes| C["Cosine / Inner Product<br/>방향 중심"]
  N -->|No| L["L2 Distance<br/>크기 + 방향"]
  C --> R["Semantic Similarity"]
  L --> M["Magnitude-sensitive Matching"]

8.2 수식

두 벡터 $x, y$에 대해 L2 distance는 다음과 같다.

\[d_{L2}(x,y) = ||x-y||_2 = \sqrt{\sum_i (x_i-y_i)^2}\]

Cosine similarity와 cosine distance는 다음과 같다.

\[\cos(x,y) = \frac{x \cdot y}{||x||_2 ||y||_2}\] \[d_{cos}(x,y) = 1 - \cos(x,y)\]
만약 두 벡터가 모두 unit vector로 정규화되어 $   x   _2 =   y   _2 = 1$이면 다음 관계가 성립한다.
\[||x-y||_2^2 = 2 - 2(x \cdot y) = 2(1-\cos(x,y)) = 2d_{cos}(x,y)\]

즉, 정규화된 벡터에서는 L2 distance와 cosine distance가 같은 순위를 만들 수 있다. 반대로 정규화하지 않은 벡터에서는 L2가 벡터 크기의 영향을 강하게 받는다.

8.3 장단점

기준 L2 distance Cosine distance
고려 요소 크기 + 방향 방향 중심
정규화 필요성 데이터 특성에 따라 선택 보통 정규화와 함께 사용
의미 검색 embedding이 정규화되어 있으면 사용 가능 텍스트 embedding 검색에서 널리 사용
크기 정보 보존 대부분 무시
이상치 영향 큰 값/스케일에 민감 크기 차이에 둔감
해석 실제 좌표 거리 각도 기반 유사도

8.4 언제 L2를 쓰는가?

상황 이유
벡터의 크기 자체가 의미 있음 예: 센서값, 위치 좌표, 이미지 feature magnitude
feature scaling이 잘 되어 있음 L2는 스케일 차이에 민감하므로 전처리가 중요
clustering/nearest neighbor에서 실제 거리 의미가 필요 공간적 근접성이 중요한 문제
embedding provider가 L2를 권장 모델 학습 목표와 metric을 맞추는 것이 우선

8.5 언제 cosine을 쓰는가?

상황 이유
텍스트 embedding semantic search 문장 길이/벡터 크기보다 방향이 의미 유사도를 잘 반영하는 경우가 많음
문서 길이 차이가 큼 긴 문서와 짧은 문서의 크기 차이를 줄일 수 있음
ranking에서 상대적 의미 유사도가 중요 질의와 문서가 같은 방향의 의미를 갖는지 판단
vector DB에서 cosine index를 제공 MongoDB Atlas Search, pgvector, Pinecone 등에서 흔히 지원

8.6 L2, cosine, inner product 관계

벡터 상태 L2 vs cosine 실무 해석
둘 다 unit-normalized 순위가 단조 관계로 거의 동일 cosine, L2, inner product 중 index/DB 성능이 좋은 것을 선택 가능
정규화되지 않음 결과가 달라질 수 있음 크기 정보가 ranking에 섞임
embedding 모델이 이미 normalized output 제공 cosine과 dot product가 유사하게 동작 모델 문서 확인 필요
magnitude가 confidence를 담음 cosine만 쓰면 정보 손실 가능 L2 또는 inner product 검토
quadrantChart
  title Distance Metric Selection
  x-axis "크기 정보 약함" --> "크기 정보 중요"
  y-axis "의미/방향 약함" --> "의미/방향 중요"
  quadrant-1 "혼합 판단"
  quadrant-2 "Cosine"
  quadrant-3 "Preprocess First"
  quadrant-4 "L2"
  "Text Embedding": [0.25, 0.85]
  "Geo/Sensor Vector": [0.85, 0.35]
  "Normalized Embedding": [0.35, 0.75]
  "Raw Numeric Features": [0.75, 0.45]

8.7 간단 예제: Python 계산

import numpy as np
from sklearn.metrics.pairwise import cosine_distances, euclidean_distances

x = np.array([[3.0, 4.0]])
y = np.array([[6.0, 8.0]])
z = np.array([[4.0, 3.0]])

print("L2 x-y:", euclidean_distances(x, y)[0, 0])
print("Cosine x-y:", cosine_distances(x, y)[0, 0])
print("L2 x-z:", euclidean_distances(x, z)[0, 0])
print("Cosine x-z:", cosine_distances(x, z)[0, 0])

xy는 방향은 같지만 크기가 다르다. Cosine distance는 거의 0이지만, L2 distance는 크기 차이를 거리로 본다. 이 예제가 두 지표의 철학 차이를 가장 잘 보여준다.

8.8 실용 예제: pgvector metric 선택

-- L2 distance
SELECT id, content
FROM documents
ORDER BY embedding <-> '[0.1,0.2,0.3]'
LIMIT 5;

-- cosine distance
SELECT id, content
FROM documents
ORDER BY embedding <=> '[0.1,0.2,0.3]'
LIMIT 5;

-- negative inner product
SELECT id, content
FROM documents
ORDER BY embedding <#> '[0.1,0.2,0.3]'
LIMIT 5;

pgvector는 L2, inner product, cosine distance 연산자를 제공한다. 같은 데이터라도 어떤 연산자로 인덱스를 만들고 검색하느냐에 따라 결과와 성능이 달라질 수 있다.

8.9 MongoDB Atlas Vector Search 예시

{
  "fields": [
    {
      "type": "vector",
      "path": "embedding",
      "numDimensions": 1536,
      "similarity": "cosine"
    }
  ]
}

MongoDB Atlas Vector Search는 vector index에서 euclidean, cosine, dotProduct 같은 similarity 설정을 사용한다. 텍스트 RAG에서는 보통 embedding 모델 권장 metric 또는 cosine/dotProduct 계열을 먼저 확인한다.

8.10 실무 선택 가이드

질문 권장 판단
모델 문서가 특정 metric을 권장하는가? 그 metric을 우선 사용
embedding이 unit-normalized인가? cosine, dot product, L2 순위가 유사할 수 있음
벡터 크기가 의미를 갖는가? L2 또는 inner product 검토
의미 기반 텍스트 검색인가? cosine 또는 dot product 우선
정형 feature vector인가? scale/standardization 후 L2 검토
vector DB index가 특정 metric에 최적화되어 있는가? DB의 index metric과 query metric을 일치

8.11 리스크/반례

리스크 설명 대응
metric mismatch 모델 학습 metric과 DB 검색 metric이 다름 모델 문서와 vector DB 설정 확인
normalization 누락 cosine을 기대했지만 L2로 크기 영향이 들어감 저장 전/검색 전 정규화 정책 고정
mixed embeddings 서로 다른 모델 embedding을 같은 index에 저장 모델별 index 분리
recall 저하 ANN index metric과 query metric 불일치 index 재생성 및 offline recall 평가
top-k 착시 cosine score와 distance score 방향을 혼동 score가 클수록 좋은지, 작을수록 좋은지 명시

8.12 근거 URL

  • scikit-learn cosine distances: https://scikit-learn.org/stable/modules/generated/sklearn.metrics.pairwise.cosine_distances.html
  • scikit-learn euclidean distances: https://scikit-learn.org/stable/modules/generated/sklearn.metrics.pairwise.euclidean_distances.html
  • pgvector distance operators: https://github.com/pgvector/pgvector
  • MongoDB Atlas Vector Search index fields: https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-type/
  • Pinecone vector similarity metrics: https://docs.pinecone.io/guides/indexes/understanding-indexes#similarity-metrics
  • Qdrant distance metrics: https://qdrant.tech/documentation/concepts/search/

9. RCPS 보통주 전환

9.1 소개

RCPS는 Redeemable Convertible Preferred Shares, 즉 상환전환우선주다. 보통주에는 없는 상환권과 전환권을 포함하는 우선주 형태로, 스타트업/벤처 투자에서 자주 사용된다.

상환권은 일정 조건에서 회사에 투자금 상환을 청구할 수 있는 권리이고, 전환권은 우선주를 보통주 등 다른 종류주식으로 바꿀 수 있는 권리다.

주의: 이 장은 일반 리서치 요약이며 법률/세무/회계 자문이 아니다. 실제 전환은 정관, 투자계약서, 주주간계약, 회계기준, 등기 실무를 전문가와 확인해야 한다.

9.2 전환 관련 법적 체크

항목 체크포인트
정관 종류주식, 상환, 전환 조건 근거가 있는가
전환 조건 전환비율, 전환가액, 리픽싱, 전환청구기간
청구 절차 전환청구서, 주권/전자등록 절차
효력 발생 주주 청구 시 청구한 때 효력 발생
등기 전환으로 인한 변경등기 기한 확인
회계 K-IFRS상 부채/자본 분류 영향 검토
flowchart LR
  A["RCPS 발행"] --> B["전환 조건 도래"]
  B --> C["투자자 전환청구"]
  C --> D["보통주 발행/전환 효력"]
  D --> E["변경등기"]
  D --> F["부채/자본 재분류 검토"]
  D --> G["지분율 희석 분석"]

9.3 재무/지배구조 영향

영향 설명
자본구조 RCPS가 부채로 인식되던 경우 보통주 전환 후 자본총계가 개선될 수 있음
지분율 보통주 수 증가로 기존 주주의 지분율 희석 가능
의결권 전환 후 보통주 의결권이 발생할 수 있음
IPO 상장 전 RCPS 정리가 재무 건전성/자본잠식 이슈 완화에 도움될 수 있음
투자자 수익 주가 상승/공모가 기대가 있으면 상환보다 전환을 선호할 수 있음

9.4 간단 계산 예시

전환 전 보통주가 1,000,000주이고, RCPS 100,000주가 1:1로 보통주 전환된다면:

\[전환후총주식수 = 1,000,000 + 100,000 = 1,100,000\]

기존 100,000주 보유자의 지분율은:

\[전환전 = 100,000 / 1,000,000 = 10\%\] \[전환후 = 100,000 / 1,100,000 \approx 9.09\%\]

9.5 실무 체크리스트

단계 확인 사항
1 정관의 종류주식/상환/전환 조항 확인
2 투자계약서의 전환비율, 리픽싱, 자동전환 조건 확인
3 전환 후 cap table과 완전희석 지분율 산출
4 K-IFRS/K-GAAP 회계처리 검토
5 변경등기 및 주주명부/전자등록 반영
6 IPO/투자 라운드 영향 검토

9.6 근거 URL

  • 상법 제345조~제350조 국가법령정보센터 PDF: https://www.law.go.kr/lbook/lbFileDownload.do?flExt=pdf&lbookConflSeq=37001&lbookSeq=44683
  • 전환 절차 조문: https://law.go.kr/LSW/lsLawLinkInfo.do?chrClsCd=010202&lsJoLnkSeq=900424871
  • NABO TIPS 평가 RCPS 설명: https://korea.nabo.go.kr/board/file/down.do?fid=33318010
  • ZUZU RCPS 설명: https://zuzu.network/resource/guide/rcps/
  • PwC M&A Guide Book 회계 영향: https://www.pwc.com/kr/ko/services/samilpwc_mna_guide-book.pdf

10. 저지연 파이프라인 최적화: STT → LLM → TTS

10.1 소개

음성 agent의 체감 품질은 전체 응답 완료 시간보다 Time To First Token 또는 Time To First Audio가 더 중요하다. 사용자는 첫 반응이 빠르면 전체 답변이 길어도 자연스럽게 느낀다.

sequenceDiagram
  participant Mic
  participant STT
  participant LLM
  participant TTS
  participant Speaker
  Mic->>STT: 20~100ms audio chunks
  STT-->>LLM: interim/final transcript
  LLM-->>TTS: token/text chunks
  TTS-->>Speaker: first audio chunk
  LLM-->>TTS: remaining stream
  TTS-->>Speaker: continuous playback

10.2 지연 요소

구간 주요 지연 최적화
Capture 오디오 프레임 크기, 브라우저/장치 버퍼 20~100ms chunk, 불필요한 resampling 제거
STT endpointing, final transcript 대기 interim result 사용, endpointing 300~500ms 조정
LLM prompt prefill, tool call, 첫 token 짧은 system prompt, prompt caching, streaming
TTS 문장 chunk 대기, 음성 품질 모델 WebSocket TTS, low-latency 모델, chunk schedule 조정
Playback jitter buffer, codec, network opus/pcm 전략, prebuffer 최소화

10.3 TTFT/TTFA 최적화 원칙

원칙 설명
Streaming first STT, LLM, TTS 모두 streaming interface 사용
Overlap STT final을 기다리지 않고 안정적인 interim부터 LLM 준비
Early response “네, 확인해볼게요” 같은 짧은 preamble을 빠르게 생성
Context pruning RAG 결과/대화 history를 줄여 LLM prefill 감소
Prompt caching 고정 prefix를 앞에 두고 동적 데이터는 뒤에 배치
Endpoint tuning 너무 짧으면 중간 끊김, 너무 길면 반응 지연
Backpressure TTS가 느릴 때 LLM text buffer가 무한 증가하지 않도록 제한

10.4 실용 예제: 비동기 스트리밍 파이프라인 스케치

import asyncio

async def stt_stream(audio_chunks):
    async for chunk in audio_chunks:
        # 실제 구현에서는 STT WebSocket으로 전송하고 interim/final 이벤트를 받는다.
        yield {"type": "interim", "text": "안녕하세요"}

async def llm_stream(text: str):
    for token in ["네, ", "도와드릴게요."]:
        await asyncio.sleep(0.03)
        yield token

async def tts_stream(text_chunks):
    async for text in text_chunks:
        # 실제 구현에서는 TTS WebSocket으로 text chunk를 보내고 audio bytes를 받는다.
        yield text.encode()

async def pipeline(audio_chunks):
    async for stt_event in stt_stream(audio_chunks):
        if stt_event["type"] in {"interim", "final"}:
            async def text_chunks():
                async for token in llm_stream(stt_event["text"]):
                    yield token

            async for audio in tts_stream(text_chunks()):
                yield audio

10.5 Realtime API vs Cascaded Pipeline

방식 장점 단점 적합한 경우
Speech-to-speech Realtime STT/TTS 중간 단계 제거, 낮은 지연 provider 종속, 세밀한 파이프라인 제어 제한 자연 대화형 voice agent
Cascaded STT→LLM→TTS 컴포넌트 교체/튜닝 쉬움 각 단계 지연 누적 도메인 STT/TTS, 규제/로그/제어 필요

10.6 근거 URL

  • OpenAI Realtime API: https://developers.openai.com/api/docs/guides/realtime
  • OpenAI realtime conversation: https://developers.openai.com/api/docs/guides/realtime-conversations
  • OpenAI latency optimization: https://developers.openai.com/api/docs/guides/latency-optimization
  • OpenAI prompt caching: https://developers.openai.com/api/docs/guides/prompt-caching
  • Google Speech-to-Text best practices: https://docs.cloud.google.com/speech-to-text/docs/v1/best-practices
  • Deepgram endpointing/interim results: https://developers.deepgram.com/docs/understand-endpointing-interim-results
  • ElevenLabs latency optimization: https://elevenlabs.io/docs/eleven-api/guides/how-to/best-practices/latency-optimization
  • ElevenLabs audio streaming: https://elevenlabs.io/docs/eleven-api/concepts/audio-streaming

11. GStreamer

11.1 소개

GStreamer는 오디오/비디오/임의 데이터 흐름을 처리하기 위한 멀티미디어 프레임워크다. 핵심은 source, filter, encoder, muxer, sink 같은 element를 pipeline으로 연결해 데이터 흐름을 구성하는 것이다.

GStreamer는 media player뿐 아니라 실시간 transcoding, camera capture, RTP/WebRTC pipeline, AI inference 전처리, STT/TTS audio bridge에도 사용할 수 있다.

11.2 특징

개념 설명
Element source, decoder, converter, sink 같은 처리 단위
Pad element 간 데이터가 드나드는 포트
Pipeline element들이 연결된 실행 그래프
Bus error, EOS, state change 같은 메시지 전달 채널
Caps media type/format/framerate/resolution 협상 정보
Plugin codec, muxer, demuxer, protocol 기능 확장
flowchart LR
  S["filesrc / rtspsrc"] --> D["decodebin"]
  D --> C["audioconvert"]
  C --> R["audioresample"]
  R --> E["opusenc"]
  E --> M["rtpopuspay"]
  M --> K["udpsink / appsink"]

11.3 장단점

장점 단점
매우 유연한 media pipeline 구성 caps negotiation/debugging이 어렵다
실시간/저지연 파이프라인에 적합 플랫폼별 플러그인 설치 차이가 크다
C 기반 성능 + Python binding 사용 가능 Python만으로 모든 세부 제어를 이해하기 어렵다
codec/protocol plugin 생태계가 넓다 pipeline 문자열이 커지면 유지보수 난도 증가

11.4 간단 예제 Python: 테스트 영상 출력

#!/usr/bin/env python3
import sys
import gi

gi.require_version("Gst", "1.0")
from gi.repository import Gst

Gst.init(sys.argv[1:])

pipeline = Gst.parse_launch("videotestsrc pattern=smpte ! videoconvert ! autovideosink")
pipeline.set_state(Gst.State.PLAYING)

bus = pipeline.get_bus()
bus.timed_pop_filtered(Gst.CLOCK_TIME_NONE, Gst.MessageType.ERROR | Gst.MessageType.EOS)

pipeline.set_state(Gst.State.NULL)

11.5 실용 예제 Python: 마이크 PCM을 appsink로 받아 STT에 전달

#!/usr/bin/env python3
import sys
import gi

gi.require_version("Gst", "1.0")
gi.require_version("GLib", "2.0")
from gi.repository import Gst, GLib

Gst.init(sys.argv[1:])

pipeline = Gst.parse_launch(
    "autoaudiosrc ! audioconvert ! audioresample "
    "! audio/x-raw,format=S16LE,rate=16000,channels=1 "
    "! appsink name=sink emit-signals=true sync=false max-buffers=10 drop=true"
)

appsink = pipeline.get_by_name("sink")

def on_sample(sink):
    sample = sink.emit("pull-sample")
    buffer = sample.get_buffer()
    ok, map_info = buffer.map(Gst.MapFlags.READ)
    if ok:
        pcm_bytes = bytes(map_info.data)
        # 여기에서 STT WebSocket으로 pcm_bytes를 전송한다.
        buffer.unmap(map_info)
    return Gst.FlowReturn.OK

appsink.connect("new-sample", on_sample)
pipeline.set_state(Gst.State.PLAYING)

loop = GLib.MainLoop()
try:
    loop.run()
finally:
    pipeline.set_state(Gst.State.NULL)

이 예제는 저지연 STT 파이프라인에서 유용하다. max-buffers=10 drop=true는 소비가 밀릴 때 latency가 계속 늘어나는 것을 막는 backpressure 전략이다.

11.6 근거 URL

  • GStreamer 소개: https://gstreamer.freedesktop.org/documentation/application-development/introduction/gstreamer.html
  • GStreamer basic tutorials: https://gstreamer.freedesktop.org/documentation/tutorials/basic/index.html
  • GStreamer concepts tutorial: https://gstreamer.freedesktop.org/documentation/tutorials/basic/concepts.html
  • GStreamer hello world Python: https://gstreamer.freedesktop.org/documentation/tutorials/basic/hello-world.html
  • GStreamer dynamic pipeline/demuxer: https://gstreamer.freedesktop.org/documentation/tutorials/basic/dynamic-pipelines.html

12. Docker

12.1 소개

Docker는 애플리케이션과 실행 환경을 container image로 묶어 개발, 테스트, 배포를 일관되게 만드는 플랫폼이다. Docker container는 image의 실행 인스턴스이며, host OS kernel을 공유하면서 namespace/cgroup 등으로 격리된다.

12.2 특징

개념 설명
Image 실행 환경을 담은 read-only template
Container image의 실행 인스턴스
Dockerfile image build recipe
Layer Dockerfile instruction 결과로 쌓이는 변경 단위
Registry image 저장소, 예: Docker Hub, Amazon ECR
Compose 여러 container service를 YAML로 정의하고 실행
flowchart LR
  C["Source Code"] --> D["Dockerfile"]
  D --> I["Docker Image"]
  I --> R["Registry"]
  R --> T["Container Runtime"]
  T --> A["Running App"]

12.3 장단점

장점 단점
개발/운영 환경 차이를 줄인다 kernel을 공유하므로 VM과 같은 보안 경계는 아님
배포 단위가 명확하다 image 보안 취약점 관리 필요
dependency를 image에 고정할 수 있다 잘못 만들면 image가 크고 느려진다
CI/CD와 잘 맞는다 로그/상태/스토리지 설계를 따로 해야 한다

12.4 간단 예제

app.py

from flask import Flask

app = Flask(__name__)

@app.get("/")
def home():
    return {"message": "hello docker"}

Dockerfile

FROM python:3.12-slim

WORKDIR /app
RUN pip install --no-cache-dir flask
COPY app.py .

EXPOSE 8000
CMD ["flask", "--app", "app", "run", "--host", "0.0.0.0", "--port", "8000"]
docker build -t hello-docker:latest .
docker run --rm -p 8000:8000 hello-docker:latest

12.5 실용 예제: API + Redis Compose

services:
  api:
    build: .
    ports:
      - "8000:8000"
    environment:
      REDIS_URL: redis://redis:6379/0
    depends_on:
      - redis

  redis:
    image: redis:7-alpine
    volumes:
      - redis-data:/data

volumes:
  redis-data:
docker compose up --build
docker compose logs -f api
docker compose down

12.6 Docker in AWS 사용 사례

AWS 서비스 Docker 사용 방식 적합한 경우
Amazon ECR Docker/OCI image registry private image 저장, scan, lifecycle 정책
Amazon ECS on Fargate serverless container 실행 인프라 관리 최소화, 일반 API/worker
Amazon ECS on EC2 EC2 cluster에 container 배치 GPU/특수 instance/비용 최적화
Amazon EKS managed Kubernetes Kubernetes 표준/복잡한 platform
AWS Lambda container image image 기반 Lambda 배포 이벤트 기반 짧은 작업
App Runner container 기반 간단 웹 배포 운영 복잡도 낮은 웹/API

12.7 AWS 주의사항

주의사항 설명
latest tag 금지 운영에서는 git SHA, semver 등 immutable tag 권장
SIGTERM 처리 ECS는 task stop 시 SIGTERM 후 SIGKILL을 보냄
stdout/stderr logging 로그를 파일에 쓰기보다 runtime log driver로 넘김
image scan ECR scan on push, CVE 패치 루틴 필요
secret 관리 image에 secret을 굽지 말고 Secrets Manager/SSM 사용
task role 분리 execution role과 task role 권한을 분리
Fargate/EC2 보안 경계 Fargate는 task별 격리가 강하고, EC2 shared host는 추가 주의
cold start/pull time image size가 크면 task launch time 증가

12.8 근거 URL

  • Docker overview: https://docs.docker.com/get-started/docker-overview/
  • Dockerfile overview: https://docs.docker.com/build/concepts/dockerfile/
  • Docker Compose model: https://docs.docker.com/compose/intro/compose-application-model/
  • Docker build best practices: https://docs.docker.com/build/building/best-practices/
  • Amazon ECR: https://docs.aws.amazon.com/AmazonECR/latest/userguide/what-is-ecr.html
  • Amazon ECS: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html
  • Amazon ECS image best practices: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/container-considerations.html
  • Amazon ECS security: https://aws.amazon.com/blogs/security/security-considerations-for-running-containers-on-amazon-ecs/
  • Amazon EKS: https://docs.aws.amazon.com/eks/latest/userguide/what-is-eks.html

13. 멀티플렉싱

13.1 소개

멀티플렉싱은 여러 독립적인 데이터 흐름을 하나의 물리적/논리적 연결 위에 함께 실어 보내는 기술이다. 네트워크에서는 하나의 TCP/QUIC 연결 위에 여러 stream을 태우는 방식으로 나타나고, 미디어에서는 여러 audio/video/subtitle stream을 하나의 container에 muxing하는 방식으로 나타난다.

13.2 네트워크 멀티플렉싱

프로토콜 멀티플렉싱 방식 특징
HTTP/1.1 연결 여러 개 또는 pipelining pipelining은 HOL blocking 문제
HTTP/2 하나의 TCP 연결에 여러 stream frame interleaving 연결 수 감소, TCP loss 시 전체 stream 영향 가능
HTTP/3/QUIC UDP 기반 QUIC connection 안에 여러 stream stream 간 head-of-line blocking 완화
WebSocket 기본적으로 단일 message stream application-level multiplexing은 별도 구현
flowchart TD
  C["One Connection"] --> S1["Stream 1 frames"]
  C --> S2["Stream 2 frames"]
  C --> S3["Stream 3 frames"]
  S1 --> R["Receiver reassembles by stream id"]
  S2 --> R
  S3 --> R

13.3 미디어 멀티플렉싱

미디어에서 multiplexing은 audio, video, metadata, subtitle을 하나의 container stream으로 합치는 작업이다. 반대로 demultiplexing은 container에서 각 stream을 분리한다.

용어 설명
muxer 여러 stream을 하나의 container로 합침 mp4mux, matroskamux, mpegtsmux
demuxer container를 stream별로 분리 qtdemux, matroskademux, tsdemux
pad demuxer가 stream별 output pad를 동적으로 생성 audio pad, video pad
timestamp stream 동기화 기준 PTS/DTS

13.4 장단점

장점 단점
연결 수와 handshake 비용 감소 stream 간 flow control 설계 필요
작은 요청/응답의 지연 감소 우선순위 정책이 나쁘면 중요한 stream이 밀림
미디어 동기화에 유리 container/codec 조합에 따라 latency 증가
QUIC에서는 stream별 HOL blocking 완화 방화벽/프록시/관측 도구 호환성 고려

13.5 실용 예제: GStreamer mux/demux

# 비디오/오디오를 MPEG-TS로 muxing
gst-launch-1.0 \
  videotestsrc ! x264enc tune=zerolatency ! h264parse ! queue ! mux. \
  audiotestsrc ! audioconvert ! avenc_aac ! aacparse ! queue ! mux. \
  mpegtsmux name=mux ! filesink location=out.ts

# MPEG-TS demuxing
gst-launch-1.0 filesrc location=out.ts ! tsdemux name=demux \
  demux. ! queue ! decodebin ! autovideosink \
  demux. ! queue ! decodebin ! autoaudiosink

13.6 근거 URL

  • HTTP/2 RFC 9113: https://www.ietf.org/rfc/rfc9113.html
  • QUIC RFC 9000: https://www.ietf.org/rfc/rfc9000.html
  • QUIC Working Group: https://quicwg.org/
  • GStreamer dynamic pipelines/demuxer: https://gstreamer.freedesktop.org/documentation/tutorials/basic/dynamic-pipelines.html

14. 실시간 방송송출, 화상통화: VBR vs CBR

14.1 핵심 결론

실시간 방송송출과 화상통화는 둘 다 “실시간 영상”이지만 권장 rate control이 다르다.

사용 환경 더 권장되는 방식 이유
YouTube/Twitch 같은 플랫폼으로 송출하는 live ingest CBR 플랫폼 ingest, transcoding, CDN 입력 안정성, 시청자 QoS 예측 가능성이 중요
전문 live encoding/CDN 배포 CBR 또는 capped VBR/QVBR 엄격한 호환성은 CBR, 대역폭 비용/품질 효율은 capped VBR/QVBR
WebRTC 화상통화 Adaptive VBR/ABR 네트워크 상태가 계속 변하므로 bitrate, 해상도, FPS를 동적으로 낮춰 지연/끊김을 줄여야 함
녹화/VOD 파일 인코딩 VBR 실시간 제약이 약하고 장면 복잡도에 맞춰 품질/용량 최적화 가능

짧게 말하면:

방송 플랫폼에 “밀어 넣는 송출”은 CBR이 기본값이고, 양방향 화상통화는 CBR보다 adaptive bitrate가 기본 전략이다.

14.2 왜 방송송출은 CBR이 자주 권장되는가?

YouTube Live 공식 encoder 설정은 bitrate encoding을 CBR로 안내한다. Twitch도 방송 가이드에서 CBR 사용을 권장한다. 이유는 단순히 “화질이 좋아서”가 아니라, 전체 서비스 품질이 더 예측 가능하기 때문이다.

이유 설명
ingest 안정성 송출 bitrate가 갑자기 튀면 업로드 경로가 순간적으로 막혀 dropped frame이 늘 수 있음
transcoding 안정성 플랫폼이 입력 stream을 여러 화질로 변환할 때 일정한 입력률이 유리
CDN/버퍼 예측 segment 크기와 네트워크 사용량을 예측하기 쉬움
운영 모니터링 bitrate alarm, stream health, encoder 설정 검증이 쉬움
호환성 일부 장비/플랫폼은 variable bitrate burst를 잘 처리하지 못함
flowchart LR
  E["Encoder CBR"] --> I["Platform Ingest"]
  I --> T["Transcoding"]
  T --> C["CDN"]
  C --> V["Viewers"]
  E -. "bitrate spike 감소" .-> I

14.3 방송송출에서 VBR/QVBR이 유리한 예외

AWS Elemental Live 문서는 CBR이 지정 bitrate를 유지하지만 장면 복잡도에 따라 화질이 변한다고 설명한다. 반대로 VBR은 평균 bitrate와 최대 bitrate를 지정하고, QVBR은 품질 수준과 최대 bitrate를 지정한다. AWS 문서 기준으로는 장비/시청자가 variable bitrate를 처리할 수 있고 대역폭 비용이 중요하면 VBR/QVBR을 고려할 수 있다.

방식 특징 실무 판단
CBR bitrate 일정, 화질은 장면 복잡도에 따라 변동 플랫폼 ingest, 제한된 회선, 엄격한 송출 스펙
VBR 평균/최대 bitrate 지정, 복잡한 장면에서 spike 허용 관리형 live encoder, CDN 비용과 화질 균형
QVBR 목표 품질 + 최대 bitrate 지정 AWS Elemental 계열에서 bandwidth 비용 절감 목적

실무적으로는 “VBR이 화질 효율은 좋지만, live ingest에는 burst를 막는 max bitrate와 buffer 설정이 필수”라고 보는 편이 안전하다.

14.4 왜 화상통화는 Adaptive VBR/ABR이 권장되는가?

화상통화는 방송송출과 다르게 지연 시간이 매우 짧아야 하고, 사용자 네트워크가 Wi-Fi, LTE/5G, 사내망, 해외망 등으로 계속 변한다. 이때 고정 CBR을 유지하면 네트워크가 나빠진 순간 큐가 쌓이고 latency가 커지거나 packet loss가 늘어난다.

WebRTC는 RTCRtpSender.setParameters()에서 maxBitrate, maxFramerate, scaleResolutionDownBy 같은 전송 제어를 제공한다. W3C/MDN 설명처럼 maxBitrate는 “상한”이지 항상 그 bitrate로 보내라는 뜻이 아니다. 실제 전송량은 transport/network 한계, codec, frame drop, resolution scaling에 따라 바뀐다.

화상통화 최적화 설명
Congestion control RTCP feedback 기반으로 가용 bandwidth를 추정
Adaptive bitrate 가용 bandwidth에 맞춰 bitrate를 올리거나 낮춤
Frame dropping bitrate가 부족하면 frame을 줄여 latency 증가를 막음
Resolution scaling 화면 크기를 낮춰 대역폭을 맞춤
Simulcast/SVC SFU가 수신자 네트워크별로 적절한 layer를 선택
Audio priority 영상보다 음성 연속성을 우선시
flowchart TD
  N["Network changes"] --> BWE["Bandwidth Estimation"]
  BWE --> P["Sender Parameters"]
  P --> BR["Bitrate"]
  P --> FPS["Frame Rate"]
  P --> RES["Resolution"]
  BR --> L["Low Latency Playout"]
  FPS --> L
  RES --> L

14.5 실무 권장안

목적 권장 설정
YouTube/Twitch/RTMP 송출 CBR, 고정 keyframe interval, 업로드 회선의 60~80% 이하 bitrate
저지연 라이브 커머스/웨비나 CBR 또는 capped VBR, segment/LL-HLS/WebRTC relay 지연 측정 필수
방송국/전문 인코더/CDN 장비와 CDN이 허용하면 QVBR/VBR, 단 max bitrate/buffer 엄격 설정
1:1 화상통화 WebRTC adaptive bitrate, audio 우선, maxBitrate는 상한으로 사용
다자 화상회의 SFU + simulcast/SVC + 수신자별 downlink adaptation
녹화 저장본 VBR 또는 CRF/CQ 계열로 품질/용량 최적화

14.6 간단 예제: WebRTC 송신 bitrate 상한 설정

async function setSenderLimit(sender, maxBitrateBps, maxFps) {
  const params = sender.getParameters();
  params.encodings ??= [{}];
  params.encodings[0].maxBitrate = maxBitrateBps;
  params.encodings[0].maxFramerate = maxFps;
  await sender.setParameters(params);
}

이 코드는 CBR을 강제하는 코드가 아니다. WebRTC encoder가 네트워크 상태에 따라 동적으로 움직이되, 지정한 상한을 넘지 않도록 제한하는 용도다.

14.7 근거 URL

  • YouTube Live encoder settings: https://support.google.com/youtube/answer/2853702?hl=en
  • Twitch broadcasting guidelines: https://help.twitch.tv/s/article/broadcasting-guidelines?language=en_US
  • AWS Elemental Live QVBR/VBR/CBR: https://docs.aws.amazon.com/elemental-live/latest/ug/qvbr-and-rate-control-mode.html
  • MDN RTCRtpSender.setParameters(): https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpSender/setParameters
  • W3C WebRTC RTCRtpEncodingParameters: https://w3c.github.io/webrtc-pc/
  • WebRTC transport-wide congestion control: https://webrtc.googlesource.com/src/+/main/docs/native-code/rtp-hdrext/transport-wide-cc-02/README.md

15.1 소개

Fuzzy Search는 사용자의 검색어가 정확히 일치하지 않아도 “비슷한 문자열”을 찾아주는 검색 방식이다. 예를 들어 iphnoe로 검색해도 iphone을 찾거나, hundai로 검색해도 hyundai를 찾게 만드는 기술이다.

실무에서는 fuzzy search라는 말을 넓게 쓰지만, 실제 구현은 여러 계열로 나뉜다.

계열 대표 방식 잘 맞는 문제
Edit distance Levenshtein, Damerau-Levenshtein 오타, 누락, 삽입, 인접 문자 뒤바뀜
Trigram similarity 3글자 조각 유사도 짧은 이름/상품명/회사명 검색
Autocomplete + fuzzy edge n-gram + typo tolerance 검색창 자동완성, search-as-you-type
Phonetic search Soundex, Metaphone 영어권 발음 유사 이름
Semantic search embedding/vector search 의미가 비슷하지만 단어가 다른 검색
flowchart LR
  Q["User Query<br/>iphnoe"] --> N["Normalize<br/>lowercase, trim"]
  N --> F["Fuzzy Matching<br/>edit distance / trigram"]
  F --> R["Candidate Results"]
  R --> S["Ranking<br/>exact > prefix > fuzzy"]
  S --> O["iphone, iphone case, ..."]

15.2 핵심 원리

가장 대표적인 기준은 edit distance다. 두 문자열을 같게 만들기 위해 필요한 최소 편집 횟수를 계산한다.

\[d(a,b) = min(\text{insert}, \text{delete}, \text{substitute}, \text{transpose})\]

예를 들어 kittensitting의 Levenshtein distance는 3이다.

오타 유형 처리 방식
substitution iphineiphone 문자 1개 교체
insertion iphooneiphone 문자 1개 삭제
deletion iphoniphone 문자 1개 삽입
transposition ipohneiphone 인접 문자 교환

Elasticsearch/OpenSearch의 fuzziness: AUTO는 단어 길이에 따라 허용 edit distance를 정한다. 보통 짧은 단어는 정확히 맞추고, 긴 단어는 1~2회 오타를 허용한다.

15.3 장단점

장점 단점
오타가 있어도 검색 성공률이 올라간다 후보 확장이 많아지면 검색 비용이 커진다
고객명, 종목명, 상품명 검색 UX가 좋아진다 너무 관대하면 엉뚱한 결과가 상위에 뜬다
자동완성/검색어 추천과 잘 결합된다 한국어 형태소, 초성, 띄어쓰기 처리는 별도 설계 필요
vector search보다 해석 가능성이 높다 의미 기반 검색은 잘 못한다

15.4 주요 구현 선택지

구현 특징 추천 상황
Elasticsearch fuzzy/match Levenshtein 기반, fuzziness, prefix_length, max_expansions 제어 대규모 전문 검색, relevance tuning
OpenSearch fuzzy/match Elasticsearch와 유사한 DSL, Damerau-Levenshtein 거리 설명 AWS/OpenSearch 기반 검색
MongoDB Atlas Search autocomplete/text operator에 fuzzy 옵션 MongoDB 앱에서 검색 기능 확장
PostgreSQL pg_trgm trigram similarity와 GIN/GiST index 기존 Postgres 앱의 이름/상품명 검색
RapidFuzz Python fuzzy string matching 라이브러리 작은 후보군 reranking, 데이터 정제, record matching
Fuse.js 브라우저/Node.js lightweight fuzzy search 프론트엔드 로컬 검색
Meilisearch typo tolerance가 기본 검색 랭킹에 통합 빠른 검색 UX, 운영 단순성
기준 Fuzzy Search Vector Search
핵심 기준 문자열 형태 유사도 의미/문맥 유사도
samgsungsamsung 휴대폰스마트폰
강점 오타, 이름, 코드, SKU 자연어 질문, 문서 의미 검색
약점 동의어/의미 이해 약함 정확한 문자열/코드 검색 약함
실무 조합 exact/prefix/fuzzy 후 semantic rerank semantic 후보 후 keyword filter

실무 검색 UX는 보통 하나만 쓰지 않는다. exact match > prefix/autocomplete > fuzzy > semantic 순으로 후보를 만들고, 업무 중요도에 맞춰 점수를 섞는다.

15.6 간단 예제: Python RapidFuzz

from rapidfuzz import process, fuzz

choices = ["Samsung Electronics", "Hyundai Motor", "NVIDIA", "Microsoft"]

result = process.extract(
    "samsng electornics",
    choices,
    scorer=fuzz.WRatio,
    limit=3,
)

print(result)

RapidFuzz는 검색엔진이라기보다 문자열 유사도 계산/후보 재정렬에 가깝다. 대용량 전체 검색에는 DB index나 검색엔진으로 후보를 줄인 뒤 RapidFuzz로 reranking하는 구조가 더 안전하다.

15.7 실용 예제: PostgreSQL pg_trgm

CREATE EXTENSION IF NOT EXISTS pg_trgm;

CREATE TABLE companies (
  id bigserial PRIMARY KEY,
  name text NOT NULL
);

CREATE INDEX companies_name_trgm_idx
ON companies
USING gin (name gin_trgm_ops);

SELECT id, name, similarity(name, 'samsng') AS score
FROM companies
WHERE name % 'samsng'
ORDER BY score DESC
LIMIT 10;

pg_trgm은 문자열을 trigram으로 쪼개 유사도를 계산한다. GIN/GiST index를 함께 쓰면 Postgres 안에서 실용적인 fuzzy search를 만들 수 있다.

15.8 실용 예제: Elasticsearch fuzzy query

{
  "query": {
    "match": {
      "company_name": {
        "query": "samsng",
        "fuzziness": "AUTO",
        "prefix_length": 1,
        "max_expansions": 50
      }
    }
  }
}

prefix_length는 앞부분 몇 글자를 반드시 정확히 맞출지 정한다. 이 값을 키우면 엉뚱한 후보와 비용을 줄일 수 있지만, 앞글자 오타에는 약해진다.

15.9 실용 예제: MongoDB Atlas Search autocomplete fuzzy

db.products.aggregate([
  {
    $search: {
      autocomplete: {
        path: "name",
        query: "iphno",
        fuzzy: {
          maxEdits: 1,
          prefixLength: 1,
          maxExpansions: 256
        }
      }
    }
  },
  { $limit: 10 },
  { $project: { name: 1, score: { $meta: "searchScore" } } }
])

MongoDB Atlas Search의 fuzzy.maxEdits는 1 또는 2를 사용한다. 자동완성과 함께 쓸 때는 prefixLengthmaxExpansions가 품질과 비용을 좌우한다.

15.10 실무 설계 가이드

상황 추천
종목명/회사명/상품명 검색 exact + prefix + fuzzy 조합
오타 허용 검색창 autocomplete + fuzzy, exact match boost
관리자 화면 빠른 검색 Postgres pg_trgm 또는 MongoDB Atlas Search
대규모 커머스 검색 Elasticsearch/OpenSearch/Meilisearch
STT transcript 보정 RapidFuzz 후보 매칭 + LLM 검증
코드/SKU/전화번호 fuzzy를 약하게 하거나 비활성화, exact 우선
한국어 검색 형태소 분석, 초성 검색, 띄어쓰기 보정 별도 검토

15.11 리스크/반례

리스크 설명 대응
과도한 recall 비슷하지만 틀린 결과가 너무 많이 나옴 exact/prefix boost, threshold 조정
성능 저하 fuzzy expansion이 커짐 max_expansions, prefix_length, index 사용
짧은 검색어 오탐 2~3글자 query는 유사 후보가 너무 많음 짧은 query는 exact/prefix 중심
보안/권한 멀티테넌트에서 다른 tenant 후보 노출 위험 tenant filter를 fuzzy 전에 강제
한글 처리 자모/초성/띄어쓰기 문제 한국어 analyzer 또는 별도 normalized field

15.12 근거 URL

  • Elasticsearch fuzzy query: https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-fuzzy-query
  • Elasticsearch fuzziness common option: https://www.elastic.co/guide/en/elasticsearch/reference/8.19/common-options.html
  • OpenSearch fuzzy query: https://docs.opensearch.org/latest/query-dsl/term/fuzzy/
  • MongoDB Atlas Search autocomplete fuzzy: https://www.mongodb.com/docs/atlas/atlas-search/autocomplete/
  • PostgreSQL pg_trgm: https://www.postgresql.org/docs/current/static/pgtrgm.html
  • RapidFuzz documentation: https://rapidfuzz.github.io/RapidFuzz/
  • Fuse.js fuzzy search: https://www.fusejs.io/fuzzy-search.html
  • Meilisearch typo tolerance: https://www.meilisearch.com/docs/resources/internals/typo_tolerance

16. 종합 설계 제안

16.1 AI SaaS를 만든다면 추천 아키텍처

계층 추천
API FastAPI + asyncio
Tenant isolation middleware tenant context + DB RLS/filter
Agent 단순 agent는 PydanticAI 또는 LangChain
Workflow 장기 실행/승인/복구는 LangGraph
Vector 기존 MongoDB 중심이면 Atlas Vector Search, Postgres 중심이면 pgvector
Vector Metric 텍스트 RAG는 cosine/dotProduct 우선, 크기 의미가 있으면 L2 검토
Fuzzy Search 이름/종목/상품 검색은 exact + prefix + fuzzy, 의미 검색은 vector와 결합
Voice 초저지연이면 Realtime API 또는 streaming STT→LLM→TTS
Media audio bridge/transcoding은 GStreamer
Deploy Docker image → ECR → ECS Fargate
Observability tenant별 latency, TTFT, vector recall, tool failure, cost
flowchart TD
  U["Browser / Mobile"] --> API["FastAPI async API"]
  API --> TC["Tenant Middleware"]
  TC --> AG["PydanticAI / LangChain Agent"]
  AG --> WF["LangGraph for workflows"]
  AG --> VDB["MongoDB Vector / pgvector"]
  API --> VOICE["Realtime Voice Pipeline"]
  VOICE --> GST["GStreamer audio pipeline"]
  API --> Q["Async Queue"]
  API --> LOG["Tenant-aware logs/metrics"]
  subgraph AWS
    ECR["ECR"]
    ECS["ECS Fargate"]
    SM["Secrets Manager"]
  end
  ECR --> ECS
  ECS --> API
  SM --> API

16.2 우선순위

우선순위 할 일 이유
1 tenant context와 권한 경계 설계 나중에 고치기 가장 어렵다
2 streaming-first API 설계 음성/LLM 체감 성능의 핵심
3 vector DB를 기존 운영 DB와 맞춰 선택 운영 복잡도를 낮춘다
4 embedding metric과 index metric 일치 recall과 ranking 품질을 지키기 위함
5 Docker image build/release 규칙 확정 AWS 배포 안정성
6 agent framework는 PoC 후 결정 실제 workflow 복잡도에 따라 갈린다
7 fuzzy/vector 검색 역할 분리 오타 검색과 의미 검색을 혼동하지 않기 위함

17. 호환성 체크리스트

항목 확인
수식 렌더링 $...$, $$...$$ 형식 사용
코드블록 언어 태그 python, sql, javascript, json, dockerfile, yaml, bash, mermaid 사용
표 깨짐 여부 모든 표는 단순 Markdown 표로 작성
다이어그램 렌더링 Mermaid flowchart, sequenceDiagram, quadrantChart 사용
Notion 호환성 Mermaid 미지원 환경에서는 이미지로 변환 필요

18. 사실검증 메모

구분 검증 내용 판단
공식 문서 우선 Python, LangChain, PydanticAI, MongoDB, Docker, AWS, GStreamer, RFC, YouTube, Twitch, WebRTC, Elasticsearch, OpenSearch, PostgreSQL, RapidFuzz, scikit-learn, pgvector, Pinecone, Qdrant 문서는 공식 문서 중심으로 확인 사실
법률/회계 RCPS 조항은 국가법령정보센터 상법 원문과 PwC/NABO 자료로 교차 확인 사실
버전 민감도 LangChain/PydanticAI, OpenAI Realtime, SQL Server/vector DB metric 기능은 빠르게 변할 수 있음 검증필요
실무 예제 예제 코드는 개념 전달용이며 실제 API key, provider 설정, 보안 설정은 생략 추정/검증필요
성능 수치 TTFT/TTFA는 네트워크, region, 모델, endpoint 설정에 크게 의존 검증필요

19. 작성 시 사용한 사용자 질문 프롬프트

아래 내용들을 자세히 조사후 md 파일로 정리해주세요

멀티테넌트

파이썬 비동기 프로그래밍
- 소개
- 장단점
- 특징
- 간단예제
- 실용예제

LangChain, LangGraph
- 소개, 특징, 장단점
- 간단예제, 실용예제

PydanticAI
- 소개, 특징, 장단점
- 간단예제, 실용예제

LangChain, LangGraph vs PydanticAI
- 비교분석

vectorDB in MongoDB
- 소개, 특징, 장단점
- 간단예제, 실용예제

vectorDB in other SQL DB
- 소개, 특징, 장단점
- 간단예제, 실용예제

rcps 보통주 전환

저지연 파이프라인 최적화
stt llm tts 전체파이프라인의 ttft 단축 및 스트리밍 응답 최적화

리서치 항목 추가
gstreamer
- 소개
- 장단점
- 특징
- 간단예제 python
- 실용예제 python

리서치 항목추가
docker
- 소개
- 장단점
- 특징
- 간단예제
- 실용예제
- in AWS 에서 사용 사례, 주의사항

리서치 항목 추가
멀티플렉싱

리서치 주제 추가
실시간 방송송출, 화상통화에서는 VBR or CBR 중 어느것이 더 권장 되는가?
그 이유는?

리서치 주제 추가
fuzzy search

주제 추가
L2 distance vs cosine distance