콘텐츠로 이동
Study NoteAgent 배포 플랫폼

9. kagent의 Agent와 tool 리소스

결론부터
사내 포털이 사용자에게 받을 입력의 목록은 결국 Agent resource의 어느 필드를 열어 줄 것인가로 정해진다
이 장에서 처음 나오는 말4개
MCPModel Context Protocol
Agent가 외부 tool을 발견하고 호출하는 표준 protocol이다.
HITLHuman-in-the-Loop
위험한 tool 실행 전에 사람의 승인을 받도록 실행을 멈추는 방식이다.
compactionContext Compaction
길어진 대화를 요약으로 압축해 model의 context window 한계를 넘기지 않게 하는 처리다.
embeddingEmbedding
문장을 의미가 가까울수록 가까운 좌표가 되도록 숫자 벡터로 바꾼 것이다.

8장에서 kagent의 구성 요소를 봤다면 이 장은 그 위에 올라가는 resource의 내용물이다. 사내 플랫폼 관점에서 이 장을 읽는 목적은 하나다 — 사용자가 포털에서 Agent를 만들 때 우리가 폼으로 받아야 할 값과, 사용자에게 절대 열면 안 되는 값을 구분하는 것이다. 그 구분은 이 장 끝의 사내 플랫폼이 소유할 필드와 막을 필드에서 정리하고, 실제 연결은 10장에서 다룬다.

가장 작은 Declarative Agent는 model과 system prompt만 있으면 된다.

apiVersion: kagent.dev/v1alpha2
kind: Agent
metadata:
name: example-agent
namespace: kagent
spec:
type: Declarative
declarative:
modelConfig: default-model-config
systemMessage: "You are a helpful agent."
runtime: python # 또는 "go"

spec.type이 Declarative면 spec.declarative 아래가, BYO면 spec.byo 아래가 채워진다. 여기에 tool·skill·memory·context가 붙으면서 실제 Agent가 된다.

Agent resource가 modelConfig·systemMessage·tools·skills·memory·context로 구성되고 각각이 ModelConfig·RemoteMCPServer·다른 Agent·ConfigMap을 참조하는 관계

prompt·model·tool이 Agent의 행동을 정한다면 deployment는 그 Agent를 어떤 Kubernetes workload로 실행할지 정한다. 일반 Agent의 Declarative와 BYO 양쪽 모두 이 필드를 가지며, kagent controller가 Deployment와 Pod spec으로 번역한다. 다만 kagent가 더 높은 수준의 resource profile이나 DB service catalog를 제공하는 것은 아니다.

Declarative Agent는 spec.declarative.deployment, BYO Agent는 spec.byo.deployment 아래에 Kubernetes ResourceRequirements를 그대로 넣는다. 다음은 BYO Agent의 실행 자원 예다.

spec:
type: BYO
byo:
deployment:
image: registry.company/agents/report@sha256:8b4c...
replicas: 1
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "2"
memory: 2Gi

v0.9.9 구현은 값을 생략했을 때 Pod 하나에 CPU 100m·memory 384Mi를 request하고 CPU 2000m·memory 1Gi를 limit으로 넣는다. 이는 모든 Agent에 적합하다고 측정된 profile이 아니라 제품 기본값이다. API reference의 deployment schema는 Agent별 resources와 고정 replicas를 받지만 autoscaling policy를 표현하지 않는다.

따라서 사내 포털은 raw 숫자를 그대로 열기보다 small·standard·large 같은 profile을 받아 adapter가 resources로 번역한다. namespace의 ResourceQuota·LimitRange가 상한과 기본값을 강제하고, 실제 CPU throttling·memory working set·Out Of Memory(OOM)를 본 뒤 profile을 조정한다. Horizontal Pod Autoscaler(HPA)가 필요하면 kagent가 소유한 Deployment의 replicas와 충돌하지 않는지 별도 contract test를 통과시켜야 한다.

volume은 연결하지만 PVC와 DB는 만들지 않는다

