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을 생성하고BaseAI 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::Modelconcern을 포함하는 모든 객체가 될 수 있습니다. 예를 들어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에서의 활성화 여부, 애드온에 번들 포함 여부 등 여러 요소에 따라 달라집니다.
특정 리소스와 연결되지 않은 정책의 예시.
-
특정 리소스와 연결된 정책의 예시.
AI Gateway의 인증 및 인가에 대한 자세한 내용은 GitLab AI Gateway 문서를 참조하세요.
GitLab Duo 기능에 자율 에이전트가 포함된 경우, 복합 ID(composite identity) 인가를 사용해야 합니다.
요청과 응답 매칭#
여러 사용자의 요청이 병렬로 처리될 수 있기 때문에, 응답을 받을 때 응답과 원래 요청을 매칭하기 어려울 수 있습니다. 요청과 응답 모두 동일한 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 호출 및 프롬프트 구현#
CompletionWorker는 Completions::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이 선택됩니다.