InfoGrab DocsInfoGrab Docs

AI 액션

요약

이 페이지에서는 액션을 구현하고 AI Gateway로 마이그레이션하는 방법을 설명합니다. 새로운 AI 액션을 구현하려면 여러 컴포넌트에 걸쳐 변경이 필요합니다. Cloud Connector 구성에는 서비스에 접근하는 데 필요한 권한과 추가 메타데이터가 저장됩니다.

이 페이지에서는 액션을 구현하고 AI Gateway로 마이그레이션하는 방법을 설명합니다.

새로운 액션 구현 방법#

새로운 AI 액션을 구현하려면 여러 컴포넌트에 걸쳐 변경이 필요합니다. 사용자가 주어진 프롬프트에 따라 이슈 설명을 다시 작성할 수 있도록 하는 액션을 구현하는 예시를 살펴보겠습니다.

1. Cloud Connector 기능 목록에 액션 추가#

Cloud Connector 구성에는 서비스에 접근하는 데 필요한 권한과 추가 메타데이터가 저장됩니다. 기능에 대한 항목이 없다면 Cloud Connector 단위 프리미티브로 기능을 추가하세요:

자세한 내용은 Cloud Connector: 구성을 참조하세요.

2. AI Gateway에서 프롬프트 정의 생성#

AI Gateway 프로젝트에서 ai_gateway/prompts/definitions 하위에 [ai-action]/base/[prompt-version].yml 경로로 새 프롬프트 정의를 생성합니다 (프롬프트 버전 관리 규칙 참조). 사용할 모델과 제공업체를 지정하고, 모델에 제공할 프롬프트를 작성합니다. {}를 사용하여 프롬프트에 입력값을 지정할 수 있습니다.

# ai_gateway/prompts/definitions/rewrite_description/base/1.0.0.yml

name: Description rewriter
model:
  config_file: conversation_performant
  params:
    model_class_provider: anthropic
prompt_template:
  system: |
    You are a helpful assistant that rewrites the description of resources. You'll be given the current description, and a prompt on how you should rewrite it. Reply only with your rewritten description.

    <description>{description}</description>

    <prompt>{prompt}</prompt>

AI 액션이 여러 프롬프트를 사용하는 경우, [ai-action]/[prompt-name]/base/[version].yaml 형식의 트리 구조로 정의를 구성할 수 있습니다:

# ai_gateway/prompts/definitions/code_suggestions/generations/base/1.0.0.yml

name: Code generations
model:
  config_file: conversation_performant
  params:
    model_class_provider: anthropic
...

여러 모델에 대한 프롬프트를 지정하려면 정의 경로에 모델 이름을 사용합니다:

# ai_gateway/prompts/definitions/code_suggestions/generations/mistral/1.0.0.yml

name: Code generations
model:
  name: mistral
  params:
    model_class_provider: litellm
...

3. Completion 클래스 생성#

  • ee/lib/gitlab/llm/ai_gateway/completions/ 하위에 새 completion을 생성하고 Base AI Gateway Completion에서 상속합니다.
# ee/lib/gitlab/llm/ai_gateway/completions/rewrite_description.rb

module Gitlab
  module Llm
    module AiGateway
      module Completions
        class RewriteDescription < Base
          extend ::Gitlab::Utils::Override

          override :inputs
          def inputs
            { description: resource.description, prompt: prompt_message.content }
          end
        end
      end
    end
  end
end

4. Service 생성#

  • ee/app/services/llm/ 하위에 새 서비스를 생성하고 BaseService에서 상속합니다.

  • resource는 작업을 수행할 객체입니다. Ai::Model concern을 포함하는 모든 객체가 될 수 있습니다. 예를 들어 Project, MergeRequest, Issue 등이 될 수 있습니다.

# ee/app/services/llm/rewrite_description_service.rb

module Llm
  class RewriteDescriptionService < BaseService
    extend ::Gitlab::Utils::Override

    override :valid
    def valid?
      super &&
        # You can restrict which type of resources your service applies to
        resource.to_ability_name == "issue" &&
        # Always check that the user is allowed to perform this action on the resource
        Ability.allowed?(user, :rewrite_description, resource)
    end

    private

    def perform
      schedule_completion_worker
    end
  end
end

5. 카탈로그에 기능 등록#

Gitlab::Llm::Utils::AiFeaturesCatalogue로 이동하여 AI 액션에 대한 새 항목을 추가합니다.

class AiFeaturesCatalogue
  LIST = {
    # ...
    rewrite_description: {
      service_class: ::Gitlab::Llm::AiGateway::Completions::RewriteDescription,
      feature_category: :ai_abstraction_layer,
      execute_method: ::Llm::RewriteDescriptionService,
      maturity: :experimental,
      self_managed: false,
      internal: false
    }
  }.freeze