섹션 제목: “volume은 연결하지만 PVC와 DB는 만들지 않는다”

deployment.volumes와 volumeMounts에는 Kubernetes Volume을 넣을 수 있다. 아래처럼 기존 PersistentVolumeClaim(PVC)과 DB credential Secret을 붙일 수 있지만, finance-agent-data PVC와 finance-agent-db Secret은 플랫폼이 먼저 준비해야 한다.

spec:
type: BYO
byo:
deployment:
image: registry.company/agents/finance@sha256:7a21...
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: finance-agent-db
key: url
volumes:
- name: agent-data
persistentVolumeClaim:
claimName: finance-agent-data
volumeMounts:
- name: agent-data
mountPath: /var/lib/agent

kagent에는 Agent를 만들 때 PostgreSQL database·schema·user나 PVC를 함께 발급하는 service broker가 없다. BYO Agent가 별도 DB를 요구하면 포털이나 GitOps가 DB lifecycle·backup·quota·credential을 소유하고 Agent에는 reference만 넣는다. Declarative Agent가 업무 DB를 조회하는 경우에는 DB credential을 runtime에 직접 주기보다 승인된 MCP·HTTP tool로 좁혀 노출하는 편이 tool allowlist와 action policy를 유지하기 쉽다.

일반 Agent는 StatefulSet이 아니라 Deployment로 생성된다. replica 여러 개가 한 ReadWriteOnce PVC를 공유하거나 replica별 고정 volume identity가 필요한 workload는 이 계약과 맞지 않는다. 그런 상태는 외부 DB나 object storage로 내리고, filesystem semantics가 꼭 필요할 때만 access mode·rollout·retention을 별도로 검증한다.

instruction — 역할을 정하는 system prompt

섹션 제목: “instruction — 역할을 정하는 system prompt”

systemMessage가 Agent의 역할·말투·금지사항을 정한다. 공식 문서는 여기에 “무슨 역할인지, 사용자와 어떻게 상호작용할지, 어떤 action을 할 수 있는지”를 담으라고 권한다.

사내에서 중요한 건 공통 조각을 강제할 수 있다는 점이다. promptTemplate.dataSources로 ConfigMap을 alias와 함께 연결하면 Go template 문법으로 그 조각을 끼워 넣을 수 있다.

declarative:
promptTemplate:
dataSources:
- kind: ConfigMap
name: policy-bundle-pbv-12
alias: builtin
systemMessage: |
You are {{.AgentName}}.
{{include "builtin/safety-guardrails"}}

사용자가 쓴 prompt 뒤에 회사의 보안·컴플라이언스 지침을 항상 덧붙이고 싶다면, 포털이 문자열을 이어 붙이는 대신 이 구조를 쓸 수 있다. 다만 공유 ConfigMap을 제자리에서 고치면 승인된 Agent의 동작이 조용히 바뀐다. ConfigMap 이름에 PolicyBundleVersion을 넣고 immutable로 운영하며, 변경 시 pbv-13을 만들어 publication이 사용할 실효 조합을 승인한다. invocation에는 effectiveConfigHash와 policy bundle version을 남긴다.

modelConfig는 같은 namespace(또는 허용된 namespace)의 ModelConfig 이름을 가리킨다. Agent에 provider나 API key를 직접 쓰지 않는다는 뜻이다. 사내에서는 이 자리가 LiteLLM gateway를 가리키는 OpenAI-compatible ModelConfig 하나로 수렴하는 경우가 많다.

포털이 사용자에게 보여줄 “모델 선택” 드롭다운은 결국 승인된 ModelConfig 목록이다. 사용자가 임의의 provider·baseUrl을 입력하게 두면 model 비용과 data 유출 경계가 동시에 깨진다. 같은 이름의 ModelConfig를 덮어쓰지 않고 model policy version과 content hash를 AgentVersion에 고정한다.

