개발 취재록

AI 코딩 에이전트로 백그라운드 프로그램을 띄우면 몇 초 뒤 사라지는 이유 — 버그가 아니라 에이전트 셸의 프로세스 정리였다

윈도우에서 늘 대기하다가 "Hey Jarvis"라고 부르면 말을 받아 적어 Claude Code에 넘기고 답을 읽어 주는 로컬 음성 비서(voice-assistant)를 쓰고 있었다. 어느 날 재부팅 뒤 비서가 떠 있지 않아서 AI 코딩 에이전트에게 원인을 찾게 했다. 그런데 에이전트가 직접 띄워 본 프로세스도 20초쯤 지나면 계속 사라졌다. 그래서 "떠도 바로 죽는 버그"처럼 보였다.

결론

에이전트 셸에서 띄운 백그라운드 프로세스가 사라졌다고 해서 프로그램이 죽었다고 단정하면 안 된다. 에이전트의 명령 실행 환경이 호출이 끝날 때 자기가 띄운 자식 프로세스를 함께 정리했을 수 있다. 이 사건에서는 같은 프로그램을 에이전트 셸에서 띄우면 사라졌지만, 셸 밖(WMI)에서 띄우니 30초 내내 살아 있었고 로그도 계속 쌓였다 .

"떠서 죽는다"고 결론 내기 전에 다음 세 가지로 실행 환경 탓인지부터 가른다.

  1. 띄우는 호출과 확인하는 호출을 나눈다. 띄우는 명령은 바로 반환시키고, 살아 있는지는 별도 호출에서 확인한다
  2. 프로세스 목록만 보지 말고 로그가 늘어나는지도 본다. 한 호출 안에서 로그 파일 크기와 프로세스 등장·소멸을 촘촘히 추적한다
  3. 에이전트 셸의 프로세스 트리 밖에서 띄워 본다. 거기서 살아남는다면 코드가 아니라 실행 환경 문제다

3번을 PowerShell로 하면 다음과 같다. 일반적인 예시이고, 세션에서 실행한 명령 원문은 아니다.

