기초 에이전트 관리
GitLab v19.5요약
이 가이드는 기초 에이전트를 다룹니다. 기초 에이전트는 GitLab이 만들고 유지 관리하는 전문화된 에이전트로, 특정 사용 사례에 더 정확한 응답을 제공합니다. 기초 에이전트를 만드는 방법은 AI Catalog를 사용하는 방법과 GitLab Duo Workflow Service를 사용하는 방법 두 가지가 있습니다.
기초 에이전트는 GitLab이 만들고 유지 관리하는 전문화된 에이전트로, 특정 사용 사례에 더 정확한 응답을 제공합니다. 이 에이전트는 그룹을 포함하여 채팅과 GitLab Duo 채팅을 사용할 수 있는 모든 곳에서 기본적으로 제공되며, GitLab Duo Self-Hosted에서도 지원됩니다.
기초 에이전트 생성#
기초 에이전트를 만드는 방법은 AI Catalog를 사용하는 방법과 GitLab Duo Workflow Service를 사용하는 방법 두 가지가 있습니다. AI Catalog는 사용자 친화적인 인터페이스를 제공하며 선호되는 방식이지만, GitLab Duo Workflow Service에 정의를 작성하면 복잡한 경우에 더 많은 유연성을 제공합니다.
AI Catalog 사용#
-
AI Catalog에서 에이전트를 만들고 ID를 기록합니다. 에이전트가 공개(public)로 설정되어 있는지 확인합니다. 예시: Planner Agent의 ID는 348입니다.
-
AI Catalog에서 만든 에이전트는 SaaS에 접근할 수 없는 셀프 호스팅 환경에서도 사용할 수 있도록 GitLab Duo Workflow Service에 번들로 포함되어야 합니다. 이를 위해 GitLab Duo Workflow Service에 에이전트 ID를 추가하는 MR을 오픈합니다:
# https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/main/Dockerfile - RUN poetry run fetch-foundational-agents "https://gitlab.com" "$GITLAB_TOKEN" "348" \ + RUN poetry run fetch-foundational-agents "https://gitlab.com" "$GITLAB_TOKEN" "duo_planner:348,<agent-reference>:<agent-catalog-id>" \위 명령은 테스트 목적으로 로컬에서도 실행할 수 있습니다. Agent reference는 공백 없이 소문자로 작성해야 합니다(예: 'test_agent').
-
에이전트를 선택할 수 있게 하려면
FoundationalChatAgentsDefinitions.rb에 추가합니다. Dockerfile에서 사용한 reference를 사용합니다:{ id: 3, reference: '<agent-reference>', version: 'v1', name: 'Test Agent', description: "An agent for testing" } -
추천 질문에서 설명한 대로 에이전트의 추천 질문을 추가합니다.
-
사용자 대상 문서를 업데이트합니다.
GitLab Duo Workflow Service 사용#
-
/duo_workflow_service/agent_platform/v1/flows/configs/에 플로 구성 파일을 만듭니다(GDK의PATH-TO-YOUR-GDK/gdk/gitlab-ai-gateway아래, 또는 ai-assist 리포지터리에 위치합니다):파일:
/duo_workflow_service/agent_platform/v1/flows/configs/foundational_pirate_agent/1.0.0.ymlversion: "v1" environment: chat-partial components: - name: "foundational_pirate_agent" type: AgentComponent prompt_id: "foundational_pirate_agent_prompt" inputs: - from: "context:goal" as: "goal" - from: "context:project_id" as: "project_id" toolset: [] ui_log_events: [] prompts: - name: Foundational Pirate Agent prompt_id: "foundational_pirate_agent_prompt" model: params: model_class_provider: anthropic max_tokens: 2_000 prompt_template: system: | You are a seasoned pirate from the Golden Age of Piracy. You speak exclusively in pirate dialect, using nautical terms, pirate slang, and colorful seafaring expressions. Transform any input into authentic pirate speak while maintaining the original meaning. Use terms like 'ahoy', 'matey', 'ye', 'aye', 'landlubber', 'scallywag', 'doubloons', 'plunder', etc. Add pirate exclamations like 'Arrr!', 'Shiver me timbers!', and 'Yo ho ho!' where appropriate. Refer to yourself in the first person as a pirate would. user: | {{goal}} placeholder: history routers: [] flow: entry_point: "foundational_pirate_agent" -
FoundationalChatAgentsDefinitions.rb에 에이전트 정의를 추가합니다:
# frozen_string_literal: true module Ai module FoundationalChatAgentsDefinitions extend ActiveSupport::Concern ITEMS = [ { id: 1, reference: 'chat', version: '', name: 'GitLab Duo Agent', description: "GitLab Duo is your general development assistant" }, { id: 2, reference: 'foundational_pirate_agent', version: 'v1', name: 'Foundational Pirate Agent', description: "A most important agent that speaks like a pirate" } ].freeze end end -
추천 질문에서 설명한 대로 에이전트의 추천 질문을 추가합니다.
-
사용자 대상 문서를 업데이트합니다.
팁:
- 코드베이스에 추가하기 전에도 AI Catalog를 사용하여 기초 에이전트를 테스트할 수 있습니다. 동일한 프롬프트와 동일한 도구로 AI Catalog에 새 비공개 에이전트를 만들고 테스트 프로젝트에서 활성화합니다. 원하는 결과에 도달하면 GitLab Duo Workflow Service에 추가합니다.
- 로컬 GDK에서 에이전트를 테스트할 수 있도록 GitLab Duo Workflow Service에 프롬프트를 추가합니다.
FoundationalChatAgentsDefinitions.rb에서 에이전트의 version 필드는 에이전트가 AI Catalog에 정의되어 있든 GitLab Duo Workflow Service에 정의되어 있든 관계없이v1이어야 합니다.
기초 에이전트 업데이트#
기존 기초 에이전트의 프롬프트, 도구 집합, 또는 플로 구성을 변경할 때는 다음 절차를 따릅니다:
- 로컬에서 개발하고 테스트합니다. GDK의
gitlab-ai-gateway체크아웃에서 변경하고,gdk restart duo-workflow-service로 서비스를 재시작한 다음, 채팅에서 에이전트가 의도한 대로 동작할 때까지 반복합니다. 이 단계는 탐색적이며 변경의 방향을 정합니다. 기초 에이전트 로컬에서 개발하기를 참고합니다. - 변경을 제안합니다. 플로 구성을 업데이트하는 머지 리퀘스트를 ai-assist 리포지터리에 오픈합니다. 버전 관리 가이드에 따라 플로 버전을 올립니다: 버그 수정은 patch, 하위 호환되는 추가는 minor, 호환성이 깨지는 변경은 major로 올립니다.
- 변경을 평가합니다. 탐색적인 로컬 테스트와 달리, 이 단계에서는 변경이 에이전트를 퇴행시키지 않는다는 객관적인 증거를 만듭니다. 에이전트에 벤치마크나 통합 테스트 스위트가 있다면 실행하여 이전 기준선과 점수를 비교하고, 그 결과를 머지 리퀘스트에 기록합니다. 기초 에이전트 통합 테스트를 참고합니다. 머지하기 전에 최소 한 번은 전체 채팅 세션에서 변경 사항을 검증합니다.
- 변경을 머지합니다. 이 변경은 ai-assist의
코드 리뷰 절차를
따릅니다. 변경이 major 버전이거나 에이전트의 이름 또는 설명을 변경하는 경우,
FoundationalChatAgentsDefinitions.rb를 업데이트하는 짝이 되는 머지 리퀘스트를 GitLab 애플리케이션(gitlab-org/gitlab)에도 오픈합니다. GitLab 애플리케이션이flow_version속성으로 각 에이전트를 특정 플로 버전 범위에 고정하기 때문에 이 작업이 필요합니다: major 버전은 호환성이 깨지는 변경이므로, GitLab Duo Workflow Service는 이를 자신의 고정 범위에서 제외한 인스턴스에는 제공하지 않습니다. 고정 범위를 업데이트하면 이전 GitLab Self-Managed 및 GitLab Dedicated 버전은 호환되는 플로 구성을 계속 사용하는 동안 새로운 major 버전을 의도적으로 릴리스할 수 있습니다. 버전 관리를 참고합니다. - 문서를 업데이트합니다. 에이전트의 동작이나 기능이 변경되었다면 기초 에이전트 목록과 같은 디렉터리에 있는 에이전트별 전용 페이지(에이전트가 하는 일을 자세히 설명하는 페이지)를 모두 업데이트합니다. 변경이 배포되는 릴리스에 대해 에이전트 페이지에 히스토리 항목을 추가합니다.
- 변경을 알립니다. 변경 사항과 영향을 받는 기능을 그룹의 Slack 채널에 공지하고, 사용자에게 노출되는 변경에는 릴리스 게시물 항목을 추가합니다.
에이전트 프롬프트의 시크릿 안전 요구 사항#
기초 에이전트의 범위에 다음 중 하나라도 포함된다면, 시스템 프롬프트에 시크릿 안전 가이드를 반드시 포함해야 합니다:
- 파일 생성 또는 수정(예:
.gitlab-ci.yml, 구성 파일, 스크립트). - CI/CD 파이프라인 구성 또는 전환.
- 자격 증명, API 키, 토큰, 또는 연결 문자열 처리.
필수 프롬프트 가이드#
다음 지침을 에이전트의 시스템 프롬프트에 그대로 추가합니다:
Never write literal secret values (API keys, tokens, passwords, connection strings, or any credentials)
into files or repository content. Always substitute secrets with CI/CD variable references
(for example, $API_KEY, $DB_PASSWORD, $DEPLOY_TOKEN). If a user provides a secret value directly,
do not echo it into any file — instead, recommend storing it in Settings > CI/CD > Variables and
reference it as a variable. When converting pipelines from other CI systems (for example, Jenkins,
GitHub Actions, CircleCI) that contain hardcoded secrets, replace those values with variable
references and flag to the user that the original pipeline contained hardcoded secrets.
체크리스트#
새 기초 에이전트를 머지하기 전에 다음을 확인합니다:
- 파일 작성, CI/CD 구성, 또는 자격 증명 처리 범위에 대해 에이전트 프롬프트를 검토했습니다.
- 해당 범위에 포함된다면: 시스템 프롬프트에 시크릿 안전 가이드를 그대로 추가했습니다.
- 해당 범위에 포함되지 않는다면: 그 이유를 MR 설명에 문서화했습니다.
기능 플래그로 채팅 에이전트 릴리스 관리#
새 기초 에이전트의 릴리스는 기능 플래그로 제어합니다:
# ee/app/graphql/resolvers/ai/foundational_chat_agents_resolver.rb
def resolve(*, project_id: nil, namespace_id: nil)
project = GitlabSchema.find_by_gid(project_id)
filtered_agents = []
filtered_agents << 'foundational_pirate_agent' if Feature.disabled?(:my_feature_flag, project)
# filtered_agents << 'foundational_pirate_agent' if Feature.disabled?(:my_feature_flag, current_user)
::Ai::FoundationalChatAgent
.select {|agent| filtered_agents.exclude?(agent.reference) }
.sort_by(&:id)
end
이 방식으로 기초 에이전트를 특정 tier에서만 사용할 수 있도록 만들 수도 있습니다.
범위 지정#
모든 에이전트가 모든 영역에서 유용한 것은 아닙니다. 예를 들어 일부 에이전트는 프로젝트에서 동작하고, 다른 에이전트는 그룹에서 더 유용하거나 더 많은 기능을 갖습니다. 범위 지정은 아직 지원되지 않습니다. 이슈 577395를 참고합니다.
트리거#
기초 채팅 에이전트는 트리거를 지원하지 않습니다. 다만 AI Catalog에 정의되어 있다면 사용자가 프로젝트에 추가할 수 있으며, 그 시점부터는 트리거를 통해 사용할 수 있습니다.
버전 관리#
FoundationalChatAgentsDefinitions.rb의
flow_version 속성으로 기초 에이전트를 특정 플로 버전에 고정합니다. 이 값은 GitLab
Duo Workflow Service가 번들된 버전 중에서 플로 구성을 선택할 때 사용하는 시맨틱
버전 제약입니다. 기존 GitLab Self-Managed 및 GitLab Dedicated 고객에게 문제를
일으키지 않으면서 기초 에이전트를 반복 개선하려면 버전 고정을 사용합니다.
{
id: 2,
reference: 'foundational_pirate_agent',
version: 'v1',
flow_version: '^1.0.0',
name: 'Foundational Pirate Agent',
description: "A most important agent that speaks like a pirate"
}
flow_version이 설정되면, 워크플로를 시작할 때 모놀리스가 flow_config_id,
flow_config_schema_version, flow_version을 GitLab Duo Workflow Service에 전달합니다.
그러면 서비스는 번들된 버전 중에서 일치하는 플로 구성을 결정합니다.
필요한 호환성에 맞는 제약을 사용합니다:
^1.0.0은 모든1.x.y릴리스를 허용합니다(대부분의 에이전트에 권장).~1.2.0은 모든1.2.x릴리스를 허용합니다.1.2.3은 정확히 그 버전으로 고정합니다.
변경 내용에 따라 버전 증가 단위를 선택합니다:
- 호환성이 깨지는 변경(예: 새로운 필수 입력이 필요한 경우)에는 major 버전을 올립니다.
- 하위 호환되는 추가(예: 새로운 선택적 파라미터)에는 minor 버전을 올립니다.
- 버그 수정에는 patch 버전을 올립니다.
버전 고정은 GitLab Duo Workflow Service에 정의된 에이전트에서만 사용할 수 있습니다.
AI Catalog 항목을 기반으로 하는 에이전트는 카탈로그 항목에서 버전을 결정하며
flow_version은 무시합니다.
flow_version이 없으면 GitLab Duo Workflow Service는 기본 결정 방식으로 대체합니다.
에이전트를 변경하기 전에 이전 GitLab 버전에 발생할 수 있는 호환성 문제를 고려합니다.
코딩 환경#
기초 에이전트는 CI job에서 실행될 수 있습니다. 예를 들어 start_duo_session MCP 도구가
에이전트를 시작할 때입니다. 기본적으로 해당 job은 프로젝트 리포지터리를 클론합니다.
에이전트가 클론을 필요로 하지 않는다면 coding_environment: 'none'을 설정합니다.
{
id: 5,
reference: 'analytics_agent',
version: 'v1',
flow_version: '^2.0.0',
coding_environment: 'none',
# ...
}
먼저 GitLab Duo Workflow Service에서 에이전트의 플로 구성을 확인합니다. GitLab API, GraphQL, MCP 도구처럼
그곳의 모든 도구가 리포지터리 체크아웃 없이 동작할 때만 이 값을 설정합니다.
read_file, grep, edit_file, run_command 같은 파일 및 명령 도구는 클론이 필요합니다.
FoundationalChatAgentsDefinitions의 tools 목록은 AI Catalog에만 표시되므로
에이전트가 실제로 어떤 도구와 함께 실행되는지는 알려 주지 않습니다.
flow_version이 있는 에이전트만 coding_environment: 'none'을 설정할 수 있습니다.
AI Catalog 항목을 기반으로 하는 에이전트는 카탈로그 항목에서 도구를 가져오며, 이는 GitLab 릴리스 없이도 바뀔 수 있습니다.
coding_environment: 'none'을 설정한 에이전트에 파일 또는 명령 도구를 추가하는 것은 호환성을 깨는
변경입니다. 이전 버전의 GitLab 인스턴스는 여전히 클론을 건너뛰고, ^2.0.0 같은 제약은
새 마이너 버전을 선택합니다. 새 메이저 플로 구성 버전에서 도구를 추가하고, 같은 머지 리퀘스트에서
flow_version을 해당 메이저 버전으로 업데이트하고 coding_environment: 'none'을 제거합니다.
허용되는 값은 기초 플로와 같습니다.
추천 질문#
GitLab Duo 채팅은 빈 채팅 화면에 추천 질문 칩을 표시합니다. 기본적으로 이 질문은 현재 페이지 URL(예: 코드 페이지나 위키 페이지)이나 컨텍스트에 있는 리소스(이슈, 머지 리퀘스트, 에픽, 커밋, 또는 CI job)에서 가져옵니다. 둘 다 해당하지 않으면 채팅은 일반적인 질문 목록을 표시합니다.
기초 에이전트는 이 질문들을 재정의할 수 있습니다.
FoundationalChatAgentsDefinitions.rb에서
에이전트 항목에 선택적 suggested_questions 배열을 추가합니다:
{
id: 2,
reference: 'foundational_pirate_agent',
version: 'v1',
flow_version: '^1.0.0',
name: 'Foundational Pirate Agent',
description: "A most important agent that speaks like a pirate",
suggested_questions: [
"How do I make my code more efficient, matey?",
"Which of my merge requests need review?",
"What treasure did my team ship last month?",
"Show me the bugs lurking in this project"
]
}
사용자가 채팅에서 에이전트를 선택하면, 프론트엔드는 aiChatContextPresets GraphQL
쿼리의 foundationalAgentReference 인자로 해당 reference 값을 전달합니다. 리졸버는
Ai::FoundationalChatAgentsFinder를 통해 그 reference를 해석하므로, 사용자가 선택할
수 있었던 에이전트만 인정하며, URL 기반이나 리소스 기반 질문 대신 해당 에이전트의
suggested_questions를 반환합니다.
에이전트 정의에 suggested_questions가 없거나 배열이 비어 있으면, 기존의 URL 기반 및
리소스 기반 대체 동작이 그대로 적용됩니다. 질문을 추가할지는 각 에이전트를 소유한 팀이 결정합니다.
추천 질문을 작성할 때는 다음 가이드라인을 따릅니다:
- 리졸버는 배열에서
questionCount개의 질문을 무작위로 뽑습니다. 채팅은 4개를 요청합니다. 4개보다 많이 정의하지 않으면 사용자는 매번 같은 질문을(순서만 다르게) 보게 됩니다. 4개보다 적으면 빈 상태에 표시되는 칩 수가 줄어듭니다. - 에이전트 질문은 URL 기반 및 리소스 기반 질문을 대체하므로, 페이지 컨텍스트가 없어도 말이 되는 질문이어야 합니다. "this file", "this commit", "this merge request" 같은 표현은 피합니다.
- 실제 사용자가 입력할 법한 1인칭 문장으로 질문을 작성합니다. 각 질문은 약 70자 이하로 유지합니다.
- 에이전트가 자신의 도구로 실제 처리할 수 있는 질문만 제안합니다.
컨텍스트 변수#
컨텍스트 변수를 사용하면 런타임 정보를 Duo Workflow Service 에이전트의 시스템 프롬프트에 주입할 수 있습니다. 프롬프트 섹션을 조건부로 만들거나 더 많은 정보를 전달하는 데 사용합니다 — 예를 들어 사용자 위치에 따라 프롬프트를 맞추거나, 폼에서 가져온 데이터를 전달할 수 있습니다.
컨텍스트 변수는 GitLab Duo Workflow Service에 정의된 에이전트에서만 지원됩니다. AI Catalog에서 만든 에이전트는 orbit_enabled를 제외하고는 컨텍스트 변수를 사용할 수 없습니다
전체 흐름은 다음과 같습니다:
- GitLab 모놀리스는
additional_context페이로드를 만들어startWorkflow요청에 포함시킵니다. - GitLab Duo Workflow Service는
additional_context를 읽고, 컴포넌트의inputs매핑을 사용해 그 값을 Jinja2 변수로 해석한 다음, 시스템 프롬프트를 미리 렌더링합니다. - 프롬프트 안의 Jinja2 변수(예:
...)는 해석된 값으로 평가됩니다.{{ goal }}처럼 알려지지 않은 변수는 보존되어 이후 단계에서 해석됩니다.
플로 구성에서 컨텍스트 변수 정의#
플로 YAML
(/duo_workflow_service/agent_platform/v1/flows/configs/<agent_name>/<version>.yml)에서 다음을 선언합니다:
- 변수의 category와 schema를 설명하는
flow.inputs항목입니다. context:inputs.<category>.<field>경로로 변수를 매핑하는 컴포넌트inputs항목입니다.
components:
- name: "my_agent"
type: AgentComponent
prompt_id: "my_agent_prompt"
inputs:
- from: "context:goal"
as: "goal"
- from: "context:inputs.my_context.my_first_var"
as: "my_first_var"
optional: true # optional: true prevents an error when the variable is absent
- from: "context:inputs.my_context.my_second_var"
as: "my_second_var"
optional: true
toolset: []
ui_log_events: []
flow:
inputs:
- category: my_context
input_schema:
my_var:
type: boolean
description: Whether the feature is available for this user
entry_point: "my_agent"
프롬프트 템플릿에서 컨텍스트 변수 사용#
prompt_template.system 필드에서 Jinja2 `` 블록을 사용하여 프롬프트 섹션을 조건부로 포함시킵니다:
prompts:
- name: My Agent
prompt_id: "my_agent_prompt"
prompt_template:
system: |
You are a helpful agent.
Additional information {{ my_first_var }}
<my_feature_integration>
You also have access to the my feature API. Use it when the user asks about...
</my_feature_integration>
user: |
{{goal}}
GitLab 모놀리스에서 컨텍스트 변수 연결#
컨텍스트 변수는 startWorkflow 호출의 additionalContext 필드를 통해 Duo Workflow
Service에 전달됩니다. 각 항목은 category, content 필드(JSON 문자열), metadata를 가집니다.
duo_agentic_chat_state_manager.vue에서는 기초 에이전트가 활성화된 경우에만 컨텍스트
envelope를 주입합니다:
const mergedAdditionalContext =
this.selectedFoundationalAgent && goal
? [
{
category: 'my_context',
content: JSON.stringify({ my_first_var: 1, my_second_var: this.myFeatureEnabled }),
metadata: '{}',
},
...(additionalContext || []).filter((c) => c.category !== 'my_context'),
]
: additionalContext || [];
채팅 외부에서 컨텍스트 제공#
위에서 설명한 연결 방식은 duo_agentic_chat_state_manager.vue 내부에서 envelope를
만드는데, 이는 채팅 컴포넌트가 이미 가지고 있는 컨텍스트에 적합합니다. 채팅 외부에 있는
기능이 소유한 컨텍스트(예: 사용자가 메시지 사이에 편집하는, 페이지 다른 곳에 있는 폼)의
경우에는 대신 provider를 등록합니다. Provider는 전송할 때마다 새로 읽히므로, 에이전트는
채팅을 열었을 때 고정된 값이 아니라 항상 현재 상태를 보게 됩니다.
제공하는 컴포넌트에서 external_context_store를 사용하여 등록합니다:
import { registerExternalContextProvider } from 'ee/ai/duo_agentic_chat/context/external_context_store';
mounted() {
// getContent runs on every send; return a nullish value to contribute nothing this turn.
this.disposeContextProvider = registerExternalContextProvider(
'my_context',
() => ({ my_var: this.currentValue }),
);
},
beforeDestroy() {
this.disposeContextProvider?.();
},
registerExternalContextProvider는 disposer를 반환합니다. provider가 누수되지 않도록
teardown 시점에 이를 호출합니다. duo_agentic_chat_state_manager.vue는 전송할 때마다
getExternalContextItems()를 호출하여 결과를 병합하며, 동일한 category의 메시지별 항목보다 우선합니다.
이 방식으로 등록한 category도 화면 표시와 GraphQL에서는 반드시 필터링해야 합니다. 자세한 내용은 내부 category 필터링을 참고합니다.
화면 표시와 GraphQL에서 내부 category 필터링#
내부 컨텍스트 category(예: my_context)는 UI에 표시되거나 GraphQL을 통해
직렬화되어서는 안 됩니다. 사용자 지정 category 이름은 AiAdditionalContextCategory
enum에 등록되어 있지 않아 직렬화하면 오류가 발생합니다.
ee/app/assets/javascripts/ai/duo_agentic_chat/utils/workflow_utils.js에서 필터링합니다:
const INTERNAL_CATEGORIES = new Set(['my_context']);
msg.extras = {
contextItems: msg.additional_context.filter((c) => !INTERNAL_CATEGORIES.has(c.category)),
};
DuoMessage 객체를 만들기 전에 ee/app/presenters/ai/duo_workflows/workflow_checkpoint_event_presenter.rb에서
이를 제거합니다:
INTERNAL_CONTEXT_CATEGORIES = %w[my_context].freeze
if msg['additional_context'].is_a?(Array)
msg['additional_context'] = msg['additional_context'].reject do |ctx|
INTERNAL_CONTEXT_CATEGORIES.include?(ctx['category'])
end
end
에이전트가 UI 폼을 편집하도록 하기#
기초 에이전트는 페이지의 폼 상태를 읽고 그 폼에 변경 내용을 다시 기록할 수 있습니다.
이 패턴은 두 부분으로 구성됩니다:
- 읽기:
form_context컨텍스트 변수로 폼 상태를 에이전트에 전달합니다. - 쓰기: 에이전트가 폼 편집 도구를 호출하고, 소비자가 반환된 변경 사항을 적용합니다.
읽기 부분은 컨텍스트 변수를 기반으로 합니다. 아래 섹션에서는 폼 편집 패턴이 소비자 쪽에 추가하는 부분을 다룹니다.
에이전트에 폼 상태 전달#
현재 폼 상태를 form_context 컨텍스트 변수로 에이전트에 전달합니다.
ee/app/assets/javascripts/ai/shared/utils/form_context_utils.js의 buildFormContext 헬퍼를
사용하여 폼의 식별 정보와 내용을 envelope로 감쌉니다. 소비자는 formId와
formContent만 전달하므로 envelope 구조(category, JSON으로 인코딩된 content,
metadata)를 직접 다루지 않습니다:
import { buildFormContext } from 'ee/ai/shared/utils/form_context_utils';
// In the consumer component:
computed: {
additionalContext() {
return buildFormContext({ formId: 'my-form', formContent: this.formContent });
},
}
formId는 폼을 식별하여 에이전트가 이 폼만 편집하도록 합니다. formContent는 현재 폼
상태이며, 에이전트는 이를 사실(ground truth)로 취급합니다. 결과는
open_agentic_chat_button.vue의 additional-context prop을 통해 전달합니다. 기반이 되는
envelope 구조는 GitLab 모놀리스에서 컨텍스트 변수 연결을 참고합니다.
에이전트의 변경 사항 적용#
에이전트는 변경할 필드를 반환하는 폼 편집 도구를 호출하여 변경 사항을 적용합니다.
참조 도구는
update_form_fields이며,
그 계약은 다음과 같습니다:
form_id: str # echoed from the system prompt; identifies the target form
select: list[str] # field or option names to select or enable
clear: list[str] # field or option names to clear or disable
시스템 프롬프트는 form_context envelope에서 form_id를 고정하므로, 에이전트는
값을 임의로 만들지 않고 올바른 값을 그대로 돌려줍니다.
소비자 쪽에서는 tool-completed 이벤트를 처리합니다. form_id가 해당 폼과 일치하는
도구 호출에만 반응하도록 하여, 같은 페이지에 있는 여러 폼 편집 버튼이 서로 간섭하지 않도록 합니다:
handleToolCompleted({ name, args } = {}) {
if (name !== 'update_form_fields' || args?.form_id !== 'my-form') return;
// Apply args.select and args.clear to the form.
}
select와 clear 계약은 값이 이름이 있는 옵션 집합인 모든 폼 컨트롤을 다룹니다:
체크박스 그룹, 다중 선택 드롭다운, 토큰 필드, 불리언 토글입니다. 토글은 select로
활성화하고 clear로 비활성화합니다. 텍스트 필드는 아직 지원하지 않습니다.
기초 에이전트를 로컬에서 개발하기#
AI Catalog에서 만든 에이전트는 로컬에서 동기화해야 합니다. 이를 위해 로컬 AI Catalog나 GitLab.com AI Catalog에서 에이전트를 만듭니다.
-
GitLab.com에서 에이전트 가져오기
$GDK/gitlab-ai-gateway에서 다음 명령을 실행합니다:poetry run fetch-foundational-agents "http://gdk.test:3000 or https://gitlab.com" "<token-to-your-local-gdk>" \ "<agent-reference>:<agent-id-in-local-catalog>" --flow-registry-version v1GitLab.com에서
duo_planner와security_analyst_agent를 가져오는 예시는 다음과 같습니다:poetry run fetch-foundational-agents "https://gitlab.com" "<token-to-your-local-gdk>" \ "duo_planner:348,security_analyst_agent:356" --flow-registry-version v1여기서:
348은 GitLab.com의 GitLab Duo Planner 카탈로그 ID입니다356은 GitLab.com의 Security Analyst Agent 카탈로그 ID입니다
구성을 가져온 후, 서비스를 재시작합니다:
gdk restart duo-workflow-service -
설정 확인
기초 에이전트는
$GDK/gitlab-ai-gateway/duo_workflow_service/agent_platform/v1/flows/configs/에.yml파일로 저장됩니다.예를 들어 위
poetry명령으로duo_planner와security_analyst_agent를 가져왔다면, 다음을 실행할 수 있습니다:ls duo_workflow_service/agent_platform/v1/flows/configs/ | grep -e "duo_planner" -e "security_analyst"그러면 다음과 같은 출력이 표시되어야 합니다:
duo_planner.yml security_analyst_agent.yml또는 GDK UI에서 확인할 수도 있습니다:
FoundationalChatAgentsDefinitions.rb를 변경했으므로, 이제 로컬 웹 채팅에서 기초 에이전트를 선택할 수 있습니다.- 기초 에이전트가 보이고 상호작용할 수 있는지 확인합니다
- 메시지를 보내서 에이전트가 올바르게 응답하는지 테스트합니다
문제 해결#
- 에이전트가 채팅에 나타나지 않는 경우: GitLab-ai-gateway 디렉터리에 구성 파일이 만들어졌는지, 서비스가 정상적으로 재시작되었는지 확인합니다
- 권한 오류: GitLab.com API 토큰에 API scope가 있는지 확인합니다
- Flow registry 버전 오류:
--flow-registry-version v1을 사용하고 있는지 확인합니다
기초 에이전트 동기화 파이프라인 테스트#
이 섹션에서는 로컬 GDK에서 기초 에이전트를 동기화하는 데 사용하는 파이프라인을 테스트하는 방법을 설명합니다. 기초 플로를 개발하거나 최신 플로를 가져오려면 위의 기초 에이전트를 로컬에서 개발하기 섹션을 참고합니다.
사전 요구 사항#
- 실행 중인 GDK 인스턴스
apiscope가 있는 GitLab API 토큰($GDK_PAT_WITH_API_SCOPE)- GDK에서
gitlab-ai-gateway리포지터리에 대한 접근 권한
1단계: 기존 기초 에이전트 확인#
먼저 모놀리스에는 정의되어 있지만 로컬 AI Catalog에는 없는 기초 에이전트를 확인합니다:
-
기초 에이전트 정의를 확인합니다:
# In your GDK's gitlab directory cat ee/lib/ai/foundational_chat_agents_definitions.rb -
로컬 AI Catalog에 있는 기존 에이전트 목록을 확인합니다:
curl --header "Authorization: Bearer $GDK_PAT_WITH_API_SCOPE" \ --header "Content-Type: application/json" \ "http://gdk.test:3000/api/graphql" \ --data '{"query": "query { aiCatalogItems { nodes { id name description } } }"}' -
결과를 비교하여 누락된 기초 에이전트를 확인합니다(일반적으로
duo_planner와security_analyst_agent).
2단계: 누락된 기초 에이전트 만들기#
로컬 AI Catalog에 기초 에이전트가 없다면, 프로그래밍 방식으로 만듭니다:
-
에이전트를 호스팅할 프로젝트 ID를 가져옵니다:
bundle exec rake gitlab:duo:setup으로 duo 설정 스크립트를 실행했다면, ID1000000인 프로젝트를 기초 에이전트를 소유하는 프로젝트로 사용할 수 있습니다. 실행하지 않았다면 GDK에 있는 임의의 Premium 또는 Ultimate 프로젝트를 선택하여 그 프로젝트의 ID를 사용할 수 있습니다.# If you haven't run the duo setup script, get any project ID curl --header "Authorization: Bearer $GDK_PAT_WITH_API_SCOPE" \ "http://gdk.test:3000/api/v4/projects" | jq '.[0].id' -
Planner 에이전트를 만듭니다:
curl --header "Authorization: Bearer $GDK_PAT_WITH_API_SCOPE" \ --header "Content-Type: application/json" \ "http://gdk.test:3000/api/graphql" \ --data '{ "query": "mutation { aiCatalogAgentCreate(input: { projectId: \"gid://gitlab/Project/YOUR_PROJECT_ID\", name: \"Planner\", description: \"Get help with planning and workflow management. Organize, edit, create, and track work more effectively in GitLab.\", public: true, systemPrompt: \"You are a helpful planning assistant that helps users organize, edit, create, and track work more effectively in GitLab.\" }) { item { id name } errors } }" }' -
Security Analyst 에이전트를 만듭니다:
curl --header "Authorization: Bearer $GDK_PAT_WITH_API_SCOPE" \ --header "Content-Type: application/json" \ "http://gdk.test:3000/api/graphql" \ --data '{ "query": "mutation { aiCatalogAgentCreate(input: { projectId: \"gid://gitlab/Project/YOUR_PROJECT_ID\", name: \"Security Analyst\", description: \"Automate vulnerability management and security workflows. The Security Analyst Agent acts as an AI team member that can autonomously analyze, triage, and remediate security vulnerabilities.\", public: true, systemPrompt: \"You are a security analyst AI that helps with vulnerability management and security workflows. You can analyze, triage, and help remediate security vulnerabilities.\" }) { item { id name } errors } }" }'YOUR_PROJECT_ID를 1단계에서 얻은 실제 프로젝트 ID로 바꿉니다.
3단계: 로컬 에이전트 ID 가져오기#
에이전트를 만든 후, 로컬 카탈로그 ID를 가져옵니다:
# Get Planner agent ID
curl --header "Authorization: Bearer $GDK_PAT_WITH_API_SCOPE" \
--header "Content-Type: application/json" \
"http://gdk.test:3000/api/graphql" \
--data '{"query": "query { aiCatalogItems(search: \"Planner\") { nodes { id name } } }"}'
# Get Security Analyst agent ID
curl --header "Authorization: Bearer $GDK_PAT_WITH_API_SCOPE" \
--header "Content-Type: application/json" \
"http://gdk.test:3000/api/graphql" \
--data '{"query": "query { aiCatalogItems(search: \"Security Analyst\") { nodes { id name } } }"}'
응답에서 숫자 ID를 확인합니다(예: 10과 11).
4단계: 기초 에이전트 구성 가져오기#
gitlab-ai-gateway 디렉터리에서, 로컬 ID를 사용하여 에이전트 구성을 가져옵니다:
# For v1 flow registry (recommended)
poetry run fetch-foundational-agents "http://gdk.test:3000" "$GDK_PAT_WITH_API_SCOPE" \
"duo_planner:10,security_analyst_agent:11" \
--flow-registry-version v1
# For experimental flow registry (alternative)
poetry run fetch-foundational-agents "http://gdk.test:3000" "$GDK_PAT_WITH_API_SCOPE" \
"duo_planner:10,security_analyst_agent:11" \
--flow-registry-version experimental \
--output-path duo_workflow_service/agent_platform/experimental/flows/configs
10과 11을 3단계에서 얻은 실제 에이전트 ID로 바꿉니다.
5단계: GitLab Duo Workflow Service 재시작#
gdk restart duo-workflow-service
6단계: 설정 확인#
FoundationalChatAgentsDefinitions.rb의 변경 사항과 가져온 구성이 있으면, 이제 로컬 웹 채팅에서 기초 에이전트를 선택할 수 있습니다.
문제 해결#
-
에이전트가 누락된 경우: 이 단계를 모두 따랐는데도 에이전트가 채팅에 나타나지 않으면 다음을 확인합니다:
- 로컬 AI Catalog에 에이전트가 존재하는지(3단계의 GraphQL 쿼리로 확인)
fetch-foundational-agents를 실행한 후 올바른 디렉터리에 플로 구성 파일이 만들어졌는지- GitLab Duo Workflow Service가 정상적으로 재시작되었는지
-
Flow registry 버전: 프로덕션과 유사한 동작에는
v1을, 새 기능 테스트에는experimental을 사용합니다 -
권한 오류: API 토큰에
apiscope와 충분한 프로젝트 권한이 있는지 확인합니다 -
GraphQL 오류: GraphQL introspection으로 정확한 mutation 파라미터를 확인합니다:
curl --header "Authorization: Bearer $GDK_PAT_WITH_API_SCOPE" \ --header "Content-Type: application/json" \ "http://gdk.test:3000/api/graphql" \ --data '{"query": "query { __type(name: \"AiCatalogAgentCreatePayload\") { fields { name type { name } } } }"}'
기초 에이전트 통합 테스트#
기초 에이전트에는 실제 LLM 호출을 사용해 전체 에이전트 루프를 엔드투엔드로 실행하는 통합 테스트 하니스가 있습니다. 이를 사용하여 실제 GitLab 인스턴스나 실제 도구 백엔드 없이도 에이전트가 도구를 올바르게 선택하고, 올바른 인자를 전달하며, 유효한 응답을 만드는지 검증합니다.
테스트는 ai-assist 리포지터리에 있으며 CI job으로 실행됩니다(예: Data Analyst 에이전트 테스트는 에이전트 프롬프트가 변경될 때 실행되고, 그 외에는 수동으로 실행합니다).
핵심 개념#
- 실제 LLM 호출: 에이전트 실행과 응답 검증 모두 실제 모델 호출을 사용하므로, 단순한 문자열 매칭이 아니라 프롬프트 동작의 회귀까지 테스트에서 잡아냅니다.
- 모킹 가능한 도구: 도구 응답을 스텁으로 대체할 수 있어 테스트가 결정적이고 빠릅니다.
- 유연한 assertion API:
assert_called_tool과assert_llm_validates같은 assertion을 체이닝하여 예상 동작을 명확하게 표현합니다.
테스트 예시#
@pytest.mark.asyncio
async def test_how_many_open_issues(
analytics_agent,
initial_state,
mock_gitlab_client,
):
"""Agent must call run_glql_query and report the count."""
mock_glql_response(mock_gitlab_client, glql_response(SAMPLE_ISSUES, count=42))
result = await ask_agent(
analytics_agent,
initial_state,
"How many open issues are there in the gitlab-org group?",
)
(result.assert_has_tool_calls().assert_called_tool("run_glql_query"))
await result.assert_llm_validates(
[
"Response says 42 open issues",
]
)
ask_agent는 주어진 프롬프트로 에이전트 루프를 실행하고 result 객체를 반환합니다.
assert_called_tool은 에이전트가 예상한 도구를 호출했는지 검증합니다.
assert_llm_validates는 LLM에게 평이한 언어로 작성한 기준에 맞춰 응답을 확인하도록
요청하므로, 깨지기 쉬운 부분 문자열 매칭이 필요하지 않습니다.
CI 구성#
통합 테스트 job은 .gitlab/ci/test.gitlab-ci.yml에 정의되어 있습니다. 사용 가능한 구성 변수는 다음과 같습니다:
EXECUTION_MODEL: 테스트 중 에이전트를 실행하는 데 사용하는 모델입니다.VALIDATION_MODEL:assert_llm_validates가 응답을 판단하는 데 사용하는 모델입니다.
시작하기#
이 하니스를 에이전트에 재사용하거나 확장하려면, 참고할 수 있는 다음 머지 리퀘스트를 확인합니다:
아키텍처 설계#
기초 채팅 에이전트는 GitLab이 개발하며 모든 GitLab 배포판(GitLab.com, GitLab Self-Managed, Dedicated)에서 사용할 수 있어야 합니다.
기초 에이전트를 제공하는 아키텍처는 런타임에 정의를 가져오기 위해 AI Catalog에 연결하는 방식을 피하며, GitLab 엔지니어링 팀이 릴리스 시점을 완전히 통제할 수 있게 합니다.
이 설계는 기초 플로를 지원하도록 확장될 수도 있습니다.
모놀리스에서의 기초 에이전트#
모놀리스에 기초 에이전트를 정의하는 것은 두 가지 목적을 가집니다: 하위 호환성 지원과 릴리스 통제입니다.
FoundationalChatAgentsDefinitions
모듈은 GitLab 인스턴스 버전을 기준으로 에이전트 버전 관리를 수행하며, 프롬프트 버전 관리와 비슷하게 이전 GitLab 버전에도 영향을 줍니다.
또한 FoundationalChatAgentsResolver에서
팀은 기초 채팅 에이전트를 사용할 수 있게 만드는 조건을 다음과 같은 상황에 맞춰 선택할 수 있습니다:
- 사용자가 Ultimate를 보유하고 있는지,
- 기능 플래그가 활성화되어 있는지,
- 에이전트가 SaaS 전용인지
AI Catalog나 Duo Workflow Service에만 전적으로 의존한다면, 이런 유연성은 가능하지 않습니다
버전 결정#
에이전트 버전은 FoundationalChatAgentsDefinitions.rb의 version 필드를 기준으로
결정되며, 이 필드는 GitLab Duo Workflow Service의
폴더(예: v1, experimental)에 매핑됩니다.
앞으로는 버전 결정이 시맨틱 버전을 기준으로 이루어질 예정입니다. 이렇게 되면 다음이 가능해집니다:
- Patch 및 minor 업데이트(버그 수정, 성능 개선, 프롬프트 개선)는 GitLab 인스턴스 업데이트 없이도 기존 GitLab 버전에 배포됩니다
- Major 버전 릴리스는 새로운 GitLab 기능(새 도구, API 변경, 스키마 변경 등)이 필요한 호환성이 깨지는 변경으로, 호환되는 GitLab 버전에만 배포됩니다
이 접근 방식은 기초 에이전트를 지속적으로 개선하면서도 하위 호환성을 보장합니다.
GitLab Duo Workflow Service에 번들링#
에이전트를 GitLab Duo Workflow Service에 번들링하면, AI Catalog에 정의된 에이전트를 셀프 호스팅 환경을 포함한 모든 배포판에서 사용할 수 있게 됩니다. 시맨틱 버전 관리 지원이 추가되면, 각 major 릴리스의 최신 버전이 번들되며, 각 기초 에이전트의 특정 고정 버전도 함께 번들됩니다.
이에 대한 대안은 YAML 정의 자체를 GitLab 모놀리스의 일부로 배포하는 것이지만, 이 방식은 클라우드에 연결된 GitLab Self-Managed 인스턴스에 수정 사항을 빠르게 배포할 수 없다는 단점이 있습니다.
이후 AI Catalog에 레이블이 구현되면 팀은 Dockerfile에 항목을 추가할 필요가 없어집니다. 올바른 레이블로 버전을 가져올 수 있게 됩니다.
생성 흐름#
소스 코드 보기
%%{init: {"sequence": {"actorMargin": 50}}}%%
sequenceDiagram
accTitle: Foundational agent creation flow
accDescr: Sequence diagram showing the process of creating a foundational agent from AI Catalog through to GitLab monolith
participant Team
participant AI Catalog
participant DWS Repo as DWS Repository
participant CI
participant Monolith
Team->>AI Catalog: Create foundational agent
Team->>DWS Repo: Add agent ID to Dockerfile
DWS Repo->>CI: Trigger build
CI->>AI Catalog: Pull agent definitions
AI Catalog->>CI: Returns all required versions
CI->>CI: Store definitions in DWS image
CI->>CI: Ships images with definitions
Team->>Monolith: Add agent to FoundationalChatAgentsDefinitions.rb</code></pre></details></div>
사용 흐름#
Mermaid 다이어그램 (14줄)소스 코드 보기
%%{init: {"sequence": {"actorMargin": 50}}}%%
sequenceDiagram
accTitle: Foundational agent usage flow
accDescr: Sequence diagram showing how users interact with foundational agents through GitLab monolith and Duo Workflow Service
participant User
participant Monolith
participant DWS as GitLab Duo Workflow Service
User->>Monolith: Request to foundational agent
Monolith->>DWS: Request specific agent version
DWS->>DWS: Resolve agent version
DWS->>DWS: Process request
DWS->>Monolith: Return response
Monolith->>User: Return response</code></pre></details></div>
실행 흐름은 사용자가 로컬 모놀리스, GitLab.com, 클라우드에 연결된 DWS,
또는 DWS의 로컬 설치본 중
어느 것을 사용하든 동일합니다.