tools는 Agent가 호출할 수 있는 기능 목록이고, 항목 하나가 MCP server의 tool 묶음이거나 다른 Agent다. API reference 기준 한 Agent의 tool은 최대 20개다. 선언 방법은 아래 tool 절에서 자세히 본다.

skill은 tool과 다르다. tool이 “호출 가능한 함수”라면 skill은 Agent가 스스로 무엇을 할 수 있는지 알리는 설명이거나, 실행 가능한 구현 묶음이다. 두 형태가 있다.

형태선언 위치성격
A2A AgentSkill metadataspec.declarative.a2aConfig.skills다른 Agent·클라이언트가 Agent Card에서 읽는 능력 설명
container skillspec.skills.refs(OCI) · spec.skills.gitRefs(Git)외부에서 가져오는 실행 가능한 구현
skills:
refs:
- image: registry.company/skills/report@sha256:8b4c...
gitRefs:
- url: https://git.company.example/agent-skills.git
ref: 8f6c2d1a4b7e9c0d

container skill은 외부 code를 Agent 안으로 끌어오는 경로다. 임의의 공개 registry·Git URL을 사용자가 직접 넣게 두면 4장의 공급망 검사를 우회하는 문이 된다. 포털에서는 승인된 registry로 제한하고 OCI digest나 Git commit SHA로 고정하는 것이 기본이다.

kagent는 두 가지 개입 수단을 준다.

  • tool 승인 — requireApproval에 넣은 tool은 실행 직전에 멈추고 사용자에게 승인·거부를 묻는다. 거부 사유는 다시 model에 전달된다.
  • ask user — Agent가 스스로 사용자에게 질문을 던지고 답을 기다리는 내장 기능이다.
tools:
- type: McpServer
mcpServer:
name: kagent-tool-server
kind: RemoteMCPServer
toolNames:
- k8s_get_resources
- k8s_delete_resource
requireApproval:
- k8s_delete_resource

이 승인은 행위 위험을 막는 장치이지 권한이 아니다. 누가 그 Agent를 호출할 수 있는지는 5장 invocation authorization의 몫이고, kagent 밖에서 판단한다.

대화 상태 — session·compaction·memory

섹션 제목: “대화 상태 — session·compaction·memory”

Agent가 기억하는 것은 세 층으로 나뉜다. 사내 플랫폼에서 “대화 이력을 우리 DB에 남길 것인가”를 정하려면 이 구분이 먼저다.

층범위kagent에서의 처리
session 대화한 대화 안engine이 event로 관리
compaction한 대화가 길어질 때일정 주기로 요약해 압축
long-term memory여러 대화에 걸쳐embedding으로 저장하고 유사도로 검색

compaction은 context.compaction.compactionInterval로 주기를 정하며 기본값은 사용자 호출 5회마다다. 요약에 쓸 model을 따로 지정할 수 있다.

context:
compaction:
compactionInterval: 5
summarizer:
modelConfig: summarizer-config

long-term memory는 Agent Memory 기능으로, 대화에서 사용자 의도·선호를 주기적으로 뽑아 embedding으로 저장했다가 응답 전에 유사도로 검색해 넣는다. 물리적으로 Agent별 DB를 만드는 대신 pgvector가 활성화된 kagent 공용 PostgreSQL을 쓰고, Agent와 사용자 범위로 memory를 나눈다. Declarative Agent에서 embedding용 ModelConfig와 보관 기간(TTL)을 선언하면 된다.

declarative:
memory:
modelConfig: approved-embedding-model
ttlDays: 30

MCP는 이 built-in 기능의 필수 앞단이 아니라 요구가 built-in 범위를 넘어설 때 쓰는 대안이다.

저장 요구먼저 검토할 경로경계
같은 Agent가 같은 사용자의 선호·이전 대화 핵심을 기억kagent built-in MemoryDeclarative Agent, kagent PostgreSQL·TTL 사용
회사 공통 memory, Agent 간 공유, kagent 밖 runtime과 portability독립 memory service를 MCP tool로 연결별도 ACL·version·삭제 lifecycle 필요
승인된 사내 문서 검색과 RAGKnowledgeVersion을 조회하는 MCP·HTTP retrievalsource revision·문서 ACL·인용 lineage 필요
BYO Agent의 업무 record·transaction·checkpoint외부 DB를 application dependency로 연결schema migration·backup·credential은 플랫폼 책임

