본문으로 이동

도움말:S3 연구 메모리/문제 해결: 두 판 사이의 차이

S3 연구 메모리
S3 연구 메모리 저장소 문서 동기화
S3 연구 메모리 저장소 문서 동기화
483번째 줄: 483번째 줄:


큰 결과를 한 번에 받으려고 제한을 높이지 마세요. 먼저 검색 요약을 받고, 추린 결과에 대해 선택 field로 <code><nowiki>get_lesson</nowiki></code>을 호출합니다. <code><nowiki>citation_detail=full</nowiki></code>에서 근거 한 항목이 한도에 맞지 않으면 note를 조용히 자르지 않고 <code><nowiki>output_budget_error</nowiki></code>를 반환합니다. 필요한 근거를 더 작은 페이지로 요청하되, 한 항목 자체가 너무 크면 서버의 허용된 근거 길이와 출력 설정을 확인합니다.
큰 결과를 한 번에 받으려고 제한을 높이지 마세요. 먼저 검색 요약을 받고, 추린 결과에 대해 선택 field로 <code><nowiki>get_lesson</nowiki></code>을 호출합니다. <code><nowiki>citation_detail=full</nowiki></code>에서 근거 한 항목이 한도에 맞지 않으면 note를 조용히 자르지 않고 <code><nowiki>output_budget_error</nowiki></code>를 반환합니다. 필요한 근거를 더 작은 페이지로 요청하되, 한 항목 자체가 너무 크면 서버의 허용된 근거 길이와 출력 설정을 확인합니다.
=== 의미 검색이 켜지지 않음 ===
번들 GPU 모델을 쓸 때는 제공자와 Compose profile을 함께 켭니다.
<pre><nowiki>
S3RM_EMBEDDING_PROVIDER=openai-compatible
COMPOSE_PROFILES=domain,embedding
</nowiki></pre>
설정 뒤 고정 모델 확인, 런타임 시작, <code><nowiki>mcp-http</nowiki></code> 재생성과 연결 검사를 한 번에 실행합니다.
<pre><nowiki>
make embedding-up
make verify-embedding
</nowiki></pre>
응답의 <code><nowiki>semantic_status=disabled</nowiki></code>는 실행 오류가 아니라 제공자가 꺼진 상태입니다. <code><nowiki>building</nowiki></code>은 첫 exact index를 만드는 중이며 이때 기존 검색으로 즉시 대체합니다. <code><nowiki>unavailable</nowiki></code>이면 아래 런타임 로그와 <code><nowiki>mcp-http</nowiki></code> 로그를 확인합니다. 외부 임베딩 API로 자동 전환되지는 않습니다.
=== GPU 임베딩 서비스가 시작되지 않음 ===
모델 확인 작업과 런타임을 나눠 봅니다.
<pre><nowiki>
docker compose --profile embedding ps -a embedding-model-init embedding
docker compose --profile embedding logs --tail=200 embedding-model-init embedding
ls -l /dev/dri/renderD128
vulkaninfo --summary
</nowiki></pre>
<code><nowiki>embedding-model-init</nowiki></code>의 checksum 오류는 모델 파일, source commit, 크기, SHA-256, generation revision 중 일부가 서로 다른 상태입니다. 값을 임의로 완화하지 말고 같은 artifact 기준으로 모두 맞춥니다. 부분 파일은 다음 실행에서 이어받고, 잘못된 완성 파일은 init 작업이 제거한 뒤 다시 받습니다.
<code><nowiki>embedding</nowiki></code>에서 render node 권한 오류가 나면 호스트의 실제 장치와 group ID를 확인해 <code><nowiki>S3RM_EMBEDDING_DRI_DEVICE</nowiki></code>, <code><nowiki>S3RM_RENDER_GID</nowiki></code>를 맞춥니다. 이 서버의 기본값은 <code><nowiki>/dev/dri/renderD128</nowiki></code>, <code><nowiki>987</nowiki></code>입니다. 장치 번호를 바꾼 뒤 컨테이너 안의 별칭은 계속 <code><nowiki>Vulkan0</nowiki></code>인지 로그에서 확인합니다. 호스트 포트 8080을 열어 우회하지 마세요.
긴 입력에서 timeout이나 GPU 메모리 오류가 반복되면 먼저 기본 동시성 1과 batch 6을 유지하고 query 길이를 줄입니다. 16K token보다 큰 입력은 같은 generation 계약에서 지원하지 않습니다. 실패 중에도 <code><nowiki>legacy</nowiki></code> 검색은 계속 사용할 수 있습니다.


=== 관계 추가가 거부됨 ===
=== 관계 추가가 거부됨 ===

2026년 7월 18일 (토) 13:04 판

이 페이지는 저장소 문서에서 자동으로 동기화됩니다. 위키에서 직접 편집하지 마세요.

실패한 상태를 보존하고, 출력 길이를 제한한 진단부터 실행합니다. 원인을 찾는 동안 볼륨을 지우거나, DB 테이블을 직접 고치거나, LocalSettings.php를 다시 만들거나, 백업의 유일한 사본으로 복원을 반복하지 마세요.

docker compose config --quiet
docker compose ps -a
docker compose logs --tail=200 db mediawiki bootstrap mcp-http caddy

출력을 전달할 때는 비밀번호, session cookie, Bearer 토큰, 전체 환경 dump를 지웁니다. Lesson 내용은 공개 대상이지만 운영 자격 증명은 공개하지 않습니다.

Compose에서 필수 변수가 없다고 나옴

예상 메시지:

required variable MARIADB_PASSWORD is missing a value

