InfoGrab DocsInfoGrab Docs

GitLab Duo Chat

요약

GitLab Duo Chat는 소프트웨어 개발 생명주기(Software Development Lifecycle, SDLC) 전반에서 사용자가 아이디어를 구상하고 만들어내는 작업뿐 아니라 학습하는 작업도 AI로 지원하여, 더 빠르고 효율적으로 만드는 것을 목표로 합니다.

GitLab Duo Chat는 소프트웨어 개발 생명주기(Software Development Lifecycle, SDLC) 전반에서 사용자가 아이디어를 구상하고 만들어내는 작업뿐 아니라 학습하는 작업도 AI로 지원하여, 더 빠르고 효율적으로 만드는 것을 목표로 합니다.

Chat는 GitLab Duo 제품군의 일부입니다.

Chat는 다양한 질문에 답하고 특정 작업을 수행할 수 있습니다. 이는 프롬프트와 도구의 도움으로 이루어집니다.

Chat 인터페이스에서 사용자가 한 질문에 답하기 위해, GitLab은 GraphQL 요청을 Rails 백엔드로 보냅니다. 그러면 Rails 백엔드는 AI Gateway를 통해 거대 언어 모델(Large Language Model, LLM)에 지시를 전달합니다.

Chat 기여에 가장 적합한 사용 사례#

거대 언어 모델(LLM) 기반 AI와 사용자 간의 대화형 상호작용으로 이점을 얻을 수 있는 모든 사용 사례와 워크플로에 Chat를 적용하는 것을 목표로 합니다. 대표적으로 다음과 같습니다:

  • 한 번의 상호작용보다 반복을 통해 더 효과적이고 효율적으로 해결되는 창작·아이디어 구상 작업 및 학습 작업.
  • 보통 한 번의 상호작용으로 충족되지만 다듬어야 할 수도 있고 대화로 이어질 수도 있는 작업.
  • 후자 중에는 AI가 처음부터 정확히 맞추지 못할 수 있지만 사용자가 필요한 것을 더 정확히 말해줌으로써 쉽게 방향을 바로잡을 수 있는 작업이 있습니다. 예를 들어 "이 코드를 설명해 줘"는 대부분 만족스러운 답을 얻는 흔한 질문이지만, 때로는 사용자가 추가 질문을 할 수도 있습니다.
  • 대화 기록에서 이점을 얻는 작업으로, 사용자와 AI 모두 같은 말을 반복할 필요가 없습니다.

Chat는 컨텍스트를 인식하고, 궁극적으로는 사용자가 접근 권한을 가진 GitLab의 모든 리소스에 접근하는 것을 목표로 합니다. 처음에는 이 컨텍스트가 개별 이슈와 에픽의 내용, GitLab 문서로 한정되어 있었습니다. 이후 코드 선택 영역과 코드 파일 같은 추가 컨텍스트가 더해졌습니다. 현재는 사용자가 이런 컨텍스트에 대해 질문할 수 있도록 취약점 컨텍스트와 파이프라인 job 컨텍스트를 추가하는 작업이 진행 중입니다.

컨텍스트 인식 범위를 넓혀 DevSecOps 전체 영역에서 창작·아이디어 구상·학습 사용 사례를 확장하기 위해, GitLab Duo Chat 팀은 다른 GitLab 팀과 더 넓은 커뮤니티가 Chat 플랫폼에 기여하는 것을 환영합니다. 이들은 가속화하려는 사용 사례와 워크플로의 전문가입니다.

독립형 AI 기능으로 구현하는 것이 더 적합한 사용 사례#

독립형 AI 기능으로, 또는 최소한 독립형 AI 기능으로도 구현하는 것이 더 적합한 사용 사례는 다음과 같습니다.

  • 기존 워크플로에 AI를 깊이 통합함으로써 가속화할 수 있는 범위가 좁은 작업.
  • AI와의 대화에서 이점을 얻을 수 없는 작업.

이를 더 구체적으로 보여주는 예시가 있습니다.

변경 사항을 바탕으로 커밋 메시지를 생성하는 것은 커밋 메시지 작성 워크플로에 구현하는 것이 가장 좋습니다.

  • AI가 없으면 커밋 메시지 작성에 10초 정도 걸릴 수 있습니다.
  • IDE의 Commit message 필드에 AI가 생성한 커밋 메시지를 자동으로 채우면 이 작업이 1초로 줄어듭니다.

커밋 메시지 작성에 Chat를 사용하면 직접 작성하는 것보다 시간이 더 걸릴 가능성이 큽니다. 사용자는 Chat 창으로 전환해 요청을 입력한 뒤 결과를 커밋 메시지 필드에 복사해야 합니다.

다만 이것이 Chat가 커밋 메시지를 작성할 수 없다는 뜻은 아니며, 그렇게 하지 못하도록 막혀 있는 것도 아닙니다. Chat가 커밋 컨텍스트를 가지고 있다면(커밋 메시지 작성이 아닌 다른 이유로 언젠가 추가될 수 있습니다), 사용자는 커밋 메시지 작성을 포함해 이 커밋 콘텐츠로 원하는 무엇이든 요청할 수 있습니다. 하지만 시간만 낭비하게 되므로 사용자가 실제로 Chat로 그렇게 할 가능성은 낮습니다. 참고: 사용자가 작성한 프롬프트로 Chat에서 만든 커밋 메시지와, 전용으로 만들어진 커밋 메시지 생성 기능 뒤의 고정된 프롬프트로 만든 커밋 메시지는 결과가 다를 수 있습니다.

GitLab Duo Chat 설정#

GitLab Duo Chat를 로컬에서 설정하려면 AI 기능 일반 설정 안내를 따릅니다.

GitLab Duo Chat 작업#

프롬프트는 GitLab Duo Chat 시스템에서 가장 중요한 부분입니다. 프롬프트는 특정 작업을 수행하도록 LLM에 전달하는 지시입니다.

현재 프롬프트 상태는 몇 주에 걸친 반복 작업의 결과입니다. 현재 도구의 프롬프트를 변경하려면 반드시 기능 플래그 뒤에 두어야 합니다.

새 프롬프트나 업데이트한 프롬프트가 있으면 GitLab Duo Chat 팀 구성원에게 검토를 요청합니다. 이들은 프롬프트에 대한 경험이 풍부합니다.

문제 해결#

Chat를 로컬에서 다룰 때 오류가 발생할 수 있습니다. 가장 흔한 문제는 이 절에 문서화되어 있습니다. 문서화되지 않은 문제를 발견하면, 해결 방법을 찾은 뒤 이 절에 문서화해야 합니다.

문제 해결 방법
GitLab UI에 Chat 버튼이 없습니다. 사용자가 Premium 또는 Ultimate 라이선스를 보유하고 Chat이 활성화된 그룹에 속해 있는지 확인합니다.
Chat가 "Forbidden by auth provider" 오류로 응답합니다. 백엔드가 LLM에 접근할 수 없는 상태입니다. AI Gateway가 올바르게 설정되어 있는지 확인합니다.
요청이 UI에 나타나는 데 너무 오래 걸립니다 gdk restart rails-background-jobs를 실행해 Sidekiq을 재시작하는 것을 고려합니다. 그래도 안 되면 gdk kill 후 gdk start를 시도합니다. 또는 Sidekiq을 완전히 건너뛸 수도 있습니다. 이를 위해 Llm::CompletionWorker.perform_async 문을 임시로 Llm::CompletionWorker.perform_inline으로 바꿉니다
GDK가 non-SaaS 모드로 실행 중일 때 GitLab UI에 Chat 버튼이 없습니다 cloud connector 액세스 토큰 레코드가 없거나 시트가 할당되지 않은 상태입니다. cloud connector 액세스 레코드를 만들려면 rails console에서 다음 코드를 입력합니다: FactoryBot.create(:cloud_connector_access).

문제 해결에 도움이 되도록 Chat가 보내는 오류 코드에 대한 자세한 내용은 GitLab Duo Chat 오류 코드 해석을 참고합니다.

GitLab Duo Chat에 기여하기#

코드 관점에서 Chat는 다른 AI 기능과 비슷한 방식으로 구현되어 있습니다. GitLab의 AI 추상화 계층에 대해 더 알아봅니다.

Chat 기능은 사용자 질문과 관련 컨텍스트를 AI Gateway로 보내는 zero-shot 에이전트를 사용합니다. AI Gateway는 프롬프트를 구성해 거대 언어 모델에 요청을 보냅니다.

거대 언어 모델은 직접 답할 수 있는지, 아니면 정의된 도구 중 하나를 사용해야 하는지를 판단합니다.

각 도구는 정보를 수집하기 위해 그 도구를 어떻게 사용할지 거대 언어 모델에 지시를 제공하는 자체 프롬프트를 가지고 있습니다. 도구는 자체적으로 완결되도록 설계되어, 거대 언어 모델과 여러 번 요청을 주고받는 것을 피합니다.

도구가 필요한 정보를 수집하면 zero-shot 에이전트로 반환되고, 에이전트는 사용자 질문에 최종 답을 제공할 만큼 충분한 정보가 수집되었는지 거대 언어 모델에 묻습니다.

새 도구 추가#

새 도구를 추가하려면 AI Gateway와 Rails Monolith 양쪽 모두 변경해야 합니다. 메인 chat 프롬프트는 AI Gateway에 저장되고 조립됩니다. Rails 쪽은 프롬프트에 필요한 파라미터를 조립해 AI Gateway로 보내는 역할을 합니다. AI Gateway는 Chat 프롬프트를 조립하고 구독과 add-on에 따라 사용자가 사용할 수 있는 Chat 도구를 선택하는 역할을 합니다.

LLM이 사용할 도구를 선택하면 이 도구는 Rails 쪽에서 실행됩니다. 도구는 AI Gateway에 요청을 보낼 때 서로 다른 엔드포인트를 사용합니다. 새 도구를 추가할 때는 AI Gateway가 버전이 다른 여러 클라이언트와 GitLab 애플리케이션과 함께 동작한다는 점을 고려해야 합니다. 즉 오래된 GitLab 버전은 새 도구를 알지 못합니다. 새 도구를 추가하려면 GitLab Duo Chat 팀에 문의합니다. 이 문제에 대한 장기적인 해결책을 마련하는 중입니다.

AI Gateway에서의 변경#

  1. ai_gateway/chat/tools/gitlab.py에 도구용 새 클래스를 만듭니다. 이 클래스는 다음 속성을 포함해야 합니다:

    • 도구의 name
    • 도구가 작업하는 GitLab resource
    • 도구가 하는 일에 대한 description
    • 질문과 원하는 답변의 example
  2. ai_gateway/chat/tools/gitlab.py의 __all__ 도구 목록에 도구를 추가합니다.

  3. ai_gateway/chat/toolset.py의 DuoChatToolsRegistry에 적절한 Unit Primitive와 함께 도구 클래스를 추가합니다.

  4. 변경 사항에 대한 테스트를 추가합니다.

Rails Monolith에서의 변경#

  1. ee/lib/gitlab/llm/chain/tools/ 폴더에 도구용 파일을 만듭니다. issue_reader나 epic_reader 같은 기존 도구를 템플릿으로 사용합니다.
  2. 정보를 수집하기 위해 도구를 어떻게 사용할지 거대 언어 모델에 지시하는 클래스를 작성합니다
    • 이 도구가 사용하는 메인 프롬프트입니다.
  3. 거대 언어 모델의 응답을 파싱해 chat 에이전트로 반환하는 코드를 도구에 구현합니다.
  4. 에이전트가 알 수 있도록 ee/lib/gitlab/llm/completions/chat.rb의 tools 배열에 새 도구 이름을 추가합니다.

전체 테스트#

거대 언어 모델에 실제 요청을 보내는 RSpec 테스트를 사용해 프롬프트를 테스트하고 반복 개선합니다.

  • 프롬프트는 시행착오가 필요하며, LLM 작업의 비결정적인 특성은 예상치 못한 결과를 낼 수 있습니다.
  • Anthropic은 프롬프트 작업에 대한 좋은 가이드를 제공합니다.
  • 프롬프트 작업에 대한 GitLab 가이드.

핵심은 프롬프트와 도구 설명을 통해 거대 언어 모델에 올바르게 지시하고, 도구가 자체적으로 완결되도록 유지하며, zero-shot 에이전트에 응답을 반환하는 것입니다. 프롬프트에 약간의 시행착오를 거치면 새 도구를 추가해 Chat 기능의 역량을 확장할 수 있습니다.

이 주제를 다루는 짧은 영상이 있습니다.

다중 스레드 대화 다루기#

GitLab Duo Chat 대화와 상호작용하는 기능을 만든다면 스레드가 어떻게 동작하는지 이해해야 합니다.

GitLab Duo Chat는 여러 대화를 지원합니다. 각 대화는 스레드로 표현되며, 스레드는 여러 메시지를 포함합니다. 스레드의 주요 속성은 다음과 같습니다:

  • id: 스레드에 답장할 때 id가 필요합니다.
  • conversation_type: 사용 가능한 여러 GitLab Duo Chat 대화 유형을 구분합니다. 스레드 대화 유형 목록을 참고합니다.
    • 기능에 별도의 대화 유형이 필요하면 GitLab Duo Chat 팀에 문의합니다.

