본문으로 건너뛰기

환경 변수 설정

PlantPulse AI 의 설정은 /etc/kopens/plantpulse-ai.env 한 파일에서 출발합니다.

sudo vi /etc/kopens/plantpulse-ai.env
설정 정본은 /etc/kopens/ 밑이다

경로는 /etc/kopens/plantpulse-ai.env 입니다. 설치 디렉터리 (/opt/kopens/plantpulse-ai-docker) 안이 아니라 repo 트리 밖에 있고, 권한은 0600 입니다. platform · ai · studio 세 제품이 같은 규약으로 /etc/kopens/plantpulse-<제품>.env 를 씁니다.

🔴 compose/.env 를 고치지 마십시오. 아무도 읽지 않습니다 — 스택은 바뀌지 않습니다.

비밀번호·API 키는 직접 편집하지 마세요

아래 표의 *_PASSWORD · *_API_KEY 는 파일만 고쳐서는 반영이 끝나지 않습니다. Neo4j 처럼 서버 계정이 정본인 값은 서버측도 함께 바꿔야 하고, 순서를 틀리면 인증이 깨진 채로 남습니다. 전용 도구를 쓰세요 — 비밀번호 · API 키 변경.

값은 세 곳에 삽니다 (2026.10)​

2026.10 부터 호스트 env 에는 이 설치에만 있는 값만 둡니다. 나머지는 릴리즈와 함께 버전 관리됩니다.

어디무엇바꾸는 법
호스트 env /etc/kopens/plantpulse-ai.env하드웨어 모양(PP_HW_PROFILE) · 사이트 값(언어 · 시간대 · 인증서 이름) · 플랫폼 연결 · 비밀이 파일을 고치고 서비스를 다시 만듭니다
하드웨어 프로파일 compose/profiles/<모양>.env하드웨어마다 다른 값 — vLLM 세 벌의 GPU 몫과 그 합의 한계릴리즈가 정합니다
compose 기본값제품 기본값 — 이미지 · 모델 이름과 경로 · 서비스 튜닝릴리즈가 정합니다. 호스트 env 에 다른 값을 적으면 그 설치만 덮어씁니다

PP_HW_PROFILE 은 gb10(GB10 · aarch64) 또는 g7e(AWS g7e · x86_64)입니다. 템플릿이 이미 적어 두며, 없거나 기계의 아키텍처와 어긋나면 기동하지 않습니다.

아래 표들에서 호스트 env 템플릿에 없는 변수(기본값이 적힌 것)는 compose 기본값입니다. 그대로 쓰는 것이 정상이고, 바꿀 때만 그 줄을 호스트 env 에 다른 값으로 적습니다.

값을 바꾼 뒤에는 서비스를 다시 만들어야 합니다(docker restart 는 env 를 다시 읽지 않습니다).

cd /opt/kopens/plantpulse-ai-docker
bin/restart.sh

기동 스크립트는 올리기 전에 bin/lint-env.sh 로 이 파일의 줄마다 제자리인지 판정하고, 아래 중 하나라도 있으면 기동하지 않습니다.

판정무엇
release이미지 참조 — DOCKER_REGISTRY · DOCKER_NAMESPACE · UPSTREAM_* · *_IMAGE · PI_IMAGE_TAG_* · 값이 있는 PP_IMAGE_TAG
profile하드웨어 프로파일 키(LLM_GPU_UTIL 등)
redundantcompose 기본값을 그대로 되풀이한 줄
derivedPP_HOST — PP_DATALAKE_ADMIN_URL 의 호스트에서 계산됩니다
unknown어디에서도 읽지 않는 키
renamed이름이 바뀐 옛 키(CH_* → CO_*) — 지우라가 아니라 «옮기라» 고 말합니다(아래 「코파일럿 설정」)

그 밖에 값 자리의 ${…} 치환, PP_HW_PROFILE 없음, GPU 몫 초과도 기동을 세웁니다. compose 기본값과 다른 값은 의도한 덮어쓰기로 보고 알림([note])만 띄웁니다. 판정은 줄마다 이유를 찍고, 지울 줄을 한 번에 지우는 sed 명령(백업을 남기는 형태)도 함께 찍습니다. renamed 줄은 지울 목록에 넣지 않고, 이름만 바꾸는 sed 를 따로 찍습니다. 값은 찍지 않습니다.

그대로 두어도 아무것도 바뀌지 않는 줄은 [warn] 으로만 말하고 기동을 막지 않습니다 — 이번 릴리즈 동안 옛 이름으로도 읽는 별칭(alias), 새 이름과 같은 값으로 남은 옛 줄(oldname), 영상 · 음성 스위치가 주는 값과 같은 줄(media-same)입니다. 판정은 이것들을 한 번에 정리하는 sed 한 줄을 함께 찍고, bin/doctor.sh 는 이 줄들을 «bad» 가 아니라 «old or redundant lines» 로 따로 보여 줍니다. 영상 · 음성 스위치의 값이 true · false 밖이거나 PI_INBOUND_API_KEY 가 비었으면 기동을 세웁니다(아래 「영상 · 음성 수집」 · 「뒷단 인바운드 키」).


이미지와 레지스트리​

🔴 2026.10 부터 이미지 참조는 호스트 env 에 적지 않습니다. 어느 이미지 · 어느 태그로 뜰지는 릴리즈의 compose 가 정하고, 호스트 env 에 아래 변수가 있으면 기동 전 판정이 release 로 기동을 세웁니다. 호스트에 남은 핀이 다음 릴리즈를 가리고, 번들을 구울 때 거기로 새어 나간 일이 있었기 때문입니다.

변수뜻
DOCKER_REGISTRY · DOCKER_NAMESPACE자체 이미지를 받아오는 곳 (docker.kopens.io / pi)
UPSTREAM_DOCKERHUB · UPSTREAM_NVCR외부 이미지를 대신 받아 주는 사내 프록시
PP_IMAGE_TAG세트 기본 태그. 템플릿에 빈 줄로만 남아 있습니다
PI_IMAGE_TAG_<컴포넌트>한 컴포넌트만 다른 스냅샷에 묶을 때 (핫픽스 · 롤백). 열세 개이고 접미어는 이미지 이름을 대문자로 쓴 것입니다(plantpulse-timeseries-insight-api → PI_IMAGE_TAG_TIMESERIES_INSIGHT_API)

비상시 한 컴포넌트만 다른 태그로 띄워야 하면 파일이 아니라 셸 환경으로 그 실행에만 줍니다. 다음 평범한 기동은 릴리즈 태그로 돌아갑니다.

cd /opt/kopens/plantpulse-ai-docker
PI_IMAGE_TAG_RAG_API=<태그> bin/up.sh

2026.10 에서 자체 이미지가 열둘이 됐습니다 — 디지털 스레드(plantpulse-digital-thread-api)가 새로 들어왔고, LightRAG 와 LiteLLM 도 원본 이미지를 그대로 쓰지 않고 우리가 감싼 이미지 (pi/plantpulse-lightrag · pi/plantpulse-litellm)로 바뀌었습니다. 감싼 두 이미지도 다른 자체 이미지처럼 월 태그(2026.10)를 따르고, 하나만 고정할 때는 PI_IMAGE_TAG_LIGHTRAG · PI_IMAGE_TAG_LITELLM 을 씁니다. 감싼 바탕은 LightRAG v1.5.7 · LiteLLM v1.103.0 입니다.

2026.10 재릴리즈 3 에서 하나가 더 늘어 열셋입니다 — 녹취 서빙이 쓰는 오디오 라이브러리 이미지 pi/plantpulse-asr-audio(약 130 MB, 고정할 때 PI_IMAGE_TAG_ASR_AUDIO)입니다. 영상 · 음성을 켠 설치에서만 뜨지만 번들에는 늘 실립니다(아래 「영상 · 음성 수집」).