파일 이름이 compose.yaml 옆의 .env인지 확인하고, 필수 change-me 비밀번호를 모두 바꿉니다. 토큰을 출력하지 않고 공용 MCP 설정을 마칩니다.

test -f .env
grep -n 'change-me' .env
./scripts/configure-public-domain.sh s3wiki.yonsei.ac.kr \
  --expected-ip 165.132.118.220
docker compose config --quiet

저장소 밖에서 Compose를 실행한다면 절대 프로젝트 경로를 적습니다.

docker compose --project-directory /ABS/PATH/TO/s3wiki config --quiet

해석된 설정에는 비밀번호와 토큰 해시가 있으므로 일반 확인에는 config --quiet를 사용합니다.

호스트 포트 8765를 이미 사용 중임

8765는 도메인 배포의 loopback 진단 포트입니다. Caddy는 Compose 네트워크에서 mcp-http:8000에 연결하므로 호스트 진단 포트를 바꿔도 클라이언트 주소는 그대로입니다.

S3RM_MCP_PUBLIC_URL=https://s3wiki.yonsei.ac.kr/mcp
S3RM_MCP_BIND_ADDRESS=127.0.0.1
S3RM_MCP_HTTP_PORT=18765
S3RM_MCP_ALLOW_INSECURE_HTTP=false

공용 MCP를 다시 만들고 127.0.0.1:18765/healthz로 프로세스를 확인합니다.

docker compose up -d --force-recreate mcp-http

클라이언트 주소는 계속 https://s3wiki.yonsei.ac.kr/mcp입니다. 새 진단 포트를 외부에 열거나 로컬 대체 MCP를 시작하지 마세요.

호스트 포트 8080을 이미 사용 중임

사용하지 않는 포트를 고르고 외부 URL은 그대로 둡니다.

S3RM_HTTP_PORT=8090
MW_SERVER_URL=https://s3wiki.yonsei.ac.kr

MediaWiki를 다시 만듭니다.

docker compose up -d --force-recreate mediawiki bootstrap

이 포트는 직접 진단용입니다. 브라우저 링크와 리디렉션은 계속 https://s3wiki.yonsei.ac.kr/를 사용해야 합니다.

호스트 포트 80 또는 443을 이미 사용 중임

공개 배포에서는 Caddy가 두 포트를 모두 사용해야 합니다. 관련 없는 서비스를 바로 멈추지 말고 리스너부터 확인합니다.

ss -ltnp '( sport = :80 or sport = :443 )'
docker compose ps caddy
docker compose logs --tail=200 caddy

충돌하는 서비스를 옮기거나 설정을 바꾼 뒤 Caddy를 다시 만듭니다. 공개 포트를 다른 번호로 우회하면 일반 HTTPS URL과 인증서 검증이 실패합니다.

DNS는 맞지만 루트 주소가 연결 재설정 또는 거부로 열리지 않음

브라우저에서 루트 주소가 ERR_CONNECTION_RESET 또는 Connection refused로 끝나고 DNS가 165.132.118.220을 가리킨다면 실제 리스너부터 확인합니다.

getent ahostsv4 s3wiki.yonsei.ac.kr
ss -ltn '( sport = :80 or sport = :443 or sport = :8080 or sport = :8765 )'
docker compose ps -a

80/443은 없고 8080/8765만 보이면 MediaWiki와 MCP의 진단 포트만 열린 상태입니다. Caddy가 든 Compose domain 프로필이 시작되지 않은 것이므로 방화벽이나 커널 설정을 먼저 바꾸지 마세요.

기본 도메인 설정에서는 8080을 127.0.0.1에만 게시하므로 다른 컴퓨터에서 접속할 수 없습니다. 서버 담당자가 직접 HTTP 화면도 열기로 했다면 다음 두 값을 함께 설정하고 MediaWiki를 다시 만듭니다.

S3RM_WIKI_BIND_ADDRESS=0.0.0.0
S3RM_WIKI_DIRECT_URL=http://165.132.118.220:8080
docker compose up -d --no-deps --force-recreate mediawiki

이후 서버에서 직접 주소가 자기 주소로 이동하는지 확인합니다.

curl --silent --show-error --head http://165.132.118.220:8080/

Location이 같은 IP의 8080을 가리키면 도메인과 직접 주소가 분리된 것입니다. 이 설정은 Docker 리스너만 엽니다. 외부 여러 지역에서 계속 timeout이면 학교 경계에서 TCP 8080이 차단된 상태이므로 보안정책에 8080을 별도로 추가해야 합니다. 직접 HTTP 주소를 MCP에 등록하지 마세요. MCP는 계속 HTTPS 도메인 하나만 사용합니다.

Docker socket 접근이 permission denied로 실패하고 sudo 암호가 필요한 서버에서는 대화형 셸에서 다음 한 줄을 실행합니다.

cd /home/mrcha033/Projects/s3wiki; sudo -v; make domain-up COMPOSE='sudo docker compose'

sudo -v는 자격을 먼저 확인합니다. COMPOSE에만 sudo를 붙이면 저장소 파일과 .env는 현재 사용자 소유로 남습니다. sudo make domain-up을 실행하거나 /var/run/docker.sock을 mode 666으로 바꾸지 마세요. 이 증상 때문에 sysctl을 바꾸지 않습니다.

실행 뒤 서비스, Caddy 로그, 공개 포트, HTTPS 응답을 차례로 확인합니다.

sudo docker compose --profile domain ps -a
sudo docker compose --profile domain logs --tail=200 caddy
ss -ltn '( sport = :80 or sport = :443 )'
curl --fail --silent --show-error --head https://s3wiki.yonsei.ac.kr/
curl --fail --silent --show-error \
  'https://s3wiki.yonsei.ac.kr/api.php?action=query&meta=siteinfo&format=json' \
  >/dev/null

