문제 해결
문제가 생기면 먼저 다음 세 줄로 범위를 좁히세요.
uv run llamon doctor .LOG_LEVEL=DEBUG uv run llamon run . --no-detachdocker compose -f compose.yml logs -f agent| 증상 | 먼저 볼 곳 |
|---|---|
| 서버가 뜨지 않음 | 실행 오류 |
| graph·node 수정 뒤 실패 | 코드 수정 후 오류 |
| Registry model 호출 실패 | Registry LLM 오류 |
응답이 느리거나 <think>가 노출됨 | reasoning 모드 |
| 같은 대화가 이어지지 않음 | 세션 메모리 |
| prompt 변수가 그대로 출력됨 | Prompt binding |
| 폐쇄망 package·build 실패 | 폐쇄망 준비 |
SDK 로그 레벨 (LOG_LEVEL)
섹션 제목: “SDK 로그 레벨 (LOG_LEVEL)”LOG_LEVEL은 SDK와 app.* logger를, UVICORN_LOG_LEVEL은 서버·access log를 제어합니다.
| 설정 | 권장값 | 보이는 것 |
|---|---|---|
LOG_LEVEL | 평소 WARNING, 진단 DEBUG | routing, MCP, node, guardrail, 사용자 logger |
UVICORN_LOG_LEVEL | 평소 info | 시작 로그와 모든 HTTP access log |
TRACE_CONSOLE_ENABLED | 필요할 때만 true | 별도 trace console 채널 |
uvicorn access log는 응답 코드와 관계없이 INFO입니다. UVICORN_LOG_LEVEL=warning이면 404·500 access line도 숨고, 처리되지 않은 예외 traceback만 uvicorn.error의 ERROR로 남을 수 있습니다.
사용자 코드에서는 logging.getLogger(__name__)만 사용하고 basicConfig()를 다시 호출하지 마세요.
실행 오류
섹션 제목: “실행 오류”| 증상 | 원인·해결 |
|---|---|
| 알 수 없는 template | uv run llamon scaffold list로 현재 SDK의 Agent·Flow·Orchestrator 공개 키 확인 (agent-structured-ollama 포함) |
알 수 없는 --example | observability·rubric-judge·groundedness 중 하나 사용. outcome-evaluator에는 starter를 중첩하지 않음 |
outbound/memory/backends.py에서 DB 실패 | checkpointer 문제. POSTGRES_MEMORY_DSN 확인 |
app/nodes.py에서 asyncpg 실패 | 비즈니스 DB 문제. POSTGRES_URL 확인 |
uv run python main.py에서 postgres host 실패 | compose 밖에서 실행 중. uv run llamon run . 사용 또는 외부 DSN 지정 |
| compose 파일 없음 | 프로젝트 root에서 실행하거나 --compose-file 지정 |
Address already in use | 사용 중인 port를 종료하거나 .env의 PORT 변경 |
메모리 DSN과 비즈니스 노드 DSN은 서로 독립입니다. traceback에서 처음 등장하는 프로젝트·SDK 파일을 기준으로 구분하세요.
코드 수정 후 오류 (그래프/노드)
섹션 제목: “코드 수정 후 오류 (그래프/노드)”| 증상 | 수정 |
|---|---|
keyword-only TypeError | registry_node를 closure로 감싸 필요한 URL·config를 전달 |
NoneType을 await | node를 async def로 선언 |
node 반환 뒤 AttributeError | return {"output": ...} 같은 state update를 명시 |
| 시작 즉시 graph 오류 | build_graph()가 .build() 결과를 반환하는지 확인 |
<YOUR_...> 또는 TODO 잔존 | uv run llamon doctor .로 scaffold placeholder 확인 |
LLM이 같은 tool을 반복하거나 잘못 고르는 문제는 graph 버그와 다릅니다. 호출 순서가 업무 규칙으로 확정돼 있다면 prompt를 늘리기보다 @deterministic_tool 또는 Deterministic workflow를 사용하세요.
Registry LLM 오류
섹션 제목: “Registry LLM 오류”| 증상 | 확인 |
|---|---|
404 + loc=GATEWAY | LLMConfig(id=...)의 Registry model ID와 model 연결 |
404 + loc=PROVIDER | provider protocol과 endpoint; vLLM은 보통 OpenAI 호환 /v1 |
| Registry model이 Ollama adapter로 호출됨 | provider_type.code가 실제 PROVIDER_OLLAMA인지 확인 |
| 401·403 | Registry credential과 runtime secret 주입 |
| timeout | endpoint reachability와 LLM_TIMEOUT 확인 |
확인 순서는 provider의 provider_type.code → model ID → endpoint protocol입니다. 모델 이름만 보고 provider 방식을 추정하지 마세요.
reasoning 모드 제어
섹션 제목: “reasoning 모드 제어”reasoning=None은 모델 기본값을 유지합니다. 느린 응답, 과도한 token, <think> 노출이 있으면 실제 endpoint 종류에 맞춰 설정합니다.
| endpoint | 대표 설정 |
|---|---|
| vLLM Qwen 계열 | provider_extra={"chat_template_kwargs":{"enable_thinking":False}} |
| DeepSeek·GLM·Kimi 공식 OpenAI 호환 API | provider_extra={"thinking":{"type":"disabled"}} |
Ollama /v1 또는 이를 감싼 OpenAI 호환 proxy | provider_extra={"reasoning_effort":"none"} |
| Direct Ollama adapter | reasoning=False |
| OpenAI native reasoning model | reasoning="low" 또는 Reasoning(effort="low") |
| Anthropic | reasoning=True 또는 Reasoning(budget_tokens=...) |
provider_extra는 SDK 변환보다 우선하는 raw provider 옵션입니다. 같은 모델도 vLLM에 올렸는지, 공식 API인지, Ollama /v1인지에 따라 필드가 달라집니다. 지원하지 않는 reasoning parameter로 400이 나면 해당 값을 제거하세요. 전체 입력 형태는 에이전트 구성의 reasoning 필드를 참고하세요.
Registry의 provider_type.code가 PROVIDER_VLLM이어도 endpoint가 Ollama /v1로 전달하는
proxy라면 Ollama 행을 사용합니다. 예를 들어 이런 경로의 Kimi K2.6에
chat_template_kwargs.thinking=False를 보내거나 Moonshot 공식 API용
thinking.type="disabled"를 보내면 proxy가 값을 무시해 thinking이 계속될 수 있습니다.
Moonshot 직결과 Ollama proxy는 각각 Kimi K2.6 공식 API,
Ollama OpenAI 호환 API의 요청 필드를 따릅니다.
응답에 reasoning_content가 없다는 사실만으로 thinking 종료를 판단하지 마세요. gateway가
추론 내용을 숨겨도 token 사용량에는 포함될 수 있습니다. 짧은 고정 답변으로 전후를 비교해
final content보다 output_tokens가 과도하게 크거나 지연 시간이 긴지 확인합니다.
빈 final content가 반복되면 max_tokens를 늘리거나 reasoning 강도를 낮춥니다. 호출이 끝없이 대기하는 문제는 reasoning이 아니라 LLM_TIMEOUT으로 제한합니다.
ReAct 반복 상한
섹션 제목: “ReAct 반복 상한”REACT_MAX_ITERATIONS=N은 직접 ReAct Agent와 Flow의 registry_llm node 기본값입니다. 내부 LangGraph 상한은 N * 2 + 1입니다. 한 cycle이 LLM과 tool 두 전이를 쓰고 마지막 응답 LLM 호출이 한 번 더 필요하기 때문입니다.
| 범위 | 규칙 |
|---|---|
| 직접 Agent | ExtensionConfig(max_retry=N) 또는 env 값 |
| Flow 바깥 graph | LangGraph 기본 재귀 한계; max_retry와 별개 |
Flow registry_llm | node 값 > Flow 값 > 기본 3 |
원격 registry_node | 부모의 반복 상한을 전달하지 않음 |
기본 3은 recursion_limit=7입니다. Agent Card의 urn:llamon:agent-config에는 외부 계약인 maxRetry로 노출됩니다. 반복 호출이 업무상 불필요하다면 상한을 늘리기 전에 deterministic 경계로 옮기세요.
세션 메모리 오류
섹션 제목: “세션 메모리 오류”| 증상 | 원인·해결 |
|---|---|
| 같은 사용자인데 대화가 끊김 | 모든 요청의 message.contextId를 같은 값으로 유지 |
params.metadata.thread_id를 보냈는데 미동작 | 세션 키는 message.contextId |
| send는 되지만 stream에서 끊김 | message/stream에도 같은 contextId 전달 |
| 저장 메시지는 많은데 모델이 모름 | window_size, summarize, fact recall 설정 확인 |
PostgreSQL / PgBouncer 관련
섹션 제목: “PostgreSQL / PgBouncer 관련”PgBouncer는 session 모드가 기본 권장입니다. transaction 모드가 필요하면 MEMORY_PG_STATEMENT_CACHE_SIZE=0으로 prepared statement cache를 끄고 검증하세요.
| 증상 | 해결 |
|---|---|
prepared statement ... does not exist | POOL_MODE=session 또는 statement cache 비활성화 |
| 약 1시간 뒤 dead connection | SDK와 PgBouncer의 connection lifetime을 PgBouncer SERVER_LIFETIME보다 짧게 설정 |
cl_waiting > 0 | 활성 컨테이너 수 기준으로 pool 크기 재산정 |
| 대량 thread 삭제 timeout | thread ID를 batch로 나눠 삭제 |
연결 수와 세부 설정은 멀티턴 메모리 — PgBouncer을 보세요.
Prompt Template / Binding 오류
섹션 제목: “Prompt Template / Binding 오류”| 증상 | 해결 |
|---|---|
{{job}}가 그대로 출력 | PromptConfig.bindings의 source 지정 |
env.X가 비어 있음 | LLAMON_, PROMPT_, TMPL_ prefix 사용 |
단독 Agent에서 node.x.output이 비어 있음 | node.*는 Flow 전용; input·context.* 사용 |
| metadata가 prompt에 없음 | context.userId처럼 명시적으로 binding |
PromptConfig( id="<PROMPT_ID>", bindings={ "user": {"source": "context.userId"}, "job": {"source": "input"}, },)진단 코드
섹션 제목: “진단 코드”자동화는 메시지 문자열이 아니라 안정된 진단 필드를 사용합니다.
| 명령·응답 | 사용할 값 |
|---|---|
llamon doctor --output json | diagnostics[].code, repair_id, fix_safety |
llamon graph inspect --output json | diagnostics, summary.passed |
| Studio save 409 | detail.diagnostics, expected_sha, actual_sha |
fix_safety="safe"만 자동 적용하고 manual은 검토 뒤 처리하세요.
폐쇄망 준비 오류
섹션 제목: “폐쇄망 준비 오류”| 증상 | 해결 |
|---|---|
uv.lock 없음 | uv lock 후 prepare-offline 재실행 |
wheelhouse/가 비었음 | 대상 OS·Python·ABI를 지정하고 --clean으로 다시 수집 |
| SDK wheel checksum 실패 | ./update_sdk_wheel.sh .로 wheel과 SHA 갱신 |
wheelhouse.sha256 없음 | vendor-deps를 먼저 실행하거나 prepare-offline 사용 |
| base image pull 실패 | --python-base-image로 내부 Registry image 지정 |
| Nexus에 lock 버전 없음 | Nexus 기준으로 relock한 뒤 package 재생성 |
배포 단계 문제는 SSH 원격 배포, profile 적용은 인프라 프로필을 참고하세요.
환경 설정 오류
섹션 제목: “환경 설정 오류”| 증상 | 해결 |
|---|---|
uv: command not found | shell을 다시 열거나 source $HOME/.local/bin/env |
llamon: command not found | 프로젝트에서 uv run llamon 사용 또는 uv tool install |
uv sync --frozen에서 wheel 없음 | 배포 bundle의 wheel과 .sha256 파일 확인 |
OPENAI_API_KEY 누락 | .env.example을 .env로 복사하고 key 설정 |
문제를 재현할 때는 secret을 지운 doctor --output json, 처음 실패한 traceback, 사용한 contextId, Registry model ID만 함께 남기면 대부분의 원인을 좁힐 수 있습니다.