PP_IMAGE_TAG 는 비워 둡니다

비워 두면 compose 에 박힌 칼버 리터럴을 씁니다. 그 리터럴은 릴리즈마다 bin/bump-version.sh 가 옮기므로 릴리즈 월의 집이 한 곳뿐입니다. 값을 적으면 기동 전 판정이 기동을 세웁니다.

YYYY.MM 은 «움직이는» 태그입니다

같은 달 안에 다시 릴리즈하면 덮어씁니다. 시점을 못 박으려면 날짜 태그 (YYYY.MM-YYYYMMDD)를 위의 셸 환경 방식으로 주되, 이미지마다 있는지 확인하고 있는 것만 개별 고정하십시오 — 전부에 있지는 않아서 통째로 바꾸면 없는 것이 pull 에 실패합니다.

관리 콘솔은 이미지가 둘입니다 — 고정할 때 쓰는 변수는 PI_IMAGE_TAG_ADMIN_API 와 PI_IMAGE_TAG_ADMIN_WEB 입니다(둘 다 비면 PP_IMAGE_TAG 를 따라갑니다). 같은 커밋에서 나오므로 개별 고정할 때도 둘을 항상 같이 묶으십시오. 갈리면 콘솔이 자기가 부르지 않는 API 를 가진 백엔드와 짝지어집니다.


언어와 시간대​

변수기본값뜻
PP_LANGko설치의 기본 언어 — 메일 · 예약 실행 · 저장 글처럼 요청이 없는 자리의 언어입니다. 자동화의 요약 · 회차 사유 · PDF 절 이름 · Excel 시트 이름처럼 서버가 쓰는 자동화의 글도 이 언어입니다 → 자동화 — 보고서의 제목. 코파일럿 화면은 직접 고른 언어 → 브라우저 언어가 앞서고, 둘 다 한국어 · 영어가 아닐 때만 이 값입니다 → 화면 언어. 관리 콘솔은 홈 카드 이름만 이 값을 따르고, 나머지 화면은 로그인 화면의 언어 전환(English · 한국어)이 정합니다 · 값은 ko · en 둘뿐입니다. 비었거나 그 밖의 값이면 서비스가 기동하지 않습니다(설치 템플릿 기본 ko)
PP_TZAsia/Seoul설치 하나의 시간대 — 전 서비스와 호스트 OS 가 이 하나를 씁니다. 설치기가 고릅니다(설치 때 준 값 → 이미 env 에 있던 값 → 호스트 시간대(UTC 가 아니면) → Asia/Seoul 순)
LIGHTRAG_SUMMARY_LANGUAGEKoreanRAG 가 지식을 요약하는 언어

요약 언어를 화면 언어와 따로 두는 이유는, 화면은 영어로 쓰더라도 코퍼스(현장 SOP)가 한국어인 경우가 많기 때문입니다.


플랫폼에서 빌려 쓰는 것​

🔴 AI 스택은 PostgreSQL · Aster TSDB · Redis · RustFS 를 띄우지 않습니다. 플랫폼 설치본을 공용으로 씁니다. 이 값들이 틀리면 AI 는 뜨긴 해도 아무것도 저장하지 못합니다.

플랫폼 자격증명은 컨테이너가 «시작할 때» 받습니다​

2026.10 부터 플랫폼 저장소의 계정 · 비밀번호 · 포트(PG · Aster TSDB · Redis · RustFS)를 compose 가 컨테이너에 넘기지 않습니다. 그것을 쓰는 여섯 서비스(copilot-web · timeseries-insight-api · lightrag · rag-api · digital-thread-api · litellm)가 기동할 때 플랫폼의 자격증명 API 에서 받아 자기 이름으로 옮긴 뒤 앱을 띄웁니다. 호스트 env 에 적는 것은 그 API 를 부를 주소와 키 둘뿐입니다.

변수뜻
PP_DATALAKE_ADMIN_URL플랫폼 데이터레이크 관리 API — https://<플랫폼 호스트>:4950. 이 URL 의 호스트가 곧 플랫폼 호스트입니다
PP_DATALAKE_ADMIN_API_KEY그 API 의 키. 플랫폼 호스트 /etc/kopens/plantpulse-platform.env 의 같은 이름 줄을 그대로 옮깁니다

템플릿에는 두 줄이 자리표시자 값으로 들어 있고, 대화형 설치(INTERACTIVE=1)는 두 값을 묻습니다. 받기에 필요한 준비는 설치 개요 에 있습니다(플랫폼 허용목록 · 신뢰 앵커 root.crt).

받지 못하면 그 컨테이너는 «멈춥니다»
  • 두 값 중 하나만 적으면 컨테이너가 거절합니다.
  • 받기에 실패하면 FATAL 로 멈춥니다(연결 실패 · 5xx 는 잠시 재시도, 4xx 는 즉시). 지난번 값으로 뜨는 캐시는 없습니다.
  • 서버 인증서는 /etc/kopens/ca/root.crt 로만 검증합니다. 파일이 없으면 FATAL 이고, 검증을 끄는 길은 없습니다.

플랫폼에서 비밀번호를 바꿨다면 AI 쪽에서 고칠 파일은 없습니다 — 그 컨테이너를 다시 시작하면 새 값을 받습니다. 받은 값은 로그에 키 이름과 개수만 남습니다(docker logs <컨테이너> 2>&1 | grep credentials:).

호스트 스크립트도 같은 길로 받습니다. 기동 전 DB 프로비저닝(provision-platform-db.sh), 손으로 돌리는 DB 이전 스크립트, install.sh START=1 의 사전 확인이 같은 API 를 같은 규칙(root.crt 로 검증)으로 부릅니다. 그래서 호스트 env 에도 플랫폼 계정 · 비밀번호가 없습니다. 실패하면 [FATAL] [platform-credentials] … 한 줄로 이유(닿지 않음 · 401/403 · 키 없음 · URL/키/CA 없음)를 말하고 멈춥니다. 플랫폼에 닿지 않는 자리에서 시험할 때만 그 실행의 셸 환경으로 값을 주면 그것이 이깁니다.

호스트 env 에 남는 플랫폼 값은 아래뿐입니다.

변수뜻
PP_DATALAKE_ADMIN_URL · PP_DATALAKE_ADMIN_API_KEY위 — 자격증명을 받을 곳
PP_API_URL · PP_API_TOKEN플랫폼 V5 API — 자격증명 저장소에 없는 값이라 호스트 env 에 남습니다(아래 「플랫폼 통합 MCP」)
PP_PG_PORT · PP_CASSANDRA_PORT템플릿에 주석으로만 있습니다. 호스트 스크립트만 읽고, 플랫폼 기본 포트면 비워 둡니다

플랫폼 호스트(PP_HOST)는 적지 않습니다 — PP_DATALAKE_ADMIN_URL 의 호스트가 곧 그것이고, 컨테이너와 호스트 스크립트가 같은 규칙으로 계산합니다. AI 가 쓰는 PG 데이터베이스 이름(PP_LIGHTRAG_PG_DB 기본 lightrag 등)은 compose 기본값입니다.

AI 앱 자신의 PG 데이터는 플랫폼 PG 의 DB pi 에 앱마다 스키마를 나눠 둡니다(코파일럿 co · 디지털 스레드 dt, 계정은 PP_PG_USER). 옛 설치의 DB ch 는 기동할 때 pi.co 로 옮겨집니다.