caddy가 실행 중이고 80/443이 리슨하며 두 curl이 성공해야 외부 브라우저에서 확인합니다. 실패하면 Caddy 로그의 인증서 또는 포트 오류를 먼저 해결합니다.

HTTPS 인증서가 발급되지 않음

DNS가 이 서버를 가리키고 두 공개 포트가 서버까지 들어오는지 확인합니다.

getent ahostsv4 s3wiki.yonsei.ac.kr
docker compose ps caddy
docker compose logs --tail=300 caddy

예상 IPv4는 165.132.118.220입니다. DNS가 맞다면 캠퍼스·호스트 방화벽과 포트 소유 프로세스를 확인합니다. caddy_data를 지워도 DNS나 라우팅은 고쳐지지 않으며 불필요한 인증서 요청만 늘어날 수 있습니다. 외부 연결을 고친 뒤 Caddy만 다시 만들고 다른 네트워크에서 확인합니다.

docker compose up -d --force-recreate caddy
curl --fail --silent --show-error --head https://s3wiki.yonsei.ac.kr/

Caddy가 80/443을 리슨하고 서버 안에서는 HTTP 308이 나오는데 로그에 다음 문구가 있다면 애플리케이션 문제가 아닙니다.

Timeout during connect (likely firewall problem)

Let’s Encrypt의 http-01tls-alpn-01이 모두 이 오류라면 외부에서 서버의 TCP 80과 443에 들어오지 못하는 상태입니다. 연세대학교 정보통신처의 보안정책서비스 안내에 따라 보안정책 신청을 합니다. 네트워크 PORT 신청은 벽면 네트워크 포트 설치 절차이므로 이 문제와 다릅니다. 신청 화면에는 다음 값을 적습니다. 소속, 성명, 연락처, 이메일은 신청자가 직접 입력합니다. 개인 연락처나 계정 정보는 이 저장소에 남기지 않습니다.

신청 항목 입력값
소속 신청자 소속 직접 입력
성명 신청자 성명 직접 입력
연락처 신청자 연락처 직접 입력
이메일 신청자 연세 이메일 직접 입력
시작일 2026-07-16
종료일 2029-07-15
출발지 IP 공개 웹서비스 80/443 예외 적용 요청. 출발지는 공개 웹서비스이므로 특정할 수 없습니다.
목적지 IP 165.132.118.220
프로토콜 TCP만 선택
사용포트 80, 443
요청사유 및 특이사항 아래 문안 붙여넣기

정책 기간은 최대 3년이므로 위 종료일은 시작일로부터 3년 이내입니다. 출발지 IP 칸이 숫자 주소만 받는다면 임의의 IP를 넣지 말고 보안정책 담당자 02-2123-6419에 공개 웹서비스 예외 입력 방법을 확인합니다.

요청사유 및 특이사항에는 다음 내용을 붙여넣습니다.

S3 연구실에서 함께 사용하는 위키(s3wiki.yonsei.ac.kr)를 운영하려고 합니다.
DNS는 165.132.118.220으로 등록되어 있고 서버도 80/443 포트에서 대기 중이지만,
현재 외부 연결이 차단되어 HTTPS 인증서 검증이 실패합니다.

HTTPS 접속과 인증서 자동 발급·갱신을 위해 목적지
165.132.118.220의 TCP 80, 443에 대한 외부 인바운드 허용을 요청드립니다.
출발지는 공개 웹서비스이므로 특정할 수 없습니다. 80은 인증서 검증과 HTTPS 전환,
443은 위키와 MCP 접속에 사용합니다. 그 밖의 포트 개방은 요청하지 않습니다.

공식 안내에는 필요한 웹서비스의 80/443은 출발지 IP 특정 조건의 예외라고 적혀 있습니다. 보안정책 문의는 정보통신처 02-2123-6419, 인터넷 문의는 02-2123-3411입니다.

포트가 열리면 Caddy가 인증서 발급을 자동으로 다시 시도합니다. Caddy 로그의 certificate obtained successfully와 서버의 make verify-domain을 확인한 뒤 학교 밖 네트워크의 브라우저를 다시 여세요. 인증서 볼륨을 지우거나 자체 서명 인증서로 바꾸지 마세요.

docker compose --profile domain logs --follow caddy
make verify-domain

/etc/group에는 이미 사용자가 docker 그룹에 있는데 현재 셸만 Docker 권한을 읽지 못한다면 로그아웃한 뒤 다시 로그인합니다. 바로 새 셸에서 작업하려면 newgrp docker를 실행한 뒤 위 명령을 사용합니다.

MariaDB가 unhealthy 상태임

관련 상태와 로그 끝부분만 확인합니다.

docker compose ps db
docker compose logs --tail=200 db

주요 원인은 비어 있거나 잘못된 필수 비밀번호, 디스크 부족, 볼륨 소유권 문제, db_data 초기화 뒤 .env의 DB 비밀번호만 바꾼 경우입니다. 환경 변수만 바꿔도 기존 MariaDB 계정은 바뀌지 않습니다. 이전에 맞던 .env를 복구하거나 계획된 DB 계정 교체를 수행하세요. 오류를 없애려고 db_data를 지우지 마세요.

MediaWiki가 unhealthy 상태임

첫 빌드와 마이그레이션에는 몇 분이 걸릴 수 있습니다. 의존 서비스와 로컬 상태 경로를 확인합니다.

