InfoGrab DocsInfoGrab Docs

기초 에이전트 관리

요약

이 가이드는 기초 에이전트를 다룹니다. 기초 에이전트는 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를 메모합니다. 에이전트가 공개로 설정되어 있는지 확인합니다. 예시: 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>" \

위 명령은 테스트 목적으로 로컬에서도 실행할 수 있습니다. 에이전트 참조는 공백 없이 소문자여야 합니다(예: 'test_agent').

에이전트를 선택 가능하게 만들려면 FoundationalChatAgentsDefinitions.rb에 추가합니다. Dockerfile에서 사용한 참조를 사용하세요:

{
  id: 3,
  reference: '<agent-reference>',
  version: 'experimental',
  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.yml

version: "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에 추가합니다.

  • GitLab Duo Workflow Service에 프롬프트를 추가하여 로컬 GDK에서 에이전트를 테스트할 수 있게 합니다.

  • AI Catalog를 사용하는 경우 FoundationalChatAgentsDefinitions.rb의 에이전트 version 필드는 experimental이어야 합니다. GitLab Duo Workflow Service에서 정의를 생성할 때 버전은 v1이어야 합니다.

에이전트 프롬프트의 시크릿 보안 요구 사항#

기초 에이전트의 범위에 다음 중 하나가 포함되는 경우, 시스템 프롬프트에 반드시 시크릿 보안 지침을 포함해야 합니다:

  • 파일 생성 또는 수정(예: .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

이를 통해 기초 에이전트를 특정 티어에서 사용 가능하게 할 수도 있습니다.

범위 지정#

모든 에이전트가 모든 영역에서 유용한 것은 아닙니다. 예를 들어 일부 에이전트는 프로젝트에서 작동하고 다른 에이전트는 그룹에서 더 유용하거나 더 많은 기능을 갖습니다. 범위 지정은 지원되지 않습니다. 이슈 577395를 참조하세요.

트리거#

트리거는 기초 채팅 에이전트에 지원되지 않습니다. 그러나 AI Catalog에서 정의된 경우 사용자가 여전히 프로젝트에 추가할 수 있으며, 그 시점에서 트리거를 통해 사용할 수 있습니다.

버전 관리#

FoundationalChatAgentsDefinitions.rbflow_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은 정확한 버전에 고정합니다.

변경 사항에 따라 버전 증가를 선택하세요:

  • breaking changes의 경우 주(major) 버전을 증가시킵니다(예: 새로운 필수 입력을 예상하는 경우).

  • 이전 버전과 호환되는 추가의 경우 부(minor) 버전을 증가시킵니다(예: 새로운 선택적 파라미터).

  • 버그 수정의 경우 패치(patch) 버전을 증가시킵니다.

    버전 고정은 GitLab Duo Workflow Service에 정의된 에이전트에서만 사용할 수 있습니다. AI Catalog 항목으로 지원되는 에이전트는 카탈로그 항목에서 버전을 해결하며 flow_version을 무시합니다.

    flow_version이 없으면 GitLab Duo Workflow Service는 기본 해결 방식으로 폴백합니다. 에이전트를 변경하기 전에 이전 GitLab 버전에 대한 잠재적인 breaking changes를 고려하세요.

컨텍스트 변수#

컨텍스트 변수를 사용하면 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)에서 다음을 선언합니다:

  • 변수의 카테고리와 스키마를 설명하는 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에서 기초 에이전트가 활성화된 경우에만 컨텍스트 엔벨로프를 주입합니다:

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 내부에서 엔벨로프를 빌드합니다. 채팅 외부의 기능이 소유한 컨텍스트, 예를 들어 사용자가 메시지 사이에 상태를 편집하는 페이지의 다른 폼과 같은 경우에는 대신 프로바이더를 등록하세요. 프로바이더는 전송할 때마다 새로 읽히므로, 에이전트는 채팅이 열렸을 때 고정된 값이 아니라 항상 현재 상태를 봅니다.

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는 디스포저를 반환합니다. 프로바이더가 누수되지 않도록 해제 시 이를 호출하세요. duo_agentic_chat_state_manager.vue는 전송할 때마다 getExternalContextItems()를 호출하고 결과를 병합하며, 동일한 카테고리의 메시지별 항목보다 우선합니다.

이 방식으로 등록된 카테고리도 여전히 UI 및 GraphQL에서 필터링되어야 합니다. 자세한 내용은 내부 카테고리 필터링을 참조하세요.

UI 및 GraphQL에서 내부 카테고리 필터링#

내부 컨텍스트 카테고리(예: my_context)는 UI에 표시되거나 GraphQL을 통해 직렬화되어서는 안 됩니다. 사용자 정의 카테고리 이름은 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.jsbuildFormContext 헬퍼를 사용하여 폼 식별자와 내용을 엔벨로프로 래핑합니다. 소비자는 formIdformContent만 전달하므로 엔벨로프 형태(category, JSON으로 인코딩된 내용, 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.vueadditional-context prop을 통해 전달하세요. 기본 엔벨로프 형태는 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 엔벨로프에서 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.
}

selectclear 계약은 값이 명명된 옵션 집합인 모든 폼 컨트롤을 다룹니다: 체크박스 그룹, 다중 선택 드롭다운, 토큰 필드, 불리언 토글. 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 v1

GitLab.com에서 duo_plannersecurity_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_plannersecurity_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 범위가 있는지 확인하세요

  • 플로우 레지스트리 버전 오류: --flow-registry-version v1을 사용하는지 확인하세요

기초 에이전트 동기화 파이프라인 테스트#

이 섹션은 로컬 GDK에서 기초 에이전트를 동기화하는 데 사용되는 파이프라인을 테스트하는 방법을 설명합니다. 기초 플로우 개발 또는 최신 플로우 가져오기는 위의 로컬에서 기초 에이전트 개발 섹션을 참조하세요.

사전 요구 사항#

  • 실행 중인 GDK 인스턴스

  • api 범위가 있는 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_plannersecurity_analyst_agent).