2026.10 으로 올릴 때 — 옛 env 는 그대로는 뜨지 않습니다

설치기와 update.sh 는 이미 있는 env 를 다시 만들지 않습니다. 2026.09 이하의 env 에는 이제 제자리가 아닌 줄 — 이미지 참조, GPU 몫, compose 기본값과 같은 값, PP_HOST, 플랫폼 계정 · 비밀번호 (PP_PG_USER · PP_PG_PASSWORD · PP_CASSANDRA_* · PP_REDIS_PASSWORD · PP_S3_* 등) — 이 많이 남아 있어 기동 전 판정이 기동을 세웁니다. 올리기 전에 정리하십시오.

cd /opt/kopens/plantpulse-ai-docker
sudo bash bin/lint-env.sh # 무엇이 남았나 — 바꾸지 않습니다
sudo cp -p /etc/kopens/plantpulse-ai.env ~/plantpulse-ai.env.bak-$(date +%Y%m%d-%H%M)
# lint-env 가 찍은 sed 한 줄을 그대로 실행한 뒤, 하드웨어 모양을 더합니다(GB10 = gb10 · g7e = g7e)
grep -q '^PP_HW_PROFILE=' /etc/kopens/plantpulse-ai.env || echo 'PP_HW_PROFILE=gb10' | sudo tee -a /etc/kopens/plantpulse-ai.env >/dev/null
sudo bash bin/lint-env.sh && bin/restart.sh
  • 지우기 전에 넣을 것 — PP_DATALAKE_ADMIN_URL · PP_DATALAKE_ADMIN_API_KEY 를 새로 넣고 신뢰 앵커를 둡니다. 옛 플랫폼 계정 줄은 판정이 «지우라» 고만 말하므로 이 둘을 먼저 넣으십시오.
  • 옛 CH_* 줄은 판정이 renamed 로 잡고 이름만 바꾸는 sed 를 따로 찍습니다 — 그것을 실행하면 값은 그대로 CO_* 로 옮겨집니다(아래 「코파일럿 설정」).
  • 일부러 기본값과 다르게 둔 값(예: 모델 경로)은 override 알림으로 남고 지워지지 않습니다.
설비 알람은 MQTT 로 받습니다

코파일럿은 플랫폼의 설비 알람을 MQTT 로 구독합니다(2026.09, 종전 Kafka). 브로커 주소는 PP_API_URL 의 호스트를 따르고 포트 기본값은 1884(TLS)라 따로 적을 값이 없습니다. 예전의 PP_KAFKA_PORT 는 없어졌습니다 — 남아 있어도 아무도 읽지 않습니다.


플랫폼 통합 MCP​

코파일럿 채팅이 플랫폼의 실시간 데이터를 끌어오는 통로입니다.

변수뜻
PP_API_URL플랫폼 server-web 베이스 URL
PP_API_TOKEN플랫폼에서 발급한 API 토큰
토큰이 «틀려도» 기동은 됩니다

두 값은 compose 가 필수로 받습니다 — 비어 있으면 스택이 뜨지 않습니다. 자리표시자가 남아 있으면 bin/up.sh 가 띄우지 않습니다. 그러나 틀린 토큰이면 스택은 정상적으로 뜨고 채팅의 플랫폼 MCP 도구만 조용히 0개가 됩니다. 「도구가 안 보인다」는 증상이면 여기부터 보십시오.


모델과 게이트웨이​

모델 · 게이트웨이 값은 전부 compose 기본값이고(키는 설치기가 만드는 비밀만 호스트 env 에 있습니다), vLLM 이 v0.31.0, docling-serve 가 v1.36.0 입니다. 이미지(VLLM_IMAGE · DOCLING_IMAGE)는 위 「이미지와 레지스트리」의 규칙을 따르므로 호스트 env 에 적지 않습니다. 모델 위치는 LLM_MODEL_PATH · EMB_MODEL_PATH · RERANK_MODEL_PATH (기본 /opt/kopens/models 밑 Aura-* 디렉터리)입니다.

변수기본값뜻
LLM_NAMEaura-lite생성 모델을 부르는 이름. 비전 겸용입니다
EMB_NAMEaura-embedding-4b임베딩 모델 이름
RERANK_NAMEaura-reranker-0.6b재순위 모델 이름
LLM_MODEL_PATH/opt/kopens/models/Aura-Lite-NVFP4생성 모델 가중치 폴더. 마지막 폴더 이름으로 Aura-Lite-NVFP4.tar.zst 를 받습니다
LLM_MODEL_ARGS--tool-call-parser gemma4 --reasoning-parser gemma4 --async-scheduling --enable-chunked-prefillvLLM 기동 인자. 가중치(Gemma 4 계열)에 맞춘 파서라 가중치와 함께만 바꿉니다
VISION_LLM_MODEL(비움)비전 요청에 다른 모델을 쓸 때만. 비우면 LLM_NAME 을 씁니다
PI_VLLM_API_KEY설치기가 생성vLLM 앞단 키
PI_LLM_API_KEY설치기가 생성LiteLLM 마스터 키
PI_LITELLM_SALT_KEY설치기가 생성LiteLLM 이 저장 값을 암호화할 때 쓰는 솔트
PI_LITELLM_UI_USERNAME · PI_LITELLM_UI_PASSWORDadmin · admin123!LiteLLM 관리 화면(:4000/ui) 로그인. 비밀번호는 필수입니다 → 초기 비밀번호 변경
PI_LITELLM_PORT4000LiteLLM 을 호스트에 여는 포트. 이 호스트에서 다른 LiteLLM 이 이미 4000 을 쓸 때만 바꿉니다. 스택 안의 소비자는 컨테이너 망으로 plantpulse-litellm:4000 을 부르므로 이 값과 무관합니다. 바꾼 뒤에는 bin/restart.sh plantpulse-litellm 으로 다시 만듭니다
LITELLM_IMAGE 는 없어졌습니다

2026.10 부터 게이트웨이 이미지는 자체 이미지(pi/plantpulse-litellm)라 위의 이미지 태그 규칙을 따릅니다. 예전 env 에 남은 LITELLM_IMAGE 줄은 기동 전 판정이 이미지 참조(release)로 잡아 기동을 세웁니다 — 지우십시오.

모델 이름은 aura-* 입니다 — 옛 이름 별칭은 없습니다

게이트웨이에 등록되는 이름은 aura-lite · aura-vision(비전 별칭) · aura-embedding-4b · aura-reranker-0.6b 입니다. LLM 의 서빙 이름은 2026.09 에 gpt-4o → aura-35b, 2026.10 재릴리즈(2026-10-20) 에 aura-35b → aura-lite 로 바뀌었고, 옛 이름의 호환 별칭은 두지 않습니다 — 옛 이름으로 부르면 404 이므로 외부 연동의 model 값을 새 이름으로 바꿔야 합니다. VLM_NAME 도 없어졌습니다(비전 별칭은 게이트웨이 설정이 갖습니다).

서빙 이름(LLM_NAME)과 가중치 폴더(LLM_MODEL_PATH, 기본 /opt/kopens/models/Aura-Lite-NVFP4)는 별개의 설정입니다. 재릴리즈(2026-10-20) 에서 둘 다 바뀌었습니다 — 가중치 폴더는 Aura-35B-A3B-NVFP4 → Aura-Lite-NVFP4(번들 모델 파일 Aura-Lite-NVFP4.tar.zst). 이 셋(LLM_NAME · LLM_MODEL_PATH · LLM_MODEL_ARGS)을 기본값과 같은 값으로 호스트 env 에 적으면 기동 전 판정(lint-env)이 redundant 로 기동을 막습니다 — 다른 모델을 시험할 때만 «다른 값» 으로 적습니다.