docker compose ps -a
docker compose logs --tail=300 mediawiki
curl --fail --silent --show-error \
  'https://s3wiki.yonsei.ac.kr/api.php?action=query&meta=siteinfo&format=json'

DB 인증 불일치, 호환되지 않는 고정 확장 기능, Composer 빌드 실패, 디스크 부족, 잘못된 MW_SERVER_URL을 확인합니다. 로그의 원인을 고치고 서비스를 다시 만드세요. 생성된 설정 볼륨을 직접 편집하지 않습니다.

브라우저에 설치 세션 만료가 표시됨

이 메시지는 MediaWiki의 대화형 /mw-config/ 설치 화면에서 나옵니다. 이 배포는 해당 화면을 사용하지 않습니다. mediawiki entrypoint가 Apache를 시작하기 전에 CLI로 설치하고, 생성된 설정은 mediawiki_config 볼륨에 저장합니다. 세션 만료는 지원하지 않는 경로를 연 증상이지 원인이 아닙니다.

<!-- Contract marker: Do not increase session.gc_maxlifetime --> session.gc_maxlifetime를 늘리거나, 브라우저 설치를 다시 시작하거나, LocalSettings.php를 내려받거나, 볼륨을 지우지 마세요. 세션 수명만 늘려도 CLI 설정은 고쳐지지 않습니다.

설치 탭을 닫고 상태와 로그를 확인합니다.

docker compose ps -a
docker compose logs --tail=300 mediawiki bootstrap

mediawiki가 실행 중이면 설정 내용을 출력하지 않고 영구 설정과 이미지의 symlink를 확인합니다.

docker compose exec mediawiki \
  sh -c 'test -s /var/www/data/LocalSettings.php &&
    test "$(readlink -f /var/www/html/LocalSettings.php)" = /var/www/data/LocalSettings.php &&
    stat -c "%a %U %G %n" /var/www/data /var/www/data/LocalSettings.php \
      /opt/s3wiki/LocalSettings.s3.php /var/www/html/LocalSettings.php'

이미지는 시작할 때마다 다음 권한을 맞춥니다. 설정 디렉터리는 750 root:www-data, 생성된 LocalSettings.php640 root:www-data, web root symlink는 www-data 소유입니다. 비밀 정보가 없는 이미지 설정 파일은 Apache가 읽을 수 있습니다. upstream web root가 sticky이고 Linux의 보호된 symlink 동작이 있으므로 symlink 소유권도 필요합니다. API healthcheck는 설치 화면의 200 OK HTML이 아니라 MediaWiki JSON을 확인합니다.

위 검사가 성공하면 mediawiki가 healthy, bootstrap이 코드 0이 될 때까지 기다린 뒤 /mw-config/가 아니라 MW_SERVER_URL을 엽니다.

기준 데이터가 한 번도 없었던 새 시험 스택이라면 이미지와 서비스를 다시 만들어 CLI 설치를 실행합니다.

docker compose up -d --build --force-recreate mediawiki bootstrap
docker compose logs -f mediawiki bootstrap

운영하던 배포에서 LocalSettings.php를 잃었다면 여기서 진단을 멈춥니다. 기존 DB에 다시 설치하거나 볼륨을 지우지 마세요. operations.md에 따라 같은 시점의 DB, 설정, 업로드 백업을 복원합니다.

bootstrapExited (0)

정상입니다. bootstrap은 daemon이 아니라 일회성 동기화 작업입니다. 평소에는 db, mediawiki, mcp-http가 healthy이고 bootstrap은 코드 0으로 종료됩니다.

bootstrap이 0이 아닌 코드로 끝남

docker compose logs --tail=300 bootstrap

주요 원인은 다음과 같습니다.

  • administrator login failed: .envMW_ADMIN_PASSWORD가 설치된 위키와 다릅니다. 이 값은 최초 설치 때만 관리자 계정을 만듭니다. .env만 바꿔도 위키 비밀번호는 바뀌지 않습니다.
  • manifest source is missing: 이미지 또는 저장소가 불완전합니다. 온전한 checkout에서 다시 빌드합니다.
  • edit failed/permission denied: 관리자 권한이 없어졌거나 관리 페이지가 예상과 다르게 보호되어 있습니다.
  • account provisioning failed: S3RM_WIKI_USERNAME을 확인합니다. DB 테이블을 직접 고치지 말고 MediaWiki 절차로 전용 계정을 교체합니다.

원인을 고친 뒤 다시 실행합니다.

docker compose up -d --build --force-recreate bootstrap
docker compose logs --tail=200 bootstrap

bootstrap은 관리 스키마와 양식을 맞추지만 일반 Lesson revision을 덮어쓰지 않습니다. 동기화 경고가 반복되면 우회하지 말고 원인을 확인하세요.

관리자 비밀번호가 .env와 맞지 않음

첫 설치 뒤 MW_ADMIN_PASSWORD만 바꿔도 MediaWiki에 저장된 비밀번호는 바뀌지 않습니다. 기존 비밀번호를 알고 있다면 .env 값을 다시 맞춥니다. 알 수 없다면 권한이 있는 서버 담당자가 고정된 MediaWiki 버전의 명령 도움말을 확인한 뒤 재설정합니다.

docker compose exec mediawiki \
  php maintenance/run.php resetPassword --help

현재 이미지가 출력한 문법만 사용합니다. 복구 작업을 기록하고, 추적하지 않는 .env를 갱신한 뒤 bootstrap을 다시 실행합니다. 새 비밀번호를 셸 기록에 직접 넣지 마세요.