2단계: 누락된 기초 에이전트 생성#

기초 에이전트가 로컬 AI Catalog에 없는 경우 프로그래밍 방식으로 생성합니다:

에이전트 호스팅을 위한 프로젝트 ID를 가져옵니다:

bundle exec rake gitlab:duo:setup으로 duo 설정 스크립트를 실행했다면 ID 1000000인 프로젝트를 기초 에이전트 소유 프로젝트로 사용할 수 있습니다. 그렇지 않은 경우 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를 메모합니다(예: 1011).

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

1011을 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가 성공적으로 재시작되었는지 확인

플로우 레지스트리 버전: 프로덕션과 유사한 동작에는 v1, 새 기능 테스트에는 experimental 사용

권한 오류: API 토큰에 api 범위와 충분한 프로젝트 권한이 있는지 확인

GraphQL 오류: GraphQL 내성을 사용하여 정확한 뮤테이션 파라미터 확인:

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 호출: 에이전트 실행과 응답 검증 모두 실제 모델 호출을 사용하므로, 단순 문자열 매칭이 아닌 프롬프트 동작의 회귀를 감지할 수 있습니다.

  • 모킹 가능한 도구: 도구 응답을 스텁할 수 있어 테스트가 결정론적이고 빠릅니다.

  • 플루언트 어설션 API: assert_called_toolassert_llm_validates 같은 어설션을 체이닝하여 예상 동작을 명확하게 표현합니다.

예시 테스트#

@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는 주어진 프롬프트로 에이전트 루프를 실행하고 결과 객체를 반환합니다. 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, Self-Managed, Dedicated)에서 사용 가능해야 합니다.

기초 에이전트가 사용 가능하게 되는 아키텍처는 런타임에 AI Catalog에 연결하여 정의를 가져오는 것을 피하고 GitLab 엔지니어링 팀이 릴리스 시점에 대한 완전한 제어를 할 수 있게 합니다.

이 설계는 기초 플로우를 지원하도록 확장될 수도 있습니다.

모노리스에서의 기초 에이전트#

모노리스에서 기초 에이전트를 정의하는 것은 두 가지 목적을 제공합니다: 이전 버전 호환성 지원과 릴리스 제어.

FoundationalChatAgentsDefinitions를 통해 FoundationalChatAgentsDefinitions 모듈은 GitLab 인스턴스 버전을 기반으로 에이전트 버전 관리를 합니다. 이전 GitLab 버전에 영향을 미치는 방식은 프롬프트 버전 관리와 유사합니다.

