{"meta":{"title":"에이전트 루프","intro":"Copilot CLI가 사용자 메시지를 엔드투엔드로 처리하는 방식: 프롬프트부터 session.idle까지.","product":"GitHub Copilot","breadcrumbs":[{"href":"/ko/copilot","title":"GitHub Copilot"},{"href":"/ko/copilot/how-tos","title":"방법"},{"href":"/ko/copilot/how-tos/copilot-sdk","title":"코필로트 SDK"},{"href":"/ko/copilot/how-tos/copilot-sdk/features","title":"기능"},{"href":"/ko/copilot/how-tos/copilot-sdk/features/agent-loop","title":"에이전트 루프"}],"documentType":"article"},"body":"# 에이전트 루프\n\nCopilot CLI가 사용자 메시지를 엔드투엔드로 처리하는 방식: 프롬프트부터 session.idle까지.\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\n## 아키텍처\n\n![다이어그램: 설명된 프로세스를 보여 주는 그래프 다이어그램](/assets/images/help/copilot/copilot-sdk/features-agent-loop-diagram-0.png)\n\n**SDK**는 전송 계층으로, JSON-RPC 통해 **Copilot CLI** 프롬프트를 보내고 이벤트를 앱에 다시 표시합니다.\n**CLI**는 에이전트 도구 사용 루프를 실행하는 오케스트레이터로, 작업이 완료될 때까지 하나 이상의 LLM API 호출을 수행합니다.\n\n## 도구 사용 루프\n\n호출 `session.send({ prompt })`할 때 CLI는 루프를 입력합니다.\n\n![다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.](/assets/images/help/copilot/copilot-sdk/features-agent-loop-diagram-1.png)\n\n모델은 각 호출에 대한 **전체 대화 기록** (시스템 프롬프트, 사용자 메시지 및 모든 이전 도구 호출 및 결과)을 확인합니다.\n\n**주요 인사이트:** 이 루프의 각 반복은 이벤트 로그에서 한 `assistant.turn_start` / `assistant.turn_end` 쌍으로 표시되는 하나의 LLM API 호출입니다. 숨겨진 호출이 없습니다.\n\n## 턴이란 무엇인가\n\n**턴**은 단일 LLM API 호출 및 그 결과입니다.\n\n1. CLI는 LLM에 대화 기록을 보냅니다.\n2. LLM이 응답합니다(도구 요청이 있을 수 있음).\n3. 도구가 요청된 경우 CLI는 도구를 실행합니다.\n4. `assistant.turn_end` 가 내보내집니다.\n\n단일 사용자 메시지는 일반적으로 **여러 번 발생**합니다. 예를 들어 \"X는 이 코드베이스에서 어떻게 작동하나요?\"와 같은 질문이 있습니다. 다음을 생성할 수 있습니다:\n\n| 회전          | 모델에서 수행하는 작업                          | toolRequests? |\n| ----------- | ------------------------------------- | ------------- |\n| 1           | 코드베이스를 검색하기 위해 `grep` 및 `glob`을 호출합니다 |               |\n| ✅ 예         |                                       |               |\n| 2           | 검색 결과에 따라 특정 파일을 읽습니다.                |               |\n| ✅ 예         |                                       |               |\n| 3           | 더 심층적인 컨텍스트를 위해 더 많은 파일을 읽습니다.        |               |\n| ✅ 예         |                                       |               |\n| 4           | 최종 텍스트 대답을 생성합니다.                     |               |\n| ❌ → 루프 끝 없음 |                                       |               |\n\n모델은 각 턴에서 더 많은 도구를 요청할지 아니면 최종 답변을 생성할지 결정합니다. 각 호출은 **전체 누적 컨텍스트** (모든 이전 도구 호출 및 결과)를 확인하므로 충분한 정보가 있는지 여부에 대한 정보에 입각한 결정을 내릴 수 있습니다.\n\n## 다중 턴 상호 작용에 대한 이벤트 흐름\n\n![다이어그램: 설명된 프로세스를 보여 주는 순서도입니다.](/assets/images/help/copilot/copilot-sdk/features-agent-loop-diagram-2.png)\n\n## 각 턴을 트리거하는 사람은 누구인가요?\n\n| Actor           | 책임                                                    |\n| --------------- | ----------------------------------------------------- |\n| **고객님의 앱**      | 를 통해 초기 프롬프트를 보냅니다. `session.send()`                  |\n| **Copilot CLI** | 도구 사용 루프를 실행합니다. 도구를 실행하고 다음 턴을 위해 결과를 LLM에 다시 공급합니다. |\n| **Llm**         | 도구를 요청할지(계속 반복) 또는 최종 응답 생성(중지) 결정                    |\n| **SDK**         | 이벤트를 전달합니다. 는 루프를 제어하지 않습니다.                          |\n\nCLI는 그저 기계적으로 작동합니다. \"모델이 도구를 요청함 → 실행 → 모델을 다시 호출.\"\n**이 모델은** 중지할 시기를 결정하는 결정자입니다.\n\n## `session.idle` 및 `session.task_complete`\n\n이는 매우 다른 보장을 가진 두 가지 서로 다른 완료 신호입니다.\n\n### `session.idle`\n\n* 도구 사용 루프가 종료**될 때 항상 내보내**기\n* **임시**: 디스크에 유지되지 않고 세션 다시 시작 시 재생되지 않음\n* 의미: \"에이전트가 처리를 중지했으며 다음 메시지에 대한 준비가 되었습니다.\"\n* **이를** 신뢰할 수 있는 \"완료\" 신호로 사용\n\nSDK의 `sendAndWait()` 메서드는 이 이벤트를 기다립니다.\n\n```typescript\n// Blocks until session.idle fires\nconst response = await session.sendAndWait({ prompt: \"Fix the bug\" });\n```\n\n### `session.task_complete`\n\n* **선택적으로 내보내기**: 모델이 명시적으로 신호를 보낼 것을 요구합니다.\n* **지속형**: 디스크의 세션 이벤트 로그에 저장\n* 의미: \"에이전트는 전체 작업이 완료된 것으로 간주합니다.\"\n* 선택적 `summary` 필드를 전달합니다.\n\n```typescript\nsession.on(\"session.task_complete\", (event) => {\n    console.log(\"Task done:\", event.data.summary);\n});\n```\n\n### Autopilot 모드: CLI가 `task_complete`를 요청함\n\n**autopilot 모드**(헤드리스/자율 작업)에서 CLI는 모델이 호출`task_complete`되었는지 여부를 적극적으로 추적합니다. 그것 없이 도구 사용 루프가 끝나면, CLI는 모델을 유도하는 합성 사용자 메시지를 삽입합니다:\n\n> *\"task\\_complete 도구를 사용하여 작업을 완료로 표시하지 않았습니다. 계획 중인 경우 계획을 중지하고 구현을 시작합니다. 작업을 완전히 완료할 때까지 완료되지 않습니다.\"*\n\n이렇게 하면 도구 사용 루프가 사실상 다시 시작됩니다. 모델은 이 신호를 새로운 사용자 메시지로 간주하고 작업을 계속 수행합니다. 또한 이 유도는 모델에 \\*\\*\\*\\* 않도록 지시합니다.\n\n* 열린 질문이 있는 경우 호출하지 마세요. 결정을 내리고 계속 작업하세요.\n* 오류가 발생한 경우 호출하지 마세요. 해결해 보세요.\n* 남아 있는 단계가 있으면 호출하지 말고 먼저 완료하세요\n\n이렇게 하면 autopilot에서 **2단계 완성 메커니즘** 이 만들어집니다.\n\n1. 모델이 요약과 함께 `task_complete`을 호출 → CLI가 `session.task_complete`을 출력 → 완료\n2. 모델이 이를 호출하지 않고 중지됨 → CLI가 유도함 → 모델이 계속 진행되거나 `task_complete`를 호출함\n\n### `task_complete`이(가) 표시되지 않을 수 있는 이유\n\n**대화형 모드**(일반 채팅)에서는 CLI가 `task_complete`을(를) 요청하지 않습니다. 모델은 아예 건너뛸 수 있습니다. 일반적인 원인:\n\n* **대화형 Q\\&A**: 모델은 질문에 답변하고 단순히 중지합니다. 완료할 개별 \"작업\"이 없습니다.\n* **모델 재량**: 모델은 작업 완료 신호를 호출하지 않고 최종 텍스트 응답을 생성합니다.\n* **중단된 세션**: 모델이 완료 지점에 도달하기 전에 세션이 종료됩니다.\n\nCLI는 어쨌든 `session.idle`를 내보냅니다. 이는 의미적 신호(모델이 완료됐다고 판단함)가 아니라 기계적 신호(루프가 끝났다는 뜻)이기 때문입니다.\n\n### 어느 것을 사용하시겠습니까?\n\n| 사용 사례                            | 신호 |\n| -------------------------------- | -- |\n| \"에이전트가 처리를 완료할 때까지 기다립니다.\"       |    |\n| `session.idle`                   |    |\n| ✅                                |    |\n|                                  |    |\n| \"코딩 작업이 완료되면 알 수 있습니다.\"          |    |\n| `session.task_complete` (최선의 노력) |    |\n| \"시간 제한/오류 처리\"                    |    |\n| `session.idle`                   |    |\n\n*\n\n`session.error`\n✅\n|\n\n## LLM 호출 수 계산\n\n이벤트 로그의 `assistant.turn_start` / `assistant.turn_end` 쌍 수는 총 LLM API 호출 수와 같습니다. 계획, 평가 또는 완료 확인에 대한 숨겨진 호출은 없습니다.\n\n세션의 턴 카운트를 검사하려면:\n\n```bash\n# Count turns in a session's event log\ngrep -c \"assistant.turn_start\" ~/.copilot/session-state/<sessionId>/events.jsonl\n```\n\n## 추가 읽기\n\n* [스트리밍 세션 이벤트](/ko/copilot/how-tos/copilot-sdk/features/streaming-events): 모든 이벤트 유형에 대한 전체 필드 수준 참조\n* [세션 다시 시작 및 지속성](/ko/copilot/how-tos/copilot-sdk/features/session-persistence): 세션 저장 및 다시 시작 방법\n* [후크를 사용한 작업](/ko/copilot/how-tos/copilot-sdk/features/hooks): 루프에서 이벤트 가로채기(권한, 도구)"}