양식이 없거나 Lesson이 template 원문으로 표시됨

  1. bootstrap이 코드 0으로 끝났는지 확인합니다.
  2. /index.php/Special:Version에서 Semantic MediaWiki, Page Forms, S3 Research Memory가 로드되었는지 확인합니다.
  3. Form:Lesson과 기준 template이 있는지 확인합니다.
  4. bootstrap을 다시 실행하고 로그를 봅니다.
docker compose up -d --force-recreate bootstrap
docker compose logs --tail=200 bootstrap

관리 양식이나 template 페이지를 직접 고치지 마세요. bootstrap이 이미지의 원본으로 맞춥니다.

Lesson ID 또는 양식 검증이 실패함

기준 ID 형식은 다음과 같습니다.

Lesson:<lowercase_slug>

slug는 소문자, 숫자, _, -만 사용할 수 있습니다. 첫 글자는 문자나 숫자이고 최대 128자입니다. 화면 제목인 title은 별도 필드이며 일반적인 대문자를 쓸 수 있습니다. 필수 연구 필드는 비울 수 없습니다. confidence는 low, medium, high 중 하나입니다.

새 Lesson이 검색되지 않음

페이지를 직접 열어 Lesson: 네임스페이스인지 먼저 확인합니다. /index.php/Special:Search에서 제목이나 본문의 구별되는 정확한 단어로 검색합니다. 먼저 대기 중인 MediaWiki·Semantic MediaWiki 작업을 실행합니다. 색인이 손상되었거나 DB 복원 뒤 누락된 경우에만 검색 색인을 다시 만듭니다.

docker compose exec mediawiki \
  php maintenance/run.php runJobs --maxjobs 100
docker compose exec mediawiki \
  php maintenance/run.php rebuildtextindex --quiet

기본 S3RM_EMBEDDING_PROVIDER=disabled에서는 띄어쓰기와 단어 기반 검색이므로 비슷한 뜻의 다른 단어까지 찾는다고 보장하지 않습니다. 도메인을 넘는 연결은 관계나 find_analogies를 사용합니다. 의미 검색을 켰더라도 클라이언트가 retrieval_mode=hybrid_v1을 명시해야 합니다. 서비스 시작 시 단 하나의 백그라운드 작업이 전체 파생 인덱스를 프리웜합니다. hybrid 요청은 구축을 기다리지 않으며, 아직 snapshot이 없으면 semantic_status=building과 함께 즉시 기존 검색으로 대체됩니다. MCP Lesson 저장의 dirty hint는 즉시 백그라운드 대조를 시작합니다. 설정한 간격이 지나면 다음 hybrid 요청이 브라우저 편집까지 포함한 대조를 시작하며 기존 snapshot을 계속 사용합니다. 최종 결과는 MediaWiki 최신 revision으로 다시 확인하므로 오래된 의미 후보가 새 본문으로 반환되지는 않습니다.

MCP 검색만 실패한다면 어댑터와 namespace ID를 확인하고 Action API 요청에 srwhat=text가 포함되는지 확인합니다. 조회에는 Bearer 토큰이 필요하지 않습니다.

의미 검색이 시작되지 않거나 기존 검색으로 대체됨

mcp-http 시작 로그에 임베딩 설정 오류가 있으면 .env에서 다음 항목을 먼저 확인합니다.

S3RM_EMBEDDING_PROVIDER=openai-compatible
S3RM_EMBEDDING_API_URL=https://embedding.example/v1/embeddings
S3RM_EMBEDDING_MODEL=multilingual-embedding-model
S3RM_EMBEDDING_DIMENSIONS=768

provider 값은 disabled 또는 openai-compatible만 받습니다. 사용 시 URL, 모델, 차원이 모두 필요합니다. URL에는 사용자 이름, 비밀번호, query와 fragment를 넣을 수 없습니다. 비-loopback HTTP는 S3RM_EMBEDDING_ALLOW_INSECURE_HTTP=true를 명시하지 않으면 거부합니다.

설정을 고친 뒤 서비스만 다시 만듭니다.

docker compose config --quiet
docker compose up -d --build --force-recreate mcp-http
docker compose logs --tail=200 mcp-http

재시작 직후 semantic_status=building으로 기존 검색이 반환되는 것은 정상입니다. 잠시 뒤 새 첫 페이지 요청에서 ready인지 확인합니다. 사용할 기존 snapshot이 있는 동안 백그라운드 갱신 중이면 stale, 갱신에 실패하면 degraded로 hybrid 결과를 계속 제공할 수 있습니다.

unavailable이 계속되거나 hybrid_v1 요청이 반복해서 기존 검색으로 대체되면 제공자 timeout, 대기열 포화, 응답 차원 불일치 또는 0·비정상 벡터일 수 있습니다. 제공자의 모델 차원이 S3RM_EMBEDDING_DIMENSIONS와 같은지 확인합니다. 제한을 무조건 키우기 전에 endpoint 상태와 모델 설정을 확인하세요. 의미 제공자 장애만으로 /healthz를 실패시키지는 않으며 전체 텍스트와 관계 검색은 계속 제공합니다.

진단을 공유할 때 S3RM_EMBEDDING_API_KEY, Authorization 헤더, 원문 query, Lesson 본문과 전체 환경 dump를 지웁니다. API key를 명령행 인자나 임시 Lesson에 넣어 연결을 시험하지 마세요.

MCP 클라이언트가 끊겼거나 도구가 보이지 않음

모든 클라이언트는 같은 공용 Streamable HTTP URL을 사용해야 합니다. 서버에서 자격 증명을 출력하지 않고 전체 상태와 프로세스 경로를 확인합니다.