GraphQL API를 직접 호출해야 하는 기능이라면 다음 쿼리와 뮤테이션을 사용할 수 있으며, 이때 conversation_type을 지정해야 합니다.

  • Query.aiConversationThreads: 스레드 목록을 조회합니다
  • Query.aiMessages: 한 스레드의 메시지 목록을 조회합니다. threadId를 지정해야 합니다.
  • Mutation.aiAction: 메시지 하나를 생성합니다. threadId를 지정하면 해당 스레드에 메시지가 추가됩니다.

모든 chat 대화에는 관리자가 제어하는 보관 기간이 있습니다. 기본 보관 기간은 마지막 답변 후 30일입니다.

개발자 리소스#

디버깅#

전체 요청에 대해 더 많은 정보를 얻으려면 Gitlab::Llm::Logger 파일을 사용해 로그를 디버깅합니다. 프로덕션의 기본 로깅 레벨은 INFO이며, 개인 식별 정보가 포함될 수 있는 데이터는 로그에 남기지 않아야 합니다.

추상화 계층에서 AI 요청과 관련된 디버깅 메시지를 확인하려면 다음을 사용할 수 있습니다:

export LLM_DEBUG=1
gdk start
tail -f log/llm.log

프로덕션 환경에서 디버깅#

프로덕션 환경에서 디버깅과 문제 해결에 관련된 모든 정보는 GitLab Duo Chat On-Call 런북에 모여 있습니다.

LangSmith로 트레이싱#

트레이싱은 LLM 애플리케이션의 동작을 이해하는 데 강력한 도구입니다. LangSmith는 업계 최고 수준의 트레이싱 기능을 갖추고 있으며 GitLab Duo Chat와 통합되어 있습니다. 트레이싱은 다음과 같은 문제를 추적하는 데 도움이 됩니다:

  • GitLab Duo Chat를 처음 접하고 내부에서 어떤 일이 일어나는지 알고 싶은 경우.
  • 예상치 못한 답변을 받았을 때 프로세스가 정확히 어디서 실패했는지.
  • 어떤 프로세스가 지연 시간의 병목이었는지.
  • 모호한 질문에 어떤 도구가 사용되었는지.

LangSmith UI

트레이싱은 대규모 데이터셋으로 GitLab Duo Chat를 실행하는 평가에 특히 유용합니다. LangSmith 통합은 GitLab 중앙 평가 프레임워크(CEF)를 비롯한 모든 도구와 함께 동작합니다.

LangSmith로 트레이싱 사용#

Note

트레이싱은 Development, Testing 환경에서만 사용할 수 있습니다. Production 환경에서는 사용할 수 없습니다.

  1. LangSmith에 접속해 계정을 만듭니다

    1. Lumos를 통해 액세스를 요청합니다
    2. Editor 역할에 대해 액세스 요청을 생성합니다(템플릿 LangSmith_Access_Request)
  2. API 키를 생성합니다(API 키를 어디에 만드는지 주의합니다 - 개인 네임스페이스나 GL 네임스페이스에 만들 수 있습니다).

  3. GDK에서 다음 환경 변수를 설정합니다.

    gdk.yml에서 정의할 수 있습니다:

    # on your gdk.yml
    env:
      LANGCHAIN_TRACING_V2: 'true'
      LANGCHAIN_API_KEY: '<your-api-key>'
      LANGCHAIN_PROJECT: '<your-project-name>'
      LANGCHAIN_ENDPOINT: 'https://api.smith.langchain.com'
      GITLAB_RAILS_RACK_TIMEOUT: '180' # Extending puma timeout for using LangSmith with CEF as the evaluation tool.
    

    또는 터미널에서 직접 export합니다:

    export LANGCHAIN_TRACING_V2=true
    export LANGCHAIN_API_KEY='<your-api-key>'
    export LANGCHAIN_PROJECT='<your-project-name>'
    export LANGCHAIN_ENDPOINT='https://api.smith.langchain.com'
    export GITLAB_RAILS_RACK_TIMEOUT=180 # Extending puma timeout for using LangSmith with CEF as the evaluation tool.
    

    프로젝트 이름은 LangSmith에 있는 기존 프로젝트이거나 새 프로젝트일 수 있습니다. 환경 변수에 새 이름을 넣기만 하면 요청 중에 프로젝트가 생성됩니다.

  4. GDK를 재시작합니다.

  5. Chat에 아무 질문이나 합니다.

  6. LangSmith 페이지 > Projects > [Project name]에서 프로젝트를 확인합니다. 'Runs' 탭에 최근 요청이 표시되어야 합니다.

LangSmith 트레이스 공유(내부 팀원용)#

웹 브라우저에서 URL 전체를 복사해 팀원과 트레이스 URL을 직접 공유할 수 있습니다. LangSmith UI에 있는 "share" 트레이스 기능보다 이 방법을 사용하는 것이 좋습니다. 트레이스를 공개로 공유하면 OKTA를 통한 LangSmith 액세스 권한이 없는 사람도 링크만 있으면 접근할 수 있게 됩니다. 트레이스에는 CI 토큰과 같은 민감한 정보가 담겨 있습니다.

클릭 한 번으로 머지 리퀘스트 평가#

CEF로 머지 리퀘스트를 평가하려면 Evaluation Runner(내부용)를 사용할 수 있습니다. 머지 리퀘스트에서 평가 실행하기 안내를 따릅니다.

머지 리퀘스트에서 회귀 방지#

GitLab Duo Chat나 관련 컴포넌트를 변경할 때는 머지 리퀘스트의 품질 저하와 버그를 탐지하기 위해 회귀 평가기를 실행해야 합니다. 여기에는 도구 실행과 슬래시 명령을 포함한 모든 GitLab Duo Chat 실행 패턴이 포함됩니다.

회귀 평가기를 실행하려면 머지 리퀘스트에서 평가를 실행하고 회귀 평가기의 재생 버튼을 클릭합니다. 이후 머지 리퀘스트의 평가 결과를 master와 비교할 수 있습니다. LangSmith의 비교 페이지에서 품질 저하와 버그가 없는지 확인합니다.

비교 결과를 해석하는 엄격한 가이드라인은 없지만, 참고할 만한 유용한 팁이 있습니다:

  • 저하된 점수의 수가 개선된 점수의 수보다 많다면, 머지 리퀘스트가 품질 저하를 유발했을 수 있습니다.
  • 평가 중 오류가 발생한 예시가 있다면, 머지 리퀘스트에 잠재적인 버그가 있을 수 있습니다.

이런 상황이 발생하면 추가 조사를 권장합니다:

  1. 결과를 일일 평가 결과와 비교합니다. 예를 들어 어제와 그 전날의 일일 평가를 확인합니다.
  2. 이 일일 평가에서 비슷한 패턴이 보인다면 머지 리퀘스트를 안전하게 머지할 수 있을 가능성이 큽니다. 반면 패턴이 다르다면 머지 리퀘스트가 예상치 못한 변경을 유발했을 수 있습니다.

다음 환경에서는 회귀 평가기를 반드시 실행하는 것을 강력히 권장합니다:

환경 평가 파이프라인 이름
GitLab Self-Managed와 널리 채택된 커스텀 모델 duo-chat regression sm: [bedrock_mistral_8x7b_instruct]
GitLab.com과 GitLab Duo Enterprise add-on duo-chat regression .com: [duo_enterprise]
GitLab.com과 GitLab Duo Pro add-on duo-chat regression .com: [duo_pro]

이 외에도 특정 범위에 대해 더 포괄적인 데이터셋을 가진 gitlab-docs 같은 다른 평가기를 실행할 수 있습니다. 자세한 내용은 사용 가능한 평가 파이프라인을 참고합니다.

회귀 데이터셋에 예시 추가#

새 기능을 도입했거나 사용자로부터 회귀 보고를 받았다면, 커버리지를 넓히기 위해 회귀 데이터셋에 새 예시를 추가해야 합니다. 회귀 데이터셋에 예시를 추가하려면 이 절을 따릅니다.

자세한 내용은 회귀 평가기 가이드라인을 참고합니다.

GitLab Duo Chat Self-managed 엔드투엔드 테스트#

MR에서는 엔드투엔드 테스트가 latest 버전의 AI Gateway와 통합된 GitLab Linux 패키지 인스턴스를 사용해 GitLab Self-Managed 인스턴스의 GitLab Duo Chat 기능을 테스트합니다. AI Gateway 인스턴스는 모의 응답을 반환하도록 설정되어 있습니다. 이 테스트의 결과를 보려면 e2e:test-on-omnibus-ee 하위 파이프라인을 열어 ai-gateway job을 확인합니다.

ai-gateway job은 테스트를 실행하기 전에 클라우드 라이선스를 활성화하고 테스트 사용자에게 GitLab Duo Pro 시트를 할당합니다.

자세한 내용은 AiGateway 시나리오를 참고합니다.

클라이언트 측 관측 가능성#

Duo Agentic Chat는 모니터링과 트리아지를 지원하기 위해 클라이언트 측 오류를 Sentry에 보고합니다.

Sentry 오류 캡처#

Sentry를 직접 호출하는 대신 ee/app/assets/javascripts/ai/duo_agentic_chat/observability/sentry_utils.js의 captureExceptionForDuoChat 래퍼를 사용합니다. 이 래퍼는 모든 예외에 feature_category: 'duo_chat' 태그를 자동으로 추가합니다. 호출자는 추가 태그를 붙일 수 있지만 feature_category는 재정의할 수 없습니다.

import { captureExceptionForDuoChat } from '../observability/sentry_utils';

// Report an error with no extra context.
captureExceptionForDuoChat(new Error('Something went wrong'));

// Report an error with extra metadata.
captureExceptionForDuoChat(error, { extra: { info, component: 'MyComponent' } });

프론트엔드에서 Duo Chat 통합#

두 개의 공유 Vue 컴포넌트 중 하나를 사용해 기능에 Duo Chat 통합을 추가할 수 있습니다. 두 컴포넌트 모두 현재 사용자가 Duo Chat을 사용할 수 있는지 확인하며, 사용할 수 없으면 아무것도 렌더링하지 않습니다.

  • DuoChatQuickAction(ee/app/assets/javascripts/ai/shared/widgets/duo_chat_quick_action.vue): Duo Chat을 열고 프롬프트를 보내는 버튼을 렌더링합니다. 페이지에서 댓글 요약이나 리소스 설명처럼 특정 Duo Chat 작업을 실행하고 싶을 때 사용합니다.
  • OpenAgenticChatButton(ee/app/assets/javascripts/ai/shared/widgets/open_agentic_chat_button.vue): 특정 에이전트가 미리 선택된 상태로 Duo Chat을 열되, 프롬프트는 자동으로 보내지 않는 버튼을 렌더링합니다. 커스텀 에이전트와 하나 이상의 프롬프트 제안과 함께 Duo Chat을 열고 싶을 때 사용합니다.

미리 정의된 프롬프트로 Duo Chat 열기(DuoChatQuickAction)#

DuoChatQuickAction을 사용해 Duo Chat을 열고 미리 정의된 프롬프트를 보내는 버튼을 추가합니다. 이 컴포넌트는 사용자의 현재 chat 모드 (Classic 또는 Agentic)를 존중해 각 모드에 맞는 프롬프트를 보냅니다.

이 컴포넌트는 ee/app/assets/javascripts/ai/shared/widgets/duo_chat_quick_action.vue에 있습니다.

속성#

