문제 해결
AI 스택은 docker compose 하나입니다. 그래서 문제 해결의 출발점도 하나입니다 —
어느 컨테이너가 이상한지 찾고, 그 컨테이너의 로그를 본다.
cd /opt/kopens/plantpulse-ai-docker/bin
./doctor.sh # 아무것도 바꾸지 않고 진찰만 합니다. 장애 중에 먼저 돌리십시오
./status.sh # 무엇이 떠 있나
./health.sh # 디스크 · 자원 · 서비스별 최근 로그까지
스택이 뜨지 않습니다
형제 저장소 둘이 있는지부터
ls /opt/kopens
# plantpulse-ai-docker
# plantpulse-ai-inference-server ← 없으면 compose 가 뜨지 않습니다
# plantpulse-timeseries-insight-server ← 없으면 compose 가 뜨지 않습니다
compose 가 이 둘의 파일을 상대 경로로 bind-mount 합니다(예: 게이트웨이 설정 litellm-config.yaml).
없으면 설치기가 기동을 거부하고 빠진 저장소 이름을 찍습니다 → 설치 개요.
설정 파일이 있는지
sudo test -f /etc/kopens/plantpulse-ai.env && echo 있음 || echo 없음
없으면 bin/install.sh 를 다시 돌리거나 compose/env.gb10.example 을 그 경로로 복사합니다.
🔴 compose/.env 를 고치지 마십시오. 아무도 읽지 않습니다 — 정본은
/etc/kopens/plantpulse-ai.env 입니다.
기동 전 판정이 세웠는지
bin/up.sh · restart.sh · update.sh 는 compose 를 올리기 전에 env 파일을 판정하고, 어긋나면 컨테이너를 하나도
만들지 않고 멈춥니다. 2026.10 에서 가장 흔한 것은 둘입니다.
cd /opt/kopens/plantpulse-ai-docker
sudo bash bin/lint-env.sh # 줄마다 제자리인지 — 바꾸지 않습니다
| 출력 | 원인 | 조치 |
|---|---|---|
lines that do not belong in … 와 줄마다 release · profile · redundant · derived · unknown | 2026.09 이하의 env 를 그대로 올렸다 — 이미지 참조 · GPU 몫 · 기본값과 같은 값 · PP_HOST · 옛 플랫폼 계정 줄이 남아 있다 | 찍힌 sed 한 줄로 지웁니다. 지우기 전에 플랫폼 자격증명 두 값을 넣습니다 → 환경 변수 설정 |
renamed keys still use their old names | 옛 이름 CH_* 이 남았다 | 지우지 말고 찍힌 sed(이름만 바꿈)를 실행합니다 → 아래 「CH_ 접두사」 |
PP_HW_PROFILE is not set | 하드웨어 모양 줄이 없다 | GB10 이면 PP_HW_PROFILE=gb10, AWS g7e 면 g7e 를 넣습니다 |
still has template placeholders | CHANGE_ME_* 가 남았다 | 찍힌 키를 채웁니다. 공개 템플릿에 적힌 값으로는 띄우지 않습니다 |
[FATAL] [platform-credentials] … | 기동 전 DB 프로비저닝이 플랫폼 자격증명을 못 받았다 | 아래 「컨테이너가 FATAL 로 멈춥니다」와 같은 원인입니다 |
PI_INBOUND_API_KEY is empty and PI_INBOUND_AUTH_DISABLED is not true | 인바운드 키가 비었다 | 아래 「뒷단 서비스가 기동을 거부합니다」 |
PI_MEDIA_ENABLED=<값> — true 또는 false 만 받는다 | 영상 · 음성 스위치에 다른 값을 적었다 | true 나 false 로 고칩니다 → 영상 · 음성 수집 |
줄 목록에 ASR_URL … media | 호스트 env 의 ASR_URL 이 영상 · 음성 스위치가 주는 값과 다르다 | 그 줄을 지웁니다. 녹취를 켜는 것은 PI_MEDIA_ENABLED=true 한 줄입니다 |
[warn] 으로 찍히는 줄(lines to tidy — the stack starts as is)은 기동을 막지 않습니다 — 옛 이름 MEDIA_INGEST_ENABLED
(이번 릴리즈 동안 별칭, alias), 스위치와 같은 값의 ASR_URL(media-same), 새 이름과 같은 값으로 남은 옛 줄(oldname)입니다.
함께 찍힌 sed 한 줄로 정리합니다. 별칭은 2026.11 에 걷어 내므로 그 전에 옮기십시오.
compose 자체가 요구하는 값(PP_DATALAKE_ADMIN_URL · PP_DATALAKE_ADMIN_API_KEY · PP_HW_PROFILE 등)이 비었는지는
이렇게 봅니다.
docker compose --env-file /etc/kopens/plantpulse-ai.env -f compose/docker-compose.yml config >/dev/null
컨테이너 하나가 계속 재시작합니다
docker compose ps # 어느 것이 Restarting 인가
docker compose logs --tail=200 <컨테이너> # 왜 죽는가
| 자주 나오는 원인 | 확인 |
|---|---|
| GPU 를 못 잡음 | nvidia-smi · docker compose logs plantpulse-llm |
| 플랫폼 DB 에 못 붙음 | 아래 「플랫폼 DB」 |
| 메모리 부족 | docker stats · dmesg -T | grep -i oom |
| 포트 충돌 | ss -ltnp | grep -E '80|443|4000|5959|5960|7115|8970' — 설치기가 이미 «남이 쥔 포트» 로 경고했을 수 있습니다 → 서비스 포트 맵 |
| 플랫폼 자격증명을 못 받음 | 아래 「컨테이너가 FATAL 로 멈춥니다」 |
뒷단 서비스가 inbound · INBOUND_API_KEY is empty 로 멈춤 | 아래 「뒷단 서비스가 기동을 거부합니다」 |
| 코파일럿만 기동 거부 | 아래 「코파일럿만 뜨지 않습니다」 |
컨테이너가 FATAL 로 멈춥니다 — 플랫폼 자격증명
2026.10 부터 코파일럿 · 시계열 인사이트 API · LightRAG · RAG API · 디지털 스레드 · LiteLLM 은 기동할 때 플랫폼에서 계정 · 비밀번호를 받습니다. 받지 못하면 지난 값으로 뜨지 않고 FATAL 로 멈춥니다 — 그래서 이 여섯 중 여럿이 한꺼번에 재시작을 되풀이하면 여기부터 보십시오.
docker logs --tail=50 plantpulse-copilot-web 2>&1 | grep -iE 'credentials|fatal'
sudo grep -E '^PP_DATALAKE_ADMIN_(URL|API_KEY)=' /etc/kopens/plantpulse-ai.env
ls -l /etc/kopens/ca/root.crt /etc/kopens/ca/CA.crt
| 원인 | 조치 |
|---|---|
PP_DATALAKE_ADMIN_URL · PP_DATALAKE_ADMIN_API_KEY 중 하나만 있음 | 둘 다 넣습니다. 하나만 있으면 컨테이너가 거절합니다 |
/etc/kopens/ca/root.crt 가 없음 | 플랫폼 신뢰 앵커를 둡니다(같은 내용을 CA.crt 로도). 인증서 검증을 끄는 길은 없습니다 |
| 키가 틀렸거나 AI 호스트 IP 가 플랫폼 허용목록에 없음(4xx) | 플랫폼 호스트 /etc/kopens/plantpulse-platform.env 의 PP_DATALAKE_ADMIN_API_KEY 를 그대로 옮기고, 허용목록에 AI 호스트 IP 를 넣습니다. 4xx 는 재시도 없이 바로 멈춥니다 |
플랫폼 :4950 에 안 닿음 · 5xx | 잠시 재시도한 뒤 멈춥니다. curl -sk https://<플랫폼 호스트>:4950 로 닿는지부터 봅니다 |
호스트 스크립트(기동 전 DB 프로비저닝 · install.sh START=1 의 사전 확인)도 같은 값으로 받습니다. 거기서 실패하면
컨테이너가 뜨기 전에 [FATAL] [platform-credentials] … 한 줄이 이유를 말하고 멈춥니다 — 조치는 위 표와 같습니다.
받기에 성공하면 로그에 credentials: 로 시작하는 줄이 키 이름과 개수만 찍습니다. 값을 고친 뒤에는
bin/restart.sh 로 다시 만듭니다 → 설치 개요
뒷단 서비스가 기동을 거부합니다 — 인바운드 키
RAG · 시계열 인사이트 API · 문서 이해 · 비전 · 디지털 스레드는 인바운드 키가 비면 뜨지 않습니다(2026.10 재릴리즈 전에는 인증 없이 열린 채 healthy 로 떴습니다).
sudo grep -c '^PI_INBOUND_API_KEY=.' /etc/kopens/plantpulse-ai.env # 1 이면 값이 있습니다
docker logs --tail=50 plantpulse-rag-api 2>&1 | grep -iE 'inbound|fatal'
| 증상 | 원인 | 조치 |
|---|---|---|
bin/up.sh 가 컨테이너를 하나도 만들지 않고 [fail] PI_INBOUND_API_KEY is empty … 를 찍는다 | env 에 줄이 없거나 값이 비었다 — 기동 전 판정이 멈춥니다 | sudo bin/passwd.sh --generate PI_INBOUND_API_KEY 로 넣습니다(파일을 고친 뒤 스택을 다시 올립니다) |
[fail] PI_INBOUND_AUTH_DISABLED=<값> — write true or false | 무인증 스위치에 다른 값을 적었다 | true · false 로 고치거나 줄을 지웁니다 |
로그에 FATAL: RAG_INBOUND_API_KEY is empty — refusing to start … 같은 줄 | 컨테이너에 빈 키가 들어갔다 — compose 를 우회해 띄웠거나 이미지를 따로 돌렸다 | 위와 같이 키를 넣고 bin/restart.sh 로 다시 만듭니다 |
스택은 뜨는데 관리 콘솔 · 채팅의 RAG · 시계열 호출이 401 | 키를 바꾼 뒤 일부만 다시 만들었다 | bin/restart.sh 로 전체를 다시 만듭니다 — 아래 「관리 콘솔이 502 · upstream_auth」 |
인증 없이 띄우는 길은 개발용 스위치 PI_INBOUND_AUTH_DISABLED=true 하나이고, 키가 있으면 그 스위치는 무시됩니다
([note] … is ignored — PI_INBOUND_API_KEY is set and the key wins). 운영 설치에서는 키를 넣는 것이 답입니다 →
환경 변수 설정
코파일럿만 뜨지 않습니다 — 저장 자격증명 암호화 키
나머지 스택은 초록인데 plantpulse-copilot-web 만 기동을 거부한다면 PI_COPILOT_SECRET_KEY 를 봅니다.
docker logs --tail=50 plantpulse-copilot-web 2>&1 | grep -iE 'SECRET_KEY|secrets'
| 로그 | 원인 | 조치 |
|---|---|---|
PI_COPILOT_SECRET_KEY=… 한 줄을 넣으라고 찍음 | 키가 없거나 모양이 틀림 — 2026.09 이하에서 올린 호스트는 줄이 없습니다(설치기가 기존 env 에 더하지 않습니다) | openssl rand -base64 32 값으로 넣고 다시 만듭니다 → 환경 변수 설정 |
Stored secrets cannot be decrypted | 키가 바뀌었는데 옛 값을 주지 않음 | 옛 값을 PI_COPILOT_SECRET_KEY_PREVIOUS 에 둡니다 → 교체 절차. 옛 값을 잃었다면 로그가 찍는 SQL 로 봉한 행을 비우고 그 자격증명을 화면에서 다시 넣습니다 |
디지털 스레드의 PI_DT_SECRET_KEY 가 비면 스택은 뜨고 커넥터 등록부만 config_error(503)로 답합니다.
기동 전 판정(bin/lint-env.sh)이 두 키가 빠졌는지 «저장 자격증명 암호화 키가 없다» 로 알려 줍니다.
설정을 바꿨는데 코파일럿이 무시합니다 — CH_ 접두사
2026.10 에서 코파일럿 환경 변수의 접두사가 CH_ → CO_ 로 바뀌었고 폴백이 없습니다. 예전 env 의
CH_API_V1_KEY · CH_LLM_MAX_COMPLETION_TOKENS · CH_OTEL_GENAI_CONTENT 같은 줄은 코파일럿이 읽지 않습니다.
줄을 지우기만 하면 값이 기본값으로 돌아갑니다 — 예컨대 CH_API_V1_KEY 로 부르던 외부 연동은 그 키로 더는
들어오지 못합니다.
기동 전 판정은 이 줄들을 renamed 로 잡아 기동을 세우고, 줄마다 이름만 바꾸는 sed 한 줄을 찍습니다(값은
그대로, 백업을 남김). 그것을 실행하고 bin/restart.sh plantpulse-copilot-web 으로 다시 만듭니다.
cd /opt/kopens/plantpulse-ai-docker
sudo bash bin/lint-env.sh 2>&1 | grep -A2 'renamed'
옛 이름과 새 이름이 둘 다 있고 값이 다르면 새 이름이 이깁니다 — 어느 값이 맞는지 확인한 뒤 옛 줄을 지웁니다 → 환경 변수 설정
올린 뒤 로그가 안 남거나 쓰기가 실패합니다 — 볼륨 소유권
2026.10 부터 컨테이너는 plantpulse-dcgm 하나를 빼고 전부 비root 로 돕니다(우리 이미지는 uid 10001, gid 0).
옛 설치에서 root 로 만들어진 쓰기 볼륨(앱 로그 · 시계열 파인튜닝 가중치 · LightRAG · Qdrant · Neo4j · Phoenix 저장소,
vLLM 캐시, 프록시 인증서)에는 그대로 쓰지 못합니다. 그 실패는 대개 조용하고(로그 파일 대신 콘솔에만 남는 식),
Qdrant 는 바로 죽고, 프록시는 인증서 키를 못 읽어 처방을 찍고 멈춥니다.
bin/up.sh · restart.sh · update.sh 는 올리기 전에 bin/volumes-nonroot.sh 로 소유권을 한 번 맞춥니다.
docker compose up 을 맨손으로 불렀다면 이 단계를 건너뛴 것입니다.
cd /opt/kopens/plantpulse-ai-docker/bin
./volumes-nonroot.sh # 이미 맞으면 아무것도 바꾸지 않습니다
./restart.sh
맞추지 못하면 볼륨 소유권을 <uid:gid> 로 맞추지 못했다 를 찍고 기동을 멈춥니다 → 서비스 운영
플랫폼 DB 에 못 붙습니다
🔴 AI 스택은 PostgreSQL · Aster TSDB · Redis · RustFS 를 띄우지 않습니다. 플랫폼 설치본을 공용으로 씁니다. 이 넷이 죽으면 AI 도 함께 멈춥니다.
# 플랫폼 호스트는 이 URL 의 호스트입니다 (PP_HOST 는 따로 적지 않습니다)
sudo grep -E '^PP_DATALAKE_ADMIN_URL=' /etc/kopens/plantpulse-ai.env
# 실제로 닿는가
nc -zv <플랫폼 호스트> 5432 # PostgreSQL
nc -zv <플랫폼 호스트> 9042 # Cassandra
안 닿으면 플랫폼 쪽 문제입니다 → 서비스 포트 맵.
PG · Aster TSDB · Redis · RustFS 의 계정 · 비밀번호 · 포트는 컨테이너도 호스트 스크립트도 시작할 때 플랫폼에서 받습니다. 인증이 거절되면 env 가 아니라 플랫폼의 값과 위 「컨테이너가 FATAL 로 멈춥니다」를 보십시오. 플랫폼에서 비밀번호를 바꿨다면 AI 컨테이너를 다시 시작해야 새 값을 받습니다.
관리 콘솔이 502 · upstream_auth 를 띄웁니다
콘솔 화면의 한 메뉴가 … rejected the console's inbound API key (401) - check <변수> 로 실패한다면, 콘솔
뒤의 서비스가 콘솔의 인바운드 키를 거절한 것입니다 — 콘솔 세션 만료가 아닙니다. 예전 판은 이 401 을
세션 만료로 읽어 로그인 화면으로만 되돌려 보냈습니다(다시 로그인해도 같았습니다).
뒷단과 콘솔이 같은 PI_INBOUND_API_KEY 로 떠 있는지가 원인입니다. 한쪽만 다시 만들었거나 키를 바꾼 뒤
일부만 재기동한 경우가 대부분이므로, 스택 전체를 다시 만듭니다.
cd /opt/kopens/plantpulse-ai-docker && bin/restart.sh
관리 콘솔 주소는 2026.10 부터 http://<AI 서버>:5959 · https://<AI 서버>:5960 입니다(종전 9080).
LLM 화면이 502 · llm_upstream 을 띄웁니다
콘솔의 LLM 읽기 화면(API 키 · 로그 · 모델 등록 목록 · 업스트림 상태 등)이 502 와 사유 llm_upstream 으로
실패한다면, 게이트웨이(LiteLLM)나 그 DB 가 5xx 를 낸 것입니다 — 콘솔 백엔드가 터진 것이 아닙니다. 응답의
upstream_status 가 게이트웨이가 낸 상태 코드입니다. 예전 판은 이것을 500 으로 그대로 흘려 콘솔 고장처럼
보였습니다.
docker compose logs --tail=100 plantpulse-litellm # 게이트웨이가 왜 5xx 를 냈나 (DB 접속 등)
게이트웨이에 아예 닿지 못하면 같은 502 에 사유가 llm_unreachable 입니다. 4xx(입력 오류)는 게이트웨이의 사유가
그대로 화면에 나옵니다.
답이 안 나옵니다
순서대로 좁힙니다 — 게이트웨이 → 모델 → 화면.
docker compose logs --tail=100 plantpulse-litellm # 게이트웨이가 요청을 받았나
docker compose logs --tail=100 plantpulse-llm # 모델이 답했나
docker compose logs --tail=100 plantpulse-copilot-web
| 증상 | 흔한 원인 |
|---|---|
| 게이트웨이 로그에 요청이 없다 | 화면에서 게이트웨이 주소·키가 틀림 |
| 게이트웨이가 401 | PI_LLM_API_KEY 불일치 |
| 외부 연동만 모델 이름 오류로 실패 | 옛 이름(aura-35b · gpt-4o · text-embedding-3-large 등)을 부름 — 지금은 aura-lite · aura-embedding-4b 입니다 → API 연동 가이드 |
| 모델이 오래 걸리다 끊김 | GPU 메모리 부족 — nvidia-smi |
| 「답을 만들지 못했습니다 … 모델이 빈 응답을 돌려줬습니다」 | 다시 시도해도 모델이 빈 답을 냈습니다(API 로는 502). 반복되면 사고 모드와 생성 상한을 봅니다 → 환경 변수 설정 |
| 「⚠ 같은 내용이 반복되어 답변 생성을 중단했습니다」 | 모델이 같은 말을 되풀이해 코파일럿이 끊었습니다. 질문을 좁혀 다시 묻습니다 |
「연결이 끊겼습니다. 서버는 답을 계속 만들고 있어…」
묻기 도중 연결만 끊긴 것입니다(네트워크 전환 · 프록시 절단 등). 새 화면의 문구는 「연결이 끊겼습니다. 서버가 답을 마저 만들고 있어, 끝나는 대로 여기에 불러옵니다」 입니다. 서버는 답을 끝까지 만들어 저장하므로, 화면은 이 안내를 띄운 채 5초마다, 최대 5분 동안 그 대화의 답을 다시 조회해 도착하면 불러옵니다. 기다리면 됩니다 — 폰에서도 같습니다. 5분 안에 못 찾으면 오류 안내로 바뀌고 다시 시도 단추가 남습니다 — 이때는 대화를 다시 열어 답이 저장됐는지 먼저 보십시오.
문서를 못 찾습니다 (RAG)
docker compose logs --tail=100 plantpulse-rag-api
docker compose logs --tail=100 plantpulse-lightrag
curl -s http://127.0.0.1:6333/healthz # Qdrant(벡터 색인)
| 증상 | 볼 곳 |
|---|---|
| 채팅이 「문서 검색을 지금 쓸 수 없습니다(MCP 게이트웨이 응답 없음) …」 라고만 하고 답하지 않는다 | 채팅의 문서 검색은 MCP 게이트웨이로만 갑니다. 게이트웨이가 떠 있는지 — docker compose logs --tail=100 plantpulse-mcp-gateway-api, 코파일럿 로그의 [MCP_GATEWAY] unreachable · [DOC_SEARCH_GUARD]. 같은 때 다른 질문의 답 앞머리에는 「도구 게이트웨이에 닿지 않습니다 …」 가 붙습니다 |
| 채팅이 「문서 검색 도구가 꺼져 있거나 이 계정에 허용되지 않았습니다 …」 라고만 하고 답하지 않는다 | 게이트웨이는 응답하는데 rag_search 가 모델에 오지 않습니다. AI 관리 콘솔 › MCP 게이트웨이 에서 서버의 RAG Gateway 와 도구의 rag_search 가 켜져 있는지 봅니다(둘 다 처음부터 켜져 있으니 누가 끈 것입니다). 켜져 있으면 그 사람의 채팅 도구 권한(tool:mcp)과 게이트웨이 «권한» 탭을 봅니다 → RAG — 채팅의 문서 검색 |
| 넣은 문서가 검색에 안 걸린다 | 색인 작업이 끝났는지 — plantpulse-rag-api 로그 · Sync History 의 건너뛴 이유 → RAG |
| 문서 업로드가 실패한다 | plantpulse-docling-serve · plantpulse-document-understanding-api |
| 답이 엉뚱한 문서를 인용한다 | 색인이 낡음 — 다시 넣고 색인 |
| AI 가 「문서에서 찾지 못했다」고만 한다 | 정상 동작일 수 있습니다 — 검색이 빈손이면 답을 짓지 않고 retrieved: false 로 돌려줍니다. rag_list_documents 로 그 문서가 색인돼 있는지부터 봅니다 |
RAG /health 가 degraded | 응답의 ingest · neo4j · qdrant 중 ok 가 아닌 것 |
큰 PDF 가 색인 도중 실패합니다
LightRAG 는 문서 조각마다 LLM 으로 엔티티를 뽑습니다. 한 조각이 시간 안에 못 끝나면 문서 전체가 실패로 남고, 남은 조각은 시도도 하지 않습니다.
docker compose logs plantpulse-lightrag | grep -E 'Worker execution timeout|workers initialized'
| 로그 | 뜻 |
|---|---|
extract LLM func: Worker execution timeout after 480s | 예전 기본값(호출당 240초)으로 도는 설치입니다 |
(Timeouts: Func: 3600s, Worker: 7200s, …) | 지금 기본값입니다 |
시간 예산은 /etc/kopens/plantpulse-ai.env 의 LIGHTRAG_LLM_TIMEOUT(기본 3600초)이고,
실제 한도는 그 두 배입니다. 채팅과 질의가 몰려 모델이 느린 시간대에 색인이 잘리면 이 값을 봅니다.
바꾼 뒤에는 재시작이 아니라 재생성(bin/restart.sh)이 필요합니다.
한 조각의 출력 상한(LIGHTRAG_LLM_MAX_TOKENS, 기본 32768)이 함께 걸려 있어 긴 예산이 안전합니다.
상한을 지우고 예산만 늘리면 폭주한 요청 하나가 GPU 슬롯을 한 시간 붙잡습니다.
문서·사진 도구가 refused to fetch 로 실패합니다
문서 이해 · 비전 도구는 받은 URL 이 사내 주소(루프백 · 사설망 · 링크로컬) 로 풀리면 거절합니다. 사유에
resolves to a non-public address 가 보이면 이 경우입니다.
사내 파일 서버를 일부러 열어 주려면 그 호스트 이름을 FETCH_ALLOWED_HOSTS 에 적고 두 서비스를 다시 만듭니다.
URL 에 쓰는 이름 그대로(포트를 붙이면 그 포트만) 적어야 맞습니다.
echo 'FETCH_ALLOWED_HOSTS=files.example.local' | sudo tee -a /etc/kopens/plantpulse-ai.env >/dev/null
cd /opt/kopens/plantpulse-ai-docker
bin/restart.sh plantpulse-document-understanding-api plantpulse-vision-api
도면이 일반 문서로 색인되거나 도면 화면이 안 나옵니다
도면 수집은 기본으로 꺼져 있습니다(DRAWING_INGEST_ENABLED=false). 꺼져 있으면 rag-api 에 도면 API 자체가 없고,
DXF · PDF 도면은 도면으로 읽히지 않습니다.
docker exec plantpulse-rag-api printenv DRAWING_INGEST_ENABLED
false 면 호스트 env 에 DRAWING_INGEST_ENABLED=true 를 적고 bin/restart.sh plantpulse-rag-api 로 다시 만든 뒤,
도면을 다시 올립니다 — 켜기 전에 올린 파일은 도면으로 다시 읽히지 않습니다. PDF 는 올릴 때 종류를 «도면» 으로
줘야 도면으로 읽힙니다 → 환경 변수 설정
| 콘솔이 내는 말 | 뜻 |
|---|---|
drawing is platform-managed — update it in the platform, not here (409) | 플랫폼 자산 문서로 들어온 도면을 콘솔에서 덮어 올리려 했습니다(2026.10 재릴리즈 3). 고치는 것은 플랫폼에서 합니다 |
drawing is platform-managed — delete it in the platform ledger, or exclude it from RAG (POST …/exclude) (409) | 플랫폼 원장 도면을 콘솔에서 지우려 했습니다. 지우는 것은 플랫폼 원장에서 하고, 검색에서만 빼려면 «코퍼스에서 제외» 합니다 |
manually uploaded drawings cannot be excluded — delete the drawing or re-index it instead (platform-ledger drawings can be excluded) (409) | 콘솔에서 직접 올린 도면은 «검색 제외» 를 할 수 없습니다. 지우거나 다시 색인합니다. 플랫폼 원장 도면은 제외할 수 있습니다 |
extension not allowed (400) | DWG 입니다. DXF 나 PDF 로 내보내 올립니다 |
채팅에 넣은 파일을 읽지 못합니다
묻기 입력칸의 파일 넣기로 넣은 파일은 코파일럿이 받아 객체 저장소에 두고, 문서 이해 서비스(plantpulse-document-understanding-api)에
읽게 합니다 — 문서는 docling 으로, 도면은 도면 판독으로, 영상 · 음성은 녹취(/api/v1/transcribe → plantpulse-asr)로. 쓰는 법은 AI 채팅 — 파일 넣기에 있습니다.
docker logs --tail=200 plantpulse-copilot-web 2>&1 | grep -E '\[CHAT_ATTACH|\[attach\]|\[CHAT_MEDIA' # 올림 · 판독 · 녹취 · 실패 사유
docker compose logs --tail=100 plantpulse-document-understanding-api
docker compose logs --tail=100 plantpulse-docling-serve
docker compose logs --tail=100 plantpulse-asr # 영상 · 음성 — PI_MEDIA_ENABLED=true 일 때만 뜹니다
올릴 때 거절되는 것 — 칩에 아래 문장이 그대로 뜨고, 그 파일은 보내지 않습니다.
| 칩에 뜨는 말 | 원인 · 할 일 |
|---|---|
| 「이 파일 형식은 올릴 수 없습니다. 오피스(xlsx·xls·csv·docx·pptx)·PDF·도면(DXF·PDF)·영상(mp4·mov·mkv·webm)·음성(m4a·mp3·wav) 파일을 올려 주세요」 | 받는 형식이 아닙니다. 형식은 내용으로 판정하므로 확장자만 바꿔서는 들어가지 않습니다 |
| 「영상·음성 파일의 이름과 내용이 맞지 않습니다 …」 | 확장자는 영상 · 음성인데 파일 머리가 그 형식이 아닙니다. 변환기에서 확장자만 바꾼 파일이면 원래 형식으로 다시 내보냅니다 |
| 「영상·음성 파일이 너무 큽니다(최대 1GB)」 | 영상 · 음성은 1GB 까지입니다. 나누거나 해상도를 낮춰 넣습니다 |
| 「영상·음성이 너무 깁니다(최대 60분). 잘라서 올려 주세요」 | 60분이 넘습니다. 앞부분만 받지 않습니다 — 잘라서 나눠 넣습니다 |
| 「지금은 녹취를 기다리는 파일이 많습니다. 잠시 뒤 다시 올려 주세요」 | 설치 전체에서 녹취를 기다리거나 올리는 중인 영상 · 음성이 4개입니다. 앞의 것이 처리되면 다시 넣습니다 |
| 「DWG 는 읽지 못합니다. DXF 나 PDF 로 내보내 올려 주세요」 | CAD 에서 DXF 나 PDF 로 내보내 넣습니다 |
| 「사진은 이미지로 붙여 주세요(입력칸에 놓으면 이미지로 붙습니다)」 | 사진 파일이 첨부 길로 왔습니다. 입력칸에 다시 넣으면 사진으로 붙습니다 |
| 「파일이 너무 큽니다(최대 50MB)」 | 파일 하나는 50MB 까지입니다. 나눠서 넣습니다 |
| 「한 대화에는 파일을 20개까지 올릴 수 있습니다」 | 이 대화에 이미 20개가 있습니다. 새 대화에서 넣습니다 |
| 「파일이 비어 있습니다」 | 0바이트 파일입니다 |
| 「이 파일을 읽지 못했습니다: 손상됐거나 끝까지 받지 못했습니다」 | 파일이 깨졌거나 올리는 중에 끊겼습니다. 원본을 열어 본 뒤 다시 넣습니다 |
| 「파일 구조가 너무 커서 받지 않았습니다(압축을 푼 크기·항목 수 상한)」 | 오피스 파일 안의 항목이 2만 개를 넘거나 풀린 크기가 500MB 를 넘습니다 |
| 「파일을 저장하지 못했습니다. 잠시 뒤 다시 올려 주세요」 | 객체 저장소에 쓰지 못했습니다. 코파일럿 로그와 객체 저장소 상태를 봅니다 |
올린 뒤 판독이 실패한 것 — 칩에 「이 파일을 읽지 못했습니다: 사유」 가 뜹니다. 사유는 서버가 남긴 영어 문장입니다. 이 파일은 보낼 수 있고, AI 는 «읽지 못한 파일» 로 압니다.
| 사유 | 원인 · 할 일 |
|---|---|
document reader unreachable · drawing reader unreachable | 문서 이해 서비스에 닿지 못했습니다. plantpulse-document-understanding-api 가 떠 있는지 봅니다 |
document reader is not configured | 코파일럿에 문서 이해 서비스 주소가 없습니다. 기본 compose 에서는 생기지 않습니다 — 설정을 손으로 바꿨는지 봅니다 |
reading took longer than 10 min | 판독이 10분을 넘었습니다. 큰 PDF 이거나 색인 작업과 겹친 때입니다. 파일을 빼고 한산할 때 다시 넣거나, 필요한 쪽만 잘라 넣습니다 |
too many files are being read — remove it and add it again | 동시에 읽는 파일이 너무 많습니다. 칩을 빼고 잠시 뒤 다시 넣습니다 |
reading was interrupted — remove the file and add it again | 판독 중에 코파일럿이 다시 시작했습니다(15분 넘게 진행이 없으면 이렇게 접습니다). 빼고 다시 넣습니다 |
document reader answered 503 등 숫자 | 문서 이해 서비스가 바쁘거나 키가 맞지 않습니다. 문서 이해 로그를 봅니다 |
| 그 밖의 문장 | 문서 이해 서비스가 준 사유 그대로입니다(예: 열리지 않는 옛 오피스 파일). 원본을 PDF 나 새 형식(xlsx · docx · pptx)으로 다시 저장해 넣습니다 |
영상 · 음성의 녹취가 실패한 것 — 칩에 「녹취하지 못했습니다: 사유」 또는 「받지 않았습니다: 사유」 가 뜹니다. 사유는 문서 이해 서비스가 준 영어 문장 그대로입니다. 연결 · 혼잡 같은 일시 실패는 1 · 5 · 30초 뒤 세 번 다시 해 본 뒤에 실패로 접고, 설정 · 입력 문제는 바로 실패로 접습니다. 실패한 파일도 보낼 수 있고 원본도 재생되지만, AI 는 «받아 적지 못한 파일» 로 압니다.
| 사유 | 원인 · 할 일 |
|---|---|
media transcription is disabled: ASR_URL is not set | 영상 · 음성이 꺼진 설치입니다. 관리자가 호스트 env 에 PI_MEDIA_ENABLED=true 를 넣고 녹취 모델을 받아 다시 띄웁니다 → 영상 · 음성 수집 |
media transcription is misconfigured: … | 녹취 설정이 맞지 않습니다(서빙 이름 등). 문서 이해의 /health 와 로그를 봅니다 |
transcription service unreachable · transcription service answered 503 등 | 문서 이해 서비스나 녹취 서빙(plantpulse-asr)에 닿지 못했거나 바빴습니다. 둘이 떠 있는지 보고 빼고 다시 넣습니다 |
transcription service is not configured | 코파일럿에 문서 이해 서비스 주소가 없습니다. 기본 compose 에서는 생기지 않습니다 |
| 「받지 않았습니다: …」(길이 초과) | 머리에서 길이를 읽지 못해 받은 파일이 받아 적는 중에 60분을 넘었습니다. 잘라서 넣습니다 |
| 다른 증상 | 원인 |
|---|---|
| 보내기가 눌리지 않고 「파일을 읽는 중입니다 — 다 읽으면 보낼 수 있습니다」 가 남아 있다 | 판독이 끝나지 않았습니다. 다 읽거나 실패하면 풀립니다. 읽는 중인 파일을 빼도 풀립니다 |
| 「첨부 파일을 아직 읽는 중입니다. 다 읽은 뒤 보내 주세요」 | 보내는 순간 서버에서 아직 읽는 중인 파일이 있었습니다. 칩이 «읽음» 이 된 뒤 다시 보냅니다 |
| 칩을 눌렀더니 「이 파일을 찾을 수 없습니다. 지워졌거나 볼 수 없는 파일입니다」 | 파일이 지워졌거나 남의 대화의 파일입니다. 첨부는 대화의 주인만 엽니다(관리자도 같습니다) |
| 칩을 눌렀더니 「파일을 불러오지 못했습니다. 잠시 뒤 다시 열어 주세요」 | 객체 저장소에서 원본이나 읽은 글을 가져오지 못했습니다 |
| 파일은 «읽음» 인데 AI 가 파일 내용을 모른다고 한다 | 그 사람에게 채팅 도구 권한 tool:builtin 이 없으면 AI 가 첨부를 읽는 도구를 받지 못합니다 → 권한 |
| 긴 문서의 뒷부분을 AI 가 모른다 | 앞 100쪽(시트 · 슬라이드는 하나를 한 쪽으로)만 읽습니다. 필요한 부분을 잘라 넣습니다 |
| PDF 도면의 치수 · 부품표를 엉뚱하게 읽는다 | 문서로 읽힌 것입니다. 칩의 도면 단추를 눌러 도면으로 다시 읽힌 뒤 보냅니다 |
| 영상을 넣고 물었는데 AI 가 「아직 받아 적는 중」 이라고 한다 | 녹취가 끝나지 않았습니다. 5분 · 200MB 이하는 질문이 20초까지 기다리고, 그보다 긴 파일은 뒤에서 받아 적습니다. 「녹취 준비됨」 이 된 뒤 다시 묻습니다 |
| 칩이 오래 「녹취 대기 중」 에 머문다 | 받아 적기는 설치 전체에서 한 번에 하나씩, 넣은 순서대로 합니다(짧은 파일 먼저). 앞의 파일이 끝나기를 기다립니다. 계속 그대로면 [CHAT_MEDIA 로그를 봅니다 |
| 「말·자막을 찾지 못했습니다」 | 말소리도 내장 자막도 없습니다. 화면 글자 · 입힌 자막은 읽지 않습니다 |
| 영상이 재생되지 않는다 | 브라우저가 못 여는 코덱(예: H.265)입니다. 받아 적기와 답은 그대로 됩니다 |
| 큰 영상을 올리다 HTML 413 이 뜬다 | 프록시의 채팅 첨부 경로는 1040MB 로 열려 있습니다(호스트의 MEDIA_MAX_FILE_MB 를 따르지 않습니다). 프록시 이미지를 손으로 바꿨거나 앞에 다른 프록시가 있는지 봅니다 |
음성으로 묻기가 「지금 음성 입력을 쓸 수 없습니다」로 끝납니다
채팅의 음성으로 묻기는 녹음을 문서 이해 서비스의 녹취 입구로 보내고, 문서 이해가 녹취 서빙(plantpulse-asr)을
부릅니다. 이 안내(「…녹취 서비스가 꺼져 있거나 바쁩니다」)는 그 길 어딘가가 닫혀 있다는 뜻입니다. 코파일럿 로그에
문서 이해가 낸 상태 코드가 남습니다.
docker logs --tail=100 plantpulse-copilot-web 2>&1 | grep '\[voice\]' # 예: [voice] doc-und answered 503: …
docker exec plantpulse-document-understanding-api printenv ASR_URL # 비었으면 영상 · 음성이 꺼진 설치
cd /opt/kopens/plantpulse-ai-docker && bin/status.sh # plantpulse-asr · plantpulse-asr-audio
| 원인 | 보이는 것 | 조치 |
|---|---|---|
| 영상 · 음성이 꺼져 있다(기본) | 문서 이해의 ASR_URL 이 비어 있고, 녹취 입구가 503(media transcription is disabled: ASR_URL is not set) | 호스트 env 에 PI_MEDIA_ENABLED=true 를 넣고 녹취 모델을 받은 뒤 bin/restart.sh → 영상 · 음성 수집 |
| 켰는데 문서 이해가 옛 값으로 떠 있다 | ASR_URL 이 여전히 비어 있음 | 스위치를 바꾼 뒤 docker restart 가 아니라 bin/restart.sh 로 다시 만듭니다 |
plantpulse-asr 가 unhealthy · 재시작 반복 | 문서 이해 /health 의 components.asr.status 가 down, 전체 status 가 degraded | docker logs plantpulse-asr — 모델(/opt/kopens/models/Aura-ASR-Turbo)이 없으면 bin/fetch-models.sh 로 받습니다. 첫 기동은 컴파일 때문에 오래 걸릴 수 있습니다 |
plantpulse-asr-audio 가 0 이 아닌 코드로 끝났다 | bin/status.sh 에서 «Exited (0)» 이 아님. 이것에 기대는 plantpulse-asr 도 뜨지 않습니다 | docker logs plantpulse-asr-audio 를 보고, 이미지가 받아졌는지 확인한 뒤 bin/restart.sh |
| 녹취 서빙이 바쁘다 | 영상 처리와 겹친 시간 | 잠시 뒤 다시 합니다 |
plantpulse-asr-audio 가 «Exited (0)» 으로 남아 있는 것은 정상입니다 — 오디오 라이브러리를 볼륨에 옮기고 끝나는
일회성 서비스이고, bin/status.sh 도 정상으로 셉니다.
| 다른 안내 | 원인 |
|---|---|
| 「음성 입력은 HTTPS 주소에서만 됩니다」 | 브라우저가 평문 주소에서는 마이크를 주지 않습니다. https:// 로 접속합니다 |
| 「마이크 권한이 거부됐습니다」 | 주소창의 자물쇠 → 마이크 «허용» |
| 「녹음이 너무 깁니다(최대 60초)」 · 「녹음이 너무 큽니다(최대 4MB)」 | 질문 한 번은 60초 · 4MB 까지입니다 |
| 「말소리를 알아듣지 못했습니다」 | 녹취가 빈 결과였습니다. 마이크에 가까이 대고 다시 말합니다 |
MCP 도구가 안 보입니다
PP_API_URL · PP_API_TOKEN 은 비어 있으면 스택이 뜨지 않지만, 토큰이 틀리면 스택은 정상으로 뜨고 채팅의 플랫폼
MCP 도구만 0개가 됩니다. 그래서 「고장」처럼 안 보입니다.
sudo grep -E '^PP_API_(URL|TOKEN)' /etc/kopens/plantpulse-ai.env
값을 채운 뒤에는 재시작이 아니라 재생성이 필요합니다 — docker restart 는 env 를 다시
읽지 않습니다.
cd /opt/kopens/plantpulse-ai-docker && bin/restart.sh
시계열 분석이 안 됩니다
docker compose logs --tail=100 plantpulse-timeseries-insight-api # :8970
docker compose logs --tail=100 plantpulse-timeseries-insight-server # :8980 (호스트에는 안 열립니다)
이 둘은 플랫폼 Aster TSDB 에서 값을 읽습니다. 위 「플랫폼 DB」를 먼저 확인하십시오.
예측이 500 이거나, 전부 NAIVE 로 옵니다
설정 오류는 서버를 죽이지 않습니다 — 같은 프로세스가 이상탐지도 서비스하므로 무관한 기능까지 멈추지는 않습니다. 먼저 추론 서버의 /health 를 봅니다.
# 이 이미지에는 curl 이 없습니다 — python 으로 찌릅니다
docker compose exec plantpulse-timeseries-insight-server \
python -c "import urllib.request; print(urllib.request.urlopen('http://localhost:8980/health').read().decode())"
models.ttm.loaded: false 에 status: "degraded" 면 예측 모델이 못 올라온 것이고, error 에 이유가
있습니다. models 항목이 아예 없으면 이전 판이라 헬스체크로는 안 보입니다 — 아래 로그로
가리십시오.
docker compose logs plantpulse-timeseries-insight-server | grep -E 'MODEL_LOAD|WARMUP|INFER_FORECAST|fallback naive'
| 로그 | 뜻 | 할 일 |
|---|---|---|
[MODEL_WARMUP_FAIL] TTM ch=… 설정이 체크포인트와 맞지 않는다 | 체크포인트 세대와 로더 클래스가 어긋났습니다. 예측은 500 입니다 | TS_TTM_MODEL_CLASS 를 비워 두거나(체크포인트가 고름) 세대에 맞춥니다 → 설명 |
[MODEL_LOAD_FAIL] … 무작위 초기화 모델로 대체하지 «않는다» | 같은 원인입니다. 적재를 거부한 자리입니다 | 위와 같습니다 |
[MODEL_WARMUP_SKIP] TTM ch=… | 2026-09-21 이전 판의 같은 원인입니다. 그 판에서는 예측이 200 에 model_used="NAIVE" 로 나옵니다 | 위와 같습니다 |
TTM 을 돌릴 데이터가 모자라다 -> fallback naive. reason=… | 데이터 부족. 200 에 NAIVE 입니다 — 지금 판은 이것만 단순 외삽으로 흡수합니다 | reason 을 읽습니다 |
TTM failed -> fallback naive. reason='<태그>_prediction_q0.1' | 모든 예측이 NAIVE 로 옵니다. R3 가중치는 실렸는데 분위수 열 이름 수정이 빠진 이미지입니다(예: 2026.09-20260924-1004) | 수정이 들어간 이미지로 다시 받습니다(./update.sh) |
TTM failed -> fallback naive. reason=… (그 밖) | 이전 판의 폴백입니다 — 그 판은 데이터 부족 외의 실패도 200 NAIVE 로 삼켰습니다 | reason 을 읽습니다 |
NAIVE 로 답한 경우에는 응답의 fallback_reason 에도 같은 이유가 담겨 옵니다 — 로그에 못 들어가는 자리에서는 그쪽을 보십시오.
설정 오류가 단순 외삽으로 둔갑하던 것을 2026-09-21 에 고쳤습니다. 예전 판은 /health 정상 · 예측 200 · 모든 답이 조용히 단순 외삽인 채로 돌 수 있었습니다. 어느 판이든 볼 곳은 같습니다 — 위 로그와 TS_TTM_MODEL_CLASS 입니다.
판 번호로 가리지 마십시오 — 이 달의 이미지는 2026.09-<날짜>-<시각> 으로 여러 번 다시 구워집니다. 위 로그 줄이 가장 확실한 구분입니다.
설정을 바꿨는데 수치가 한 자리도 안 변했습니다
그러면 그 설정은 안 먹은 것입니다. 모델 라이브러리의 파라미터는 모르는 이름을 조용히 삼키는 경우가 있어, 잘못 준 값이 오류 없이 무시됩니다. 실제로 이상탐지의 집계·평활 파라미터(aggr_win_size · smoothing_window_size)가 라이브러리 인자 개명 이후 전부 무시된 채로 돌고 있었고(2026-07-24 감사), 그동안 오류도 경고도 없었습니다.
「오류가 안 났다」는 확인이 아닙니다. 바꾸기 전후의 점수 분포나 탐지 건수를 비교해서, 한 자리도 안 변했으면 설정이 닿지 않은 것으로 보십시오.
극단값으로 한 번 시험해 보는 것이 가장 빠릅니다 — 값을 크게 바꿨는데 결과가 똑같다면 그 설정은 닿고 있지 않습니다.
디스크가 찹니다
docker system df
df -h /data1
컨테이너 로그는 도커가 회전시키므로 손으로 지울 것이 없습니다. 대개 이미지와 볼륨입니다.
docker image prune -f # 태그 없는 옛 이미지
docker volume prune 을 함부로 돌리지 마십시오Neo4j · Qdrant · LightRAG 저장소가 볼륨에 있습니다. 컨테이너가 내려간 사이에 돌리면 지식 그래프와 벡터 색인이 사라집니다.
긴급 복구
cd /opt/kopens/plantpulse-ai-docker/bin
./restart.sh # 스택 전체. 0 이면 «쓸 수 있다» 는 뜻입니다
docker compose restart plantpulse-lightrag # 하나만
이미지를 새로 받아 올리려면:
./update.sh
LightRAG 원본 문서 · 색인 · 지식 그래프는 이름 붙은 도커 볼륨에 있습니다
(pi-lightrag-inputs · pi-lightrag-storage · pi-qdrant-data · pi-neo4j-data, 2026.10 부터 공장 그래프
거울의 pi-digital-thread-neo4j-data 와 시계열 파인튜닝 가중치 pi-ttm-tuned-models).
호스트 디렉토리가 아니므로 rm -rf 로는 지워지지 않고, 반대로 docker volume prune 한 번에
같이 날아갑니다. 지우기 전에 반드시 백업하십시오 — bin/backup.sh 가 compose 볼륨(로그 · 캐시 제외)을 받습니다.