docker compose ps -a caddy mcp-http mediawiki bootstrap db
curl --fail --silent --show-error http://127.0.0.1:8765/healthz
docker compose logs --tail=200 mcp-http caddy

로컬 health 요청은 프로세스 실행만 확인합니다. 다른 PC에서 setup.md의 토큰 없는 초기화를 정확한 https://s3wiki.yonsei.ac.kr/mcp 주소로 실행합니다. Authorization 없이 초기화되어야 하며 도구 목록과 다섯 조회 도구도 공개되어야 합니다.

다음 값을 확인합니다.

S3RM_MCP_PUBLIC_URL=https://s3wiki.yonsei.ac.kr/mcp
S3RM_MCP_WRITE_AUTH_MODE=token
S3RM_MCP_BIND_ADDRESS=127.0.0.1
S3RM_MCP_ALLOW_INSECURE_HTTP=false

먼저 Authorization 없이 공개 조회를 시험합니다. 로컬 health만 성공하고 원격 초기화가 실패하면 Caddy 로그, TLS, DNS, 80/443을 확인합니다. 클라이언트를 localhost에 연결하거나 별도 MCP 프로세스를 만들지 마세요.

클라이언트 주소는 정확히 공용 URL이어야 합니다. token 모드에서 변경 도구를 쓸 때만 공용 Bearer 토큰을 불러옵니다. open 모드에서는 조회와 변경 도구 네 개에 인증이 필요하지 않습니다. 클라이언트 사용자에게 Docker 명령, MediaWiki API URL, 위키 자격 증명을 전달하지 마세요. 플랫폼별 확인은 mcp-clients.md를 봅니다.

MCP /healthz가 실패함

서버에서 Connection refused가 나오면 mcp-http가 설정된 bind·port에 리슨하지 않는 상태입니다. timeout은 호스트 방화벽이나 멈춘 프로세스일 수 있습니다.

docker compose ps mcp-http
docker compose logs --tail=200 mcp-http
docker compose up -d --force-recreate mcp-http

주요 시작 오류는 잘못된 쓰기 인증 모드, token 모드에서 잘못되거나 빠진 64자리 공용 토큰 해시, 43~256자 URL-safe revision HMAC 키 누락, github 모드에서 빠진 client ID·secret·allowlist, /mcp로 끝나지 않는 공개 URL, 명시적인 허용 없이 쓴 비-loopback HTTP, 이미 사용 중인 bind port입니다. .env를 고치고 docker compose config --quiet를 실행한 뒤 mcp-http만 다시 만듭니다.

GitHub OAuth 연결이 실패함

GitHub OAuth App callback URL이 다음 값과 정확히 같은지 확인합니다.

https://s3wiki.yonsei.ac.kr/oauth/github/callback

S3RM_GITHUB_ALLOWED_USERSS3RM_GITHUB_ALLOWED_ORGS는 GitHub 로그인 이름을 쉼표로 구분합니다. private 조직 membership을 확인하려면 사용자가 GitHub 승인 화면에서 read:org를 허용해야 합니다. mcp-http를 다시 만들면 메모리에 있던 OAuth client와 token이 사라지므로 ChatGPT 앱 인증을 다시 진행합니다. 일반 설정은 URL https://s3wiki.yonsei.ac.kr/mcp, bind 127.0.0.1, allow flag false입니다. 같은 endpoint의 네 변경 도구에는 mcp:write scope가 필요합니다.

health는 성공하지만 공용 /mcp가 실패하면 프로세스는 살아 있습니다. 직접 IP 경로와 아래 HTTP 상태 항목을 확인합니다. /healthz는 변경 자격 증명이나 위키 로그인을 확인하지 않습니다.

MCP 변경 도구에서 인증 오류가 남

먼저 .envS3RM_MCP_WRITE_AUTH_MODE를 확인합니다. open인데 인증 오류가 남는다면 설정 변경 뒤 mcp-http를 다시 만들지 않은 상태일 수 있습니다.

docker compose up -d --build --force-recreate mcp-http

아래 토큰 진단은 token 모드에만 적용합니다.

이 오류가 있어도 익명 초기화, 도구 목록, 조회는 동작해야 합니다. 네 변경 도구의 인증 오류는 Bearer 헤더가 없거나 형식이 틀리거나 S3RM_MCP_TOKEN_SHA256과 맞지 않는다는 뜻입니다. 비교할 때 어느 값도 출력하지 마세요. GitHub 모드에서는 mcp:write scope가 필요합니다. open 모드라면 네 도구에 별도 인증이 없습니다. revise_lesson 요청이 위키 저장 경계에서 거부되면 서버 내부의 S3RM_WIKI_REVISION_HMAC_KEYmediawikimcp-http가 같은 값으로 읽는지 확인하되 값을 출력하지 않습니다.

서버에서 기존 HTTPS 토큰과 해시를 바꾸거나 출력하지 않고 확인합니다.

./scripts/configure-mcp-token.sh \
  --public-url https://s3wiki.yonsei.ac.kr/mcp

비공개 클라이언트 토큰이 없거나 맞지 않는다고 나오면 기존 전달 사본에서 원문을 복구합니다. 모든 쓰기 클라이언트를 함께 바꿀 수 있을 때만 --rotate를 사용하세요. mcp-http를 다시 만들면 이전 토큰이 무효가 됩니다.

쓰기 클라이언트에서는 시작 전에 지원하는 secret 또는 환경 설정으로 토큰을 불러옵니다. 추적되는 JSON·TOML이나 공개 진단에 넣지 마세요. 정적 헤더를 저장하지 못하는 호스팅 커넥터에는 OAuth 진입점이 필요합니다.

