极狐 GitLab

基于第三方集成的 AI 功能

极狐GitLab Duo 功能由 AI 模型和集成提供支持。本文档概述了在极狐GitLab 中使用 AI 功能进行开发的相关内容。

有关在开发环境中设置极狐GitLab Duo 许可的详细说明,请参阅极狐GitLab Duo 本地开发许可

设置您的本地开发环境#

这里列出了从一台全新的、未安装 GDK 的电脑开始,到完全具备 AI 开发能力所需完成的所有主要步骤。

准备您的 GDK#

请按照极狐GitLab 开发套件中的说明,为本地开发目的设置极狐GitLab Duo。这些说明描述了如何在您的本地环境中满足前提条件,并设置核心后端组件。

更新现有的 GDK#

如果您已经安装了 GDK,仍然必须参考极狐GitLab 开发套件说明来设置 DAP,包括正确的环境变量、NGINX、您的国内 SOTA 大模型密钥等。

运行 gitlab:duo:setup 任务#

运行 gitlab:duo:setup Rake 任务,以播种一个测试群组和一个已启用极狐GitLab Duo 功能的项目。

此任务是幂等的,如果 `gitlab-duo` 群组已存在,则会跳过重新播种。 要从此任务强制重新播种,请设置 `GITLAB_DUO_RESEED=1`。 有关所用种子数据的详细信息,请参阅[开发种子文件](../development_seed_files.md#seed-project-and-group-resources-for-gitlab-duo)。

这可以确保您的实例或群组拥有正确的许可证、设置和功能标志,以便在本地测试极狐GitLab Duo 功能。以下是几种选项。如果您不确定,请使用选项 1。

运行此脚本时,始终会创建 Duo Core 附加组件。

请务必从极狐GitLab Rails 根目录(通常为 /path/to/gdk/gitlab)运行 Rake 任务,而不是从 GDK 根目录。

  1. JihuLab.com 模式

    shell
    GITLAB_SIMULATE_SAAS=1 bundle exec 'rake gitlab:duo:setup'

    此操作会:

    • 创建一个名为 gitlab-duo 的测试群组,其中包含一个名为 test 的项目
    • 为该群组应用旗舰版许可证
    • 为该群组设置极狐GitLab Duo Enterprise 席位
    • 启用该群组的所有功能标志
    • 更新群组设置以启用所有可用的极狐GitLab Duo 功能

    或者,如果您想为该群组添加极狐GitLab Duo Pro 许可证(仅启用于部分功能),可以运行:

    shell
    GITLAB_SIMULATE_SAAS=1 bundle exec 'rake gitlab:duo:setup[duo_pro]'

    要仅测试 Duo Core 功能,可以运行:

    shell
    GITLAB_SIMULATE_SAAS=1 bundle exec 'rake gitlab:duo:setup[duo_core]'
  2. 私有化部署模式

    shell
    GITLAB_SIMULATE_SAAS=0 bundle exec 'rake gitlab:duo:setup'

    此操作会:

    • 创建一个名为 gitlab-duo 的测试群组,其中包含一个名为 test 的项目
    • 为实例应用旗舰版许可证
    • 为实例设置极狐GitLab Duo Enterprise 席位
    • 启用实例的所有功能标志
    • 更新实例设置以启用所有可用的极狐GitLab Duo 功能

    或者,如果您想为实例添加极狐GitLab Duo Pro 附加组件(仅启用于部分功能),可以运行:

    shell
    GITLAB_SIMULATE_SAAS=0 bundle exec 'rake gitlab:duo:setup[duo_pro]'

    要仅测试 Duo Core 功能,可以运行:

    shell
    GITLAB_SIMULATE_SAAS=0 bundle exec 'rake gitlab:duo:setup[duo_core]'

脚本无错误运行完成后,请转到 gitlab-duo/test,验证您是否能看到极狐GitLab Duo Chat。向 Chat 发送一个问题,确保没有错误。

故障排除#

在大多数情况下,您只需运行 AI 服务脚本即可重置 GDK 环境变量,这通常足以修复出现的任何错误。

如果您收到错误 A9999,这是一个通用错误。最常见的原因是未按照 AI Gateway 安装说明中的描述正确设置 AI Gateway URL。 否则,请确保 gitlab-ai-gateway 仓库中的测试通过(使用 make test),并且 gdk tail gitlab-ai-gateway 没有返回错误。

A1003 更多是与权限相关,可能是国内 SOTA 大模型令牌无效/缺失,或者 gcloud 配置错误。

在 Agentic Chat 中,可能会发生身份验证错误,并且不会导致 A1003 错误。使用 gdk tail duo-workflow-service 确保工作流服务正常运行。如果您看到身份验证错误,则需要获取一个新的国内 SOTA 大模型密钥重新运行 AI 设置脚本

本地开发技巧#

  1. 当响应在用户界面中显示时间过长时,请考虑通过运行 gdk restart rails-background-jobs 重启 Sidekiq。如果不起作用,请尝试 gdk kill 然后 gdk start
  2. 或者,完全绕过 Sidekiq,同步运行服务。这有助于调试错误,因为 GraphQL 错误现在可在网络检查器中查看,而不是在 Sidekiq 日志中。为此,请在 Llm::CompletionWorker 类中临时修改 perform_for 方法,将 perform_async 改为 perform_inline
  3. 测试模型选择时,将 export FETCH_MODEL_SELECTION_DATA_FROM_LOCAL=1 添加到您的 env.runit 文件中,这样您的 GDK 将从本地 AI Gateway 而不是云连接的 AIGW 获取模型信息。

功能开发(抽象层)#

功能标志#

对任何 AI 功能工作应用以下功能标志:

  • 一个适用于所有其他 AI 功能的通用标志 (ai_global_switch)。它默认启用。
  • 一个特定于该功能的标志。功能标志名称必须不同于许可功能名称。

有关所有功能标志及其使用方法的列表,请参阅功能标志跟踪史诗

将功能标志推送到 AI Gateway#

您可以将功能标志推送到 AI Gateway。这有助于逐步推出面向用户的更改,即使功能驻留在 AI Gateway 中也是如此。 请参阅以下示例:

ruby
# 将功能标志状态推送到 AI Gateway。 Gitlab::AiGateway.push_feature_flag(:new_prompt_template, user)

之后,您可以在 AI Gateway 中通过以下方式使用功能标志状态:

python
1from ai_gateway.feature_flags import is_feature_enabled 2 3# 检查功能标志“new_prompt_template”是否已启用。 4if is_feature_enabled('new_prompt_template'): 5 # 使用新提示模板构建提示 6else: 7 # 使用旧提示模板构建提示

重要提示:在清理步骤中,请先移除 AI Gateway 仓库中的功能标志,然后再移除 GitLab-Rails 仓库中的标志。 如果先在 GitLab-Rails 仓库中清理标志,AI Gateway 中的功能标志将立即被禁用(因为这是默认状态),从而可能导致意外行为。

重要提示:在 AI Gateway 中清理功能标志会立即将更改分发到所有极狐GitLab 实例,包括 JihuLab.com 和私有化部署。

技术细节

  • push_feature_flag 针对已启用的功能标志运行时,该标志的名称会被缓存在当前上下文中,之后当 GitLab-Sidekiq/Rails 向 AI Gateway 发送请求时,会将其附加到 x-gitlab-enabled-feature-flags HTTP 头中。
  • 当前端客户端(例如 LSP)请求 User JWT(UJWT)以进行直接 AI Gateway 通信时,极狐GitLab 会返回:
    • 公共头(包括 x-gitlab-enabled-feature-flags)。
    • 生成的 UJWT(1 小时过期)。

前端客户端必须在 UJWT 过期时重新生成它。后端更改(例如通过 ChatOps 更新功能标志)会导致头值过时。这些头值将在下次生成 UJWT 时刷新。

同样,我们也有 push_frontend_feature_flag 用于将功能标志推送到前端。

GraphQL API#

要使用抽象层连接到 AI 提供商的 API,请使用一个名为 aiAction 的可扩展 GraphQL API。 input 接受键/值对,其中 key 是需要执行的操作。我们每次变更请求只允许一个 AI 操作。

变更示例:

graphql
mutation { aiAction(input: {summarizeComments: {resourceId: "gid://gitlab/Issue/52"}}) { clientMutationId } }

例如,假设我们要构建一个“解释代码”的操作。为此,我们使用一个新键 explainCode 扩展 input。变更如下所示:

graphql
1mutation { 2 aiAction( 3 input: { 4 explainCode: { resourceId: "gid://gitlab/MergeRequest/52", code: "foo() { console.log() }" } 5 } 6 ) { 7 clientMutationId 8 } 9}

然后,GraphQL API 使用国内 SOTA 大模型客户端发送响应。

如何接收响应#

向 AI 提供商的 API 请求在后台作业中处理。因此,我们不会保持请求处于活动状态,前端需要将请求与来自订阅的响应进行匹配。

仅使用 `userId` 和 `resourceId` 来确定对请求的正确响应可能会导致问题。例如,当两个 AI 功能使用相同的 `userId` 和 `resourceId` 时,两个订阅都会收到彼此的响应。为了防止这种干扰,我们引入了 `clientSubscriptionId`。

要匹配 aiCompletionResponse 订阅上的响应,您可以向 aiAction 变更提供一个 clientSubscriptionId

  • clientSubscriptionId 应在每个功能内和页面内是唯一的,以免干扰其他 AI 功能。我们建议使用 UUID
  • 只有在 aiAction 变更中提供了 clientSubscriptionId 时,才会将其用于广播 aiCompletionResponse
  • 如果未提供 clientSubscriptionId,则 aiCompletionResponse 仅使用 userIdresourceId

以下是一个总结评论的变更示例,我们在变更中提供了一个 randomId

graphql
1mutation { 2 aiAction( 3 input: { 4 summarizeComments: { resourceId: "gid://gitlab/Issue/52" } 5 clientSubscriptionId: "randomId" 6 } 7 ) { 8 clientMutationId 9 } 10}

然后,在我们的组件中,我们使用 userIdresourceIdclientSubscriptionId ("randomId") 监听 aiCompletionResponse

graphql
1subscription aiCompletionResponse( 2 $userId: UserID 3 $resourceId: AiModelID 4 $clientSubscriptionId: String 5) { 6 aiCompletionResponse( 7 userId: $userId 8 resourceId: $resourceId 9 clientSubscriptionId: $clientSubscriptionId 10 ) { 11 content 12 errors 13 } 14}

Chat 的订阅行为有所不同。

为了避免同时存在过多并发订阅,您还应该仅在发送变更后通过使用 skip() 来订阅该订阅。

澄清不同的 ID 参数#

在使用 aiAction 变更时,有几个 ID 参数用于正确路由请求和响应。以下是每个参数的作用:

  • user_id(必需)
    • 用途:识别和验证请求用户
    • 用于:权限检查、请求归属和响应路由
    • 示例:gid://gitlab/User/123
    • 注意:此 ID 由 GraphQL API 框架自动包含
  • client_subscription_id(推荐用于流式传输或多个功能)
    • 客户端生成的 UUID,用于跟踪特定的请求/响应对
    • 当使用流式响应或当多个 AI 功能共享同一页面时必需
    • 示例:"9f5dedb3-c58d-46e3-8197-73d653c71e69"
    • 对于简单的、无流式传输的独立请求,可以省略
  • resource_id(上下文相关 - 某些功能必需)
    • 用途:引用为 AI 操作提供上下文的特定极狐GitLab 实体(项目、议题、合并请求)
    • 用于:权限验证和上下文信息收集
    • 实际示例:"gid://gitlab/Issue/164723626"
    • 注意:某些功能可能不需要特定资源
  • project_id(上下文相关 - 某些功能必需)
    • 用途:标识 AI 操作的项目上下文
    • 用于:项目特定权限检查和上下文
    • 实际示例:"gid://gitlab/Project/278964"
    • 注意:某些功能可能不需要特定项目

当前抽象层流程#

下图以 VertexAI 为例。您可以使用不同的提供商。

Rendering chart...

为多个模型重用现有 AI 组件#

我们努力为每个 LLM 优化 AI 组件,例如提示词、输入/输出解析器、工具/函数调用, 但是,为每个模型分化组件可能会增加维护开销。 因此,通常建议为多个模型重用现有组件,只要这不会降低功能质量即可。 以下是一些经验法则:

  1. 为多个模型迭代现有的提示词模板。除非对特定模型造成质量下降,否则不要引入新的模板。
  2. 为多个模型迭代现有的输入/输出解析器和工具/函数调用。除非对特定模型造成质量下降,否则不要引入新的解析器或调用。
  3. 如果检测到某个特定模型的质量下降,则应为该特定模型分化共享组件。

一个例子是,我们可以将针对国内 SOTA 大模型的特定 CoT 优化应用于其他模型(如 Mixtral),只要这不会导致质量下降。

监控#

安全#

请参阅人工智能 (AI) 功能的安全编码指南

帮助#