또한 FoundationalChatAgentsResolver에서 팀은 다음과 같은 상황에서 기초 채팅 에이전트를 사용할 수 있는 조건을 선택할 수 있습니다:

  • 사용자가 Ultimate를 가지고 있는지

  • 기능 플래그가 활성화되어 있는지

  • 에이전트가 SaaS 전용인지

AI Catalog 또는 Duo Workflow Service에만 의존한다면 이러한 유연성은 불가능할 것입니다

버전 해결#

에이전트 버전은 FoundationalChatAgentsDefinitions.rbversion 필드를 기반으로 해결되며, 이는 GitLab Duo Workflow Service의 폴더(예: v1, experimental)에 매핑됩니다.

향후에는 시맨틱 버전 관리를 기반으로 버전 해결이 이루어질 것입니다. 이를 통해 다음이 가능해집니다:

  • 패치 및 마이너 업데이트(버그 수정, 성능 개선, 프롬프트 개선)를 GitLab 인스턴스 업데이트 없이 기존 GitLab 버전에 제공

  • 주요 버전 릴리스(새 도구, API 변경, 스키마 수정 등 GitLab 신기능이 필요한 breaking changes)를 호환 가능한 GitLab 버전에만 제공

이 접근 방식은 이전 버전 호환성을 보장하면서 기초 에이전트의 지속적인 개선을 가능하게 합니다.

GitLab Duo Workflow Service에 번들링#

에이전트를 GitLab Duo Workflow Service에 번들링하면 AI Catalog에서 정의된 에이전트가 셀프 호스팅 설정을 포함한 모든 배포에서 사용 가능해집니다. 시맨틱 버전 관리 지원으로, 각 주요 릴리스의 최신 버전이 번들되며, 각 기초 에이전트의 특정 고정 버전도 함께 번들됩니다.

이에 대한 대안은 YAML 정의 자체를 GitLab 모노리스의 일부로 제공하는 것이지만, 이는 클라우드 연결된 셀프 매니지드 인스턴스에 신속하게 수정을 제공하지 못하는 단점이 있습니다.

결국 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

사용 플로우#

