환경 설정
0. 템플릿 패키지 받기
섹션 제목: “0. 템플릿 패키지 받기”llamon CLI는 llamon-agent-template 패키지에 동봉된 SDK wheel로 동작합니다. 먼저 이 패키지를 확보하세요.
| 출처 | 내용 |
|---|---|
| 내부 배포 채널 | llamon-agent-template-<version>.tar.gz 배포 패키지 |
| 압축 해제 후 포함 파일 | llamon_agent-*.whl, llamon_agent-*.whl.sha256, uv.lock, update_sdk_wheel.sh |
압축을 푼 뒤, 해당 디렉토리 안에서 모든 명령을 실행합니다.
tar -xzf llamon-agent-template-X.Y.Z.tar.gzcd llamon-agent-template사전 요구 사항
섹션 제목: “사전 요구 사항”| 항목 | 최소 버전 |
|---|---|
| Python | 3.11 이상, 기본 권장 3.14 |
| uv | 최신 버전 |
| Docker | 20.10 이상 (llamon run 실행 시 필요) |
| docker compose | v2 이상 |
서버 CPU·메모리 권장치(예약/상한)는 실행과 배포 → 서버 리소스 권장에 정리되어 있습니다.
1. uv 설치
섹션 제목: “1. uv 설치”uv는 Python 패키지 매니저입니다. llamon-agent-template 프로젝트 실행에 사용합니다.
curl -LsSf https://astral.sh/uv/install.sh | sh설치 후 터미널을 재시작하거나 아래 명령으로 PATH를 적용하세요.
source $HOME/.local/bin/envpowershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"winget을 사용한다면:
winget install --id=astral-sh.uv -e설치 후 PowerShell을 재시작하세요.
설치 확인:
uv --version2. Python 설치 (uv로 관리)
섹션 제목: “2. Python 설치 (uv로 관리)”uv python install 3.14uv가 Python 버전을 관리하므로 시스템에 Python을 따로 설치할 필요가 없습니다.
3. llamon-agent-template 프로젝트 설정
섹션 제목: “3. llamon-agent-template 프로젝트 설정”제공받은 llamon-agent-template 디렉토리에는 다음 파일이 이미 들어 있습니다.
| 파일 | 설명 |
|---|---|
llamon_agent-*.whl | SDK 패키지 (별도 다운로드 불필요) |
llamon_agent-*.whl.sha256 | 무결성 검증용 체크섬 |
uv.lock | 의존성 버전 고정 파일 (frozen) |
사용자가 할 작업은 .venv 가상 환경을 만드는 것뿐입니다.
uv sync --frozen # .venv 생성 + 의존성 설치 (uv.lock 기준)--frozen은 동봉된uv.lock을 변경 없이 그대로 사용합니다.uv sync로 실행해도 결과는 동일하지만,--frozen이 lock 파일 변경을 방지해 더 안전합니다.- SDK wheel의 SHA-256 무결성 검증은 Docker 빌드 시 자동 수행됩니다 (
Dockerfile내sha256sum -c). - 완료되면
.venv/안에llamonCLI가 자동 등록됩니다.
4. llamon CLI 실행 방법
섹션 제목: “4. llamon CLI 실행 방법”llamon-agent-template 디렉토리 안에서 uv run 접두사로 실행합니다.
# 생성uv run llamon --helpuv run llamon agent --help # 단일 에이전트 프로젝트 생성uv run llamon flow --help # 플로우(멀티 에이전트 그래프) 프로젝트 생성
# 로컬 실행/점검uv run llamon run --help # 로컬 docker compose 실행/정리uv run llamon doctor --help # 프로젝트 점검
# 오프라인 준비/패키징uv run llamon prepare-offline --help # doctor → vendor-deps → doctor → package 한 번에 실행uv run llamon vendor-deps --help # (개별) 오프라인 wheelhouse만 준비uv run llamon package --help # (개별) 배포용 tar.gz만 생성uv run llamon profile list --help # 사용 가능한 인프라 프로필 확인uv run llamon profile apply --help # wheelhouse/package 재생성 없이 프로필 값만 적용
# 배포/운영uv run llamon deploy --help # SSH 접근 가능한 원격 서버 배포 (폐쇄망 아님)uv run --no-sync llamon restore-online --help # prepare-offline 이전 Dockerfile 복원
# 보조 도구uv run llamon studio --help # 플로우 Studio 실행uv run llamon memory --help # 메모리 DB 관리 (prune 등)각 명령의 역할은 위 주석에 정리되어 있습니다. GitLab/server 배포 자산은 --deploy-profile gitlab-server로 생성합니다. 실행과 배포 예시는 실행과 배포를 참고하세요.
전역 설치 (선택 사항)
섹션 제목: “전역 설치 (선택 사항)”프로젝트 디렉토리 밖에서도 llamon 명령을 바로 쓰려면:
uv tool install ./llamon_agent-*.whl설치 후에는 접두사 없이 사용할 수 있습니다.
llamon agent제거하려면:
uv tool uninstall llamon-agent5. 새 프로젝트 생성
섹션 제목: “5. 새 프로젝트 생성”llamon-agent-template 디렉토리 안에서 새 프로젝트를 생성합니다.
생성된 프로젝트는 현재 디렉토리 아래에 만들어집니다.
# 단일 에이전트: 대화형uv run llamon agent
# 단일 에이전트: 한 줄 생성 (Registry 기반 기본)uv run llamon agent my-agent --template agent-general --yes
# 멀티 에이전트 플로우: 대화형uv run llamon flow
# 멀티 에이전트 플로우: 한 줄 생성uv run llamon flow my-flow --template flow-seq --yes자세한 내용은 에이전트/플로우 생성 (llamon agent/flow)과 실행과 배포 (run/doctor/deploy/prepare-offline)를 참고하세요.
6. 환경 변수 (한눈에)
섹션 제목: “6. 환경 변수 (한눈에)”.env.example을 .env로 복사한 뒤 채웁니다.
템플릿을 고르면 생성된 .env에는 해당 시나리오에 필요한 변수만 들어갑니다. 보통 아래 “연결 변수” 한두 개만 채우면 됩니다.
시나리오 → 템플릿 → 연결 변수
섹션 제목: “시나리오 → 템플릿 → 연결 변수”내 상황에 맞는 한 줄만 보면 됩니다.
| 시나리오 | 권장 템플릿 | 채울 연결 변수 |
|---|---|---|
| LLaMON Registry 사용 | agent-general (기본) · agent-structured · data-summary · outcome-evaluator | LLAMON_REGISTRY_HOST |
| OpenAI API 직접 | agent-openai | OPENAI_API_KEY |
| Anthropic API 직접 | agent-anthropic | ANTHROPIC_API_KEY |
| Ollama 직접 연결 | agent-ollama | OLLAMA_BASE_URL (기본 http://localhost:11434) |
각 연결 변수는 해당 템플릿에서만 쓰입니다. provider 템플릿은 모델명을 지정하는 OPENAI_MODEL·ANTHROPIC_MODEL·OLLAMA_MODEL도 함께 생성하지만, 기본값이 있어 선택입니다. Registry 접근권이 없다면 직접 모델 연결로 이동하세요.
관측성·로깅 (전부 선택)
섹션 제목: “관측성·로깅 (전부 선택)”어느 템플릿에서나 똑같이 동작하는 SDK 공통 변수입니다. 하나도 채우지 않아도 앱은 정상 동작합니다(이 경우 트레이싱만 꺼집니다). 트레이싱을 켜려면 아래 표 뒤의 조건부 필수를 보세요.
| 변수 | 용도 | 예시 |
|---|---|---|
TRACE_BACKEND | 트레이스 백엔드 선택 — langfuse(기본) · relay · none(끄기) | langfuse |
LANGFUSE_PUBLIC_KEY · LANGFUSE_SECRET_KEY | Langfuse 인증 키 (둘 다 있으면 langfuse 백엔드 자동 활성화) | pk-lf-... · sk-lf-... |
LANGFUSE_BASE_URL | Langfuse 호스트 | https://us.cloud.langfuse.com |
LANGFUSE_ENABLED | Langfuse 트레이싱 강제 켜기/끄기 (미설정 시 키 유무로 자동 판단) | true |
LANGFUSE_CAPTURE_CONTENT | 프롬프트·응답 본문을 트레이스에 함께 남길지 (기본 켜짐, PII 주의) | true |
TRACE_CONSOLE_ENABLED | 트레이스 로그를 콘솔(stdout)에도 출력 (기본 켜짐, Langfuse 전송·LOG_LEVEL과 무관) | true |
OTEL_INSTRUMENTATION_A2A_SDK_ENABLED | A2A 통신 라이브러리가 자체 OTEL span 을 자동 생성 (대부분 중복·노이즈라 기본 꺼짐) | false |
A2A_DISTRIBUTED_TRACING_ENABLED | 같은 Flow/Orchestrator 실행의 원격 A2A 호출에 W3C trace context를 자동 전파. 긴급 rollback은 false | true |
LOG_LEVEL | SDK·사용자 코드(app.*) 로그 레벨 (DEBUG/INFO/WARNING/ERROR) | WARNING |
UVICORN_LOG_LEVEL | uvicorn 서버 로그 레벨 (LOG_LEVEL과 별개) | info |
TRACE_BACKEND로 백엔드를 고르고, LANGFUSE_*가 Langfuse 연결 여부를 정합니다. none이면 트레이싱이 통째로 꺼집니다.
생성된 agent·flow·orchestrator 프로젝트는 모두 app/config.py에
build_observability()를 포함합니다. 기본값은 비어 있어 아무 동작도 바꾸지 않습니다.
비교용 cohort와 서비스 역할이 필요할 때만 주석을 풀고 값을 정하세요.
from llamon_agent.observability import ObservabilityConfig
def build_observability() -> ObservabilityConfig: return ObservabilityConfig( tags=["customer-support", "channel:web"], metadata={"serviceRole": "intent-router"}, )channel:web의 콜론과 serviceRole은 SDK 필수 문법이나 예약 필드가 아닙니다. 단계별
observation type, Flow node override, score와 네트워크 없는 테스트는
Observability 개요와 공통 설정을
참고하세요.
LANGFUSE_CAPTURE_CONTENT=true 상태에서 서비스별 PII를 가려야 한다면 create_server(..., sensitive_data_mask=...)에 Langfuse mask 시그니처의 동기 함수를 전달하세요. SDK는 이 함수를 Langfuse 클라이언트 생성자의 공식 mask=에 적용합니다. A2A Task.history는 마스킹 대상이 아니라 상태와 관계없이 항상 history=[]로 저장·반환됩니다.
from typing import Any
from app.pii_mask import mask_structure
def sensitive_data_mask(*, data: Any, **_: Any) -> Any: return mask_structure(data)
app = await create_server( # card, agent, settings, ... sensitive_data_mask=sensitive_data_mask,)직접 만든 영속 저장소가 필요하면 같은 호출에 task_store=<TaskStore>를 전달합니다. SDK privacy wrapper가 그 저장소 앞에 적용되므로 factory 모듈의 InMemoryTaskStore 심볼을 바꾸거나 Langfuse 클라이언트의 private _mask 속성을 수정하지 않습니다. 현재 실행 입력은 RequestContext.message에서 계속 읽으며, 외부 워크플로우가 전달한 metadata.history도 기존처럼 가드레일을 거쳐 cold-start 대화 상태에 시드됩니다. 제거되는 것은 Task 저장소와 A2A 응답에 반영되는 프로토콜 필드 Task.history뿐입니다.
A2A_DISTRIBUTED_TRACING_ENABLED는 별도 설정 없이 기본 ON입니다. 활성 trace가 있을 때만 SDK의 A2A 전송 경로(Flow registry node, Orchestrator ctx.call(), ReAct A2A tool, raw fallback)가 traceparent/tracestate를 붙입니다. 한 실행 안의 순차·병렬·재시도 호출은 같은 trace ID 아래 서로 다른 child span으로 기록되고, 독립 실행은 새 trace ID를 사용합니다. 수신 에이전트는 원격 parent를 root로 다시 이름 붙이지 않습니다. 서비스들이 같은 Langfuse 프로젝트로 전송될 때 UI에서도 하나의 trace로 조회할 수 있습니다.
이 전파는 A2A JSON-RPC payload·metadata·timeout을 바꾸지 않으며 baggage도 보내지 않습니다. 문제가 생기면 A2A_DISTRIBUTED_TRACING_ENABLED=false로 기존 헤더 동작에 즉시 복귀할 수 있습니다.
조건부 필수 (앱 구동엔 불필요, 트레이싱을 켤 때만):
- Langfuse로 보내려면
LANGFUSE_PUBLIC_KEY·LANGFUSE_SECRET_KEY가 한 쌍으로 있어야 활성화됩니다(하나만 있으면 켜지지 않음).LANGFUSE_BASE_URL은 미설정 시https://us.cloud.langfuse.com으로 폴백하므로, US 클라우드면 선택이고 자체 호스팅이면 필요합니다. TRACE_BACKEND=relay(폐쇄망 ingestion)는LANGFUSE_RELAY_BASE_URL이 없으면 부팅이 실패합니다(인프라 프로필 참조).
LOG_LEVEL은 scaffold main.py가 부팅 때 한 번 호출하는 setup_logging(settings)를 통해 SDK와 app.* 로거에 적용됩니다. 세부 동작은 문제 해결 → SDK 로그 레벨에서 다룹니다.
동작 튜닝 (선택)
섹션 제목: “동작 튜닝 (선택)”에이전트의 동작 방식을 바꾸는 값입니다. 아래 성능 튜닝과 달리 pydantic Settings 필드라 .env로 로드됩니다(os.environ을 직접 읽지 않음). REACT_MAX_ITERATIONS 노출 여부는 템플릿 구성에 따라 다릅니다. 기본 Registry Flow 템플릿은 registry_llm 노드가 없어 .env에 노출하지 않습니다. 세션 메모리 기본값은 --memory로 생성한 프로젝트의 .env에 들어 있습니다. fact recall 관련 값은 .env.example에 주석 예시로만 들어가며, 명시적으로 켜기 전까지 비활성입니다.
| 변수 | 용도 | 기본값 |
|---|---|---|
REACT_MAX_ITERATIONS | ReAct tool-calling 루프 최대 반복 횟수 — 내부적으로 LangGraph recursion_limit = N*2+1로 환산됩니다(예: 3→7). Flow 전체의 재귀 한계는 바꾸지 않지만, registry_llm 노드가 자체 max_retry를 생략하면 그 내부 Agent의 기본값으로 상속됩니다. registry_node에는 적용되지 않습니다. 자세히는 ReAct 반복 상한 | 3 |
MEMORY_WINDOW_SIZE | LLM에 전달할 최근 메시지 수 — 비용·토큰 제어용. 메모리를 켰을 때만 적용됩니다 | 20 |
MEMORY_PERSIST_TRIM_KEEP_GROUPS | 저장본(체크포인트)에 남길 최근 turn 그룹 수. 0이면 끔(무삭제). 0보다 크면 오래된 turn을 저장본에서 영구 삭제해 장수 대화의 메모리 누적(OOM)을 막습니다(삭제는 비가역). MEMORY_WINDOW_SIZE와 독립 — 이쪽은 저장본 자체를 줄입니다 | 0 |
MEMORY_FACTS_MODE | 선택적 fact recall 모드. off는 기존 동작 그대로, heuristic은 표준 라이브러리 기반 규칙으로 사용자 사실을 저장·회상, llm은 이미 설정된 LLM으로 추출을 시도하고 실패 시 graceful fallback 합니다. 주석을 풀고 켰을 때만 적용됩니다 | off |
MEMORY_FACT_RECALL_MAX_ITEMS | 모델 prompt에 주입할 recalled fact 최대 개수. MEMORY_FACTS_MODE=off이면 사용하지 않습니다 | 3 |
성능 튜닝 (전부 선택)
섹션 제목: “성능 튜닝 (전부 선택)”동시성·타임아웃·커넥션 풀·A2A 입력 상한을 조정하는 override 값입니다. 모두 코드에 안전한 기본값이 있어 설정하지 않아도 동작하며(폐쇄망 포함), env로 덮어쓸 때만 적용됩니다. 위 관측성 변수와 달리 pydantic Settings가 아니라 os.environ에서 호출 시점에 읽습니다. 생성된 프로젝트의 .env.example에도 [선택] 성능 튜닝 블록으로 같은 목록이 주석 처리되어 있으니, 필요한 항목만 주석을 풀면 됩니다.
HTTP 공유 풀 — 모든 outbound HTTP(자식 호출·Registry·LLM·가드레일)가 공유합니다. 기본값은 컨테이너 ulimit 1024를 기준으로 FD를 설계한 값입니다(500 + 200 = 700).
| 변수 | 용도 | 기본값 |
|---|---|---|
HTTP_MAX_CONNECTIONS | 동시 연결 상한 | 500 |
HTTP_MAX_KEEPALIVE_CONNECTIONS | keep-alive 재사용 상한 | 100 |
HTTP_STREAMING_MAX_CONNECTIONS | SSE 등 장기 연결 상한 | 200 |
HTTP_TIMEOUT_CONNECT | 연결 수립 제한 시간(초) | 10 |
HTTP_TIMEOUT_READ | 응답 수신 제한 시간(초) | 30 |
동시성
| 변수 | 용도 | 기본값 |
|---|---|---|
FANOUT_MAX_CONCURRENCY | 병렬 호출을 한 번에 몇 개까지 동시 실행할지 — ctx.gather·병렬 flow 노드·멀티 에이전트 호출에 적용. 분기마다 공유 HTTP 풀을 쓰므로, 크게 올릴 땐 HTTP_MAX_CONNECTIONS 도 함께 올려 풀 고갈(PoolTimeout)을 피하세요 | 16 |
A2A 요청 입력
| 변수 | 용도 | 기본값 |
|---|---|---|
A2A_HISTORY_MAX_MESSAGES | 수신한 metadata.history에서 변환·시드할 최대 text 메시지 수. 초과하면 가장 오래된 메시지부터 제거하고 최근 메시지를 유지합니다. 미설정·빈값·파싱 실패·1 미만 값은 기본값으로 폴백합니다 | 50 |
외부 호출 · LLM 호출 — 자식 에이전트·Registry·가드레일 호출(상단 5개), 그리고 Agent 자신의 LLM 호출(LLM_* 2개 — primary 모델 호출에 적용, 자식 호출 아님) (각 행 끝 — 뒤가 트리거)
| 변수 | 용도 | 기본값 |
|---|---|---|
REGISTRY_HTTP_TIMEOUT | Registry API 제한 시간(초) — registry:<id> 자식 resolve·메타 조회 시 | 10 |
A2A_CARD_TIMEOUT | 자식 호출 전 그 에이전트의 AgentCard(스킬·엔드포인트 명세) 조회 제한 시간(초) — 자식 연결(카드 로드) 시, 신규·구 well-known 폴백 포함 | 30 |
A2A_SEND_TIMEOUT | 자식 단발 호출(message/send) 제한 시간(초) — call_agent_auto·call_agent(flow), orchestrator ctx.call/ctx.gather | 120 |
A2A_CONNECT_TIMEOUT | 자식 스트리밍 호출 연결 수립 제한 시간(초) — call_agent_auto(스트리밍)·call_agent_stream_result | 10 |
A2A_STREAM_TOTAL_TIMEOUT | 자식 스트리밍 호출 1건 전체의 제한 시간(초) — call_agent_auto(스트리밍)·call_agent_stream_result·call_agent_stream. SSE 는 read timeout 을 켤 수 없어(바이트 수신 간격 기준이라 자식이 긴 tool 실행으로 침묵하면 스트림이 끊김) 연결만 수락하고 침묵하는 자식에는 상한이 없습니다. 이 값을 주면 그 경우가 무한 대기 대신 UPSTREAM_TIMEOUT(retriable) 실패로 관측됩니다. A2A_SEND_TIMEOUT(120s)·LLM_TIMEOUT(600s)과 같은 “hang 방지” 스케일로 잡으세요 — SLA 용이 아닙니다. 예산에는 자식의 LLM 추론·tool 실행 대기와 호출자 콜백(on_text_chunk/async for 본문) 처리 시간이 전부 포함되고, 초과 시 진행 중인 턴이 그대로 절단되므로(자식은 계산을 계속하고 부모만 포기) 평시 p99 의 수 배로 두는 것이 안전합니다. 응답 시간 SLA 는 상위(UI·워크플로우) 계층에서 강제하세요. 0 또는 미설정이면 무제한 | 미설정(무제한) |
GUARDRAIL_HTTP_TIMEOUT | 가드레일 엔드포인트 제한 시간(초) — 가드레일을 붙인 에이전트 호출 시 | 5 |
LLM_MAX_RETRIES | LLM 일시 오류(5xx·429) 재시도 횟수 — Agent 가 모델 호출 시(OpenAI·Anthropic provider) | 3 |
LLM_TIMEOUT | LLM 단발 호출 제한 시간(초) — 무한 대기 방지. 미설정 시에도 기본 적용되며 message/send·message/stream·skill·judge 등 모든 LLM 호출 공통. 0 이면 무제한 | 600 |
메모리·상태 저장소
| 변수 | 용도 | 기본값 |
|---|---|---|
MEMORY_INMEMORY_MAX_THREADS | in-memory 백엔드 thread 상한 (0=무제한, 초과 시 오래된 것부터 자동 정리) | 10000 |
MEMORY_PG_COMMAND_TIMEOUT | (postgres 메모리) 쿼리 제한 시간(초) | 10 |
MEMORY_PG_STATEMENT_CACHE_SIZE | (postgres 메모리) PgBouncer transaction 모드면 0 권장 | 100 |
ORCH_PG_POOL_MAX_SIZE | (orchestrator, state_backend="postgres") 풀 최대 연결 수 | 5 |
ORCH_PG_STATEMENT_TIMEOUT_MS | (orchestrator, postgres) turn 당 SQL 제한 시간(ms) | 5000 |
값이 잘못됐거나 허용 범위를 벗어나도 부팅은 멈추지 않고, 경고를 남긴 뒤 기본값으로 폴백합니다(env 하나 때문에 서버가 죽지 않도록).
문제 해결
섹션 제목: “문제 해결”자주 발생하는 오류와 해결 방법은 문제 해결을 참고하세요.