built-in Memory는 backend를 다른 vector store로 교체할 수 없고, Agent 간 memory 공유와 memory 한 건 단위 삭제를 지원하지 않는다. 공식 제한사항을 수용할 수 없을 때만 사내 표준 memory를 MCP로 붙인다. 즉 “vector를 쓴다”는 공통점만으로 업무 Knowledge나 application DB까지 kagent Memory에 넣지 않는다.

이 memory는 3장의 KnowledgeVersion을 대신하지 않는다. 개인 대화에서 추출한 memory와 승인된 업무 corpus의 source revision·ACL·index lineage는 수명과 삭제 책임이 다르다. kagent에 제품 중립 knowledge binding을 직접 매핑할 필드가 없다면 회사 runner의 retrieval client 또는 승인된 MCP capability로 주입하고 그 version을 trace에 남긴다.

kagent가 다루는 tool은 세 갈래이고, Agent에서는 다른 Agent도 tool처럼 참조한다.

종류무엇인가사내 취급
내장 toolkagent가 제공하는 Kubernetes 조작 tool 묶음조회 계열만 기본 허용
MCP toolMCP server가 노출하는 tool승인 목록으로 관리 (7장)
HTTP toolOpenAPI schema가 있는 사내 APIschema 등록으로 자동 노출
다른 Agentsub-agent 호출호출 그래프와 순환을 검사

MCP tool은 RemoteMCPServer(이미 떠 있는 server를 가리킴) 또는 MCPServer(kmcp가 배포)를 참조하고, 그중 쓸 tool 이름만 골라 나열한다.

tools:
- type: McpServer
mcpServer:
name: kagent-tool-server
namespace: tools
kind: RemoteMCPServer
toolNames:
- k8s_get_resources

toolNames가 allowlist라는 점이 중요하다. server가 30개 tool을 노출해도 Agent는 여기 적힌 것만 본다. 포털의 “이 Agent에 붙일 tool 고르기” 화면이 그대로 이 배열이 된다.

tool 호출에 API key가 필요하면 headersFrom으로 Secret이나 ConfigMap에서 값을 가져온다. resource에 값을 직접 쓰지 않는다.

tools:
- type: McpServer
mcpServer:
name: kagent-tool-server
kind: RemoteMCPServer
toolNames:
- k8s_get_resources
headersFrom:
- name: Authorization
valueFrom:
type: Secret
name: tool-api-secret
key: api-key

이 Secret은 Agent가 속한 namespace에 있어야 한다. 사용자마다 다른 자격증명으로 tool을 호출해야 한다면 이 구조로는 부족하다 — Agent 단위 자격증명이지 사용자 단위가 아니기 때문이다. 사용자 위임이 필요한 tool은 5장 tool action authorization의 설계를 따른다.

tools:
- type: Agent
agent:
name: promql-agent
namespace: other-namespace

전문 Agent를 범용 Agent가 호출하는 구성이다. 편리하지만 사내에서는 두 가지를 검사해야 한다 — 호출 순환(A가 B를, B가 A를)과 권한 상승(권한이 낮은 Agent가 높은 Agent를 통해 tool에 닿는 것)이다. cross-namespace 참조는 allowedNamespaces로 제한한다.

kagent는 cluster 안의 MCP server를 자동으로 발견한다. 승인되지 않은 server가 목록에 뜨는 것을 막으려면 kagent.dev/discovery=disabled label로 대상에서 제외하고, agentgateway 같은 통제된 경로로만 노출한다. 사내 플랫폼이 tool catalog를 소유한다면 이 자동 discovery는 대체로 꺼야 할 기본값이다.