속성 타입 필수 여부 설명
buttonText String 예 버튼에 표시되는 레이블입니다.
resourceId String 예 리소스의 GraphQL 전역 ID입니다(예: gid://gitlab/Issue/1). Duo Chat에 관련 객체의 컨텍스트를 제공하는 데 사용합니다.
trackingInfo Object 예 트래킹 메타데이터입니다. 최소 두 단어로 된 snake_case label 키를 포함해야 합니다(예: { label: 'issue_view_summary' }).
command Object 예 agenticPrompt(Agentic 모드용 자연어 프롬프트) 또는 agent(에이전트 객체)를 포함해야 합니다.
classicQuickAction String 아니요 Classic Chat 모드에서 보낼 슬래시 명령입니다(예: '/summarize_comments'). 기본값은 null입니다.
buttonOptions Object 아니요 하위 GlButton에 전달되는 추가 props입니다(예: { size: 'small' }).

이벤트#

이벤트 페이로드 설명
duo-tool-completed { name, args } 에이전틱 도구가 완료되면 발생합니다. name은 도구 이름이고, args는 도구의 출력입니다.

예시#

// app/assets/javascripts/my_feature/components/my_component.vue
import { DUO_CHAT_QUICK_ACTION_SUMMARIZE, DUO_CHAT_AGENT_PLANNER } from '~/ai/constants';
import { s__ } from '~/locale';

export default {
  name: 'MyComponent',
  components: {
    DuoChatQuickAction: () => import('ee_component/ai/shared/widgets/duo_chat_quick_action.vue'),
  },
  inject: {
    resourceGlobalId: { default: null },
    noteableType: { default: '' },
  },
  computed: {
    summarizeTracking() {
      return { label: 'my_feature_view_summary', property: this.noteableType };
    },
  },
  buttonOptions: { size: 'small' },
  classicQuickAction: DUO_CHAT_QUICK_ACTION_SUMMARIZE,
  summarizeCommand: {
    agent: { name: DUO_CHAT_AGENT_PLANNER },
    agenticPrompt: s__('AI|Summarize the comments on this issue.'),
  },
};
<duo-chat-quick-action
  v-if="resourceGlobalId"
  :button-text="s__('AISummary|View summary')"
  :resource-id="resourceGlobalId"
  :tracking-info="summarizeTracking"
  :classic-quick-action="$options.classicQuickAction"
  :command="$options.summarizeCommand"
  :button-options="$options.buttonOptions"
/>

프롬프트 제안과 함께 Duo Chat 열기(OpenAgenticChatButton)#

OpenAgenticChatButton을 사용해, 커스텀 에이전트가 미리 선택되고 Duo Agentic Chat의 빈 상태 UI에 나타나는 하나 이상의 프롬프트 제안과 함께 Duo Chat을 여는 버튼을 추가합니다.

이 컴포넌트는 ee/app/assets/javascripts/ai/shared/widgets/open_agentic_chat_button.vue에 있습니다.

속성#

속성 타입 필수 여부 설명
buttonText String 예 버튼에 표시되는 레이블입니다.
resourceId String 예 리소스의 GraphQL 전역 ID입니다. 스트리밍 응답을 바인딩하는 데 사용합니다.
agent Object 예 미리 선택할 에이전트로, name으로 식별합니다(예: { name: 'My Feature Assistant' }).
welcomeMessage String 아니요 사용자가 입력하기 전 빈 상태 패널에 표시되는 메시지입니다.
predefinedPrompts Array 아니요 빈 상태에 표시되는 제안 칩입니다.
buttonOptions Object 아니요 하위 GlButton에 전달되는 추가 props입니다.

이벤트#

이벤트 페이로드 설명
tool-completed { name, args } 에이전트의 도구가 완료되면 발생합니다. name은 도구 이름이고, args는 도구의 출력입니다.

예시: Duo Chat으로 웹 폼을 채우는 기능 구현#

구현은 세 부분으로 이루어집니다:

  1. 사용자로부터 정보를 수집하고 컴포넌트가 사용할 수 있는 구조화된 데이터를 반환하는 자체 도구를 가진 커스텀 에이전트. 각 에이전트는 반드시 자체 도구를 정의해야 하며, 공유되는 범용 도구는 없습니다.
  2. 해당 에이전트가 미리 선택되고 몇 가지 프롬프트 제안이 있는 상태로 Duo Chat을 여는 버튼.
  3. 도구 완료 이벤트를 수신해 결과를 적용하는 컴포넌트.
1단계: 도구를 가진 커스텀 에이전트 만들기#

AI Gateway 리포지터리의 duo_workflow_service/agent_platform/v1/flows/configs/ 아래에 플로 설정을 만듭니다. 에이전트용 자체 도구를 반드시 정의해야 합니다. 여기서 선택한 도구 이름이 3단계에서 프론트엔드가 수신할 이름입니다.

전체 에이전트 생성 과정은 foundational_chat_agents.md를 참고합니다.

2단계: 컴포넌트에 버튼 추가하기#

OpenAgenticChatButton을 임포트하고, 에이전트와 환영 메시지, 미리 정의된 프롬프트를 컴포넌트 수준 상수로 정의합니다.

// ee/app/assets/javascripts/my_feature/components/my_component.vue
import OpenAgenticChatButton from 'ee/ai/shared/widgets/open_agentic_chat_button.vue';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { TYPENAME_USER } from '~/graphql_shared/constants';
import { s__, __ } from '~/locale';

const AGENT = { name: __('My Feature Assistant') };
const TOOL_NAME = 'my_feature_tool';
const WELCOME_MESSAGE = s__('MyFeature|I can help you configure this feature.');
const PREDEFINED_PROMPTS = [
  s__('MyFeature|Enable read access to repositories.'),
  s__('MyFeature|Set up CI/CD pipeline permissions.'),
];

export default {
  name: 'MyComponent',
  components: { OpenAgenticChatButton },
  computed: {
    resourceId() {
      return convertToGraphQLId(TYPENAME_USER, window.gon?.current_user_id);
    },
  },
  methods: {
    handleToolCompleted({ name, args } = {}) {
      if (name !== TOOL_NAME || !args || typeof args !== 'object') return;

      // Apply the tool output to your component
      this.myField = args.my_field;
    },
  },
  AGENT,
  WELCOME_MESSAGE,
  PREDEFINED_PROMPTS,
};
<open-agentic-chat-button
  :button-text="__('Configure with Duo')"
  :resource-id="resourceId"
  :agent="$options.AGENT"
  :welcome-message="$options.WELCOME_MESSAGE"
  :predefined-prompts="$options.PREDEFINED_PROMPTS"
  @tool-completed="handleToolCompleted"
/>

predefinedPrompts는 chat 패널이 비어 있을 때 제안 칩으로 표시되는 문자열 배열입니다. welcomeMessage를 사용해 에이전트가 할 수 있는 일을 사용자에게 설명합니다. 둘 다 선택 사항이지만 첫 프롬프트까지의 시간을 줄이려면 권장합니다.

3단계: 도구 완료 이벤트 처리하기#

에이전트의 도구가 완료되면 OpenAgenticChatButton은 tool-completed 이벤트를 발생시킵니다. 페이로드는 { name, args } 형태이며, name은 도구 이름이고 args는 도구가 반환한 인수 객체입니다.

모든 도구 완료가 같은 이벤트로 브로드캐스트되므로, 페이로드에 따라 동작하기 전에 name이 에이전트 설정에서 정의한 도구 이름과 일치하는지 확인합니다.

const TOOL_NAME = 'my_feature_tool'; // Must match the tool name in your agent config

methods: {
  handleToolCompleted({ name, args } = {}) {
    if (name !== TOOL_NAME || !args || typeof args !== 'object') return;

    // Apply the tool output to your component
    this.myField = args.my_field;
  },
},

이벤트 페이로드는 다음과 같은 형태입니다:

{
  name: 'my_feature_tool', // tool name as defined in your agent config
  args: {
    // fields defined by your tool
    my_field: 'value',
  }
}

완전한 실제 예시는 ee/app/assets/javascripts/personal_access_tokens/components/create_granular_token/ask_dap_permissions.vue를 참고합니다.

알려진 제약 사항#

  • 에이전트는 반드시 자체 도구를 구현해야 합니다. AI Catalog 에이전트는 이 패턴에서 도구를 공유할 수 없습니다. (ai-assist#2113)
  • 커스텀 질문은 에이전트 YAML에 정의할 수 없으며, 호출하는 컴포넌트에 하드코딩해야 합니다. (GitLab#594533)
  • 특정 페이지용으로 만든 에이전트도 사이트 전체에서 기반 에이전트로 선택할 수 있습니다.
  • 스트리밍 응답은 지원하지 않습니다.
  • 에이전트는 기존 폼 필드 값을 읽지 않습니다.

GraphQL 서브스크립션#

Chat용 GraphQL 서브스크립션은 사용자 중심이기 때문에 동작이 조금 다릅니다. 사용자는 여러 브라우저 탭이나 IDE에서 동시에 Chat을 열어 둘 수 있습니다. 따라서 여러 클라이언트에 메시지를 브로드캐스트해 동기화 상태를 유지해야 합니다. chat 액션이 있는 aiAction 뮤테이션은 다음과 같이 동작합니다:

  1. 완료된 모든 Chat 메시지(사용자의 메시지 포함)는 userId, aiAction: "chat"를 식별자로 브로드캐스트됩니다.
  2. 스트리밍되는 Chat 메시지의 청크는 뮤테이션의 clientSubscriptionId를 식별자로 브로드캐스트됩니다.

Vue 컴포넌트에서 GraphQL 서브스크립션의 예시:

  1. 완료된 Chat 메시지

    import aiResponseSubscription from 'ee/graphql_shared/subscriptions/ai_completion_response.subscription.graphql';
    [...]
    
    apollo: {
     $subscribe: {
       aiCompletionResponse: {
         query: aiResponseSubscription,
         variables() {
           return {
             userId, // for example "gid://gitlab/User/1"
             aiAction: 'CHAT',
           };
         },
         result({ data }) {
           // handle data.aiCompletionResponse
         },
         error(err) {
           // handle error
         },
       },
     },
    
  2. 스트리밍된 Chat 메시지

    import aiResponseSubscription from 'ee/graphql_shared/subscriptions/ai_completion_response.subscription.graphql';
    [...]
    
    apollo: {
     $subscribe: {
       aiCompletionResponseStream: {
         query: aiResponseSubscription,
         variables() {
           return {
             aiAction: 'CHAT',
             userId, // for example "gid://gitlab/User/1"
             clientSubscriptionId // randomly generated identifier for every message
             htmlResponse: false, // important to bypass HTML processing on every chunk
           };
         },
         result({ data }) {
           // handle data.aiCompletionResponse
         },
         error(err) {
           // handle error
         },
       },
     },
    

clientSubscriptionId는 요청마다 고유해야 한다는 점에 유의합니다. clientSubscriptionId를 재사용하면 서브스크립션 응답에서 여러 원치 않는 부작용이 발생합니다.

GitLab Duo Chat GraphQL 쿼리#

  1. GitLab Duo Chat 설정

  2. GraphQL 익스플로러에 접속합니다.

  3. aiAction 뮤테이션을 실행합니다. 예시는 다음과 같습니다:

    mutation {
      aiAction(
        input: {
          chat: {
            resourceId: "gid://gitlab/User/1",
            content: "Hello"
          }
        }
      ){
        requestId
        errors
      }
    }
    
  4. 다음 쿼리를 실행해 응답을 가져옵니다:

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

응답을 가져올 수 없다면 graphql_json.log, sidekiq_json.log, llm.log, modelgateway_debug.log에 오류 정보가 있는지 확인합니다.

GitLab Duo Chat 대화 스레드 GraphQL 쿼리#

대화 스레드의 메시지 조회#

특정 스레드에서 메시지를 가져오려면 스레드 ID와 함께 aiMessages 쿼리를 사용합니다:

query {
  aiMessages(threadId: "gid://gitlab/Ai::Conversation::Thread/1") {
    nodes {
      requestId
      content
      role
      timestamp
      chunkId
      errors
    }
  }
}

새 대화 스레드 시작#

aiAction 뮤테이션에 threadId를 포함하지 않으면 새 스레드가 생성됩니다:

mutation {
  aiAction(input: {
    chat: {
      content: "This will create a new conversation thread"
    },
    conversationType: DUO_CHAT
  })
  {
    requestId
    errors
    threadId  # This will contain the ID of the newly created thread
  }
}

기존 대화 스레드에 새 메시지 생성#

기존 스레드에 메시지를 추가하려면 aiAction 뮤테이션에 threadId를 포함합니다:

mutation {
  aiAction(input: {
    chat: {
      content: "this is another message in the same thread"
    },
    conversationType: DUO_CHAT,
    threadId: "gid://gitlab/Ai::Conversation::Thread/1",
  })
  {
    requestId
    errors
    threadId
  }
}

프로덕션과 유사한 환경에서 GitLab Duo Chat 테스트#

GitLab Duo Chat는 Staging과 Staging Ref GitLab 환경에서 활성화되어 있습니다.

현재 GitLab Duo Chat는 Premium, Ultimate 등급 그룹의 구성원만 사용할 수 있으므로, GitLab 팀원이라면 Staging Ref가 변경 사항을 테스트하기 더 쉬운 곳일 수 있습니다. 이는 Staging Ref에서 자신을 인스턴스 Admin으로 만들 수 있고, Admin으로서 테스트용 라이선스가 있는 그룹을 쉽게 만들 수 있기 때문입니다.

중요한 테스트 고려 사항#

Note

GitLab Duo add-on 등급이 서로 다른 여러 그룹에 시트를 가진 사용자는 인스턴스 전체에서 가장 높은 등급의 경험을 얻습니다.

테스트 계정이 더 높은 등급의 add-on에 시트를 가지고 있으면 서로 다른 GitLab Duo add-on 간의 기능 분리를 테스트할 수 없습니다. 등급별로 제대로 테스트하려면 테스트해야 하는 등급마다 별도의 테스트 계정을 만듭니다.

Staging 테스트 그룹#

staging에서의 테스트를 간소화하기 위해, 적절한 라이선스와 add-on이 설정된 그룹 여러 개가 미리 만들어져 있습니다:

그룹 GitLab Duo Add-on GitLab 라이선스
duo_pro_gitlab_premium Pro Premium
duo_pro_gitlab_ultimate Pro Ultimate
duo_enterprise_gitlab_ultimate Enterprise Ultimate

Slack의 #g_duo_chat 채널에서 이 그룹의 Owner로 추가해 달라고 요청합니다. Owner로 추가된 뒤에는 보조 계정을 Developer 권한으로 그룹에 추가하고 GitLab Duo add-on 시트를 할당할 수 있습니다. 그런 다음 Developer 사용자로 로그인해 GitLab Duo Chat에 대한 접근 제어를 테스트할 수 있습니다.

라이브 환경에서 GitLab Duo Chat 엔드투엔드 테스트#

GitLab Duo Chat 엔드투엔드 테스트는 Staging과 Production GitLab 환경에서 지속적으로 실행됩니다.

이 테스트는 예약된 파이프라인에서 실행되며 엔드투엔드 사용자 경험이 올바르게 동작하는지 확인합니다. 결과는 #e2e-run-staging, #e2e-run-production Slack 채널에서 확인할 수 있습니다. 파이프라인은 아래에서 찾을 수 있으며, 액세스는 #s_developer_experience에서 요청할 수 있습니다:

제품 분석#

기능이 어떻게 사용되는지 더 잘 이해하기 위해, 프로덕션의 각 사용자 입력 메시지를 LLM과 Ruby로 분석하며, 그 분석 결과를 Snowplow 이벤트로 추적합니다.

이 분석에는 최신 iglu 스키마에 정의된 속성이 포함될 수 있습니다.

  • 카테고리와 세부 카테고리는 사용자의 실제 질문을 볼 수 없으므로 제품 매니저와 제품 디자이너가 미리 정의했습니다. 누락되거나 혼란스러운 카테고리가 있다고 판단되면 변경할 수 있습니다. 정의를 수정하려면 AI Gateway와 monolith 양쪽의 categories.xml을 업데이트합니다.
  • 수집되는 속성 목록은 labesl.xml에서 확인할 수 있습니다.
    • 다음은 아직 구현되지 않았습니다:
      • is_proper_sentence
    • 다음은 지원 종료되었습니다:
      • number_of_questions_in_history
      • length_of_questions_in_history
      • time_since_first_question

각 질문 카테고리와 세부 카테고리의 요청 수와 사용자 수는 이 Tableau 대시보드에서 확인할 수 있습니다(GitLab 팀원 전용).

access_duo_classic_chat 정책의 동작 방식#

이 표는 access_duo_classic_chat 정책이 여러 컨텍스트에서 true를 반환하기 위한 요구 사항을 설명합니다.

GitLab.com Dedicated 또는 GitLab Self-Managed 모든 인스턴스
프로젝트나 그룹 밖의 사용자(user.can?(:access_duo_classic_chat)) duo_features_enabled 그룹 설정이 켜져 있는 Premium 또는 Ultimate 등급 그룹에 최소 하나 이상 속해 있어야 합니다 - 인스턴스가 Premium 또는 Ultimate 등급이어야 합니다
- 인스턴스에서 duo_features_enabled 설정이 켜져 있어야 합니다
그룹 컨텍스트의 사용자(user.can?(:access_duo_classic_chat, group)) - experiment_and_beta_features 그룹 설정이 켜져 있는 Premium 또는 Ultimate 등급 그룹에 최소 하나 이상 속해 있어야 합니다
- 그룹의 최상위 조상 그룹이 Premium 또는 Ultimate 등급이어야 하고, 그룹에서 duo_features_enabled 설정이 켜져 있어야 합니다
- 인스턴스가 Premium 또는 Ultimate 등급이어야 합니다
- 인스턴스에서 duo_features_enabled 설정이 켜져 있어야 합니다
사용자가 그룹에 대해 최소 읽기 권한을 가지고 있어야 합니다
프로젝트 컨텍스트의 사용자(user.can?(:access_duo_classic_chat, project)) - experiment_and_beta_features 그룹 설정이 켜져 있는 Premium 또는 Ultimate 등급 그룹에 최소 하나 이상 속해 있어야 합니다
- 프로젝트의 최상위 조상 그룹이 Premium 또는 Ultimate 등급이어야 하고, 프로젝트에서 duo_features_enabled 설정이 켜져 있어야 합니다
- 인스턴스가 Ultimate 등급이어야 합니다
- 인스턴스에서 duo_features_enabled 설정이 켜져 있어야 합니다
사용자가 프로젝트에 대해 최소 읽기 권한을 가지고 있어야 합니다

(지원 종료) 이슈와 에픽 실험#

Note

이 절은 지원 종료되었으며 개발 시드 파일로 대체되었습니다.

평가 프레임워크를 사용하려면(평가 문서에 설명된 대로) 다음 Rake 태스크를 사용해 필요한 그룹과 프로젝트를 가져올 수 있습니다:

GITLAB_SIMULATE_SAAS=1 bundle exec 'rake gitlab:duo:setup_evaluation[<test-group-name>]'

그룹을 생성하려면(하위 그룹을 가져오는 데 필요) "saas" 모드가 필요한 Setup 클래스(ee/lib/gitlab/duo/developments/setup.rb 아래)를 사용하므로, GITLAB_SIMULATE_SAAS=1을 설정해야 합니다. 이는 가져오기를 성공적으로 완료하기 위한 것일 뿐이며, 원한다면 이후 GITLAB_SIMULATE_SAAS=0으로 다시 전환할 수 있습니다.

(지원 종료) 에픽과 이슈 픽스처#

Note

이 절은 지원 종료되었으며 개발 시드 파일로 대체되었습니다.

이 픽스처는 GitLab이 소유한 프로젝트와 그룹의 공개 이슈, 에픽을 복제한 것입니다. 샘플링할 때 내부 노트는 제외했습니다. 이 픽스처는 정본 gitlab 리포지터리에 커밋되어 있습니다. 픽스처를 생성하는 데 사용한 스니펫을 참고합니다.

Chat 프롬프트가 구성되는 방식#

모든 Chat 요청은 GitLab GraphQL API로 처리됩니다. 그리고 현재는 서드파티 LLM용 프롬프트가 GitLab 코드베이스에 하드코딩되어 있습니다.

하지만 Chat 프롬프트를 변경하고 싶다면, 파일 하나에서 문자열을 찾는 것처럼 간단하지 않습니다. 프롬프트가 여러 단계를 거쳐 조립되기 때문에 Chat 프롬프트 구성 과정은 따라가기 어렵습니다. Chat 프롬프트를 구성하는 흐름은 다음과 같습니다:

  1. GraphQL AI 뮤테이션에 API 요청이 만들어집니다. 이 요청에는 사용자 Chat 입력이 담겨 있습니다. (코드)

  2. GraphQL 뮤테이션이 Llm::ExecuteMethodService#execute를 호출합니다 (코드)

  3. Llm::ExecuteMethodService#execute는 GraphQL API로 chat 메서드가 전달된 것을 확인하고 Llm::ChatService#execute를 호출합니다 (코드)

  4. Llm::ChatService#execute는 schedule_completion_worker를 호출하며, 이는 Llm::BaseService(ChatService의 베이스 클래스)에 정의되어 있습니다 (코드)

  5. schedule_completion_worker는 Llm::CompletionWorker.perform_for를 호출하며, 이는 job을 비동기로 큐에 넣습니다 (코드)

  6. job이 실행되면 Llm::CompletionWorker#perform이 호출됩니다. 이 메서드는 사용자 입력과 그 밖의 메시지 컨텍스트를 역직렬화하여 Llm::Internal::CompletionService#execute로 전달합니다 (코드)

  7. Llm::Internal::CompletionService#execute는 Gitlab::Llm::CompletionsFactory#completion!을 호출합니다. 이 메서드는 원래 GraphQL 요청에서 ai_action을 꺼내 Gitlab::Llm::Completions::Chat의 새 인스턴스를 초기화하고 그 위에서 execute를 호출합니다 (코드)

  8. Gitlab::Llm::Completions::Chat#execute는 Gitlab::Duo::Chat::ReactExecutor를 호출합니다. (코드)

  9. Gitlab::Duo::Chat::ReactExecutor#execute는 #step_forward를 호출하고, 이는 Gitlab::Duo::Chat::StepExecutor#step을 호출합니다 (코드).

  10. Gitlab::Duo::Chat::StepExecutor#step은 Gitlab::Duo::Chat::StepExecutor#perform_agent_request를 호출하며, 이는 AI Gateway의 /v2/chat/agent/ 엔드포인트로 요청을 보냅니다 (코드).

  11. AI Gateway의 /v2/chat/agent 엔드포인트는 api.v2.agent.chat.agent.chat 함수에서 요청을 받습니다 (코드)

  12. api.v2.agent.chat.agent.chat은 gl_agent_remote_executor_factory를 통해 GLAgentRemoteExecutor를 생성합니다 (코드).

    GLAgentRemoteExecutor를 생성할 때 다음 파라미터가 전달됩니다:

    • tools_registry - 사용 가능한 모든 도구의 레지스트리이며, 팩토리를 통해 전달됩니다 (코드)
    • agent - 선택된 LLM 모델, 프롬프트 템플릿 등 프롬프트 정보를 감싸는 ReActAgent 객체
  13. api.v2.agent.chat.agent.chat은 GLAgentRemoteExecutor.on_behalf를 호출합니다. 이 메서드는 오류가 발생하면 가능한 한 빨리 예외를 발생시키기 위해 사용자 도구를 먼저 가져옵니다 (코드).

  14. api.v2.agent.chat.agent.chat은 GLAgentRemoteExecutor.stream을 호출합니다 (코드).

  15. GLAgentRemoteExecutor.stream은 메시지와 사용 가능한 도구 목록 등의 입력과 함께 agent(ReActAgent의 인스턴스)에서 astream을 호출합니다 (코드).

  16. ReActAgent는 프롬프트를 구성하며, 사용 가능한 도구는 시스템 프롬프트 템플릿에 삽입됩니다 (코드).

  17. ReActAgent.astream은 LLM 모델에 호출을 보냅니다 (코드)

  18. LLM 응답이 Rails로 반환됩니다 (코드 경로: ReActAgent.astream -> GLAgentRemoteExecutor.stream -> api.v2.agent.chat.agent.chat -> Rails)

  19. 이제 AI Gateway로 첫 요청을 보냈습니다. LLM이 첫 요청에 대한 답이 최종이라고 하면, Rails가 답을 파싱하고 이후 응답 처리를 위해 Gitlab::Llm::Completions::Chat로 그 답을 반환합니다.

  20. 답이 최종이 아니면, 첫 LLM 요청의 "thoughts"와 "picked tools"를 파싱한 뒤 관련 도구 클래스를 호출합니다. (코드 | 도구 클래스 예시)

    1. 도구 실행기 클래스는 Concerns::AiDependent를 포함하고 그 request 메서드를 사용합니다. (코드)
    2. request 메서드는 ai_request 인스턴스를 사용합니다 이는 Llm::Completions::Chat에서 context에 주입된 것입니다. Chat의 경우 이는 Gitlab::Llm::Chain::Requests::AiGateway입니다. (코드).
    3. ai_request는 /v1/prompts/chat 엔드포인트로 프롬프트를 보냅니다 (코드).
    4. AI Gateway의 /v1/prompts/chat 엔드포인트는 api.v1.prompts.invoke에서 요청을 받습니다 (코드).
    5. api.v1.prompts.invoke는 도구 프롬프트 레지스트리에서 올바른 도구 프롬프트를 가져옵니다 (코드).
    6. 프롬프트는 스트림이나 스트리밍하지 않는 호출 중 하나로 호출됩니다.
    7. 도구의 답이 최종이 아니면 응답을 agent_scratchpad에 추가하고 Gitlab::Duo::Chat::ReactExecutor의 루프가 다시 시작되어 요청에 추가 컨텍스트를 더합니다. 최종 답에 도달할 때까지 최대 10회 반복합니다. (코드)

GitLab Duo Chat 오류 코드 해석#

GitLab Duo Chat에는 디버깅을 돕기 위해 정해진 의미를 가진 오류 코드가 있습니다.

모든 GitLab Duo Chat 오류 코드 목록은 GitLab Duo Chat 문제 해결 문서를 참고합니다.

GitLab Duo Chat을 개발할 때는 오류를 반환할 때 이 오류 코드를 포함하고, 특히 사용자에게 노출되는 오류라면 문서화합니다.

오류 코드 형식#

오류 코드는 형식을 따릅니다.

예를 들면:

  • M1001: 모놀리스 계층의 네트워크 통신 오류입니다.
  • G2005: AI Gateway 계층의 데이터 형식/처리 오류입니다.
  • A3010: 서드파티 API의 인증 또는 데이터 접근 권한 오류입니다.

오류 코드 레이어 식별자#

코드 레이어
M 모놀리스
G AI Gateway
A 서드파티 API

오류 시리즈#

시리즈 유형
1000 네트워크 통신 오류
2000 데이터 형식/처리 오류
3000 인증 및/또는 데이터 접근 권한 오류
4000 코드 실행 예외
5000 잘못된 설정 또는 잘못된 파라미터 오류
6000 의미론적 또는 추론 오류(모델이 이해하지 못하거나 헐루시네이션을 일으키는 경우)

GitLab Duo Chat

GitLab v19.4
원문 보기

요약

GitLab Duo Chat는 소프트웨어 개발 생명주기(Software Development Lifecycle, SDLC) 전반에서 사용자가 아이디어를 구상하고 만들어내는 작업뿐 아니라 학습하는 작업도 AI로 지원하여, 더 빠르고 효율적으로 만드는 것을 목표로 합니다.

GitLab Duo Chat는 소프트웨어 개발 생명주기(Software Development Lifecycle, SDLC) 전반에서 사용자가 아이디어를 구상하고 만들어내는 작업뿐 아니라 학습하는 작업도 AI로 지원하여, 더 빠르고 효율적으로 만드는 것을 목표로 합니다.

Chat는 GitLab Duo 제품군의 일부입니다.

Chat는 다양한 질문에 답하고 특정 작업을 수행할 수 있습니다. 이는 프롬프트와 도구의 도움으로 이루어집니다.

Chat 인터페이스에서 사용자가 한 질문에 답하기 위해, GitLab은 GraphQL 요청을 Rails 백엔드로 보냅니다. 그러면 Rails 백엔드는 AI Gateway를 통해 거대 언어 모델(Large Language Model, LLM)에 지시를 전달합니다.

Chat 기여에 가장 적합한 사용 사례#

거대 언어 모델(LLM) 기반 AI와 사용자 간의 대화형 상호작용으로 이점을 얻을 수 있는 모든 사용 사례와 워크플로에 Chat를 적용하는 것을 목표로 합니다. 대표적으로 다음과 같습니다:

  • 한 번의 상호작용보다 반복을 통해 더 효과적이고 효율적으로 해결되는 창작·아이디어 구상 작업 및 학습 작업.
  • 보통 한 번의 상호작용으로 충족되지만 다듬어야 할 수도 있고 대화로 이어질 수도 있는 작업.
  • 후자 중에는 AI가 처음부터 정확히 맞추지 못할 수 있지만 사용자가 필요한 것을 더 정확히 말해줌으로써 쉽게 방향을 바로잡을 수 있는 작업이 있습니다. 예를 들어 "이 코드를 설명해 줘"는 대부분 만족스러운 답을 얻는 흔한 질문이지만, 때로는 사용자가 추가 질문을 할 수도 있습니다.
  • 대화 기록에서 이점을 얻는 작업으로, 사용자와 AI 모두 같은 말을 반복할 필요가 없습니다.

Chat는 컨텍스트를 인식하고, 궁극적으로는 사용자가 접근 권한을 가진 GitLab의 모든 리소스에 접근하는 것을 목표로 합니다. 처음에는 이 컨텍스트가 개별 이슈와 에픽의 내용, GitLab 문서로 한정되어 있었습니다. 이후 코드 선택 영역과 코드 파일 같은 추가 컨텍스트가 더해졌습니다. 현재는 사용자가 이런 컨텍스트에 대해 질문할 수 있도록 취약점 컨텍스트와 파이프라인 job 컨텍스트를 추가하는 작업이 진행 중입니다.

컨텍스트 인식 범위를 넓혀 DevSecOps 전체 영역에서 창작·아이디어 구상·학습 사용 사례를 확장하기 위해, GitLab Duo Chat 팀은 다른 GitLab 팀과 더 넓은 커뮤니티가 Chat 플랫폼에 기여하는 것을 환영합니다. 이들은 가속화하려는 사용 사례와 워크플로의 전문가입니다.

독립형 AI 기능으로 구현하는 것이 더 적합한 사용 사례#

독립형 AI 기능으로, 또는 최소한 독립형 AI 기능으로도 구현하는 것이 더 적합한 사용 사례는 다음과 같습니다.

  • 기존 워크플로에 AI를 깊이 통합함으로써 가속화할 수 있는 범위가 좁은 작업.
  • AI와의 대화에서 이점을 얻을 수 없는 작업.

이를 더 구체적으로 보여주는 예시가 있습니다.

변경 사항을 바탕으로 커밋 메시지를 생성하는 것은 커밋 메시지 작성 워크플로에 구현하는 것이 가장 좋습니다.

  • AI가 없으면 커밋 메시지 작성에 10초 정도 걸릴 수 있습니다.
  • IDE의 Commit message 필드에 AI가 생성한 커밋 메시지를 자동으로 채우면 이 작업이 1초로 줄어듭니다.

커밋 메시지 작성에 Chat를 사용하면 직접 작성하는 것보다 시간이 더 걸릴 가능성이 큽니다. 사용자는 Chat 창으로 전환해 요청을 입력한 뒤 결과를 커밋 메시지 필드에 복사해야 합니다.

다만 이것이 Chat가 커밋 메시지를 작성할 수 없다는 뜻은 아니며, 그렇게 하지 못하도록 막혀 있는 것도 아닙니다. Chat가 커밋 컨텍스트를 가지고 있다면(커밋 메시지 작성이 아닌 다른 이유로 언젠가 추가될 수 있습니다), 사용자는 커밋 메시지 작성을 포함해 이 커밋 콘텐츠로 원하는 무엇이든 요청할 수 있습니다. 하지만 시간만 낭비하게 되므로 사용자가 실제로 Chat로 그렇게 할 가능성은 낮습니다. 참고: 사용자가 작성한 프롬프트로 Chat에서 만든 커밋 메시지와, 전용으로 만들어진 커밋 메시지 생성 기능 뒤의 고정된 프롬프트로 만든 커밋 메시지는 결과가 다를 수 있습니다.

GitLab Duo Chat 설정#

GitLab Duo Chat를 로컬에서 설정하려면 AI 기능 일반 설정 안내를 따릅니다.

GitLab Duo Chat 작업#

프롬프트는 GitLab Duo Chat 시스템에서 가장 중요한 부분입니다. 프롬프트는 특정 작업을 수행하도록 LLM에 전달하는 지시입니다.

현재 프롬프트 상태는 몇 주에 걸친 반복 작업의 결과입니다. 현재 도구의 프롬프트를 변경하려면 반드시 기능 플래그 뒤에 두어야 합니다.

새 프롬프트나 업데이트한 프롬프트가 있으면 GitLab Duo Chat 팀 구성원에게 검토를 요청합니다. 이들은 프롬프트에 대한 경험이 풍부합니다.

문제 해결#

Chat를 로컬에서 다룰 때 오류가 발생할 수 있습니다. 가장 흔한 문제는 이 절에 문서화되어 있습니다. 문서화되지 않은 문제를 발견하면, 해결 방법을 찾은 뒤 이 절에 문서화해야 합니다.

문제 해결 방법
GitLab UI에 Chat 버튼이 없습니다. 사용자가 Premium 또는 Ultimate 라이선스를 보유하고 Chat이 활성화된 그룹에 속해 있는지 확인합니다.
Chat가 "Forbidden by auth provider" 오류로 응답합니다. 백엔드가 LLM에 접근할 수 없는 상태입니다. AI Gateway가 올바르게 설정되어 있는지 확인합니다.
요청이 UI에 나타나는 데 너무 오래 걸립니다 gdk restart rails-background-jobs를 실행해 Sidekiq을 재시작하는 것을 고려합니다. 그래도 안 되면 gdk kill 후 gdk start를 시도합니다. 또는 Sidekiq을 완전히 건너뛸 수도 있습니다. 이를 위해 Llm::CompletionWorker.perform_async 문을 임시로 Llm::CompletionWorker.perform_inline으로 바꿉니다
GDK가 non-SaaS 모드로 실행 중일 때 GitLab UI에 Chat 버튼이 없습니다 cloud connector 액세스 토큰 레코드가 없거나 시트가 할당되지 않은 상태입니다. cloud connector 액세스 레코드를 만들려면 rails console에서 다음 코드를 입력합니다: FactoryBot.create(:cloud_connector_access).

문제 해결에 도움이 되도록 Chat가 보내는 오류 코드에 대한 자세한 내용은 GitLab Duo Chat 오류 코드 해석을 참고합니다.

GitLab Duo Chat에 기여하기#

코드 관점에서 Chat는 다른 AI 기능과 비슷한 방식으로 구현되어 있습니다. GitLab의 AI 추상화 계층에 대해 더 알아봅니다.

Chat 기능은 사용자 질문과 관련 컨텍스트를 AI Gateway로 보내는 zero-shot 에이전트를 사용합니다. AI Gateway는 프롬프트를 구성해 거대 언어 모델에 요청을 보냅니다.

거대 언어 모델은 직접 답할 수 있는지, 아니면 정의된 도구 중 하나를 사용해야 하는지를 판단합니다.

각 도구는 정보를 수집하기 위해 그 도구를 어떻게 사용할지 거대 언어 모델에 지시를 제공하는 자체 프롬프트를 가지고 있습니다. 도구는 자체적으로 완결되도록 설계되어, 거대 언어 모델과 여러 번 요청을 주고받는 것을 피합니다.

도구가 필요한 정보를 수집하면 zero-shot 에이전트로 반환되고, 에이전트는 사용자 질문에 최종 답을 제공할 만큼 충분한 정보가 수집되었는지 거대 언어 모델에 묻습니다.

새 도구 추가#

새 도구를 추가하려면 AI Gateway와 Rails Monolith 양쪽 모두 변경해야 합니다. 메인 chat 프롬프트는 AI Gateway에 저장되고 조립됩니다. Rails 쪽은 프롬프트에 필요한 파라미터를 조립해 AI Gateway로 보내는 역할을 합니다. AI Gateway는 Chat 프롬프트를 조립하고 구독과 add-on에 따라 사용자가 사용할 수 있는 Chat 도구를 선택하는 역할을 합니다.

LLM이 사용할 도구를 선택하면 이 도구는 Rails 쪽에서 실행됩니다. 도구는 AI Gateway에 요청을 보낼 때 서로 다른 엔드포인트를 사용합니다. 새 도구를 추가할 때는 AI Gateway가 버전이 다른 여러 클라이언트와 GitLab 애플리케이션과 함께 동작한다는 점을 고려해야 합니다. 즉 오래된 GitLab 버전은 새 도구를 알지 못합니다. 새 도구를 추가하려면 GitLab Duo Chat 팀에 문의합니다. 이 문제에 대한 장기적인 해결책을 마련하는 중입니다.

AI Gateway에서의 변경#

  1. ai_gateway/chat/tools/gitlab.py에 도구용 새 클래스를 만듭니다. 이 클래스는 다음 속성을 포함해야 합니다:

    • 도구의 name
    • 도구가 작업하는 GitLab resource
    • 도구가 하는 일에 대한 description
    • 질문과 원하는 답변의 example
  2. ai_gateway/chat/tools/gitlab.py의 __all__ 도구 목록에 도구를 추가합니다.

  3. ai_gateway/chat/toolset.py의 DuoChatToolsRegistry에 적절한 Unit Primitive와 함께 도구 클래스를 추가합니다.

  4. 변경 사항에 대한 테스트를 추가합니다.

Rails Monolith에서의 변경#

  1. ee/lib/gitlab/llm/chain/tools/ 폴더에 도구용 파일을 만듭니다. issue_reader나 epic_reader 같은 기존 도구를 템플릿으로 사용합니다.
  2. 정보를 수집하기 위해 도구를 어떻게 사용할지 거대 언어 모델에 지시하는 클래스를 작성합니다
    • 이 도구가 사용하는 메인 프롬프트입니다.
  3. 거대 언어 모델의 응답을 파싱해 chat 에이전트로 반환하는 코드를 도구에 구현합니다.
  4. 에이전트가 알 수 있도록 ee/lib/gitlab/llm/completions/chat.rb의 tools 배열에 새 도구 이름을 추가합니다.

전체 테스트#

거대 언어 모델에 실제 요청을 보내는 RSpec 테스트를 사용해 프롬프트를 테스트하고 반복 개선합니다.

  • 프롬프트는 시행착오가 필요하며, LLM 작업의 비결정적인 특성은 예상치 못한 결과를 낼 수 있습니다.
  • Anthropic은 프롬프트 작업에 대한 좋은 가이드를 제공합니다.
  • 프롬프트 작업에 대한 GitLab 가이드.

핵심은 프롬프트와 도구 설명을 통해 거대 언어 모델에 올바르게 지시하고, 도구가 자체적으로 완결되도록 유지하며, zero-shot 에이전트에 응답을 반환하는 것입니다. 프롬프트에 약간의 시행착오를 거치면 새 도구를 추가해 Chat 기능의 역량을 확장할 수 있습니다.

이 주제를 다루는 짧은 영상이 있습니다.

다중 스레드 대화 다루기#

GitLab Duo Chat 대화와 상호작용하는 기능을 만든다면 스레드가 어떻게 동작하는지 이해해야 합니다.

GitLab Duo Chat는 여러 대화를 지원합니다. 각 대화는 스레드로 표현되며, 스레드는 여러 메시지를 포함합니다. 스레드의 주요 속성은 다음과 같습니다:

  • id: 스레드에 답장할 때 id가 필요합니다.
  • conversation_type: 사용 가능한 여러 GitLab Duo Chat 대화 유형을 구분합니다. 스레드 대화 유형 목록을 참고합니다.
    • 기능에 별도의 대화 유형이 필요하면 GitLab Duo Chat 팀에 문의합니다.

GraphQL API를 직접 호출해야 하는 기능이라면 다음 쿼리와 뮤테이션을 사용할 수 있으며, 이때 conversation_type을 지정해야 합니다.

  • Query.aiConversationThreads: 스레드 목록을 조회합니다
  • Query.aiMessages: 한 스레드의 메시지 목록을 조회합니다. threadId를 지정해야 합니다.
  • Mutation.aiAction: 메시지 하나를 생성합니다. threadId를 지정하면 해당 스레드에 메시지가 추가됩니다.

모든 chat 대화에는 관리자가 제어하는 보관 기간이 있습니다. 기본 보관 기간은 마지막 답변 후 30일입니다.

개발자 리소스#

디버깅#

전체 요청에 대해 더 많은 정보를 얻으려면 Gitlab::Llm::Logger 파일을 사용해 로그를 디버깅합니다. 프로덕션의 기본 로깅 레벨은 INFO이며, 개인 식별 정보가 포함될 수 있는 데이터는 로그에 남기지 않아야 합니다.

추상화 계층에서 AI 요청과 관련된 디버깅 메시지를 확인하려면 다음을 사용할 수 있습니다:

export LLM_DEBUG=1
gdk start
tail -f log/llm.log

프로덕션 환경에서 디버깅#

프로덕션 환경에서 디버깅과 문제 해결에 관련된 모든 정보는 GitLab Duo Chat On-Call 런북에 모여 있습니다.

LangSmith로 트레이싱#

트레이싱은 LLM 애플리케이션의 동작을 이해하는 데 강력한 도구입니다. LangSmith는 업계 최고 수준의 트레이싱 기능을 갖추고 있으며 GitLab Duo Chat와 통합되어 있습니다. 트레이싱은 다음과 같은 문제를 추적하는 데 도움이 됩니다:

  • GitLab Duo Chat를 처음 접하고 내부에서 어떤 일이 일어나는지 알고 싶은 경우.
  • 예상치 못한 답변을 받았을 때 프로세스가 정확히 어디서 실패했는지.
  • 어떤 프로세스가 지연 시간의 병목이었는지.
  • 모호한 질문에 어떤 도구가 사용되었는지.

LangSmith UI

트레이싱은 대규모 데이터셋으로 GitLab Duo Chat를 실행하는 평가에 특히 유용합니다. LangSmith 통합은 GitLab 중앙 평가 프레임워크(CEF)를 비롯한 모든 도구와 함께 동작합니다.

LangSmith로 트레이싱 사용#

Note

트레이싱은 Development, Testing 환경에서만 사용할 수 있습니다. Production 환경에서는 사용할 수 없습니다.

  1. LangSmith에 접속해 계정을 만듭니다

    1. Lumos를 통해 액세스를 요청합니다
    2. Editor 역할에 대해 액세스 요청을 생성합니다(템플릿 LangSmith_Access_Request)
  2. API 키를 생성합니다(API 키를 어디에 만드는지 주의합니다 - 개인 네임스페이스나 GL 네임스페이스에 만들 수 있습니다).

  3. GDK에서 다음 환경 변수를 설정합니다.

    gdk.yml에서 정의할 수 있습니다:

    # on your gdk.yml
    env:
      LANGCHAIN_TRACING_V2: 'true'
      LANGCHAIN_API_KEY: '<your-api-key>'
      LANGCHAIN_PROJECT: '<your-project-name>'
      LANGCHAIN_ENDPOINT: 'https://api.smith.langchain.com'
      GITLAB_RAILS_RACK_TIMEOUT: '180' # Extending puma timeout for using LangSmith with CEF as the evaluation tool.
    

    또는 터미널에서 직접 export합니다:

    export LANGCHAIN_TRACING_V2=true
    export LANGCHAIN_API_KEY='<your-api-key>'
    export LANGCHAIN_PROJECT='<your-project-name>'
    export LANGCHAIN_ENDPOINT='https://api.smith.langchain.com'
    export GITLAB_RAILS_RACK_TIMEOUT=180 # Extending puma timeout for using LangSmith with CEF as the evaluation tool.
    

    프로젝트 이름은 LangSmith에 있는 기존 프로젝트이거나 새 프로젝트일 수 있습니다. 환경 변수에 새 이름을 넣기만 하면 요청 중에 프로젝트가 생성됩니다.

  4. GDK를 재시작합니다.

  5. Chat에 아무 질문이나 합니다.

  6. LangSmith 페이지 > Projects > [Project name]에서 프로젝트를 확인합니다. 'Runs' 탭에 최근 요청이 표시되어야 합니다.

LangSmith 트레이스 공유(내부 팀원용)#

웹 브라우저에서 URL 전체를 복사해 팀원과 트레이스 URL을 직접 공유할 수 있습니다. LangSmith UI에 있는 "share" 트레이스 기능보다 이 방법을 사용하는 것이 좋습니다. 트레이스를 공개로 공유하면 OKTA를 통한 LangSmith 액세스 권한이 없는 사람도 링크만 있으면 접근할 수 있게 됩니다. 트레이스에는 CI 토큰과 같은 민감한 정보가 담겨 있습니다.

클릭 한 번으로 머지 리퀘스트 평가#

CEF로 머지 리퀘스트를 평가하려면 Evaluation Runner(내부용)를 사용할 수 있습니다. 머지 리퀘스트에서 평가 실행하기 안내를 따릅니다.

머지 리퀘스트에서 회귀 방지#

GitLab Duo Chat나 관련 컴포넌트를 변경할 때는 머지 리퀘스트의 품질 저하와 버그를 탐지하기 위해 회귀 평가기를 실행해야 합니다. 여기에는 도구 실행과 슬래시 명령을 포함한 모든 GitLab Duo Chat 실행 패턴이 포함됩니다.

회귀 평가기를 실행하려면 머지 리퀘스트에서 평가를 실행하고 회귀 평가기의 재생 버튼을 클릭합니다. 이후 머지 리퀘스트의 평가 결과를 master와 비교할 수 있습니다. LangSmith의 비교 페이지에서 품질 저하와 버그가 없는지 확인합니다.

비교 결과를 해석하는 엄격한 가이드라인은 없지만, 참고할 만한 유용한 팁이 있습니다:

  • 저하된 점수의 수가 개선된 점수의 수보다 많다면, 머지 리퀘스트가 품질 저하를 유발했을 수 있습니다.
  • 평가 중 오류가 발생한 예시가 있다면, 머지 리퀘스트에 잠재적인 버그가 있을 수 있습니다.

이런 상황이 발생하면 추가 조사를 권장합니다:

  1. 결과를 일일 평가 결과와 비교합니다. 예를 들어 어제와 그 전날의 일일 평가를 확인합니다.
  2. 이 일일 평가에서 비슷한 패턴이 보인다면 머지 리퀘스트를 안전하게 머지할 수 있을 가능성이 큽니다. 반면 패턴이 다르다면 머지 리퀘스트가 예상치 못한 변경을 유발했을 수 있습니다.

다음 환경에서는 회귀 평가기를 반드시 실행하는 것을 강력히 권장합니다:

환경 평가 파이프라인 이름
GitLab Self-Managed와 널리 채택된 커스텀 모델 duo-chat regression sm: [bedrock_mistral_8x7b_instruct]
GitLab.com과 GitLab Duo Enterprise add-on duo-chat regression .com: [duo_enterprise]
GitLab.com과 GitLab Duo Pro add-on duo-chat regression .com: [duo_pro]

이 외에도 특정 범위에 대해 더 포괄적인 데이터셋을 가진 gitlab-docs 같은 다른 평가기를 실행할 수 있습니다. 자세한 내용은 사용 가능한 평가 파이프라인을 참고합니다.

회귀 데이터셋에 예시 추가#

새 기능을 도입했거나 사용자로부터 회귀 보고를 받았다면, 커버리지를 넓히기 위해 회귀 데이터셋에 새 예시를 추가해야 합니다. 회귀 데이터셋에 예시를 추가하려면 이 절을 따릅니다.

자세한 내용은 회귀 평가기 가이드라인을 참고합니다.

GitLab Duo Chat Self-managed 엔드투엔드 테스트#

MR에서는 엔드투엔드 테스트가 latest 버전의 AI Gateway와 통합된 GitLab Linux 패키지 인스턴스를 사용해 GitLab Self-Managed 인스턴스의 GitLab Duo Chat 기능을 테스트합니다. AI Gateway 인스턴스는 모의 응답을 반환하도록 설정되어 있습니다. 이 테스트의 결과를 보려면 e2e:test-on-omnibus-ee 하위 파이프라인을 열어 ai-gateway job을 확인합니다.

ai-gateway job은 테스트를 실행하기 전에 클라우드 라이선스를 활성화하고 테스트 사용자에게 GitLab Duo Pro 시트를 할당합니다.

자세한 내용은 AiGateway 시나리오를 참고합니다.

클라이언트 측 관측 가능성#

Duo Agentic Chat는 모니터링과 트리아지를 지원하기 위해 클라이언트 측 오류를 Sentry에 보고합니다.

Sentry 오류 캡처#

Sentry를 직접 호출하는 대신 ee/app/assets/javascripts/ai/duo_agentic_chat/observability/sentry_utils.js의 captureExceptionForDuoChat 래퍼를 사용합니다. 이 래퍼는 모든 예외에 feature_category: 'duo_chat' 태그를 자동으로 추가합니다. 호출자는 추가 태그를 붙일 수 있지만 feature_category는 재정의할 수 없습니다.

import { captureExceptionForDuoChat } from '../observability/sentry_utils';

// Report an error with no extra context.
captureExceptionForDuoChat(new Error('Something went wrong'));

// Report an error with extra metadata.
captureExceptionForDuoChat(error, { extra: { info, component: 'MyComponent' } });

프론트엔드에서 Duo Chat 통합#

두 개의 공유 Vue 컴포넌트 중 하나를 사용해 기능에 Duo Chat 통합을 추가할 수 있습니다. 두 컴포넌트 모두 현재 사용자가 Duo Chat을 사용할 수 있는지 확인하며, 사용할 수 없으면 아무것도 렌더링하지 않습니다.

  • DuoChatQuickAction(ee/app/assets/javascripts/ai/shared/widgets/duo_chat_quick_action.vue): Duo Chat을 열고 프롬프트를 보내는 버튼을 렌더링합니다. 페이지에서 댓글 요약이나 리소스 설명처럼 특정 Duo Chat 작업을 실행하고 싶을 때 사용합니다.
  • OpenAgenticChatButton(ee/app/assets/javascripts/ai/shared/widgets/open_agentic_chat_button.vue): 특정 에이전트가 미리 선택된 상태로 Duo Chat을 열되, 프롬프트는 자동으로 보내지 않는 버튼을 렌더링합니다. 커스텀 에이전트와 하나 이상의 프롬프트 제안과 함께 Duo Chat을 열고 싶을 때 사용합니다.

미리 정의된 프롬프트로 Duo Chat 열기(DuoChatQuickAction)#

DuoChatQuickAction을 사용해 Duo Chat을 열고 미리 정의된 프롬프트를 보내는 버튼을 추가합니다. 이 컴포넌트는 사용자의 현재 chat 모드 (Classic 또는 Agentic)를 존중해 각 모드에 맞는 프롬프트를 보냅니다.

이 컴포넌트는 ee/app/assets/javascripts/ai/shared/widgets/duo_chat_quick_action.vue에 있습니다.

속성#

속성 타입 필수 여부 설명
buttonText String 예 버튼에 표시되는 레이블입니다.
resourceId String 예 리소스의 GraphQL 전역 ID입니다(예: gid://gitlab/Issue/1). Duo Chat에 관련 객체의 컨텍스트를 제공하는 데 사용합니다.
trackingInfo Object 예 트래킹 메타데이터입니다. 최소 두 단어로 된 snake_case label 키를 포함해야 합니다(예: { label: 'issue_view_summary' }).
command Object 예 agenticPrompt(Agentic 모드용 자연어 프롬프트) 또는 agent(에이전트 객체)를 포함해야 합니다.
classicQuickAction String 아니요 Classic Chat 모드에서 보낼 슬래시 명령입니다(예: '/summarize_comments'). 기본값은 null입니다.
buttonOptions Object 아니요 하위 GlButton에 전달되는 추가 props입니다(예: { size: 'small' }).

이벤트#

이벤트 페이로드 설명
duo-tool-completed { name, args } 에이전틱 도구가 완료되면 발생합니다. name은 도구 이름이고, args는 도구의 출력입니다.

예시#

// app/assets/javascripts/my_feature/components/my_component.vue
import { DUO_CHAT_QUICK_ACTION_SUMMARIZE, DUO_CHAT_AGENT_PLANNER } from '~/ai/constants';
import { s__ } from '~/locale';

export default {
  name: 'MyComponent',
  components: {
    DuoChatQuickAction: () => import('ee_component/ai/shared/widgets/duo_chat_quick_action.vue'),
  },
  inject: {
    resourceGlobalId: { default: null },
    noteableType: { default: '' },
  },
  computed: {
    summarizeTracking() {
      return { label: 'my_feature_view_summary', property: this.noteableType };
    },
  },
  buttonOptions: { size: 'small' },
  classicQuickAction: DUO_CHAT_QUICK_ACTION_SUMMARIZE,
  summarizeCommand: {
    agent: { name: DUO_CHAT_AGENT_PLANNER },
    agenticPrompt: s__('AI|Summarize the comments on this issue.'),
  },
};
<duo-chat-quick-action
  v-if="resourceGlobalId"
  :button-text="s__('AISummary|View summary')"
  :resource-id="resourceGlobalId"
  :tracking-info="summarizeTracking"
  :classic-quick-action="$options.classicQuickAction"
  :command="$options.summarizeCommand"
  :button-options="$options.buttonOptions"
/>

프롬프트 제안과 함께 Duo Chat 열기(OpenAgenticChatButton)#

OpenAgenticChatButton을 사용해, 커스텀 에이전트가 미리 선택되고 Duo Agentic Chat의 빈 상태 UI에 나타나는 하나 이상의 프롬프트 제안과 함께 Duo Chat을 여는 버튼을 추가합니다.

이 컴포넌트는 ee/app/assets/javascripts/ai/shared/widgets/open_agentic_chat_button.vue에 있습니다.

속성#

속성 타입 필수 여부 설명
buttonText String 예 버튼에 표시되는 레이블입니다.
resourceId String 예 리소스의 GraphQL 전역 ID입니다. 스트리밍 응답을 바인딩하는 데 사용합니다.
agent Object 예 미리 선택할 에이전트로, name으로 식별합니다(예: { name: 'My Feature Assistant' }).
welcomeMessage String 아니요 사용자가 입력하기 전 빈 상태 패널에 표시되는 메시지입니다.
predefinedPrompts Array 아니요 빈 상태에 표시되는 제안 칩입니다.
buttonOptions Object 아니요 하위 GlButton에 전달되는 추가 props입니다.

이벤트#

이벤트 페이로드 설명
tool-completed { name, args } 에이전트의 도구가 완료되면 발생합니다. name은 도구 이름이고, args는 도구의 출력입니다.

예시: Duo Chat으로 웹 폼을 채우는 기능 구현#

구현은 세 부분으로 이루어집니다:

  1. 사용자로부터 정보를 수집하고 컴포넌트가 사용할 수 있는 구조화된 데이터를 반환하는 자체 도구를 가진 커스텀 에이전트. 각 에이전트는 반드시 자체 도구를 정의해야 하며, 공유되는 범용 도구는 없습니다.
  2. 해당 에이전트가 미리 선택되고 몇 가지 프롬프트 제안이 있는 상태로 Duo Chat을 여는 버튼.
  3. 도구 완료 이벤트를 수신해 결과를 적용하는 컴포넌트.
1단계: 도구를 가진 커스텀 에이전트 만들기#

AI Gateway 리포지터리의 duo_workflow_service/agent_platform/v1/flows/configs/ 아래에 플로 설정을 만듭니다. 에이전트용 자체 도구를 반드시 정의해야 합니다. 여기서 선택한 도구 이름이 3단계에서 프론트엔드가 수신할 이름입니다.

전체 에이전트 생성 과정은 foundational_chat_agents.md를 참고합니다.

2단계: 컴포넌트에 버튼 추가하기#

OpenAgenticChatButton을 임포트하고, 에이전트와 환영 메시지, 미리 정의된 프롬프트를 컴포넌트 수준 상수로 정의합니다.

// ee/app/assets/javascripts/my_feature/components/my_component.vue
import OpenAgenticChatButton from 'ee/ai/shared/widgets/open_agentic_chat_button.vue';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { TYPENAME_USER } from '~/graphql_shared/constants';
import { s__, __ } from '~/locale';

const AGENT = { name: __('My Feature Assistant') };
const TOOL_NAME = 'my_feature_tool';
const WELCOME_MESSAGE = s__('MyFeature|I can help you configure this feature.');
const PREDEFINED_PROMPTS = [
  s__('MyFeature|Enable read access to repositories.'),
  s__('MyFeature|Set up CI/CD pipeline permissions.'),
];

export default {
  name: 'MyComponent',
  components: { OpenAgenticChatButton },
  computed: {
    resourceId() {
      return convertToGraphQLId(TYPENAME_USER, window.gon?.current_user_id);
    },
  },
  methods: {
    handleToolCompleted({ name, args } = {}) {
      if (name !== TOOL_NAME || !args || typeof args !== 'object') return;

      // Apply the tool output to your component
      this.myField = args.my_field;
    },
  },
  AGENT,
  WELCOME_MESSAGE,
  PREDEFINED_PROMPTS,
};
<open-agentic-chat-button
  :button-text="__('Configure with Duo')"
  :resource-id="resourceId"
  :agent="$options.AGENT"
  :welcome-message="$options.WELCOME_MESSAGE"
  :predefined-prompts="$options.PREDEFINED_PROMPTS"
  @tool-completed="handleToolCompleted"
/>

predefinedPrompts는 chat 패널이 비어 있을 때 제안 칩으로 표시되는 문자열 배열입니다. welcomeMessage를 사용해 에이전트가 할 수 있는 일을 사용자에게 설명합니다. 둘 다 선택 사항이지만 첫 프롬프트까지의 시간을 줄이려면 권장합니다.

3단계: 도구 완료 이벤트 처리하기#

에이전트의 도구가 완료되면 OpenAgenticChatButton은 tool-completed 이벤트를 발생시킵니다. 페이로드는 { name, args } 형태이며, name은 도구 이름이고 args는 도구가 반환한 인수 객체입니다.

모든 도구 완료가 같은 이벤트로 브로드캐스트되므로, 페이로드에 따라 동작하기 전에 name이 에이전트 설정에서 정의한 도구 이름과 일치하는지 확인합니다.

const TOOL_NAME = 'my_feature_tool'; // Must match the tool name in your agent config

methods: {
  handleToolCompleted({ name, args } = {}) {
    if (name !== TOOL_NAME || !args || typeof args !== 'object') return;

    // Apply the tool output to your component
    this.myField = args.my_field;
  },
},

이벤트 페이로드는 다음과 같은 형태입니다:

{
  name: 'my_feature_tool', // tool name as defined in your agent config
  args: {
    // fields defined by your tool
    my_field: 'value',
  }
}

완전한 실제 예시는 ee/app/assets/javascripts/personal_access_tokens/components/create_granular_token/ask_dap_permissions.vue를 참고합니다.

알려진 제약 사항#

  • 에이전트는 반드시 자체 도구를 구현해야 합니다. AI Catalog 에이전트는 이 패턴에서 도구를 공유할 수 없습니다. (ai-assist#2113)
  • 커스텀 질문은 에이전트 YAML에 정의할 수 없으며, 호출하는 컴포넌트에 하드코딩해야 합니다. (GitLab#594533)
  • 특정 페이지용으로 만든 에이전트도 사이트 전체에서 기반 에이전트로 선택할 수 있습니다.
  • 스트리밍 응답은 지원하지 않습니다.
  • 에이전트는 기존 폼 필드 값을 읽지 않습니다.

GraphQL 서브스크립션#

Chat용 GraphQL 서브스크립션은 사용자 중심이기 때문에 동작이 조금 다릅니다. 사용자는 여러 브라우저 탭이나 IDE에서 동시에 Chat을 열어 둘 수 있습니다. 따라서 여러 클라이언트에 메시지를 브로드캐스트해 동기화 상태를 유지해야 합니다. chat 액션이 있는 aiAction 뮤테이션은 다음과 같이 동작합니다:

  1. 완료된 모든 Chat 메시지(사용자의 메시지 포함)는 userId, aiAction: "chat"를 식별자로 브로드캐스트됩니다.
  2. 스트리밍되는 Chat 메시지의 청크는 뮤테이션의 clientSubscriptionId를 식별자로 브로드캐스트됩니다.

Vue 컴포넌트에서 GraphQL 서브스크립션의 예시:

  1. 완료된 Chat 메시지

    import aiResponseSubscription from 'ee/graphql_shared/subscriptions/ai_completion_response.subscription.graphql';
    [...]
    
    apollo: {
     $subscribe: {
       aiCompletionResponse: {
         query: aiResponseSubscription,
         variables() {
           return {
             userId, // for example "gid://gitlab/User/1"
             aiAction: 'CHAT',
           };
         },
         result({ data }) {
           // handle data.aiCompletionResponse
         },
         error(err) {
           // handle error
         },
       },
     },
    
  2. 스트리밍된 Chat 메시지

    import aiResponseSubscription from 'ee/graphql_shared/subscriptions/ai_completion_response.subscription.graphql';
    [...]
    
    apollo: {
     $subscribe: {
       aiCompletionResponseStream: {
         query: aiResponseSubscription,
         variables() {
           return {
             aiAction: 'CHAT',
             userId, // for example "gid://gitlab/User/1"
             clientSubscriptionId // randomly generated identifier for every message
             htmlResponse: false, // important to bypass HTML processing on every chunk
           };
         },
         result({ data }) {
           // handle data.aiCompletionResponse
         },
         error(err) {
           // handle error
         },
       },
     },
    

clientSubscriptionId는 요청마다 고유해야 한다는 점에 유의합니다. clientSubscriptionId를 재사용하면 서브스크립션 응답에서 여러 원치 않는 부작용이 발생합니다.

GitLab Duo Chat GraphQL 쿼리#

  1. GitLab Duo Chat 설정

  2. GraphQL 익스플로러에 접속합니다.

  3. aiAction 뮤테이션을 실행합니다. 예시는 다음과 같습니다:

    mutation {
      aiAction(
        input: {
          chat: {
            resourceId: "gid://gitlab/User/1",
            content: "Hello"
          }
        }
      ){
        requestId
        errors
      }
    }
    
  4. 다음 쿼리를 실행해 응답을 가져옵니다:

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

응답을 가져올 수 없다면 graphql_json.log, sidekiq_json.log, llm.log, modelgateway_debug.log에 오류 정보가 있는지 확인합니다.

GitLab Duo Chat 대화 스레드 GraphQL 쿼리#

대화 스레드의 메시지 조회#

특정 스레드에서 메시지를 가져오려면 스레드 ID와 함께 aiMessages 쿼리를 사용합니다:

query {
  aiMessages(threadId: "gid://gitlab/Ai::Conversation::Thread/1") {
    nodes {
      requestId
      content
      role
      timestamp
      chunkId
      errors
    }
  }
}

새 대화 스레드 시작#

aiAction 뮤테이션에 threadId를 포함하지 않으면 새 스레드가 생성됩니다:

mutation {
  aiAction(input: {
    chat: {
      content: "This will create a new conversation thread"
    },
    conversationType: DUO_CHAT
  })
  {
    requestId
    errors
    threadId  # This will contain the ID of the newly created thread
  }
}

기존 대화 스레드에 새 메시지 생성#

기존 스레드에 메시지를 추가하려면 aiAction 뮤테이션에 threadId를 포함합니다:

mutation {
  aiAction(input: {
    chat: {
      content: "this is another message in the same thread"
    },
    conversationType: DUO_CHAT,
    threadId: "gid://gitlab/Ai::Conversation::Thread/1",
  })
  {
    requestId
    errors
    threadId
  }
}

프로덕션과 유사한 환경에서 GitLab Duo Chat 테스트#

GitLab Duo Chat는 Staging과 Staging Ref GitLab 환경에서 활성화되어 있습니다.

현재 GitLab Duo Chat는 Premium, Ultimate 등급 그룹의 구성원만 사용할 수 있으므로, GitLab 팀원이라면 Staging Ref가 변경 사항을 테스트하기 더 쉬운 곳일 수 있습니다. 이는 Staging Ref에서 자신을 인스턴스 Admin으로 만들 수 있고, Admin으로서 테스트용 라이선스가 있는 그룹을 쉽게 만들 수 있기 때문입니다.

중요한 테스트 고려 사항#

Note

GitLab Duo add-on 등급이 서로 다른 여러 그룹에 시트를 가진 사용자는 인스턴스 전체에서 가장 높은 등급의 경험을 얻습니다.

테스트 계정이 더 높은 등급의 add-on에 시트를 가지고 있으면 서로 다른 GitLab Duo add-on 간의 기능 분리를 테스트할 수 없습니다. 등급별로 제대로 테스트하려면 테스트해야 하는 등급마다 별도의 테스트 계정을 만듭니다.

Staging 테스트 그룹#

staging에서의 테스트를 간소화하기 위해, 적절한 라이선스와 add-on이 설정된 그룹 여러 개가 미리 만들어져 있습니다:

그룹 GitLab Duo Add-on GitLab 라이선스
duo_pro_gitlab_premium Pro Premium
duo_pro_gitlab_ultimate Pro Ultimate
duo_enterprise_gitlab_ultimate Enterprise Ultimate

Slack의 #g_duo_chat 채널에서 이 그룹의 Owner로 추가해 달라고 요청합니다. Owner로 추가된 뒤에는 보조 계정을 Developer 권한으로 그룹에 추가하고 GitLab Duo add-on 시트를 할당할 수 있습니다. 그런 다음 Developer 사용자로 로그인해 GitLab Duo Chat에 대한 접근 제어를 테스트할 수 있습니다.

라이브 환경에서 GitLab Duo Chat 엔드투엔드 테스트#

GitLab Duo Chat 엔드투엔드 테스트는 Staging과 Production GitLab 환경에서 지속적으로 실행됩니다.

이 테스트는 예약된 파이프라인에서 실행되며 엔드투엔드 사용자 경험이 올바르게 동작하는지 확인합니다. 결과는 #e2e-run-staging, #e2e-run-production Slack 채널에서 확인할 수 있습니다. 파이프라인은 아래에서 찾을 수 있으며, 액세스는 #s_developer_experience에서 요청할 수 있습니다:

제품 분석#

기능이 어떻게 사용되는지 더 잘 이해하기 위해, 프로덕션의 각 사용자 입력 메시지를 LLM과 Ruby로 분석하며, 그 분석 결과를 Snowplow 이벤트로 추적합니다.

이 분석에는 최신 iglu 스키마에 정의된 속성이 포함될 수 있습니다.

  • 카테고리와 세부 카테고리는 사용자의 실제 질문을 볼 수 없으므로 제품 매니저와 제품 디자이너가 미리 정의했습니다. 누락되거나 혼란스러운 카테고리가 있다고 판단되면 변경할 수 있습니다. 정의를 수정하려면 AI Gateway와 monolith 양쪽의 categories.xml을 업데이트합니다.
  • 수집되는 속성 목록은 labesl.xml에서 확인할 수 있습니다.
    • 다음은 아직 구현되지 않았습니다:
      • is_proper_sentence
    • 다음은 지원 종료되었습니다:
      • number_of_questions_in_history
      • length_of_questions_in_history
      • time_since_first_question

각 질문 카테고리와 세부 카테고리의 요청 수와 사용자 수는 이 Tableau 대시보드에서 확인할 수 있습니다(GitLab 팀원 전용).

access_duo_classic_chat 정책의 동작 방식#

이 표는 access_duo_classic_chat 정책이 여러 컨텍스트에서 true를 반환하기 위한 요구 사항을 설명합니다.

GitLab.com Dedicated 또는 GitLab Self-Managed 모든 인스턴스
프로젝트나 그룹 밖의 사용자(user.can?(:access_duo_classic_chat)) duo_features_enabled 그룹 설정이 켜져 있는 Premium 또는 Ultimate 등급 그룹에 최소 하나 이상 속해 있어야 합니다 - 인스턴스가 Premium 또는 Ultimate 등급이어야 합니다
- 인스턴스에서 duo_features_enabled 설정이 켜져 있어야 합니다
그룹 컨텍스트의 사용자(user.can?(:access_duo_classic_chat, group)) - experiment_and_beta_features 그룹 설정이 켜져 있는 Premium 또는 Ultimate 등급 그룹에 최소 하나 이상 속해 있어야 합니다
- 그룹의 최상위 조상 그룹이 Premium 또는 Ultimate 등급이어야 하고, 그룹에서 duo_features_enabled 설정이 켜져 있어야 합니다
- 인스턴스가 Premium 또는 Ultimate 등급이어야 합니다
- 인스턴스에서 duo_features_enabled 설정이 켜져 있어야 합니다
사용자가 그룹에 대해 최소 읽기 권한을 가지고 있어야 합니다
프로젝트 컨텍스트의 사용자(user.can?(:access_duo_classic_chat, project)) - experiment_and_beta_features 그룹 설정이 켜져 있는 Premium 또는 Ultimate 등급 그룹에 최소 하나 이상 속해 있어야 합니다
- 프로젝트의 최상위 조상 그룹이 Premium 또는 Ultimate 등급이어야 하고, 프로젝트에서 duo_features_enabled 설정이 켜져 있어야 합니다
- 인스턴스가 Ultimate 등급이어야 합니다
- 인스턴스에서 duo_features_enabled 설정이 켜져 있어야 합니다
사용자가 프로젝트에 대해 최소 읽기 권한을 가지고 있어야 합니다

(지원 종료) 이슈와 에픽 실험#

Note

이 절은 지원 종료되었으며 개발 시드 파일로 대체되었습니다.

평가 프레임워크를 사용하려면(평가 문서에 설명된 대로) 다음 Rake 태스크를 사용해 필요한 그룹과 프로젝트를 가져올 수 있습니다:

GITLAB_SIMULATE_SAAS=1 bundle exec 'rake gitlab:duo:setup_evaluation[<test-group-name>]'

그룹을 생성하려면(하위 그룹을 가져오는 데 필요) "saas" 모드가 필요한 Setup 클래스(ee/lib/gitlab/duo/developments/setup.rb 아래)를 사용하므로, GITLAB_SIMULATE_SAAS=1을 설정해야 합니다. 이는 가져오기를 성공적으로 완료하기 위한 것일 뿐이며, 원한다면 이후 GITLAB_SIMULATE_SAAS=0으로 다시 전환할 수 있습니다.

(지원 종료) 에픽과 이슈 픽스처#

Note

이 절은 지원 종료되었으며 개발 시드 파일로 대체되었습니다.

이 픽스처는 GitLab이 소유한 프로젝트와 그룹의 공개 이슈, 에픽을 복제한 것입니다. 샘플링할 때 내부 노트는 제외했습니다. 이 픽스처는 정본 gitlab 리포지터리에 커밋되어 있습니다. 픽스처를 생성하는 데 사용한 스니펫을 참고합니다.

Chat 프롬프트가 구성되는 방식#

모든 Chat 요청은 GitLab GraphQL API로 처리됩니다. 그리고 현재는 서드파티 LLM용 프롬프트가 GitLab 코드베이스에 하드코딩되어 있습니다.

하지만 Chat 프롬프트를 변경하고 싶다면, 파일 하나에서 문자열을 찾는 것처럼 간단하지 않습니다. 프롬프트가 여러 단계를 거쳐 조립되기 때문에 Chat 프롬프트 구성 과정은 따라가기 어렵습니다. Chat 프롬프트를 구성하는 흐름은 다음과 같습니다:

  1. GraphQL AI 뮤테이션에 API 요청이 만들어집니다. 이 요청에는 사용자 Chat 입력이 담겨 있습니다. (코드)

  2. GraphQL 뮤테이션이 Llm::ExecuteMethodService#execute를 호출합니다 (코드)

  3. Llm::ExecuteMethodService#execute는 GraphQL API로 chat 메서드가 전달된 것을 확인하고 Llm::ChatService#execute를 호출합니다 (코드)

  4. Llm::ChatService#execute는 schedule_completion_worker를 호출하며, 이는 Llm::BaseService(ChatService의 베이스 클래스)에 정의되어 있습니다 (코드)

  5. schedule_completion_worker는 Llm::CompletionWorker.perform_for를 호출하며, 이는 job을 비동기로 큐에 넣습니다 (코드)

  6. job이 실행되면 Llm::CompletionWorker#perform이 호출됩니다. 이 메서드는 사용자 입력과 그 밖의 메시지 컨텍스트를 역직렬화하여 Llm::Internal::CompletionService#execute로 전달합니다 (코드)

  7. Llm::Internal::CompletionService#execute는 Gitlab::Llm::CompletionsFactory#completion!을 호출합니다. 이 메서드는 원래 GraphQL 요청에서 ai_action을 꺼내 Gitlab::Llm::Completions::Chat의 새 인스턴스를 초기화하고 그 위에서 execute를 호출합니다 (코드)

  8. Gitlab::Llm::Completions::Chat#execute는 Gitlab::Duo::Chat::ReactExecutor를 호출합니다. (코드)

  9. Gitlab::Duo::Chat::ReactExecutor#execute는 #step_forward를 호출하고, 이는 Gitlab::Duo::Chat::StepExecutor#step을 호출합니다 (코드).

  10. Gitlab::Duo::Chat::StepExecutor#step은 Gitlab::Duo::Chat::StepExecutor#perform_agent_request를 호출하며, 이는 AI Gateway의 /v2/chat/agent/ 엔드포인트로 요청을 보냅니다 (코드).

  11. AI Gateway의 /v2/chat/agent 엔드포인트는 api.v2.agent.chat.agent.chat 함수에서 요청을 받습니다 (코드)

  12. api.v2.agent.chat.agent.chat은 gl_agent_remote_executor_factory를 통해 GLAgentRemoteExecutor를 생성합니다 (코드).

    GLAgentRemoteExecutor를 생성할 때 다음 파라미터가 전달됩니다:

    • tools_registry - 사용 가능한 모든 도구의 레지스트리이며, 팩토리를 통해 전달됩니다 (코드)
    • agent - 선택된 LLM 모델, 프롬프트 템플릿 등 프롬프트 정보를 감싸는 ReActAgent 객체
  13. api.v2.agent.chat.agent.chat은 GLAgentRemoteExecutor.on_behalf를 호출합니다. 이 메서드는 오류가 발생하면 가능한 한 빨리 예외를 발생시키기 위해 사용자 도구를 먼저 가져옵니다 (코드).

  14. api.v2.agent.chat.agent.chat은 GLAgentRemoteExecutor.stream을 호출합니다 (코드).

  15. GLAgentRemoteExecutor.stream은 메시지와 사용 가능한 도구 목록 등의 입력과 함께 agent(ReActAgent의 인스턴스)에서 astream을 호출합니다 (코드).

  16. ReActAgent는 프롬프트를 구성하며, 사용 가능한 도구는 시스템 프롬프트 템플릿에 삽입됩니다 (코드).

  17. ReActAgent.astream은 LLM 모델에 호출을 보냅니다 (코드)

  18. LLM 응답이 Rails로 반환됩니다 (코드 경로: ReActAgent.astream -> GLAgentRemoteExecutor.stream -> api.v2.agent.chat.agent.chat -> Rails)

  19. 이제 AI Gateway로 첫 요청을 보냈습니다. LLM이 첫 요청에 대한 답이 최종이라고 하면, Rails가 답을 파싱하고 이후 응답 처리를 위해 Gitlab::Llm::Completions::Chat로 그 답을 반환합니다.

  20. 답이 최종이 아니면, 첫 LLM 요청의 "thoughts"와 "picked tools"를 파싱한 뒤 관련 도구 클래스를 호출합니다. (코드 | 도구 클래스 예시)

    1. 도구 실행기 클래스는 Concerns::AiDependent를 포함하고 그 request 메서드를 사용합니다. (코드)
    2. request 메서드는 ai_request 인스턴스를 사용합니다 이는 Llm::Completions::Chat에서 context에 주입된 것입니다. Chat의 경우 이는 Gitlab::Llm::Chain::Requests::AiGateway입니다. (코드).
    3. ai_request는 /v1/prompts/chat 엔드포인트로 프롬프트를 보냅니다 (코드).
    4. AI Gateway의 /v1/prompts/chat 엔드포인트는 api.v1.prompts.invoke에서 요청을 받습니다 (코드).
    5. api.v1.prompts.invoke는 도구 프롬프트 레지스트리에서 올바른 도구 프롬프트를 가져옵니다 (코드).
    6. 프롬프트는 스트림이나 스트리밍하지 않는 호출 중 하나로 호출됩니다.
    7. 도구의 답이 최종이 아니면 응답을 agent_scratchpad에 추가하고 Gitlab::Duo::Chat::ReactExecutor의 루프가 다시 시작되어 요청에 추가 컨텍스트를 더합니다. 최종 답에 도달할 때까지 최대 10회 반복합니다. (코드)

GitLab Duo Chat 오류 코드 해석#

GitLab Duo Chat에는 디버깅을 돕기 위해 정해진 의미를 가진 오류 코드가 있습니다.

모든 GitLab Duo Chat 오류 코드 목록은 GitLab Duo Chat 문제 해결 문서를 참고합니다.

GitLab Duo Chat을 개발할 때는 오류를 반환할 때 이 오류 코드를 포함하고, 특히 사용자에게 노출되는 오류라면 문서화합니다.

오류 코드 형식#

오류 코드는 형식을 따릅니다.

예를 들면:

  • M1001: 모놀리스 계층의 네트워크 통신 오류입니다.
  • G2005: AI Gateway 계층의 데이터 형식/처리 오류입니다.
  • A3010: 서드파티 API의 인증 또는 데이터 접근 권한 오류입니다.

오류 코드 레이어 식별자#

코드 레이어
M 모놀리스
G AI Gateway
A 서드파티 API

오류 시리즈#

시리즈 유형
1000 네트워크 통신 오류
2000 데이터 형식/처리 오류
3000 인증 및/또는 데이터 접근 권한 오류
4000 코드 실행 예외
5000 잘못된 설정 또는 잘못된 파라미터 오류
6000 의미론적 또는 추론 오류(모델이 이해하지 못하거나 헐루시네이션을 일으키는 경우)