PI_LITELLM_SALT_KEY 는 바꾸지 마십시오

관리 콘솔의 모델 등록 화면에서 넣은 외부 제공자 API 키를 암호화하는 열쇠입니다. 바꾸면 이미 저장된 것을 풀지 못합니다 — 컨테이너는 healthy 로 뜨고 모델 목록도 그대로인데 호출만 조용히 실패합니다. 처음 정한 값을 그대로 두고, 백업 대상에 넣으십시오.

GPU 메모리 몫​

vLLM 셋(생성 · 임베딩 · 재순위)과 음성 녹취 vLLM(plantpulse-asr), 시계열 추론 서버가 같은 GPU 를 나눠 씁니다. 각자의 몫과 그 합의 한계는 전부 하드웨어 프로파일(compose/profiles/<PP_HW_PROFILE>.env)이 듭니다 — 호스트 env 에 적으면 기동 전 판정이 profile 로 기동을 세웁니다.

변수gb10 / g7e뜻
LLM_GPU_UTIL · EMB_GPU_UTIL · RERANK_GPU_UTIL0.4 · 0.10 · 0.08 / 0.53 · 0.13 · 0.10vLLM 셋의 GPU 메모리 몫
TS_GPU_UTIL0.13 / 0.15시계열 추론 서버의 몫
ASR_GPU_UTIL0.03 / 0.04음성 녹취 vLLM 의 몫 — 영상 · 음성을 켠 설치(PI_MEDIA_ENABLED=true)에서만 뜨지만, 꺼져 있어도 합에 넣습니다(켜는 날 한계를 넘지 않게)
PP_GPU_BUDGET_CEILING0.75 / 0.95다섯 몫의 합 한계. 넘으면 기동 전에 멈춥니다

GB10 은 통합 메모리라 한계가 0.75(합 0.74), 전용 VRAM 장비(AWS g7e)는 0.95(합 0.95)입니다.

합이 넘으면 vLLM 이 24초마다 죽고 되살아납니다

vLLM 은 기동할 때 «남은 메모리 ≥ 자기 몫» 을 확인하고, 모자라면 죽습니다. 합이 넘치면 먼저 뜨는 쪽이 이기는 경주가 되고, 진 쪽은 재시작을 반복하며 채팅이 멈춥니다 — 로그 어디에도 「설정이 과했다」는 말은 나오지 않습니다. 그래서 기동 전에 산수로 막습니다. 줄여야 하면 가장 큰 몫부터 줄이십시오.

GB10 은 GPU 메모리가 시스템 RAM 과 같은 풀이라 한계를 올리면 OS · DB 가 쓸 것이 없어집니다. 템플릿과 기계의 아키텍처가 어긋나면 설치기가 멈추는 것도 이 때문입니다.


코파일럿 설정 — 접두사는 CO_ 입니다​

코파일럿(copilot-web)에 가는 환경 변수는 2026.10 부터 CO_ 로 시작합니다(종전 CH_). CO_LLM_* · CO_TOOL_RESULT_MAX_CHARS · CO_API_V1_KEY · CO_JAVA_OPTS · CO_NAVIGATOR_CRON · CO_ANOMALY_CRON · CO_INCIDENT_DIAG_CONCURRENCY · CO_OTEL_* 가 모두 그렇습니다.

2026.10 으로 올릴 때 — CH_* 줄은 지우지 말고 «옮기십시오»

옛 이름으로 폴백하지 않습니다. 설치기는 이미 있는 env 를 다시 만들지 않으므로, 예전 env 의 CH_API_V1_KEY · CH_LLM_MAX_COMPLETION_TOKENS · CH_OTEL_GENAI_CONTENT 같은 줄은 그대로 남지만 코파일럿은 그 이름을 읽지 않습니다. 줄을 지우기만 하면 그 값은 기본값으로 돌아갑니다 — 예를 들어 CH_API_V1_KEY 로 열어 두었던 공개 API 는 그 키로 더는 들어올 수 없습니다.

기동 전 판정(bin/lint-env.sh)은 이 줄들을 renamed 로 잡아 기동을 세우고, 줄마다 할 일을 말합니다.

판정이 찍는 말뜻 · 할 일
only the old name is set — rename it옛 이름만 있습니다. 함께 찍힌 sed 한 줄(백업을 남김)이 이름만 바꾸고 값은 그대로 둡니다
both set with the same value새 이름이 이미 같은 값으로 있습니다. 옛 줄을 지웁니다
both set and DIFFERENT둘 다 있고 값이 다릅니다. 새 이름이 이깁니다 — 어느 값이 맞는지 확인한 뒤 옛 줄을 지웁니다
sudo grep -n '^CH_' /etc/kopens/plantpulse-ai.env # 남은 옛 줄

옮긴 뒤 bin/restart.sh plantpulse-copilot-web 으로 다시 만듭니다.

자동화가 내보내는 곳 — 메일 · 메신저 · PDF​

자동화의 결과를 메일 · 메신저로 내보내는 길은 기본이 닫혀 있고, 아래 값이 있어야 열립니다. PDF 는 변환 서비스에 닿을 때만 만들어집니다.

무엇어디서 정하나비어 있으면
PDF 변환 서비스(Gotenberg)환경 변수 CO_GOTENBERG_URL — compose 기본값 http://plantpulse-gotenberg:3000(스택에 함께 뜨는 변환 컨테이너)값이 비어 있거나 그 주소의 변환 컨테이너가 응답하지 않으면 PDF 만 꺼집니다. 보고서의 PDF 내려받기와 자동화 메일의 PDF 첨부 단추가 꺼지고 화면이 그 이유를 말합니다. Excel · CSV 는 이 값과 무관합니다
메일 허용 도메인관리 콘솔 › 알림 채널의 «메일 허용 도메인»(설정 키 automation.mail.allowed-domains, 쉼표로 나눔 · 20개까지)🔴 자동화 메일이 꺼져 있습니다. 사내 도메인을 적어야 켜집니다
메일 서버관리 콘솔 › 시스템 설정의 smtp.host · smtp.port · smtp.username · smtp.password · smtp.starttls, 보낸 사람 navigator.report.email.from메일이 나가지 않습니다(실행 기록에 「메일 서버가 설정돼 있지 않습니다」)
메신저 채널(Teams · Slack)관리 콘솔 › 알림 채널에서 웹훅 주소를 등록 — 환경 변수가 아닙니다자동화의 «보내기» 에서 메신저 채널을 고를 수 없습니다
메일 · 메신저 본문의 링크관리 콘솔 › 시스템 설정의 app.base.url(이 설치의 바깥 주소)본문에 링크를 넣지 않습니다

CO_GOTENBERG_URL 은 http:// · https:// 주소여야 합니다. 그 밖의 값이면 경고를 남기고 PDF 를 끕니다. 화면의 PDF 단추 · 첨부 칩은 주소가 적혀 있는지가 아니라 변환기가 지금 응답하는지(/health, 30초마다 다시 확인)를 따릅니다 — 주소만 있고 컨테이너가 없는 설치에서는 꺼져 보입니다. 변환기에 닿지 않을 때는 메일이 PDF 만 빼고 나가고 (실행 기록에 「첨부하지 못함」), 보고서의 내려받기는 「지금은 PDF 를 만들 수 없습니다.」 로 답합니다. 변환기의 상태는 /actuator/health/deps 의 gotenberg 에 off · unreachable · up 으로 보이고, 변환기가 죽어도 코파일럿의 기동 판정에는 들어가지 않습니다.