%%{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

실행 플로우는 사용자가 로컬 모노리스, GitLab.com, 클라우드 연결 DWS 또는 DWS 로컬 설치를 사용하든 동일합니다.

기초 에이전트 관리

GitLab v19.2
원문 보기
요약

이 가이드는 기초 에이전트를 다룹니다. 기초 에이전트는 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를 메모합니다. 에이전트가 공개로 설정되어 있는지 확인합니다. 예시: 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>" \

위 명령은 테스트 목적으로 로컬에서도 실행할 수 있습니다. 에이전트 참조는 공백 없이 소문자여야 합니다(예: 'test_agent').

에이전트를 선택 가능하게 만들려면 FoundationalChatAgentsDefinitions.rb에 추가합니다. Dockerfile에서 사용한 참조를 사용하세요:

{
  id: 3,
  reference: '<agent-reference>',
  version: 'experimental',
  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.yml

version: "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에 추가합니다.

  • GitLab Duo Workflow Service에 프롬프트를 추가하여 로컬 GDK에서 에이전트를 테스트할 수 있게 합니다.

  • AI Catalog를 사용하는 경우 FoundationalChatAgentsDefinitions.rb의 에이전트 version 필드는 experimental이어야 합니다. GitLab Duo Workflow Service에서 정의를 생성할 때 버전은 v1이어야 합니다.

에이전트 프롬프트의 시크릿 보안 요구 사항#

기초 에이전트의 범위에 다음 중 하나가 포함되는 경우, 시스템 프롬프트에 반드시 시크릿 보안 지침을 포함해야 합니다:

  • 파일 생성 또는 수정(예: .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

이를 통해 기초 에이전트를 특정 티어에서 사용 가능하게 할 수도 있습니다.

범위 지정#

모든 에이전트가 모든 영역에서 유용한 것은 아닙니다. 예를 들어 일부 에이전트는 프로젝트에서 작동하고 다른 에이전트는 그룹에서 더 유용하거나 더 많은 기능을 갖습니다. 범위 지정은 지원되지 않습니다. 이슈 577395를 참조하세요.

트리거#

트리거는 기초 채팅 에이전트에 지원되지 않습니다. 그러나 AI Catalog에서 정의된 경우 사용자가 여전히 프로젝트에 추가할 수 있으며, 그 시점에서 트리거를 통해 사용할 수 있습니다.

버전 관리#

FoundationalChatAgentsDefinitions.rbflow_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은 정확한 버전에 고정합니다.

변경 사항에 따라 버전 증가를 선택하세요:

  • breaking changes의 경우 주(major) 버전을 증가시킵니다(예: 새로운 필수 입력을 예상하는 경우).

  • 이전 버전과 호환되는 추가의 경우 부(minor) 버전을 증가시킵니다(예: 새로운 선택적 파라미터).

  • 버그 수정의 경우 패치(patch) 버전을 증가시킵니다.

    버전 고정은 GitLab Duo Workflow Service에 정의된 에이전트에서만 사용할 수 있습니다. AI Catalog 항목으로 지원되는 에이전트는 카탈로그 항목에서 버전을 해결하며 flow_version을 무시합니다.

    flow_version이 없으면 GitLab Duo Workflow Service는 기본 해결 방식으로 폴백합니다. 에이전트를 변경하기 전에 이전 GitLab 버전에 대한 잠재적인 breaking changes를 고려하세요.

컨텍스트 변수#

컨텍스트 변수를 사용하면 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)에서 다음을 선언합니다:

  • 변수의 카테고리와 스키마를 설명하는 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에서 기초 에이전트가 활성화된 경우에만 컨텍스트 엔벨로프를 주입합니다:

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 내부에서 엔벨로프를 빌드합니다. 채팅 외부의 기능이 소유한 컨텍스트, 예를 들어 사용자가 메시지 사이에 상태를 편집하는 페이지의 다른 폼과 같은 경우에는 대신 프로바이더를 등록하세요. 프로바이더는 전송할 때마다 새로 읽히므로, 에이전트는 채팅이 열렸을 때 고정된 값이 아니라 항상 현재 상태를 봅니다.

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는 디스포저를 반환합니다. 프로바이더가 누수되지 않도록 해제 시 이를 호출하세요. duo_agentic_chat_state_manager.vue는 전송할 때마다 getExternalContextItems()를 호출하고 결과를 병합하며, 동일한 카테고리의 메시지별 항목보다 우선합니다.

이 방식으로 등록된 카테고리도 여전히 UI 및 GraphQL에서 필터링되어야 합니다. 자세한 내용은 내부 카테고리 필터링을 참조하세요.

UI 및 GraphQL에서 내부 카테고리 필터링#

내부 컨텍스트 카테고리(예: my_context)는 UI에 표시되거나 GraphQL을 통해 직렬화되어서는 안 됩니다. 사용자 정의 카테고리 이름은 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.jsbuildFormContext 헬퍼를 사용하여 폼 식별자와 내용을 엔벨로프로 래핑합니다. 소비자는 formIdformContent만 전달하므로 엔벨로프 형태(category, JSON으로 인코딩된 내용, 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.vueadditional-context prop을 통해 전달하세요. 기본 엔벨로프 형태는 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 엔벨로프에서 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.
}

selectclear 계약은 값이 명명된 옵션 집합인 모든 폼 컨트롤을 다룹니다: 체크박스 그룹, 다중 선택 드롭다운, 토큰 필드, 불리언 토글. 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 v1

GitLab.com에서 duo_plannersecurity_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_plannersecurity_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 범위가 있는지 확인하세요

  • 플로우 레지스트리 버전 오류: --flow-registry-version v1을 사용하는지 확인하세요

기초 에이전트 동기화 파이프라인 테스트#

이 섹션은 로컬 GDK에서 기초 에이전트를 동기화하는 데 사용되는 파이프라인을 테스트하는 방법을 설명합니다. 기초 플로우 개발 또는 최신 플로우 가져오기는 위의 로컬에서 기초 에이전트 개발 섹션을 참조하세요.

사전 요구 사항#

  • 실행 중인 GDK 인스턴스

  • api 범위가 있는 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_plannersecurity_analyst_agent).

2단계: 누락된 기초 에이전트 생성#

기초 에이전트가 로컬 AI Catalog에 없는 경우 프로그래밍 방식으로 생성합니다:

에이전트 호스팅을 위한 프로젝트 ID를 가져옵니다:

bundle exec rake gitlab:duo:setup으로 duo 설정 스크립트를 실행했다면 ID 1000000인 프로젝트를 기초 에이전트 소유 프로젝트로 사용할 수 있습니다. 그렇지 않은 경우 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를 메모합니다(예: 1011).

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

1011을 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가 성공적으로 재시작되었는지 확인

플로우 레지스트리 버전: 프로덕션과 유사한 동작에는 v1, 새 기능 테스트에는 experimental 사용

권한 오류: API 토큰에 api 범위와 충분한 프로젝트 권한이 있는지 확인

GraphQL 오류: GraphQL 내성을 사용하여 정확한 뮤테이션 파라미터 확인:

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 호출: 에이전트 실행과 응답 검증 모두 실제 모델 호출을 사용하므로, 단순 문자열 매칭이 아닌 프롬프트 동작의 회귀를 감지할 수 있습니다.

  • 모킹 가능한 도구: 도구 응답을 스텁할 수 있어 테스트가 결정론적이고 빠릅니다.

  • 플루언트 어설션 API: assert_called_toolassert_llm_validates 같은 어설션을 체이닝하여 예상 동작을 명확하게 표현합니다.

예시 테스트#

@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는 주어진 프롬프트로 에이전트 루프를 실행하고 결과 객체를 반환합니다. 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, Self-Managed, Dedicated)에서 사용 가능해야 합니다.