MCP가 HTTP 403을 반환함

이 파일럿에서 403은 보통 요청 Origin이 정확히 허용되지 않았다는 뜻입니다. 민감한 값을 지운 요청 Origin을 S3RM_MCP_PUBLIC_URL, S3RM_MCP_ALLOWED_ORIGINS와 비교합니다. 의도한 정확한 HTTP(S) Origin만 쉼표로 추가하고 서비스를 다시 만듭니다.

docker compose up -d --force-recreate mcp-http

*를 추가하거나 Origin 검사를 끄지 마세요. Origin은 전체 /mcp URL이 아닙니다. CLI 클라이언트는 보통 Origin을 생략하지만 호스팅형·브라우저형 클라이언트는 보낼 수 있습니다.

MCP가 HTTP 421을 반환함

421은 정확한 Host 헤더가 공개 URL host 또는 S3RM_MCP_ALLOWED_HOSTS 항목과 맞지 않는다는 뜻입니다. 프록시가 Host를 바꾸거나, 클라이언트가 이전 IP URL을 쓰거나, 공개 URL의 포트가 틀린 경우가 많습니다.

클라이언트 주소를 S3RM_MCP_PUBLIC_URL과 맞춥니다. 저장소의 Caddyfile은 공개 Host를 보존하므로 Caddy를 통과한 421은 보통 .env나 클라이언트가 이전 주소를 쓰는 경우입니다. 도메인 스크립트를 다시 실행하고 mcp-http와 Caddy를 다시 만듭니다. 등록된 공용 URL 대신 localhost나 IP를 쓰지 마세요.

MCP HTTP는 열리지만 도구가 위키 인증에 실패함

초기화는 성공하지만 조회와 변경 도구에서 위키 인증 오류가 나오면 S3RM_WIKI_USERNAME 또는 S3RM_WIKI_PASSWORDbootstrap이 만든 계정과 맞지 않을 수 있습니다. 전용 계정을 맞추고 공용 어댑터를 다시 만듭니다.

docker compose up -d --force-recreate bootstrap
docker compose logs --tail=100 bootstrap
docker compose up -d --force-recreate mcp-http

Compose 내부 API 주소는 http://mediawiki/api.php입니다. 호스트의 localhost 주소가 아닙니다. 관리자 자격 증명을 넣거나, api.php를 클라이언트에 직접 열거나, MCP 변경 인증을 끄는 방식으로 우회하지 마세요.

Cursor가 잘못되었거나 요청과 맞지 않음

Cursor는 불투명한 값이며, 이를 만든 도구, query, filter, 선택 field, citation detail, analogy threshold에 묶입니다. get_lesson의 하위 cursor와 audit_lessons cursor는 읽은 revision에도 묶입니다. next_cursor를 바꾸지 말고 그대로 넘깁니다. parameter나 대상 revision이 달라졌다면 이전 cursor를 버리고 첫 페이지부터 시작합니다. Cursor는 Lesson ID가 아니며 해독하거나 편집하지 않습니다.

결과가 잘렸거나 limit보다 적음

모든 직렬화 결과에는 크기 제한이 있습니다. 목록 페이지에는 page_limited_by_output, 모든 결과에는 output_truncated가 표시될 수 있습니다. field 수나 limit을 줄이고 next_cursor를 이어서 사용합니다. 목록 limit은 1~20이며 기본값은 5입니다. S3RM_MAX_OUTPUT_BYTES 기본값은 32768이고 2048~65536만 받습니다. 그보다 높은 hard limit으로 올릴 수 없습니다. SDK 검증 오류를 포함한 전체 JSON-RPC HTTP body에는 별도 212992바이트 제한이 있습니다.

큰 결과를 한 번에 받으려고 제한을 높이지 마세요. 먼저 검색 요약을 받고, 추린 결과에 대해 선택 field로 get_lesson을 호출합니다. citation_detail=full에서 근거 한 항목이 한도에 맞지 않으면 note를 조용히 자르지 않고 output_budget_error를 반환합니다. 필요한 근거를 더 작은 페이지로 요청하되, 한 항목 자체가 너무 크면 서버의 허용된 근거 길이와 출력 설정을 확인합니다.

의미 검색이 켜지지 않음

번들 GPU 모델을 쓸 때는 제공자와 Compose profile을 함께 켭니다.

S3RM_EMBEDDING_PROVIDER=openai-compatible
COMPOSE_PROFILES=domain,embedding

설정 뒤 고정 모델 확인, 런타임 시작, mcp-http 재생성과 연결 검사를 한 번에 실행합니다.

make embedding-up
make verify-embedding

응답의 semantic_status=disabled는 실행 오류가 아니라 제공자가 꺼진 상태입니다. building은 첫 exact index를 만드는 중이며 이때 기존 검색으로 즉시 대체합니다. unavailable이면 아래 런타임 로그와 mcp-http 로그를 확인합니다. 외부 임베딩 API로 자동 전환되지는 않습니다.

GPU 임베딩 서비스가 시작되지 않음

모델 확인 작업과 런타임을 나눠 봅니다.

docker compose --profile embedding ps -a embedding-model-init embedding
docker compose --profile embedding logs --tail=200 embedding-model-init embedding
ls -l /dev/dri/renderD128
vulkaninfo --summary

embedding-model-init의 checksum 오류는 모델 파일, source commit, 크기, SHA-256, generation revision 중 일부가 서로 다른 상태입니다. 값을 임의로 완화하지 말고 같은 artifact 기준으로 모두 맞춥니다. 부분 파일은 다음 실행에서 이어받고, 잘못된 완성 파일은 init 작업이 제거한 뒤 다시 받습니다.