# 에이전트 셸의 자식이 아니라 WMI(CIM)가 새 프로세스를 만든다
Invoke-CimMethod -ClassName Win32_Process -MethodName Create `
  -Arguments @{ CommandLine = 'cmd /c "C:\path\to\start_assistant.bat"' }

# 다음 호출에서 따로 확인: 프로세스가 있고, 로그가 늘어나는가
Get-Process pythonw -ErrorAction SilentlyContinue
(Get-Item C:\path\to\data\main_log.txt).Length

정확히 어떤 메커니즘(예: Windows job object)이 프로세스를 정리했는지는 이 사건에서 확인하지 못했다. 에이전트의 추정이었다 . 그래도 셸 안에서 띄웠을 때와 밖에서 띄웠을 때 결과가 다르다는 사실만으로 가짜 실패를 걸러 낼 수 있었다.

상황

증상

원인

진단에 쓰던 에이전트의 실행 환경이 자기가 띄운 프로세스를 정리하고 있었다. 이 때문에 멀쩡한 프로그램이 죽는 것처럼 보였다.

한계도 있다. vbs 경로는 끝까지 깔끔하게 설명되지 않았다. 같은 세션에서 vbs를 띄운 한 번은 로그가 전혀 늘지 않았고 , 다른 한 번은 로그에 새 "준비 완료"가 찍힌 뒤 20초 만에 사라졌다 . 에이전트는 이것을 "wscript가 곧바로 종료되면서 정리된 것"이며, 부팅 때 explorer가 띄우는 실제 상황과는 다르다고 해석했다 . 이 해석도 검증된 것은 아니다.

해결

덤 — 가짜 단서는 하나 더 있었다

pythonw 실행을 테스트하던 중 error: unrecognized arguments: USB Audio가 떴다. 입력 장치 인자 --device "KT USB Audio"가 공백에서 쪼개져 argparse가 죽은 것으로 보였다 . 하지만 실제 bat을 그대로 돌리자 정상이었다. 그 에러는 테스트용 PowerShell Start-Process 명령의 인용부호 문제였다 .

두 가짜 단서의 뿌리는 같다. 진단하려고 만든 실행 경로가 실제 실행 경로와 달랐다.

다음 날 같은 증상이 다시 나타났을 때, 다른 조사에서는 wscript로 VBS를 네 번 돌려 네 번 모두 실패하자 "부팅 실패를 그대로 재현했다"고 판단했다 . 그런데 바로 다음 실행은 같은 경로로 성공했다 . 그 조사에는 에이전트 셸 밖에서 wscript를 돌려 보는 테스트 기록이 없다. 그래서 그 "4/4 재현"이 실제 부팅 실패와 같은 원인인지, 셸의 프로세스 정리 때문인지는 구분되지 않는다. 이 부분은 두 조사를 대조한 판단이며 검증된 사실은 아니다.

취재 후기 — 범인은 우리 손에 든 돋보기였다

박도은
윈도우에서 늘 대기하다가 "Hey Jarvis" 하면 대답하는 음성 비서 있잖아. 재부팅하고 7분이 지났는데 pythonw가 하나도 없어. 로그도 8월 23일에서 멈췄어
정바다
시작 프로그램에서 빠진 거 아냐? 바로가기가 지워지면 부팅할 때 아무것도 안 뜨잖아.
박도은
시작 프로그램 폴더를 열어 봤는데 VoiceAssistant.lnk가 그대로 있어. 가리키는 곳도 숨김 실행용 VBS 그대로고
정하늘
그럼 '안 떴다'인지 '떴다가 죽었다'인지부터 가르자. 우리가 직접 한 번 띄워 보면 알 수 있어.
박도은
내 셸에서 띄워 봤는데 프로세스가 없어. 로그에 새 줄도 안 붙었어
정바다
그럼 떠서 바로 죽는 거네. 코드 어딘가에서 예외가 터지는데, 콘솔 창이 없는 pythonw라 에러가 안 보이는 거야.
정하늘
그건 콘솔 창이 있는 python.exe로 돌려 보면 가려져. 죽는다면 에러가 화면에 찍힐 테니까.
박도은
콘솔로는 45초가 지나도 안 죽어. 마이크 장치도 잡았고 "준비 완료"까지 떴어
정하늘
코드 문제는 아니네. 남는 차이는 pythonw로 띄우는 bat·vbs 경로야.
박도은
Start-Processpythonw를 띄웠더니 unrecognized arguments: USB Audio가 나왔어
정바다
이거다. 장치 이름 "KT USB Audio"가 공백에서 쪼개져서 argparse, 그러니까 파이썬 명령줄 인자 해석기가 "USB Audio"를 모르는 인자로 보고 죽은 거야.
정하늘
잠깐, 그 인자는 우리가 테스트 명령에 옮겨 적은 거잖아. 진짜 bat을 cmd /c로 그대로 돌려 보면 갈려.
박도은
bat을 돌렸더니 40초가 넘도록 명령이 안 끝나. 로그에는 "준비 완료. Hey Jarvis"가 찍혔어
정하늘
cmd가 안 끝난다는 건 그 밑에서 pythonw가 살아 있다는 뜻이야. 인자 에러는 우리 테스트 명령의 따옴표 문제였어.
박도현
진단하려고 만든 명령이 실제 경로와 다르면, 그 차이가 새로운 버그처럼 보여. 재현은 원래 실행 경로 그대로 해야 해.
박도은
이번엔 부팅 때처럼 vbs로 띄웠어. 20초 뒤에 사라지더라. 아까 bat도 내 백그라운드 작업이 끝나니까 exit 255로 같이 죽었고
정바다
이번엔 내가 조심할게. 우리 셸이 명령이 끝날 때 자기가 띄운 자식 프로세스까지 같이 치우는 거 아닐까? 부팅 때는 explorer가 부모라서 그럴 일이 없고.
정하늘
그럼 띄우는 호출은 바로 끝내고, 살아 있는지는 다른 호출에서 보자. 그래도 없으면 우리 셸의 프로세스 트리 밖, WMI로 띄워 본다.
박도은
호출을 나눠도 없었어. WMI로 처음 띄운 것도 18초 뒤에 사라졌고
박도은
그런데 WMI로 cmd /c bat을 띄우니까 30초 내내 pythonw 두 개가 살아 있어. 로그도 60615에서 60777바이트로 늘었어
정하늘
셸 밖에서는 살고 안에서는 죽는다. 그동안 본 '떠서 죽는다' 상당수는 우리 실행 환경이 만든 거였어. 다만 어떤 장치가 프로세스를 치웠는지는 아직 확인 못 했어.
정바다
그럼 부팅 때 안 뜬 건? 작업 관리자에서 '사용 안 함'으로 꺼져 있으면 바로가기가 있어도 이 증상이 나잖아.
박도은
레지스트리를 봤는데 두 바로가기 모두 비활성 목록에 없어. 꺼져 있는 건 다른 프로그램 하나뿐이야
정하늘
그럼 이번 부팅에서 자동 시작이 그냥 실행되지 않았다는 데까지만 말할 수 있어. 왜 그랬는지는 재현이 안 돼서 확정 못 해
박도현
다음 날 "wscript로 네 번 돌려 네 번 다 실패"했다는 재현도 셸 밖에서 돌려 본 기록이 없어. 바로 다음 판엔 성공했고
박도현
자동화 셸에서 띄운 프로세스가 사라지면, 프로그램을 의심하기 전에 그 셸 밖에서 한 번 더 띄워 봐. 돋보기가 증거를 지우고 있을 수도 있으니까.