6. 기본 프롬프트 버전 쿼리 추가#

Gitlab::Llm::PromptVersions로 이동하여 원하는 프롬프트 버전이 포함된 쿼리와 함께 AI 액션에 대한 항목을 추가합니다 (새로운 기능의 경우 보통 ^1.0.0이 됩니다. 프롬프트 버전 해석 참조):

class PromptVersions
  class << self
    VERSIONS = {
      # ...
      "rewrite_description/base": "^1.0.0"

AI 액션 업데이트#

AI 기능의 템플릿, 모델, 또는 파라미터를 변경하려면 AI Gateway에 새 YAML 버전 파일을 생성합니다:

# ai_gateway/prompts/definitions/rewrite_description/base/1.0.1.yml

name: Description rewriter with Claude 3.5
model:
  name: claude-3-5-sonnet-20240620
  params:
    model_class_provider: anthropic
prompt_template:
  system: |
    You are a helpful assistant that rewrites the description of resources. You'll be given the current description, and a prompt on how you should rewrite it. Reply only with your rewritten description.

    <description>{description}</description>

    <prompt>{prompt}</prompt>

프롬프트 버전의 점진적 롤아웃#

안정적인 프롬프트 버전이 AI Gateway에 추가된 후에는 변경해서는 안 됩니다. 파일 이름에 pre-release 접미사를 추가하여(예: 1.0.1-dev.yml) 변경 가능한 버전을 생성할 수 있습니다. 이렇게 하면 클라이언트에 자동으로 제공되는 것도 방지됩니다. 그런 다음 기능 플래그를 사용하여 이 새 버전의 롤아웃을 제어할 수 있습니다. GitLab Duo Self-Hosted의 경우, 강제 버전은 무시되며 PromptVersions에 정의된 버전만 사용됩니다. 이를 통해 해당 버전이 지정되지 않은 모델에 실수로 버전을 활성화하는 것을 방지합니다.

AI 액션이 AiGateway::Completions::Base의 서브클래스로 구현된 경우, 서브클래스에서 프롬프트 버전을 재정의하여 이를 구현할 수 있습니다:

# ee/lib/gitlab/llm/ai_gateway/completions/rewrite_description.rb

module Gitlab
  module Llm
    module AiGateway
      module Completions
        class RewriteDescription < Base
          extend ::Gitlab::Utils::Override

          override :prompt_version
          def prompt_version
            '1.0.1-dev' if Feature.enabled?(:my_feature_flag) # You can also scope it to `user` or `resource`, as appropriate
          end

          # ...

이 버전을 안정적으로 만들고 호환 클라이언트에 자동 제공을 시작할 준비가 되면, YAML 정의 파일의 이름을 변경하여 pre-release 접미사를 제거하고 prompt_version 재정의를 삭제하면 됩니다.

기존 액션을 AI Gateway로 마이그레이션하는 방법#

AI 액션은 처음에 GitLab 모노리스 내부에 구현되었습니다. 모노리스가 모델에 접근하기 위한 유일한 접근점으로서의 AI Gateway 에픽의 일환으로, 프롬프트, 모델 선택 및 모델 파라미터를 AI Gateway로 마이그레이션하고 있습니다. 이를 통해 프롬프트 및 모델 변경을 모노리스 릴리스에서 분리하여 GitLab Self-Managed 사용자에게 개선 사항을 더 빠르게 제공할 수 있습니다. 기존 액션을 마이그레이션하려면:

  • 새로운 액션 구현 방법의 1~3단계를 따릅니다.

  • 카탈로그에서 AI 액션 항목을 수정하여 새 completion 클래스를 aigw_service_class로 나열합니다.

class AiFeaturesCatalogue
  LIST = {
    # ...
    generate_description: {
      service_class: ::Gitlab::Llm::Anthropic::Completions::GenerateDescription,
      aigw_service_class: ::Gitlab::Llm::AiGateway::Completions::GenerateDescription,
      prompt_class: ::Gitlab::Llm::Templates::GenerateDescription,
      feature_category: :ai_abstraction_layer,
      execute_method: ::Llm::GenerateDescriptionService,
      maturity: :experimental,
      self_managed: false,
      internal: false
    },
    # ...
  }.freeze
  • prompt_migration_#{feature_name} 기능 플래그를 생성합니다(예: prompt_migration_generate_description).

기능 플래그가 활성화되면 aigw_service_class가 AI 액션 처리에 사용됩니다. 액션의 올바른 동작을 검증한 후, aigw_service_class 키를 제거하고 service_class를 새 AiGateway::Completions 클래스로 교체하여 영구적인 제공업체로 만들 수 있습니다.

AI 액션 마이그레이션에 필요한 변경 사항의 전체 예시는 다음 머지 리퀘스트를 참조하세요:

GitLab-Rails에서의 인가#

기능에 대한 인가를 처리하기 위해 정책을 사용하는 것을 권장합니다. 현재 다음 검사를 반드시 포함해야 합니다:

일부 기본 인가는 더 전문화된 클래스의 기반 클래스인 Abstraction Layer 클래스에 포함되어 있습니다.

코드에 포함해야 하는 사항:

  • 기능 플래그 호환성 확인: Gitlab::Llm::Utils::FlagChecker.flag_enabled_for_feature?(ai_action) - Llm::BaseService 클래스에 포함됨.

  • 리소스 인가 확인: Gitlab::Llm::Utils::Authorizer.resource(resource: resource, user: user).allowed? - Llm::BaseService 클래스에도 포함됨.

  • 두 가지 확인 모두 ::Gitlab::Llm::FeatureAuthorizer.new(container: subject_container, feature_name: action_name).allowed?에 포함됨.

  • AI 기능에 대한 접근은 성숙도, self-managed에서의 활성화 여부, 애드온에 번들 포함 여부 등 여러 요소에 따라 달라집니다.

특정 리소스와 연결되지 않은 정책의 예시.

요청과 응답 매칭#

여러 사용자의 요청이 병렬로 처리될 수 있기 때문에, 응답을 받을 때 응답과 원래 요청을 매칭하기 어려울 수 있습니다. 요청과 응답 모두 동일한 requestId UUID를 가지도록 보장되므로, requestId 필드를 이 목적에 사용할 수 있습니다.

캐싱#

AI 요청과 응답은 캐시될 수 있습니다. 캐시된 대화는 AI 기능과의 사용자 상호작용을 표시하는 데 사용됩니다. 현재 구현에서는 이 캐시가 사용자가 요청을 반복할 때 AI 서비스에 대한 연속 호출을 건너뛰는 데 사용되지 않습니다.

query {
  aiMessages {
    nodes {
      id
      requestId
      content
      role
      errors
      timestamp
    }
  }
}

이 캐시는 채팅 기능에 사용됩니다. 다른 서비스의 경우 캐싱이 비활성화됩니다. cache_response: true 옵션을 사용하여 서비스에 대해 이를 활성화할 수 있습니다.

캐싱에는 다음과 같은 제한이 있습니다:

  • 메시지는 Redis 스트림에 저장됩니다.

  • 사용자당 단일 메시지 스트림이 있습니다. 즉, 현재 모든 서비스가 동일한 캐시를 공유합니다. 필요한 경우 사용자당 여러 스트림으로 확장할 수 있습니다(Redis가 예상되는 메시지 양을 처리할 수 있는지 인프라 팀에 확인 후).

  • 최근 50개의 메시지(요청 + 응답)만 유지됩니다.

  • 스트림의 만료 시간은 마지막 메시지 추가 후 3일입니다.

  • 사용자는 자신의 메시지에만 접근할 수 있습니다. 캐싱 레벨에서는 인가가 없으며, 현재 사용자가 아닌 사람이 접근하는 경우의 인가는 서비스 레이어에서 처리됩니다.

네임스페이스 설정에 따른 리소스 기능 허용 여부 확인#

루트 네임스페이스 레벨에서 AI 기능 사용을 제한하는 설정이 하나 있습니다:

  • experiment_features_enabled

특정 네임스페이스에 대해 해당 기능이 허용되는지 확인하려면 다음을 호출합니다:

Gitlab::Llm::StageCheck.available?(namespace, :name_of_the_feature)

Gitlab::Llm::StageCheck 클래스에 기능 이름을 추가합니다. 실험적 기능과 베타 기능을 구분하는 배열이 있습니다.

이 방식으로 다음과 같은 다양한 경우에 대비할 수 있습니다:

  • 기능이 어떤 배열에도 없으면 확인이 true를 반환합니다. 예를 들어, 기능이 일반적으로 사용 가능한 경우입니다.

기능을 실험 단계에서 베타 단계로 이동하려면 기능 이름을 EXPERIMENTAL_FEATURES 배열에서 BETA_FEATURES 배열로 이동합니다.

AI API 호출 및 프롬프트 구현#

CompletionWorkerCompletions::Factory를 호출하여 Service를 초기화하고 실제 API 호출을 실행합니다. 이 예시에서는 VertexAI를 사용하여 두 개의 새 클래스를 구현합니다:

# /ee/lib/gitlab/llm/vertex_ai/completions/rewrite_description.rb

module Gitlab
  module Llm
    module VertexAi
      module Completions
        class AmazingNewAiFeature < Gitlab::Llm::Completions::Base
          def execute
            prompt = ai_prompt_class.new(options[:user_input]).to_prompt

            response = Gitlab::Llm::VertexAi::Client.new(user, unit_primitive: 'amazing_feature').text(content: prompt)

            response_modifier = ::Gitlab::Llm::VertexAi::ResponseModifiers::Predictions.new(response)

            ::Gitlab::Llm::GraphqlSubscriptionResponseService.new(
              user, nil, response_modifier, options: response_options
            ).execute
          end
        end
      end
    end
  end
end
# /ee/lib/gitlab/llm/vertex_ai/templates/rewrite_description.rb

module Gitlab
  module Llm
    module VertexAi
      module Templates
        class AmazingNewAiFeature
          def initialize(user_input)
            @user_input = user_input
          end

          def to_prompt
            <<~PROMPT
            You are an assistant that writes code for the following context:

            context: #{user_input}
            PROMPT
          end
        end
      end
    end
  end
end

여러 AI 제공업체를 지원하므로, 동일한 예시에 다른 제공업체를 사용할 수도 있습니다:

Gitlab::Llm::VertexAi::Client.new(user, unit_primitive: 'your_feature')
Gitlab::Llm::Anthropic::Client.new(user, unit_primitive: 'your_feature')

부록 A: 프롬프트 버전 관리 규칙#

프롬프트 버전은 시맨틱 버전 관리(Semantic Versioning) 표준을 따라야 합니다: MAJOR.MINOR.PATCH[-PRERELEASE].

  • MAJOR 컴포넌트의 변경은 이전 버전의 GitLab과 호환되지 않는 변경을 반영합니다. 예를 들어, 새 프롬프트가 기본값이 없는 새 속성을 받아야 하는 경우, 이 변경이 모든 GitLab 버전에 적용되면 이전 버전의 요청에서 해당 속성이 없으므로 오류가 발생합니다.

  • MINOR 컴포넌트의 변경은 기능 추가를 반영하지만 여전히 하위 호환됩니다. 예를 들어, 더 강력한 새 모델을 사용하고자 하는 경우: 이전 버전 GitLab의 요청도 여전히 작동합니다.

  • PATCH 컴포넌트의 변경은 오타와 같은 프롬프트의 작은 버그 수정을 반영합니다.

MAJOR 컴포넌트는 코드베이스의 발전을 차단하지 않으면서, 새로운 변경이 추가될 때 이전 버전의 GitLab이 중단되지 않도록 보장합니다. MINOR 및 PATCH의 변경은 더 주관적입니다.

프롬프트 버전의 불변성#

변경 사항의 추적 가능성을 보장하기 위해, pre-release 버전(예: 1.0.1-dev.yml)을 가진 프롬프트만 커밋 후 변경될 수 있습니다. 안정적인 버전을 정의하는 프롬프트는 불변이며, 변경하면 파이프라인 실패가 발생합니다.

부분 템플릿(Partials) 사용#

프롬프트를 더 잘 구성하기 위해, 부분 템플릿을 사용하여 프롬프트를 더 작은 부분으로 분할할 수 있습니다. 부분 템플릿도 버전 관리를 해야 합니다. 예를 들어:

# ai_gateway/prompts/definitions/rewrite_description/base/1.0.0.yml

name: Description rewriter
model:
  config_file: conversation_performant
  params:
    model_class_provider: anthropic
prompt_template:
  system: |
    {% include 'rewrite_description/system/1.0.0.jinja' %}
  user: |
    {% include 'rewrite_description/user/1.0.0.jinja' %}

프롬프트 버전 해석#

AI Gateway는 인수로 전달된 프롬프트 버전 쿼리와 일치하는 사용 가능한 최신 안정 버전을 가져옵니다. 쿼리는 Poetry의 버전 제약 규칙을 따릅니다. 예를 들어, 프롬프트 foo/bar에 다음 버전이 있는 경우:

  • 1.0.1.yml

  • 1.1.0.yml

  • 1.5.0-dev.yml

  • 2.0.1.yml

/v1/prompts/foo/bar가 다음으로 호출되면:

  • {'prompt_version': "^1.0.0"} → 프롬프트 버전 1.1.0.yml이 선택됩니다.

  • {'prompt_version': "1.5.0-dev"} → 프롬프트 버전 1.5.0-dev.yml이 선택됩니다.

  • {'prompt_version': "^2.0.0"} → 프롬프트 버전 2.0.1.yml이 선택됩니다.

AI 액션

GitLab v19.1
원문 보기
요약

이 페이지에서는 액션을 구현하고 AI Gateway로 마이그레이션하는 방법을 설명합니다. 새로운 AI 액션을 구현하려면 여러 컴포넌트에 걸쳐 변경이 필요합니다. Cloud Connector 구성에는 서비스에 접근하는 데 필요한 권한과 추가 메타데이터가 저장됩니다.

이 페이지에서는 액션을 구현하고 AI Gateway로 마이그레이션하는 방법을 설명합니다.

새로운 액션 구현 방법#

새로운 AI 액션을 구현하려면 여러 컴포넌트에 걸쳐 변경이 필요합니다. 사용자가 주어진 프롬프트에 따라 이슈 설명을 다시 작성할 수 있도록 하는 액션을 구현하는 예시를 살펴보겠습니다.

1. Cloud Connector 기능 목록에 액션 추가#

Cloud Connector 구성에는 서비스에 접근하는 데 필요한 권한과 추가 메타데이터가 저장됩니다. 기능에 대한 항목이 없다면 Cloud Connector 단위 프리미티브로 기능을 추가하세요:

자세한 내용은 Cloud Connector: 구성을 참조하세요.

2. AI Gateway에서 프롬프트 정의 생성#

AI Gateway 프로젝트에서 ai_gateway/prompts/definitions 하위에 [ai-action]/base/[prompt-version].yml 경로로 새 프롬프트 정의를 생성합니다 (프롬프트 버전 관리 규칙 참조). 사용할 모델과 제공업체를 지정하고, 모델에 제공할 프롬프트를 작성합니다. {}를 사용하여 프롬프트에 입력값을 지정할 수 있습니다.

# ai_gateway/prompts/definitions/rewrite_description/base/1.0.0.yml

name: Description rewriter
model:
  config_file: conversation_performant
  params:
    model_class_provider: anthropic
prompt_template:
  system: |
    You are a helpful assistant that rewrites the description of resources. You'll be given the current description, and a prompt on how you should rewrite it. Reply only with your rewritten description.

    <description>{description}</description>

    <prompt>{prompt}</prompt>

AI 액션이 여러 프롬프트를 사용하는 경우, [ai-action]/[prompt-name]/base/[version].yaml 형식의 트리 구조로 정의를 구성할 수 있습니다:

# ai_gateway/prompts/definitions/code_suggestions/generations/base/1.0.0.yml

name: Code generations
model:
  config_file: conversation_performant
  params:
    model_class_provider: anthropic
...

여러 모델에 대한 프롬프트를 지정하려면 정의 경로에 모델 이름을 사용합니다:

# ai_gateway/prompts/definitions/code_suggestions/generations/mistral/1.0.0.yml

name: Code generations
model:
  name: mistral
  params:
    model_class_provider: litellm
...

3. Completion 클래스 생성#

  • ee/lib/gitlab/llm/ai_gateway/completions/ 하위에 새 completion을 생성하고 Base AI Gateway Completion에서 상속합니다.
# ee/lib/gitlab/llm/ai_gateway/completions/rewrite_description.rb

module Gitlab
  module Llm
    module AiGateway
      module Completions
        class RewriteDescription < Base
          extend ::Gitlab::Utils::Override

          override :inputs
          def inputs
            { description: resource.description, prompt: prompt_message.content }
          end
        end
      end
    end
  end
end

4. Service 생성#

  • ee/app/services/llm/ 하위에 새 서비스를 생성하고 BaseService에서 상속합니다.

  • resource는 작업을 수행할 객체입니다. Ai::Model concern을 포함하는 모든 객체가 될 수 있습니다. 예를 들어 Project, MergeRequest, Issue 등이 될 수 있습니다.

# ee/app/services/llm/rewrite_description_service.rb

module Llm
  class RewriteDescriptionService < BaseService
    extend ::Gitlab::Utils::Override

    override :valid
    def valid?
      super &&
        # You can restrict which type of resources your service applies to
        resource.to_ability_name == "issue" &&
        # Always check that the user is allowed to perform this action on the resource
        Ability.allowed?(user, :rewrite_description, resource)
    end

    private

    def perform
      schedule_completion_worker
    end
  end
end

5. 카탈로그에 기능 등록#

Gitlab::Llm::Utils::AiFeaturesCatalogue로 이동하여 AI 액션에 대한 새 항목을 추가합니다.

class AiFeaturesCatalogue
  LIST = {
    # ...
    rewrite_description: {
      service_class: ::Gitlab::Llm::AiGateway::Completions::RewriteDescription,
      feature_category: :ai_abstraction_layer,
      execute_method: ::Llm::RewriteDescriptionService,
      maturity: :experimental,
      self_managed: false,
      internal: false
    }
  }.freeze

6. 기본 프롬프트 버전 쿼리 추가#

Gitlab::Llm::PromptVersions로 이동하여 원하는 프롬프트 버전이 포함된 쿼리와 함께 AI 액션에 대한 항목을 추가합니다 (새로운 기능의 경우 보통 ^1.0.0이 됩니다. 프롬프트 버전 해석 참조):

class PromptVersions
  class << self
    VERSIONS = {
      # ...
      "rewrite_description/base": "^1.0.0"

AI 액션 업데이트#

AI 기능의 템플릿, 모델, 또는 파라미터를 변경하려면 AI Gateway에 새 YAML 버전 파일을 생성합니다:

# ai_gateway/prompts/definitions/rewrite_description/base/1.0.1.yml

name: Description rewriter with Claude 3.5
model:
  name: claude-3-5-sonnet-20240620
  params:
    model_class_provider: anthropic
prompt_template:
  system: |
    You are a helpful assistant that rewrites the description of resources. You'll be given the current description, and a prompt on how you should rewrite it. Reply only with your rewritten description.

    <description>{description}</description>

    <prompt>{prompt}</prompt>

프롬프트 버전의 점진적 롤아웃#

안정적인 프롬프트 버전이 AI Gateway에 추가된 후에는 변경해서는 안 됩니다. 파일 이름에 pre-release 접미사를 추가하여(예: 1.0.1-dev.yml) 변경 가능한 버전을 생성할 수 있습니다. 이렇게 하면 클라이언트에 자동으로 제공되는 것도 방지됩니다. 그런 다음 기능 플래그를 사용하여 이 새 버전의 롤아웃을 제어할 수 있습니다. GitLab Duo Self-Hosted의 경우, 강제 버전은 무시되며 PromptVersions에 정의된 버전만 사용됩니다. 이를 통해 해당 버전이 지정되지 않은 모델에 실수로 버전을 활성화하는 것을 방지합니다.

AI 액션이 AiGateway::Completions::Base의 서브클래스로 구현된 경우, 서브클래스에서 프롬프트 버전을 재정의하여 이를 구현할 수 있습니다:

# ee/lib/gitlab/llm/ai_gateway/completions/rewrite_description.rb

module Gitlab
  module Llm
    module AiGateway
      module Completions
        class RewriteDescription < Base
          extend ::Gitlab::Utils::Override

          override :prompt_version
          def prompt_version
            '1.0.1-dev' if Feature.enabled?(:my_feature_flag) # You can also scope it to `user` or `resource`, as appropriate
          end

          # ...

이 버전을 안정적으로 만들고 호환 클라이언트에 자동 제공을 시작할 준비가 되면, YAML 정의 파일의 이름을 변경하여 pre-release 접미사를 제거하고 prompt_version 재정의를 삭제하면 됩니다.

기존 액션을 AI Gateway로 마이그레이션하는 방법#

AI 액션은 처음에 GitLab 모노리스 내부에 구현되었습니다. 모노리스가 모델에 접근하기 위한 유일한 접근점으로서의 AI Gateway 에픽의 일환으로, 프롬프트, 모델 선택 및 모델 파라미터를 AI Gateway로 마이그레이션하고 있습니다. 이를 통해 프롬프트 및 모델 변경을 모노리스 릴리스에서 분리하여 GitLab Self-Managed 사용자에게 개선 사항을 더 빠르게 제공할 수 있습니다. 기존 액션을 마이그레이션하려면:

  • 새로운 액션 구현 방법의 1~3단계를 따릅니다.

  • 카탈로그에서 AI 액션 항목을 수정하여 새 completion 클래스를 aigw_service_class로 나열합니다.

class AiFeaturesCatalogue
  LIST = {
    # ...
    generate_description: {
      service_class: ::Gitlab::Llm::Anthropic::Completions::GenerateDescription,
      aigw_service_class: ::Gitlab::Llm::AiGateway::Completions::GenerateDescription,
      prompt_class: ::Gitlab::Llm::Templates::GenerateDescription,
      feature_category: :ai_abstraction_layer,
      execute_method: ::Llm::GenerateDescriptionService,
      maturity: :experimental,
      self_managed: false,
      internal: false
    },
    # ...
  }.freeze
  • prompt_migration_#{feature_name} 기능 플래그를 생성합니다(예: prompt_migration_generate_description).

기능 플래그가 활성화되면 aigw_service_class가 AI 액션 처리에 사용됩니다. 액션의 올바른 동작을 검증한 후, aigw_service_class 키를 제거하고 service_class를 새 AiGateway::Completions 클래스로 교체하여 영구적인 제공업체로 만들 수 있습니다.

AI 액션 마이그레이션에 필요한 변경 사항의 전체 예시는 다음 머지 리퀘스트를 참조하세요:

GitLab-Rails에서의 인가#

기능에 대한 인가를 처리하기 위해 정책을 사용하는 것을 권장합니다. 현재 다음 검사를 반드시 포함해야 합니다:

일부 기본 인가는 더 전문화된 클래스의 기반 클래스인 Abstraction Layer 클래스에 포함되어 있습니다.

코드에 포함해야 하는 사항:

  • 기능 플래그 호환성 확인: Gitlab::Llm::Utils::FlagChecker.flag_enabled_for_feature?(ai_action) - Llm::BaseService 클래스에 포함됨.

  • 리소스 인가 확인: Gitlab::Llm::Utils::Authorizer.resource(resource: resource, user: user).allowed? - Llm::BaseService 클래스에도 포함됨.

  • 두 가지 확인 모두 ::Gitlab::Llm::FeatureAuthorizer.new(container: subject_container, feature_name: action_name).allowed?에 포함됨.

  • AI 기능에 대한 접근은 성숙도, self-managed에서의 활성화 여부, 애드온에 번들 포함 여부 등 여러 요소에 따라 달라집니다.

특정 리소스와 연결되지 않은 정책의 예시.

요청과 응답 매칭#

여러 사용자의 요청이 병렬로 처리될 수 있기 때문에, 응답을 받을 때 응답과 원래 요청을 매칭하기 어려울 수 있습니다. 요청과 응답 모두 동일한 requestId UUID를 가지도록 보장되므로, requestId 필드를 이 목적에 사용할 수 있습니다.

캐싱#

AI 요청과 응답은 캐시될 수 있습니다. 캐시된 대화는 AI 기능과의 사용자 상호작용을 표시하는 데 사용됩니다. 현재 구현에서는 이 캐시가 사용자가 요청을 반복할 때 AI 서비스에 대한 연속 호출을 건너뛰는 데 사용되지 않습니다.

query {
  aiMessages {
    nodes {
      id
      requestId
      content
      role
      errors
      timestamp
    }
  }
}

이 캐시는 채팅 기능에 사용됩니다. 다른 서비스의 경우 캐싱이 비활성화됩니다. cache_response: true 옵션을 사용하여 서비스에 대해 이를 활성화할 수 있습니다.

캐싱에는 다음과 같은 제한이 있습니다:

  • 메시지는 Redis 스트림에 저장됩니다.

  • 사용자당 단일 메시지 스트림이 있습니다. 즉, 현재 모든 서비스가 동일한 캐시를 공유합니다. 필요한 경우 사용자당 여러 스트림으로 확장할 수 있습니다(Redis가 예상되는 메시지 양을 처리할 수 있는지 인프라 팀에 확인 후).

  • 최근 50개의 메시지(요청 + 응답)만 유지됩니다.

  • 스트림의 만료 시간은 마지막 메시지 추가 후 3일입니다.

  • 사용자는 자신의 메시지에만 접근할 수 있습니다. 캐싱 레벨에서는 인가가 없으며, 현재 사용자가 아닌 사람이 접근하는 경우의 인가는 서비스 레이어에서 처리됩니다.

네임스페이스 설정에 따른 리소스 기능 허용 여부 확인#

루트 네임스페이스 레벨에서 AI 기능 사용을 제한하는 설정이 하나 있습니다:

  • experiment_features_enabled

특정 네임스페이스에 대해 해당 기능이 허용되는지 확인하려면 다음을 호출합니다:

Gitlab::Llm::StageCheck.available?(namespace, :name_of_the_feature)

Gitlab::Llm::StageCheck 클래스에 기능 이름을 추가합니다. 실험적 기능과 베타 기능을 구분하는 배열이 있습니다.

이 방식으로 다음과 같은 다양한 경우에 대비할 수 있습니다:

  • 기능이 어떤 배열에도 없으면 확인이 true를 반환합니다. 예를 들어, 기능이 일반적으로 사용 가능한 경우입니다.

기능을 실험 단계에서 베타 단계로 이동하려면 기능 이름을 EXPERIMENTAL_FEATURES 배열에서 BETA_FEATURES 배열로 이동합니다.

AI API 호출 및 프롬프트 구현#

CompletionWorkerCompletions::Factory를 호출하여 Service를 초기화하고 실제 API 호출을 실행합니다. 이 예시에서는 VertexAI를 사용하여 두 개의 새 클래스를 구현합니다:

# /ee/lib/gitlab/llm/vertex_ai/completions/rewrite_description.rb

module Gitlab
  module Llm
    module VertexAi
      module Completions
        class AmazingNewAiFeature < Gitlab::Llm::Completions::Base
          def execute
            prompt = ai_prompt_class.new(options[:user_input]).to_prompt

            response = Gitlab::Llm::VertexAi::Client.new(user, unit_primitive: 'amazing_feature').text(content: prompt)

            response_modifier = ::Gitlab::Llm::VertexAi::ResponseModifiers::Predictions.new(response)

            ::Gitlab::Llm::GraphqlSubscriptionResponseService.new(
              user, nil, response_modifier, options: response_options
            ).execute
          end
        end
      end
    end
  end
end
# /ee/lib/gitlab/llm/vertex_ai/templates/rewrite_description.rb

module Gitlab
  module Llm
    module VertexAi
      module Templates
        class AmazingNewAiFeature
          def initialize(user_input)
            @user_input = user_input
          end

          def to_prompt
            <<~PROMPT
            You are an assistant that writes code for the following context:

            context: #{user_input}
            PROMPT
          end
        end
      end
    end
  end
end

여러 AI 제공업체를 지원하므로, 동일한 예시에 다른 제공업체를 사용할 수도 있습니다:

Gitlab::Llm::VertexAi::Client.new(user, unit_primitive: 'your_feature')
Gitlab::Llm::Anthropic::Client.new(user, unit_primitive: 'your_feature')

부록 A: 프롬프트 버전 관리 규칙#

프롬프트 버전은 시맨틱 버전 관리(Semantic Versioning) 표준을 따라야 합니다: MAJOR.MINOR.PATCH[-PRERELEASE].

  • MAJOR 컴포넌트의 변경은 이전 버전의 GitLab과 호환되지 않는 변경을 반영합니다. 예를 들어, 새 프롬프트가 기본값이 없는 새 속성을 받아야 하는 경우, 이 변경이 모든 GitLab 버전에 적용되면 이전 버전의 요청에서 해당 속성이 없으므로 오류가 발생합니다.

  • MINOR 컴포넌트의 변경은 기능 추가를 반영하지만 여전히 하위 호환됩니다. 예를 들어, 더 강력한 새 모델을 사용하고자 하는 경우: 이전 버전 GitLab의 요청도 여전히 작동합니다.

  • PATCH 컴포넌트의 변경은 오타와 같은 프롬프트의 작은 버그 수정을 반영합니다.

MAJOR 컴포넌트는 코드베이스의 발전을 차단하지 않으면서, 새로운 변경이 추가될 때 이전 버전의 GitLab이 중단되지 않도록 보장합니다. MINOR 및 PATCH의 변경은 더 주관적입니다.

프롬프트 버전의 불변성#

변경 사항의 추적 가능성을 보장하기 위해, pre-release 버전(예: 1.0.1-dev.yml)을 가진 프롬프트만 커밋 후 변경될 수 있습니다. 안정적인 버전을 정의하는 프롬프트는 불변이며, 변경하면 파이프라인 실패가 발생합니다.

부분 템플릿(Partials) 사용#

프롬프트를 더 잘 구성하기 위해, 부분 템플릿을 사용하여 프롬프트를 더 작은 부분으로 분할할 수 있습니다. 부분 템플릿도 버전 관리를 해야 합니다. 예를 들어:

# ai_gateway/prompts/definitions/rewrite_description/base/1.0.0.yml

name: Description rewriter
model:
  config_file: conversation_performant
  params:
    model_class_provider: anthropic
prompt_template:
  system: |
    {% include 'rewrite_description/system/1.0.0.jinja' %}
  user: |
    {% include 'rewrite_description/user/1.0.0.jinja' %}

프롬프트 버전 해석#

AI Gateway는 인수로 전달된 프롬프트 버전 쿼리와 일치하는 사용 가능한 최신 안정 버전을 가져옵니다. 쿼리는 Poetry의 버전 제약 규칙을 따릅니다. 예를 들어, 프롬프트 foo/bar에 다음 버전이 있는 경우:

  • 1.0.1.yml

  • 1.1.0.yml

  • 1.5.0-dev.yml

  • 2.0.1.yml

/v1/prompts/foo/bar가 다음으로 호출되면:

  • {'prompt_version': "^1.0.0"} → 프롬프트 버전 1.1.0.yml이 선택됩니다.

  • {'prompt_version': "1.5.0-dev"} → 프롬프트 버전 1.5.0-dev.yml이 선택됩니다.

  • {'prompt_version': "^2.0.0"} → 프롬프트 버전 2.0.1.yml이 선택됩니다.