embedding에서 render node 권한 오류가 나면 호스트의 실제 장치와 group ID를 확인해 S3RM_EMBEDDING_DRI_DEVICE, S3RM_RENDER_GID를 맞춥니다. 이 서버의 기본값은 /dev/dri/renderD128, 987입니다. 장치 번호를 바꾼 뒤 컨테이너 안의 별칭은 계속 Vulkan0인지 로그에서 확인합니다. 호스트 포트 8080을 열어 우회하지 마세요.

긴 입력에서 timeout이나 GPU 메모리 오류가 반복되면 먼저 기본 동시성 1과 batch 6을 유지하고 query 길이를 줄입니다. 16K token보다 큰 입력은 같은 generation 계약에서 지원하지 않습니다. 실패 중에도 legacy 검색은 계속 사용할 수 있습니다.

관계 추가가 거부됨

양쪽 Lesson이 이미 있어야 하고 기준 ID 형식이어야 합니다. 자기 자신으로 향하는 관계, 같은 edge 중복, 일곱 개 어휘 밖의 관계 이름은 거부합니다. analogous_to는 양방향으로 조회하지만 한 번만 저장합니다. 양끝을 바꾼 edge를 따로 만들 필요가 없습니다.

supersedes 관계를 추가해도 연결만 기록합니다. 두 Lesson의 호환 상태는 바꾸지 않습니다.

근거 첨부가 거부됨

다음을 확인합니다.

  • 대상 Lesson이 있습니다.
  • citation은 추적 가능한 3~500자의 사람이 읽을 수 있는 참고문헌입니다.
  • kindpaper, code, dataset, log, benchmark, other 중 하나입니다.
  • verification_basisfull_text, official_abstract, partial_source, metadata_only, not_recorded 중 하나입니다.
  • 선택 사항인 evidence ID는 해당 Lesson에서 고유하고 영문·숫자·._:-만 사용합니다.
  • 선택 URL은 HTTP(S)이며 사용자 이름과 비밀번호가 없습니다.
  • note는 2000자 이하입니다.

확인 범위는 신뢰도가 아니라 실제 읽은 자료 범위입니다. 서지정보만 확인했다면 metadata_only로 표시하고 기술 내용을 채우지 않습니다. 검증을 없애거나 관리자 자격 증명을 넣지 마세요. 근거 위치를 고치고 다시 시도합니다.

Lesson revision이 거부됨

revise_lesson은 현재 expected_revision_id, 다른 값이 있는 핵심 필드, 고유한 operation_id, 이유와 이미 붙은 basis evidence 1~8개가 필요합니다.

  • revision_conflict: 다른 변경이 먼저 저장됐습니다. get_lesson을 다시 읽고 변경안을 재계산합니다. 자동 병합하거나 이전 revision으로 반복하지 않습니다.
  • missing_basis_evidence: 근거를 먼저 attach_evidence로 붙이고, 응답의 current_revision_id를 새 기준으로 사용합니다.
  • no_changes: 현재 내용과 같은 요청입니다. 새 Technical Review Lesson을 만들지 않습니다.
  • idempotency_conflict: 같은 operation_id를 다른 요청에 재사용했습니다. 성공 여부가 불분명한 재시도는 원래 요청을 그대로 보내고, 새 작업에는 새 ID를 사용합니다.
  • write_outcome_unknown: 원래 operation_id와 요청을 그대로 재시도합니다. 적용 여부를 확인하기 전에 새 ID로 같은 수정을 보내지 않습니다.

operation replay와 충돌 검사는 해당 Lesson의 최근 50개 revision을 확인합니다. write_outcome_unknown은 즉시 같은 요청으로 재시도하고, 오래 보관할 작업 ID는 다시 쓰지 않습니다.

같은 주장이나 같은 논문의 보강은 같은 Lesson ID의 revision으로 남깁니다. 출처만 추가할 때는 evidence, 독립된 새 주장이 이전 주장을 실제로 대신할 때만 새 Lesson과 supersedes를 사용합니다.

백업이 실패함

완료되지 않은 출력은 진단을 위해 보존하되 복구 지점으로 표시하지 않습니다. 디스크 여유 공간, 대상 권한, 서비스 상태, 마지막 오류를 확인합니다. 이전 정상 백업을 지우지 마세요. 원인을 고친 뒤 새 시각의 디렉터리로 다시 실행합니다.

복원 스크립트가 백업을 거부함

checksum, manifest, archive, version 검증 실패는 현재 기준 데이터를 보호합니다. --yes를 반복해서 붙이거나, manifest를 고치거나, 다른 시각의 파일을 섞거나, SQL만 직접 가져오지 마세요. 복구 세트의 작업 사본에서 출처나 전송 손상을 조사하고, 가장 최근의 온전하고 호환되는 백업을 사용합니다. operations.md를 참고하세요.

디스크 사용량이 갑자기 늘어남

DB, upload, build cache, log, 보관 백업을 나눠 확인합니다. 이름이 있는 볼륨을 지우지 마세요. 업로드 근거 기준과 백업 보관 정책을 확인합니다. 다시 만들 수 있는 Docker build cache·image만 서버 담당자의 확인 뒤 정리합니다. 큰 원본 파일은 정해진 object store로 옮기고 Lesson에는 오래 유지되는 인용을 남깁니다.

그래도 문제가 남으면 버전, 정확한 명령, 종료 코드, 민감한 값을 지운 로그 끝부분, docker compose ps -a, 비파괴 재시작 뒤에도 재현되는지를 기록합니다.