하루 발송 상한은 시스템 설정의 값입니다(재시작 없이 바뀝니다). 한 번도 고친 적이 없어도 관리 콘솔 › 시스템 설정에 기본값과 함께 보이고, 거기서 고치거나 기본값으로 되돌립니다. 자동화의 주기 · 토큰 상한(agentdef.*)과 2인 승인 도구(access.two_person.tools)도 같은 목록에 있습니다 → 코파일럿 관리 콘솔 — 시스템 설정

설정 키기본값뜻
automation.deliver.mail.daily-max6자동화 하나가 한 사람에게 하루에 보내는 메일 수
automation.deliver.webhook.daily-max12자동화 하나가 채널 하나에 하루에 보내는 메신저 건수
automation.deliver.role.max-members50받는 사람을 역할로 골랐을 때 펼쳐지는 인원

화면에서 하는 일은 코파일럿 관리 콘솔 — 알림 채널에 있습니다.

코파일럿 채팅 — 사고 모드와 상한 셋​

대화형 코파일럿(copilot-web)이 게이트웨이를 부르는 방식을 정하는 값 셋입니다. 셋 다 같은 실패 하나를 서로 다른 손잡이로 다룹니다 — 모델이 답하기 전에 «생각» 하고, 그 생각도 생성 토큰을 먹는다는 것입니다.

변수기본값뜻
CO_LLM_THINKING_ENABLEDtrue (compose, 2026.10 재릴리즈(2026-10-20) 부터. 앱 단독 기본은 비움)사고 모드 스위치 → chat_template_kwargs.enable_thinking. 비우면 보내지 않습니다(모델 기본값을 따릅니다 — AURA-Lite 의 템플릿 기본값은 «끔» 입니다)
CO_LLM_MAX_COMPLETION_TOKENS4096 (자체 스택 배포는 16384)호출 한 번의 생성 토큰 상한. 사고와 답이 함께 들어갈 만큼 커야 합니다. 0 이면 상한을 보내지 않습니다
CO_TOOL_RESULT_MAX_CHARS24000도구 결과 하나가 모델에 실리는 최대 문자 수. 넘으면 깊은 배열부터 덜어내고 _truncated 표식을 남깁니다. 0 이면 자르지 않습니다
사고를 끄면 빨라지지만 «지어냅니다»

Qwen3.5 계열에서 CO_LLM_THINKING_ENABLED=false 로 끄면 응답이 몇 초로 줄지만, 모델이 도구를 부르지 않고 존재하지 않는 자산·알람을 지어냅니다(2026-09-18 스테이징 실측). 속도와 품질을 저울질하는 문제가 아니라 답이 맞느냐 틀리느냐의 문제입니다.

끄는 선택지는 사고 없이도 도구를 부르는 모델에서만 의미가 있습니다.

생각 정도 — 경로별 기본값​

2026.10 재릴리즈(2026-10-20) 부터 생각을 켜고 끄는 것에 더해 얼마나 생각할지(reasoning_effort)를 고릅니다. env 가 아니라 코파일럿 관리 › 시스템 설정(/admin/config)의 키이고, 저장하면 재기동 없이 다음 호출부터 적용됩니다.

키화면 이름
llm.reasoning.chat채팅 생각 정도 기본값
llm.reasoning.automation자동화 생각 정도
llm.reasoning.diagnosis이상 진단 생각 정도
llm.reasoning.proposal수행제안 생각 정도
llm.reasoning.other그 밖의 생성 생각 정도
  • 값은 none(끔) · low · medium · high, 또는 비움(«서버 기본값 따름»). none 은 생각을 끄고, 나머지는 생각을 켠 채 그 정도로 보냅니다.
  • 정하는 차례는 사용자가 묻기에서 고른 값 → 위 경로별 키 → CO_LLM_THINKING_ENABLED 입니다.
  • 묻기 화면의 생각 정도 단추는 전역 값이나 llm.reasoning.chat 이 정해져 있을 때만 보입니다.
답이 «빈 채로» 끝나면 상한을 보십시오

사고가 상한 안에 끝나지 못하면 생성이 length 로 잘려 본문이 0자가 됩니다. 스트림은 정상 종료되므로 화면에는 「답이 안 나온다」로만 보이고, 게이트웨이 장애처럼 읽힙니다.

같은 질문을 스테이징에서 나란히 잰 결과입니다.

설정결과
사고 켬 + 4096빈 답 — 사고가 상한을 다 씁니다
사고 끔빠르지만 도구를 건너뛰고 지어냅니다
사고 켬 + 16384도구를 부르고 맞는 답 (질문에 따라 20초~4분)

상한을 올려도 안 끝나면 그때는 프롬프트나 도구 결과 크기(CO_TOOL_RESULT_MAX_CHARS)를 줄이는 쪽을 봅니다.


문서 색인(LightRAG) 시간 예산​

기본값 그대로가 정상입니다. 「이 장비에서는 더/덜 필요하다」를 재 보고 바꿀 때만 손댑니다.

변수기본값뜻
LIGHTRAG_LLM_TIMEOUT3600개체 추출 LLM 호출의 제한(초). 워커 제한은 이 값의 두 배입니다
LIGHTRAG_LLM_MAX_TOKENS32768추출 호출 한 번이 뽑을 수 있는 최대 토큰 — 폭주 천장
LIGHTRAG_MAX_ASYNC4동시 LLM 호출 수. 🔴 줄이면 더 느려집니다
Worker execution timeout 으로 색인이 실패하면

사고하는 모델은 호출 한 번에 토큰을 많이 씁니다. 예전 기본값(240초, 워커 480초)에서는 큰 PDF 가 색인 도중에 통째로 실패했습니다. 이 오류가 보이면 LIGHTRAG_LLM_TIMEOUT 을 올리되 LIGHTRAG_LLM_MAX_TOKENS 도 함께 보십시오 — 상한이 없으면 폭주 한 건이 GPU 슬롯을 그만큼 잡습니다.


공개 API 기계 인증​

외부 시스템이 코파일럿의 공개 API(/api/v1)를 부를 때 쓰는 키입니다 → API 연동 가이드

변수기본값뜻
CO_API_V1_KEY(비움)헤더 X-API-Key: <값> 으로 받는 키. 2026.09 까지의 이름은 CH_API_V1_KEY 입니다 — 옮기십시오
비우면 이 키로는 «못 들어옵니다» — 통과가 아닙니다