기초 에이전트가 사용 가능하게 되는 아키텍처는 런타임에 AI Catalog에 연결하여 정의를 가져오는 것을 피하고 GitLab 엔지니어링 팀이 릴리스 시점에 대한 완전한 제어를 할 수 있게 합니다.

이 설계는 기초 플로우를 지원하도록 확장될 수도 있습니다.

모노리스에서의 기초 에이전트#

모노리스에서 기초 에이전트를 정의하는 것은 두 가지 목적을 제공합니다: 이전 버전 호환성 지원과 릴리스 제어.

FoundationalChatAgentsDefinitions를 통해 FoundationalChatAgentsDefinitions 모듈은 GitLab 인스턴스 버전을 기반으로 에이전트 버전 관리를 합니다. 이전 GitLab 버전에 영향을 미치는 방식은 프롬프트 버전 관리와 유사합니다.

또한 FoundationalChatAgentsResolver에서 팀은 다음과 같은 상황에서 기초 채팅 에이전트를 사용할 수 있는 조건을 선택할 수 있습니다:

  • 사용자가 Ultimate를 가지고 있는지

  • 기능 플래그가 활성화되어 있는지

  • 에이전트가 SaaS 전용인지

AI Catalog 또는 Duo Workflow Service에만 의존한다면 이러한 유연성은 불가능할 것입니다

버전 해결#

에이전트 버전은 FoundationalChatAgentsDefinitions.rbversion 필드를 기반으로 해결되며, 이는 GitLab Duo Workflow Service의 폴더(예: v1, experimental)에 매핑됩니다.

향후에는 시맨틱 버전 관리를 기반으로 버전 해결이 이루어질 것입니다. 이를 통해 다음이 가능해집니다:

  • 패치 및 마이너 업데이트(버그 수정, 성능 개선, 프롬프트 개선)를 GitLab 인스턴스 업데이트 없이 기존 GitLab 버전에 제공

  • 주요 버전 릴리스(새 도구, API 변경, 스키마 수정 등 GitLab 신기능이 필요한 breaking changes)를 호환 가능한 GitLab 버전에만 제공

이 접근 방식은 이전 버전 호환성을 보장하면서 기초 에이전트의 지속적인 개선을 가능하게 합니다.

GitLab Duo Workflow Service에 번들링#

에이전트를 GitLab Duo Workflow Service에 번들링하면 AI Catalog에서 정의된 에이전트가 셀프 호스팅 설정을 포함한 모든 배포에서 사용 가능해집니다. 시맨틱 버전 관리 지원으로, 각 주요 릴리스의 최신 버전이 번들되며, 각 기초 에이전트의 특정 고정 버전도 함께 번들됩니다.

이에 대한 대안은 YAML 정의 자체를 GitLab 모노리스의 일부로 제공하는 것이지만, 이는 클라우드 연결된 셀프 매니지드 인스턴스에 신속하게 수정을 제공하지 못하는 단점이 있습니다.

결국 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

사용 플로우#

%%{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

실행 플로우는 사용자가 로컬 모노리스, GitLab.com, 클라우드 연결 DWS 또는 DWS 로컬 설치를 사용하든 동일합니다.