MCP Apps — tool이 UI를 돌려주는 경우

섹션 제목: “MCP Apps — tool이 UI를 돌려주는 경우”

MCP tool이 JSON 대신 HTML·UI resource를 함께 돌려주면 kagent chat이 그것을 sandbox frame 안 위젯으로 렌더한다. server가 tool 설정에 _meta.ui.resourceUri를 넣으면 kagent 쪽 추가 설정 없이 동작하고, model에 되돌릴 내용은 _meta.ui.visibility로 조절한다.

사내 frontend를 직접 만든다면 이 기능은 기본적으로 따라오지 않는다. 위젯 렌더는 kagent chat UI의 기능이므로, 우리 화면에서 같은 경험을 주려면 UI resource를 해석하고 sandbox iframe으로 그리는 일을 우리가 구현해야 한다. 초기 범위에서는 MCP Apps를 쓰는 tool을 승인 목록에서 빼는 편이 단순하다.

사용자가 LangGraph·CrewAI 등으로 직접 짠 Agent는 spec.type: BYO로 image를 배포한다. 다만 kagent는 범용 container platform이 아니다 — image가 kagent가 기대하는 A2A server 계약을 구현해야 한다.

adapter의 validate 단계에서 image architecture와 protocol contract·port를 먼저 검사하고, 통과하지 못한 image는 배포 자체를 거절한다. 사내 포털에서 “내 컨테이너 올리기”를 열어 준다면 이 계약을 문서와 템플릿 저장소로 함께 제공해야 지원 부담이 줄어든다.

사내 플랫폼이 소유할 필드와 막을 필드

섹션 제목: “사내 플랫폼이 소유할 필드와 막을 필드”

이 장의 필드를 사용자 노출 기준으로 나누면 포털 폼의 명세가 그대로 나온다.

구분필드이유
사용자가 채운다systemMessage, tool 선택(toolNames), 이름·설명Agent의 목적 그 자체
목록에서 고른다versioned modelConfig, KnowledgeVersion, MCP capability, immutable skill ref승인된 것만 노출
요구만 받는다workload 크기, persistent state 필요 여부profile과 storage binding으로 바꾼 뒤 정책을 검사
플랫폼이 정한다namespace, deployment.resources·replicas·volume·env, runtime, security context, allowedNamespaces격리·비용·credential·blast radius
사용자에게 열지 않는다headersFrom의 Secret 이름, 임의 image·Git URL, cross-namespace 참조자격증명과 공급망 경계

이 표가 10장에서 backend가 만드는 manifest의 골격이 된다. 사용자 입력은 일부 필드에만 들어가고 나머지는 서버가 채운다 — 사용자가 보낸 YAML을 그대로 apply하지 않는다가 핵심이다.

  • Declarative Agent는 instruction·model·tool·skill 네 구성 요소로 이뤄진다.
  • CPU·memory·replica·volume은 Agent의 deployment에서 Kubernetes workload로 번역하며 플랫폼 policy가 상한을 강제한다.
  • kagent는 기존 PVC·Secret을 Agent Pod에 연결하지만 Agent별 PVC나 업무 DB를 직접 발급하지 않는다.
  • 공용 지침은 versioned immutable ConfigMap으로 주입하고 policy bundle version을 trace에 남긴다.
  • requireApproval은 행위 위험을 막는 장치이지 호출 권한이 아니다.
  • 대화 상태는 session·compaction·long-term memory 세 층이고, memory는 정책을 정하고 켠다.
  • 같은 Agent의 대화 개인화는 built-in Memory를 먼저 검토하고, 공통·portable memory가 필요할 때 MCP로 분리한다.
  • runtime memory와 승인된 KnowledgeVersion의 ingestion·ACL·index lifecycle을 구분한다.
  • tool은 toolNames allowlist로 좁히고 자격증명은 headersFrom 참조로 넘긴다.
  • 사용자에게 열 필드와 서버가 채울 필드를 나누는 것이 포털 폼 설계의 시작이다.