비어 있으면 이 환경 변수 키는 받지 않습니다. 그때 X-API-Key 로 들어올 수 있는 것은 코파일럿 관리 콘솔의 API 키 화면(/admin/api-keys)에서 이름을 붙여 발급한 키뿐이고, 그것도 없으면 세션 로그인만 받습니다. 설정을 빠뜨린 배포가 인증 없는 공개 API 가 되지 않게 한 것입니다. 어느 키든 권한은 공개 API 에만 닿고, 관리 화면(/admin/**)과 API 문서에는 닿지 않습니다.

환경 변수 키 하나는 누구에게 준 것인지 구분되지 않고, 새면 쓰던 곳이 한꺼번에 끊깁니다. 외부 시스템마다 따로 주려면 코파일럿 관리 콘솔에서 발급하는 쪽을 쓰십시오 → 코파일럿 관리 콘솔 — API 키


관리 콘솔과 API 키​

변수뜻
PI_ADMIN_USER · PI_ADMIN_PASSWORD관리 콘솔 로그인. 아이디 기본 admin, 비밀번호는 설치할 때 사람이 정합니다
PI_ADMIN_SESSION_SECRET관리 콘솔 세션 서명 키 — 설치기가 만듭니다
ADMIN_SESSION_MAX_AGE세션 유효 시간(분). 기본 480
PI_ADMIN_WEB_PORT관리 콘솔 HTTP 포트. 기본 5959
PI_ADMIN_WEB_TLS_PORT관리 콘솔 HTTPS 포트. 기본 5960 — 프록시가 받아 같은 콘솔로 넘깁니다(인증서는 :443 과 같은 한 벌)
PI_NEO4J_USER · PI_NEO4J_PASSWORD그래프 계정 — Neo4j 두 인스턴스(LightRAG 지식 그래프 plantpulse-neo4j · 공장 그래프 거울 plantpulse-digital-thread-neo4j)가 같은 계정을 씁니다
PI_RAG_API_KEYRAG API 호출 키
PI_INBOUND_API_KEY뒷단 서비스(RAG · 시계열 인사이트 · 문서 이해 · 비전 · 디지털 스레드)로 들어오는 요청의 키. 비면 기동 전 판정이 스택을 세웁니다(아래 「뒷단 인바운드 키」)

이 값들을 파일만 고쳐서는 끝나지 않습니다 — Neo4j 처럼 서버 계정이 정본인 것은 서버측도 함께 바꿔야 합니다. bin/passwd.sh 가 그 순서를 밟아 줍니다 → 비밀번호 · API 키 변경.

관리 콘솔 포트가 9080 에서 5959 · 5960 으로 옮겼습니다 (2026.10)

두 입구가 같은 콘솔을 부르고, 둘 다 열립니다(평문을 HTTPS 로 되돌리지 않습니다). 비워 두면 위 기본값이고, 바꾸면 설치기가 방화벽을 그 값으로 엽니다. 바꾼 뒤에는 bin/restart.sh plantpulse-admin-web plantpulse-proxy 로 두 컨테이너를 다시 만듭니다.

저장 자격증명 암호화 키 — PI_COPILOT_SECRET_KEY · PI_DT_SECRET_KEY​

화면에서 넣은 자격증명을 DB 에 AES-256-GCM 으로 봉하는 열쇠입니다. 값은 base64 로 쓴 32바이트이고, 첫 설치 때 설치기가 만듭니다.

변수무엇을 봉하나비었을 때
PI_COPILOT_SECRET_KEY코파일럿이 저장하는 자격증명 — 외부 MCP 커넥터 인증 값, LLM 키, SMTP 비밀번호, Slack 웹훅, Web Push 개인키🔴 코파일럿만 기동을 거부하고 넣을 한 줄을 로그에 찍습니다. 나머지 스택은 뜹니다
PI_DT_SECRET_KEY디지털 스레드 커넥터 등록부의 커넥터 자격증명커넥터 등록부만 config_error(503) 입니다. 그래프 거울은 돕니다
바꾸거나 잃으면 저장된 자격증명을 못 풉니다
  • /etc/kopens/plantpulse-ai.env 백업에 이 두 값이 함께 있어야 합니다. DB 만 되살리고 키가 없으면 커넥터 · 알림 자격증명을 다시 넣어야 합니다.

  • 2026.09 이하에서 올린 호스트에는 이 줄이 없습니다. 설치기는 이미 있는 env 에 줄을 더하지 않고, 기동 전 판정이 «저장 자격증명 암호화 키가 없다» 로 알려 줍니다. 직접 넣으십시오(값을 화면에 찍지 않는 형태).

    echo "PI_COPILOT_SECRET_KEY=$(openssl rand -base64 32)" | sudo tee -a /etc/kopens/plantpulse-ai.env >/dev/null
    echo "PI_DT_SECRET_KEY=$(openssl rand -base64 32)" | sudo tee -a /etc/kopens/plantpulse-ai.env >/dev/null
  • bin/passwd.sh 는 이 두 키를 돌리지 않습니다. 교체는 옛 값을 _PREVIOUS 에 두는 절차로만 합니다 → 비밀번호 · API 키 변경


디지털 스레드​

plantpulse-digital-thread-api 는 2026.10 부터 스택에 기본으로 들어 있습니다(호스트에 포트를 열지 않고, 스택 안에서 7140 으로 부릅니다). 공장 그래프 거울은 전용 Neo4j(plantpulse-digital-thread-neo4j)에 두고, 커넥터 등록부는 PG DB pi 의 스키마 dt 에 둡니다. 플랫폼 사건 독자는 켜진 채로 출하됩니다.

호스트에서 만질 수 있는 손잡이입니다. 기본값 그대로가 정상입니다.

변수기본값뜻
PI_DT_SECRET_KEY설치기가 생성커넥터 자격증명 암호화 키(위)
DT_INSIGHT_EVENTS_PUSHfalse디지털 스레드가 읽은 플랫폼 사건을 시계열 인사이트로 밀어 줄지
TS_EVENTS_SOURCEdirect시계열 인사이트가 플랫폼 사건을 어디서 받나 — direct(직접 읽음) · shadow(직접 읽고 밀린 것과 견줌) · digital_thread(밀린 것만 씀 — 위 스위치가 켜져 있어야 함)
DT_PLATFORM_READ · CO_PLATFORM_READ · TS_PLATFORM_READdb플랫폼 원장을 읽는 길 — db(플랫폼 표를 직접) · shadow(둘 다 읽고 db 로 답하며 차이를 셈) · api(플랫폼 V5 REST, 기존 PP_API_URL · PP_API_TOKEN 을 씀)

커넥터 주기 동기화와 신선도 (2026.10 재릴리즈 3)​

켜진 커넥터를 주기적으로 다시 동기화합니다. 동기화는 사라진 연결을 지우지 않고 «닫아»(끝난 시각을 적어) 두므로, 과거 시점으로 묻는 이력이 맞게 남습니다. 기본값 그대로가 정상입니다.

변수기본값뜻
DT_CONNECTOR_SYNC_ENABLEDtrue주기 동기화. false 면 멈추고, 관리 콘솔의 «지금 동기화» 만 남습니다
DT_CONNECTOR_SYNC_INTERVAL_S0동기화 간격(초). 0 이면 가족별 — 그 가족 신선도 상한의 절반, 최소 300초
DT_CONNECTOR_MAX_AGE(비움)커넥터 데이터의 신선도 상한. 가족=기간 목록(예: mes=2h,erp=1d, 단위 s · m · h · d). 비우면 가족별 기본 — ehs 1h, mes · sched · wms 2h, cmms 4h, lims 12h, 나머지 1d. 상한보다 낡은 커넥터가 있으면 회복 · 영향 수치를 내지 않습니다
DT_LINK_HISTORY_DAYS(비움 — 180)닫힌 연결을 남겨 두는 기간(일, 1~3650)

지금 도는 값과 동기화 상태는 디지털 스레드의 /api/v1/config(dt_connector_max_age_effective 등)와 /health 의 connector_sync 에 나옵니다. connector_sync 는 정보일 뿐이라 서비스를 degraded 로 만들지 않습니다.


뒷단 인바운드 키 — 비면 뜨지 않습니다​

RAG(rag-api) · 시계열 인사이트 API · 문서 이해 · 비전 · 디지털 스레드는 같은 키 하나(PI_INBOUND_API_KEY)로 들어오는 요청을 확인합니다. compose 가 이 값을 서비스마다 자기 이름(RAG_INBOUND_API_KEY · TS_INBOUND_API_KEY · INBOUND_API_KEY …)으로 나눠 넣고, 코파일럿과 관리 콘솔 백엔드도 같은 값으로 이 서비스들을 부릅니다.

키가 비면 «우연히» 인증 없이 열린 채 뜨는 길이 없습니다.

어디서키가 비면
기동 전 판정(bin/lint-env.sh)[fail] PI_INBOUND_API_KEY is empty and PI_INBOUND_AUTH_DISABLED is not true 로 컨테이너를 하나도 만들지 않고 멈춥니다
각 서비스자기 키가 비면 기동을 거부하고 FATAL: … is empty — refusing to start … 류의 한 줄을 남깁니다

인증 없이 띄우는 길은 명시적인 스위치 하나뿐이고, 개발 · 시험용입니다.

변수기본값뜻
PI_INBOUND_AUTH_DISABLEDfalsetrue 이고 키가 비어 있을 때만 다섯 서비스가 인증 없이 뜹니다. compose 가 서비스마다 RAG_INBOUND_AUTH_DISABLED · TS_INBOUND_AUTH_DISABLED · DT_INBOUND_AUTH_DISABLED · INBOUND_AUTH_DISABLED(문서 이해 · 비전)로 넘깁니다

기동 전 판정이 이 스위치를 두고 하는 말입니다.

출력뜻
[fail] PI_INBOUND_AUTH_DISABLED=<값> — write true or falsetrue · false 밖의 값
[note] PI_INBOUND_AUTH_DISABLED=true is ignored — PI_INBOUND_API_KEY is set and the key wins키가 있으면 키가 이깁니다 — 인증은 켜진 채입니다

인증 없이 뜬 서비스는 /health 에 그 사실을 싣습니다(문서 이해 inbound_auth: "disabled", 디지털 스레드 auth.inbound=disabled 등). 운영 설치에서는 키를 넣는 것이 답입니다.

인증 없이 열리는 것은 헬스 경로 /ping · /health 둘뿐입니다(정확히 그 경로만). 지표 /metrics 도 키 뒤에 있습니다 → 로그 및 모니터링

자리표시자는 이 검사를 통과합니다

CHANGE_ME_… 는 빈 값이 아니라서 compose 도 서비스도 막지 않고, 그 문자열은 모든 설치에서 같습니다. 설치기가 첫 설치에 새 값으로 바꿔 두지만, 손으로 만든 env 라면 bin/passwd.sh --generate PI_INBOUND_API_KEY 로 새 값을 넣으십시오 → 비밀번호 · API 키 변경


문서 · 사진 도구가 사내 URL 을 받게 하기​

문서 이해 · 비전 도구는 파일이 아니라 URL 을 받아 직접 내려받습니다. 그 주소가 루프백 · 사설망 · 링크로컬로 풀리면 거절합니다 → MCP 도구 지도

사내 파일 서버처럼 일부러 열어 줄 곳은 허용 목록에 적습니다. compose 가 이 값을 문서 이해와 비전 두 서비스에 같이 넘깁니다.

변수기본값뜻
FETCH_ALLOWED_HOSTS(비움)내부 주소여도 받아 올 호스트. 쉼표로 여럿. URL 의 호스트 이름과 정확히 같아야 합니다(대소문자 무시) — files.example.local 또는 files.example.local:8080 처럼 포트까지 적으면 그 포트만, IP 로 부르는 서버면 IP 를 그대로 적습니다
echo 'FETCH_ALLOWED_HOSTS=files.example.local,10.0.0.15' | 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
  • 와일드카드 · 대역(CIDR)은 없습니다. 하위 도메인도 하나씩 적습니다.
  • 허용한 호스트도 http · https 만 받고, 크기 상한(문서 200 MiB · 사진 32 MiB)은 그대로입니다. 리다이렉트는 한 번 넘어갈 때마다 다시 검사하므로, 허용한 호스트가 허용하지 않은 내부 주소로 넘기면 거기서 거절됩니다.
  • 이 줄은 compose 기본값(빈 값)을 덮어쓰는 것이라 기동 전 판정이 override 알림을 띄웁니다 — 정상입니다.

RAG 객체 저장소 버킷​

rag-api 는 손으로 올린 문서 원본 · 도면 구조와 미리보기 · 영상 재생본과 녹취를 플랫폼 RustFS 의 버킷 하나에 둡니다.

변수기본값뜻
RAG_S3_BUCKETplantpulse-rag그 버킷 이름. 같은 플랫폼을 AI 설치 둘이 함께 쓸 때만 두 번째 설치에 다른 이름을 줍니다

→ 데이터베이스


도면 수집 — 기본 꺼짐​

도면(DXF · 텍스트 층이 있는 벡터 PDF)을 표제란 · 치수 · 공차 · BOM 행으로 읽어 색인하는 기능입니다. 꺼진 채 출하되며, 꺼져 있으면 rag-api 의 도면 API 와 관련 표가 아예 생기지 않습니다(이 기능이 없던 때와 같습니다).

변수기본값뜻
DRAWING_INGEST_ENABLEDfalsetrue 면 rag-api 가 도면 수집을 켭니다. .dxf 는 늘 도면으로, PDF 는 업로드할 때 종류를 «도면»(document_kind=drawing)으로 줄 때만 도면으로 읽습니다. true · false 밖의 값은 경고를 남기고 꺼짐으로 읽습니다
echo 'DRAWING_INGEST_ENABLED=true' | sudo tee -a /etc/kopens/plantpulse-ai.env >/dev/null
cd /opt/kopens/plantpulse-ai-docker
bin/restart.sh plantpulse-rag-api
  • DWG 는 받지 않습니다 — DXF 나 PDF 로 내보내 올립니다. 한 파일 상한은 50 MB 입니다.
  • 플랫폼 자산 문서도 도면으로 들어옵니다(2026.10 재릴리즈 3). 플랫폼 자산에 붙인 문서를 가져오는 동기화가 .dxf 파일과 «문서 종류» 가 DRAWING 인 PDF 를 도면 경로로 넣습니다. 이렇게 들어온 도면은 플랫폼이 정본이라 관리 콘솔에서 덮어 올리거나 지우면 409(「drawing is platform-managed …」)입니다 — 고치거나 지우는 것은 플랫폼에서 하고, 검색에서만 빼려면 관리 콘솔 문서 표에서 «코퍼스에서 제외» 합니다(2026.10 재릴리즈 4 부터 콘솔 단추가 원장 도면에 열립니다. 직접 올린 도면은 여전히 제외할 수 없습니다). 꺼져 있으면 .dxf 는 세기만 하고(drawing_disabled) 넣지 않으며, PDF 는 일반 문서로 들어갑니다.
  • 도면의 판(리비전)이 지금 작업할 판인지는 디지털 스레드에 묻습니다(PLM 의 출도 판 · 열린 설계 변경). 표제란에 품번 · 판이 없거나 디지털 스레드가 답하지 못하면 판 상태는 unknown 이고, «최신» 으로 보이지 않습니다.
  • 켜면 rag-api 가 기동할 때 도면용 표(rag_drawing_*)를 rag_ingest DB 에 만듭니다 — 손으로 할 이전은 없습니다.

영상 · 음성 수집 — 기본 꺼짐, 한 줄로 켭니다​

영상 · 음성을 녹취(음성 → 시각이 붙은 글)해 색인하는 기능과, 코파일럿 채팅 입력의 음성으로 묻기는 같은 녹취 서빙(plantpulse-asr)을 씁니다. 꺼진 채 출하되고, 켜는 것은 호스트 env 한 줄 PI_MEDIA_ENABLED=true 입니다 (템플릿에 주석 #PI_MEDIA_ENABLED=true 로 들어 있습니다). 쓰는 법은 동영상 · 음성 검색 에 있습니다.

이 한 줄이 함께 정하는 것내용
뜨는 서비스plantpulse-asr-audio — 오디오 라이브러리를 볼륨 pi-asr-audio 에 옮기고 끝나는 일회성 서비스 · plantpulse-asr — vLLM Whisper large-v3-turbo, 서빙 이름 aura-asr, 안쪽 8000(호스트에 열지 않습니다). 운영 스크립트가 compose 프로필 media 를 붙여 띄웁니다
컨테이너 값rag-api MEDIA_INGEST_ENABLED=true · 문서 이해 ASR_URL=http://plantpulse-asr:8000(설치본의 compose/media/true.env)
모델bin/fetch-models.sh 가 녹취 모델 Aura-ASR-Turbo(내려받기 약 1.5 GB, 풀면 약 1.6 GB)를 받습니다. 꺼진 설치에서는 받지 않습니다
GPUASR_GPU_UTIL 은 꺼져 있을 때도 하드웨어 프로파일의 합에 들어 있어, 켜도 한계를 넘지 않습니다
cd /opt/kopens/plantpulse-ai-docker
sudo cp -p /etc/kopens/plantpulse-ai.env /etc/kopens/plantpulse-ai.env.bak-media-$(date +%Y%m%d-%H%M)
sudo sed -i '/^#\?PI_MEDIA_ENABLED=/d' /etc/kopens/plantpulse-ai.env && echo PI_MEDIA_ENABLED=true | sudo tee -a /etc/kopens/plantpulse-ai.env >/dev/null
sudo bash bin/fetch-models.sh # Aura-ASR-Turbo — 이미 있으면 건너뜁니다
sudo bash bin/lint-env.sh && bin/restart.sh # rag-api · 문서 이해가 새 값으로 다시 만들어집니다
bin/status.sh # 켠 설치는 23/23 — plantpulse-asr-audio 는 «Exited (0)» 이 정상입니다

켜졌는지는 세 곳에서 봅니다.

# rag-api — "media_ingest_enabled":true
curl -s -H "X-API-Key: <PI_INBOUND_API_KEY>" http://127.0.0.1:7115/api/v1/config | grep -o '"media_ingest_enabled":[a-z]*'
# 문서 이해 — components.asr.status 가 "up"
docker exec plantpulse-document-understanding-api python3 -c \
"import urllib.request;print(urllib.request.urlopen('http://localhost:7120/health').read().decode())"

bin/status.sh 는 «종료 코드 0» 으로 끝난 일회성 서비스(plantpulse-asr-audio)를 정상으로 셉니다. 0 이 아니면 plantpulse-asr 도 뜨지 않습니다 — 그 로그부터 봅니다.

  • 끄기 — 그 줄을 지우거나 PI_MEDIA_ENABLED=false 로 두고 bin/restart.sh 한 뒤, 남은 두 컨테이너를 docker rm -f plantpulse-asr plantpulse-asr-audio 로 지웁니다(프로필이 꺼지면 운영 스크립트가 그 둘을 더 다루지 않습니다).
  • 폐쇄망 — 이미지는 번들에 늘 실려 있습니다. 모델만 따로 반입합니다 → 폐쇄망 설치
  • true · false 밖의 값이면 기동 전 판정이 [fail] PI_MEDIA_ENABLED=<값> — true 또는 false 만 받는다 로 멈춥니다.
옛 이름 MEDIA_INGEST_ENABLED — 이번 릴리즈 동안만 별칭입니다

2026.10 앞 판에서 호스트 env 에 MEDIA_INGEST_ENABLED · ASR_URL 을 손으로 적었다면, 업그레이드는 멈추지 않고 그 값으로 계속 돕니다(PI_MEDIA_ENABLED 줄이 없으면 옛 이름을 스위치로 읽습니다). 운영 스크립트가 처음 돌 때 옛 이름을 PI_MEDIA_ENABLED 로 옮기고, 스위치가 주는 값과 같은 ASR_URL 줄은 지웁니다.

기동 전 판정뜻
alias [warn]옛 이름만 있습니다 — 기동은 됩니다. 함께 찍힌 sed 한 줄로 옮깁니다. 2026.11 에 별칭을 걷어 내면 옮기지 않은 줄은 renamed [fail] 이 됩니다
media-same [warn]호스트 env 의 ASR_URL 이 스위치가 주는 값과 같습니다 — 지워도 됩니다
media [fail]호스트 env 의 ASR_URL 이 스위치가 주는 값과 다릅니다 — 무엇을 원했는지 정한 뒤 지웁니다. 켜는 것은 PI_MEDIA_ENABLED=true 한 줄입니다
두 이름이 다른 값[fail] — 어느 쪽을 뜻했는지 사람이 정합니다

env 파일에 쓸 수 없는 계정으로 돌면 스스로 옮기지 못하고 [paths] [warn] cannot write … 와 사람이 칠 sudo sh -c '…' 명령을 찍습니다. 컨테이너(rag-api) 안에서 읽는 이름은 여전히 MEDIA_INGEST_ENABLED 입니다 — 그것은 스위치가 정하므로 호스트 env 에 적지 않습니다.

손잡이는 compose 기본값입니다. 기본값 그대로 두는 것이 정상입니다.

변수서비스기본값뜻
PI_MEDIA_ENABLED(호스트 스위치)false위 — 영상 · 음성 수집과 음성으로 묻기를 함께 켭니다
MEDIA_MAX_FILE_MBrag-api2048영상 한 파일의 상한(MB). 문서 상한과 따로입니다
MEDIA_MAX_DURATION_MINrag-api120영상 한 편의 길이 상한(분)
MEDIA_TEXT_TRACKSrag-apisubtitles영상 속 글자 — off · subtitles(내장 자막 트랙 · 곁 자막 srt/vtt) · all(+ 화면에 입힌 자막 · 화면 글자를 LLM 이 읽음)
MEDIA_SPAN_TARGET_SECrag-api0색인 구간 길이(초, 20~300). 0 이면 녹취 조각 하나(약 120초)가 한 구간. 범위 밖 값은 경고를 남기고 0 으로 읽습니다. 바꾸면 다시 색인한 것부터 적용됩니다
MEDIA_PROCESSING_WINDOWrag-api(비움 — 20:00-06:00)영상 처리를 시작해도 되는 시간대(PP_TZ 기준 HH:MM-HH:MM, 시작이 끝보다 늦으면 자정을 넘김). 늘 처리하려면 always. 비우거나 형식이 틀리면 rag-api 기본 20:00-06:00 입니다. 창은 처리의 시작에만 걸립니다 — 시작한 처리는 창이 닫혀도 끝까지 갑니다. 처리는 채팅과 같은 LLM 을 나눠 씁니다
ASR_URL문서 이해(스위치가 정함)녹취 서빙 주소. 켜면 http://plantpulse-asr:8000, 끄면 빈 값(녹취 입구가 503). 🔴 호스트 env 에 적지 마십시오 — 위 표의 media · media-same
ASR_NAME · ASR_BACKEND문서 이해 · asraura-asr · vllm서빙 이름 · 엔진(vllm 만 받습니다)
ASR_MODEL_PATHasr/opt/kopens/models/Aura-ASR-Turbo녹취 모델 위치
OCR_URL · OCR_BACKEND문서 이해http://plantpulse-llm:8000 · vlm영상 속 글자를 읽을 서빙 LLM. 녹취가 켜졌을 때만 씁니다

비전 글자 읽기 엔진​

변수기본값뜻
VISION_OCR_ENGINE(비움 — 비전 기본 vlm)vision_ocr 의 엔진. vlm 은 서빙 중인 LLM 이 읽고 세 번 중 두 번 글자열이 같아야 답합니다(한국어를 읽습니다). docling 은 문서 이해의 OCR 에 맡깁니다(한국어를 못 읽습니다)

관련 문서​