Foreman 101: Kubernetes 리소스로서의 에이전틱 코딩 (Agentic Coding)
요약
Kubernetes 리소스로 실행되는 에이전틱 코딩 시스템인 Foreman에 대한 가이드입니다. 워크로드, 에이전트, 태스크, 플릿 노드라는 네 가지 핵심 객체를 통해 에이전트가 코드를 작성하고 검증하는 과정을 설명합니다.
핵심 포인트
- Foreman은 Kubernetes 기반의 에이전틱 코더 시스템임
- 에이전트, 워크로드, 태스크, 플릿 노드의 4가지 핵심 객체로 구성됨
- 모델의 결과물을 맹신하지 않고 검증기(verifier)를 통해 신뢰성을 확보함
- Helm 차트를 통해 LLMKube 코어 기반으로 간편하게 설치 가능
Foreman은 Kubernetes 리소스로 실행되는 에이전틱 코더 (agentic coder)입니다. 사용자가 작업을 워크로드 (Workload)로 기술하면, 이는 태스크 (tasks)로 분해되고, 사용자의 노드에서 실행되는 에이전트 (agents)들이 이를 가져가 처리합니다. 그 결과로 브랜치 (branch)가 생성되며, 해당 브랜치와 메인 브랜치 사이에는 결정론적인 (deterministic) 무언가가 위치하게 됩니다.
이 글은 가이드입니다. 이해해야 할 네 가지 객체, 설치, 에이전트 (agent), 검증기 (verifier), 그리고 실제 실행 과정을 다룹니다. 아래의 모든 명령어와 출력값은 작동 중인 클러스터 (cluster)에서 가져온 것입니다.
네 가지 객체
Foreman은 의도적으로 작게 설계되었습니다. 당신이 하는 거의 모든 일은 다음 중 하나에 해당합니다.
- **에이전트 (Agent)**는 작업자 정의입니다: 어떤 모델 (model)과 통신하는지, 어떤 도구 (tools)를 호출할 수 있는지, 그리고 어떤 예산 (budget)을 할당받는지 등을 정의합니다. 에이전트는 역할을 가지며, 여기서 중요한 두 역할은
coder와verifier입니다. - **워크로드 (Workload)**는 사용자가 실제로 작성하는 작업 단위입니다. 의도 (intent), 저장소 (repository), 그리고 어떤 에이전트를 사용할지를 포함합니다.
- **에이전틱 태스크 (AgenticTask)**는 워크로드가 분해되어 생성되는 단위입니다. 사용자가 직접 작성하는 경우는 드물며, 현재 어떤 일이 일어나고 있는지 확인하기 위해 읽게 됩니다.
- **플릿 노드 (FleetNode)**는 태스크를 실행할 수 있다고 스스로를 광고한 노드입니다. 스케줄러 (scheduler)는 태스크에 요구되는 기능(capabilities)을 이 노드들과 매칭합니다.
실행 과정의 형태는 다음과 같습니다: 워크로드를 적용(apply)하면, 컨트롤러 (controller)가 에이전틱 태스크 (AgenticTasks)를 합성하고, 스케줄러가 각 태스크를 해당 에이전트가 처리할 수 있는 플릿 노드 (FleetNode)로 라우팅합니다. 에이전트는 도구 (tools)와 함께 모델 (model)을 루프 (loop) 내에서 실행하며, 그 결과는 브랜치 (branch)와 판결 (verdict)의 형태로 남습니다.
그 밑바탕에 깔린 아이디어
모든 설계 결정에 영향을 미치기 때문에 명확히 언급할 가치가 있습니다: 모델 (model)은 신뢰되지 않으며, 특히 성공했다는 모델의 주장은 신뢰되지 않습니다.
코더 에이전트 (coder agent)는 "완료했습니다, 판결은 GO입니다"라고 말하는 도구 (tool)를 호출하며 종료합니다. Foreman은 이를 결과가 아닌 요청 (request)으로 취급합니다. 만약 모델이 GO라고 말했지만 아무런 차이점(diff)도 생성하지 않았다면, 해당 실행은 NO-GO로 기록됩니다. 검증기 (verifier)의 체크를 통과하지 못하면, 요약(summary)이 아무리 자신만만하더라도 해당 작업은 반영되지 않습니다.
이것이 코드를 작성하는 에이전트와 계속 실행 상태로 놔둘 수 있는 시스템 사이의 차이점입니다. 이 포스트의 나머지 내용은 모두 이 아이디어를 구현하기 위한 배관(plumbing) 작업입니다.
설치 (Install)
Foreman은 LLMKube 코어에 의존하는 Helm 차트 형태로 제공됩니다. 어떤 클러스터든 상관없습니다. 일회용 kind 클러스터도 괜찮으며, 실습을 위해 GPU가 반드시 필요한 것은 아닙니다.
kind create cluster --name foreman-101
helm repo add llmkube https://defilantech.github.io/LLMKube
...
두 번째 설치 단계에서 단순히 복사하기보다는 이해해둘 가치가 있는 두 가지 플래그(flag)가 있습니다.
agent.mode=native는 실제 에이전트 루프 (agent loop)를 실행합니다. 차트의 기본값은 stub으로, 이는 FleetNode를 등록만 하고 아무 작업도 수행하지 않습니다. 덕분에 모델이나 인증 정보가 없는 클러스터에서도 차트 설치에 대한 스모크 테스트 (smoke-test)를 수행할 수 있습니다.
agent.roles는 스케줄러 (scheduler)가 매칭할 대상입니다. worker 역할만 광고하는 노드에는 코더 (coder) 작업이 절대 할당되지 않습니다. 해당 노드가 실제로 수행해야 하는 역할들을 광고하세요.
설치가 완료되면 세 개의 포드 (pod)와 등록된 노드 하나가 생성되어야 합니다:
$ kubectl get pods -n llmkube-system
NAME READY STATUS RESTARTS AGE
llmkube-controller-manager-777d9f756b-xb7xr 1/1 Running 0 56s
...
인증 정보 (Credentials)
Foreman은 두 가지 종류의 인증 정보가 필요하며, 각각 서로 다른 역할을 수행합니다.
**git 인증 정보 (git credential)**는 에이전트가 이슈 (issue)를 읽고 브랜치 (branch)를 푸시 (push)할 수 있게 합니다. **모델 인증 정보 (model credential)**는 에이전트가 호스팅된 API와 통신할 수 있게 하며, 모델을 직접 서빙하는 경우에는 전혀 필요하지 않습니다.
# git: API 토큰 및 푸시에 사용되는 인증 정보
kubectl create secret generic foreman-github \
--from-literal=GITHUB_TOKEN="$GITHUB_TOKEN" -n foreman-system
...
agent.gitRemoteURL은 브랜치가 푸시되는 위치입니다. 이를 본인의 포크 (fork) 저장소로 지정하면 에이전트의 결과물이 업스트림 (upstream) 저장소에 영향을 주지 않으며, 이는 Foreman의 기능을 익히는 동안 권장되는 구성 방식입니다.
네임스페이스(namespace)가 서로 다르다는 점에 주목하십시오. 이는 임의로 설정된 것이 아닙니다. git secrets는 에이전트 프로세스(agent process)에 의해 소비되므로 foreman-system 내에서 에이전트와 함께 존재합니다. 모델 자격 증명(model credential)은 각 에이전트별로, 해당 에이전트의 네임스페이스에서 해결되므로, 에이전트를 생성하는 곳 어디에나 속하게 됩니다. 여기서는 default입니다.
코더(coder) 정의하기
에이전트에는 모델이 필요합니다. cloud-proxy 프로바이더(provider)는 모든 OpenAI 호환 엔드포인트(endpoint)와 통신할 수 있으므로, 이 방식은 호스팅된 API와 GPU가 없는 환경에서도 작동합니다.
apiVersion: foreman.llmkube.dev/v1alpha1
kind: Agent
metadata
...
위의 세 가지 필드는 단순히 훑어보는 것 이상의 주의가 필요합니다.
예산(budgets)은 비용 제어 수단입니다. 기본값은 120턴(turns)과 90k 컨텍스트(context)이며, 매 턴마다 전체 컨텍스트를 과금되는 API로 다시 전송합니다. 12턴과 30k의 차이는 비용이 몇 푼 들지 않는 실행과 그렇지 않은 실행의 차이를 만듭니다.
도구 목록(tool list)은 에이전트의 권한입니다. 에이전트는 해당 목록에 없는 것은 아무것도 할 수 없습니다. bash를 제거하면 편집은 가능하지만 실행은 할 수 없는 에이전트가 되며, 쓰기 도구(write tools)를 제거하면 읽기 및 보고만 가능한 에이전트가 됩니다.
시스템 프롬프트(system prompt)는 행동 양식입니다. 위의 순서 지침은 단순한 장식이 아닙니다. 탐색에만 맡겨두면 코딩 모델은 저장소를 건드리기 전에 아주 오랫동안 조사만 할 것이므로, "파일을 찾아 바로 시작하라"와 "첫 번째 편집을 일찍 수행하라"는 지침은 매우 중요합니다. 마지막에 있는 범위 제한(scope fence) 또한 마찬가지인데, 이는 한 줄짜리 수정 사항이 전체 리팩터링(refactor)으로 변질되지 않도록 막아주는 역할을 합니다.
검증기(verifier) 정의하기
이것이 Foreman을 다르게 만드는 객체이며, 가장 작은 단위입니다.
apiVersion: foreman.llmkube.dev/v1alpha1
kind: Agent
metadata
...
여기에는 모델이 없습니다. 프로바이더 설정도, API 키도, 시스템 프롬프트도 없습니다. inferenceServiceRef가 비어 있는 에이전트는 *결정론적 에이전트(deterministic agent)*입니다. Foreman은 모델 루프(model loop)를 완전히 건너뛰고 도구만 실행합니다.
run_gate_job은 브랜치를 클론하고 사용자의 체크(checks)를 실행하는 Kubernetes Job을 제출합니다. Go 리포지토리의 경우, 빌드(build), 검사(vet), 린터(linter) 및 테스트(tests)와 더불어, 프로덕션 변경 사항을 되돌린 후 새로운 테스트를 다시 실행하여 변경 사항이 없을 때 테스트가 실패하는지 확인하는 바이트 체크(bite check)를 수행합니다. 수정 사항을 되돌렸음에도 여전히 통과하는 테스트는 테스트가 아닙니다.
AI의 작업이 수용 가능한지 여부를 결정하는 컴포넌트는 그 자체로 AI가 아닙니다. 그것이 바로 핵심입니다.
작업 부여하기 (Give it work)
워크로드(Workload)는 여러분이 매일 작성하는 작업 단위입니다. 엄격하게 요구되는 유일한 필드는 intent입니다.
apiVersion: foreman.llmkube.dev/v1alpha1
kind: Workload
metadata
...
intent는 여러분의 코드베이스를 본 적 없는 유능한 엔지니어에게 전달하는 브리프(brief)와 같습니다. 변경 사항을 정확하게 명시하고, spec.replicas가 아닌 maxReplicas를 지정하며, 결과물(회귀 테스트)의 이름을 지정하는 것은 그 어떤 모델 설정보다 결과에 더 큰 영향을 미칩니다. 시작해야 할 명확한 파일이 하나 있다면 그 이름을 명시하십시오. 여기서는 수정 사항이 두 개의 회계 경로(accounting paths)에 걸쳐 있으므로, 브리프에 두 경로를 모두 명시합니다.
이를 적용하고 관찰해 보세요:
$ kubectl get workload,agentictask
NAME PHASE REPO AGE
workload.foreman.llmkube.dev/abtest-s1 Dispatched defilantech/LLMKube 8s
...
워크로드는 abtest-s1-code-1311이라는 이름의 태스크(task)를 합성했습니다. 즉, 워크로드 이름, 그다음 단계, 마지막으로 이슈(issue) 순입니다. 검증기(verifier)가 구성되어 있다면, 코더(coder)가 완료되기를 기다리는 abtest-s1-verify-1311도 함께 생성됩니다.
결과 읽기 (Read the result)
완료된 태스크는 그 판결(verdict)과 그에 대한 증거를 함께 전달합니다.
verdict: GO
summary: "Charge autoscaling.maxReplicas (not spec.replicas) toward
GPUQuota usage in both the admission webhook and the GPUQuota
...
64번의 턴(turns)과 약 27분: 단순한 한 줄 수정이 아니라 회귀 테스트 (regression test)를 통해 두 가지 회계 경로(accounting paths) 전반에 걸쳐 실제적인 변화를 만들어냈으며, 해당 브랜치(branch)는 포크(fork)에 올라가 있습니다. 전체 트랜스크립트(transcript)는 ConfigMap으로 저장되어 태스크 상태(task status)에서 참조되므로, 모델이 수행한 모든 도구 호출(tool call)을 추측하는 대신 직접 읽을 수 있습니다.
실제로 보게 될 판정(verdicts) 결과와 그 의미는 다음과 같습니다:
GO: 코더(coder)가 작업을 완료하고 diff를 생성했습니다.NO-GO: 작업을 완료하지 못했거나, diff 없이 성공했다고 주장했습니다.INCOMPLETE: 턴(turns)이 소진되었거나 자신의 작업 내용을 검증하지 못했습니다.GATE-PASS: 검증자(verifier)의 체크가 해당 브랜치에서 통과되었습니다.GATE-FAIL: 체크를 통과하지 못했으며, 브랜치가 병합(land)되지 않습니다.
게이트(The gate), 구체적으로
검증자(verifier)는 당신이 지시하는 무엇이든 실행합니다. 기존 브랜치를 대상으로 검증자를 실행하여 그 메커니즘을 직접 확인할 수 있습니다.
apiVersion: foreman.llmkube.dev/v1alpha1
kind: AgenticTask
metadata
...
작성된 그대로 한 번 실행한 다음, 파일에 없는 문자열을 넣어 한 번 더 실행해 보면, Job 로그에 정확히 어떤 일이 일어났는지 나타납니다:
=== clone defilantech/LLMKube @ main ===
=== grep -q Foreman docs/site/foreman/README.md ===
GATE PASS
...
동일한 에이전트(agent), 동일한 브랜치, 명령어 하나만 달라졌을 뿐인데 판정 결과는 정반대로 나타납니다. 태스크 상태에는 deterministic: true가 포함되어 있는데, 이는 작업의 품질에 대해 어떠한 모델의 자문도 구하지 않았기 때문입니다. grep이 결정했습니다.
모델 직접 실행하기
위의 모든 과정은 누구나 오늘 바로 시도해 볼 수 있는 버전인 호스팅된 API (hosted API)를 사용했습니다. LLMKube가 존재하는 이유는 다른 경로, 즉 모델이 사용자가 소유한 하드웨어에서 실행되며 외부로 아무것도 유출되지 않는 방식 때문입니다.
에이전트(Agent)는 거의 변하지 않습니다. API 키도 외부 URL도 필요 없으며, 단지 LLMKube가 이미 서비스 중인 추론 서비스 (InferenceService)에 대한 참조만 있으면 됩니다.
spec:
role: coder
provider: local
...
Foreman은 태스크 실행 시점에 해당 참조를 서비스의 클러스터 내부 주소(in-cluster address)로 해결(resolve)합니다. 루프(loop)를 실행하는 에이전트는 해당 주소에 도달할 수 있어야 하며, 이는 클러스터 내부 서비스에 대해서는 클러스터 내부 에이전트여야 함을 의미합니다. 도구(tools), 판정(verdicts), 게이트(gate)를 포함한 모든 다운스트림(downstream) 요소는 동일합니다.
우리 클러스터 내 해당 참조 뒤에 있는 모델은 128GB 통합 메모리(unified memory)를 갖춘 AMD Strix Halo 박스에서 실행되는, 약 8B-active 파라미터를 가진 118B-parameter 오픈 웨이트(open-weight) 코더 모델입니다. 이 글을 쓰는 동안 이 모델의 풀 리퀘스트(pull request) 4개가 전체 게이트(gate)를 통과하여 LLMKube에 병합되었습니다.
경계선 (Where the line is)
이것이 귀하에게 유용할지 여부를 결정하므로, 범위를 솔직하게 밝히겠습니다.
기계적이고 범위가 잘 정해진 작업은 가능합니다: 알려진 변경 지점이 있는 문서화된 버그, 명확한 계약(contract)이 있는 리팩터링(refactor), 누락된 테스트, 문서 수정 등입니다. 파일과 범위 제한(scope fence)을 제공하면 작업을 수행하고 멈출 것입니다.
아키텍처(Architectural) 작업은 아직 불가능합니다. 두 개의 패키지를 머릿속에 담아두고 두 컴포넌트 중 어느 것이 동작을 소유해야 하는지 결정해야 하는 변경 사항은 여전히 인간의 영역입니다. 이러한 종류의 작업에서 실행이 실패할 경우, 그럴듯하지만 틀린 결과물을 내놓기보다는 보통 요약과 함께 '미완성(INCOMPLETE)' 상태로 정직하게 실패합니다. 그것이 귀하가 원하는 실패 모드(failure mode)이긴 하지만, 여전히 실패인 것은 마찬가지입니다.
여기서 시작하세요 (Start here)
친절한 클러스터, 두 개의 Helm 차트, 이미 보유하고 있는 API 키를 사용하는 하나의 코더 에이전트(coder Agent), 하나의 검증기(verifier), 그리고 정말로 작은 이슈 하나만 있으면 됩니다. 엔드 투 엔드(end to end)로 20분이면 충분합니다.
그다음, 다른 것을 추가하기 전에 검증기(verifier)를 먼저 추가하세요. 검증기가 없는 에이전트는 Kubernetes API를 사용하는 자동 완성(autocomplete)에 불과하지만, 검증기가 있는 에이전트는 계속 실행해 둘 수 있는 시스템이 됩니다.
문서는 llmkube.com/docs/foreman에서 확인할 수 있으며, 코드는 GitHub에 있습니다. 둘 다 Apache 2.0 라이선스입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기