GitLab Duo 聊天
GitLab Duo 聊天的目标是借助人工智能帮助用户在软件开发生命周期(SDLC)的各个阶段完成创意生成、创作任务以及学习任务,使其更快速高效。
聊天 是 GitLab Duo 产品的一部分。
聊天可以回答不同的问题并执行特定任务。这借助 提示词 和 工具 实现。
为了回答用户在聊天界面提出的问题,GitLab 会向 Rails 后端发送一个 GraphQL 请求。Rails 后端随后通过 AI 网关 向大语言模型(LLM)发送指令。
哪些用例最适合为聊天功能做贡献?
我们计划将聊天功能应用于所有能从对话式交互中受益的用例和工作流,这种交互发生在用户与由大语言模型(LLM)驱动的AI之间。通常包括:
- 创意生成与构思任务,以及学习任务——这类任务通过迭代解决比一次性交互更有效率和效果。
- 任务——这类任务通常可通过一次性交互满足,但可能需要细化或演变为对话。
- 后者包括那些AI 可能第一次无法完全正确理解,但用户可以通过更精确地告诉 AI 需求来轻松纠正方向的任务。例如,“解释这段代码”是一个常见问题,大多数时候能得到令人满意的答案,但有时用户可能有额外疑问。
- 受益于对话历史的任务,这样用户和 AI 都无需重复之前的内容。
聊天的目标是要具备上下文感知能力,最终能够访问用户有权访问的所有 GitLab 资源。最初,上下文仅限于单个问题、史诗(epic)的内容以及 GitLab 文档。此后又增加了其他上下文,如代码选择和代码文件。目前,团队正在推进漏洞上下文和流水线作业上下文的添加工作,以便用户可以针对这些上下文提问。
为了扩展上下文感知能力,从而在整个 DevSecOps 领域扩大创意生成、构思和学习用例的规模,Duo 聊天团队欢迎其他 GitLab 团队及更广泛社区对聊天平台的贡献。他们是加速这些用例和工作流的专家。
哪些用例更适合作为独立的 AI 功能实现?
哪些用例更适合作为独立 AI 功能实现,或者至少也适合作为独立 AI 功能实现?
- 范围狭窄的任务——通过将 AI 深度集成到现有工作流中可加速此类任务。
- 无法从与 AI 的对话中获益的任务。
为了让这一点更具体,这里有一个例子。
根据变更生成提交信息最好集成到提交信息编写工作流中。
- 没有 AI 时,编写提交信息可能需要十秒。
- 当在 IDE 的 提交信息 字段自动填充 AI 生成的提交信息时,该任务耗时缩短至一秒。
使用聊天功能编写提交信息可能比手动编写更耗时。用户需要切换到聊天窗口,输入请求,然后将结果复制到提交信息字段。
话说回来,这并不意味着聊天功能不能编写提交信息,也不是说会被阻止这样做。如果聊天功能拥有提交上下文(可能出于非提交信息编写的目的而添加),用户当然可以要求对提交内容进行任何操作,包括编写提交信息。但用户不太可能用聊天功能来做这件事,因为这只会浪费时间。注:若通过用户编写的提示词在聊天中生成提交信息,与基于专用提交信息创建功能的静态提示词生成的结果可能不同。
设置 GitLab Duo 聊天
要在本地设置 Duo 聊天,请遵循 AI 功能通用设置说明。
使用 GitLab Duo Chat
提示词是 GitLab Duo Chat 系统中最核心的部分。提示词是发送给大语言模型(LLM)以执行特定任务的指令。
提示词的状态是经过数周迭代的结果。如果想要修改当前工具中的任何提示词,必须将其置于功能开关(feature flag)之后。
如果有新的或更新的提示词,请让 Duo Chat 团队 的成员进行审核,因为他们对这些提示词有丰富的经验。
故障排除
在使用本地聊天功能时,可能会遇到错误。本节记录了最常见的问题。 如果您发现未记录的问题,应在找到解决方案后在此处记录。
| 问题 | 解决方案 |
|---|---|
| GitLab UI 中没有聊天按钮 | 确保您的用户属于拥有 Premium 或 Ultimate 许可证且已启用聊天的群组。 |
| 聊天回复显示“被身份验证提供者禁止”错误 | 后端无法访问大语言模型(LLM)。确保您的 AI 网关 设置正确。 |
| 请求在 UI 中显示过慢 | 考虑通过运行 gdk restart rails-background-jobs 重启 Sidekiq。如果无效,尝试 gdk kill 后再 gdk start。或者,您可以完全绕过 Sidekiq。为此,临时将 Llm::CompletionWorker.perform_async 语句替换为 Llm::CompletionWorker.perform_inline |
| 当 GDK 以非 SaaS 模式运行时,GitLab UI 中没有聊天按钮 | 您没有云连接器访问令牌记录或分配的席位。若要创建云连接器访问记录,请在 Rails 控制台中输入以下代码:CloudConnector::Access.new(data: { available_services: [{ name: "duo_chat", serviceStartTime: ":date_in_the_future" }] }).save。 |
更多信息,请参阅 解读 GitLab Duo Chat 错误码,这些错误码有助于故障排查。
参与 GitLab Duo Chat 开发
从代码角度来看,聊天功能的实现方式与其他 AI 功能类似。了解更多关于 GitLab AI 抽象层 的信息。
聊天功能使用了 零样本代理,它将用户问题和相关上下文发送到 AI 网关,后者构建提示词并将请求发送到大语言模型。
大语言模型会决定是否直接回答,还是需要使用其中一个定义的工具。
每个工具都有自己的提示词,向大语言模型提供如何使用该工具收集信息的指令。工具设计为自给自足,避免与大语言模型之间多次往返请求。
工具收集完所需信息后,会返回给零样本代理,该代理询问大语言模型是否已收集足够信息来提供最终答案。
自定义与 GitLab Duo Chat 的交互
您可以通过多种方式自定义用户与 GitLab Duo Chat 的交互。
以编程方式打开 GitLab Duo Chat
为了给用户提供更动态的方式访问 GitLab Duo Chat,您可以将功能直接集成到他们的应用程序中,打开 GitLab Duo Chat 界面。以下示例展示了如何使用事件监听器和 GitLab Duo Chat 全局状态打开 GitLab Duo Chat 抽屉:
import { duoChatGlobalState } from '~/super_sidebar/constants';
myFancyToggleToOpenChat.addEventListener('click', () => {
duoChatGlobalState.isShown = true;
});使用预定义提示启动 GitLab Duo Chat
在某些场景下,当用户打开 GitLab Duo Chat 时,你可能希望引导他们关注特定主题或查询。我们提供了一个实用函数,它会打开 DuoChat 抽屉并向队列发送命令,供 DuoChat 执行。这会触发加载状态并以给定提示开始流式传输。
import { sendDuoChatCommand } from 'ee/ai/utils';
[...]
methods: {
openChatWithPrompt() {
sendDuoChatCommand(
{
question: '/feedback' // 这是你的提示
resourceId: 'gid:://gitlab/WorkItem/1', // 用于识别流式操作的唯一 ID
variables: {} // 执行查询时想传递给 ee/app/assets/javascripts/ai/graphql/chat.mutation.graphql 的任何额外 GraphQL 变量
}
)
}
}注意 sendDuoChatCommand 无法被链式调用,这意味着你可以向 DuoChat 发送一条命令,必须等待该操作完成才能发送不同的命令,否则之前的命令可能无法按预期工作。
此增强功能通过引导 GitLab Duo Chat 中的对话朝着预先定义的兴趣领域或关注点发展,从而提供更定制化的用户体验。
添加新工具
若要添加新工具,需同时修改 AI 网关 和 Rails 单体应用。主要聊天提示存储并在 AI 网关中组装。Rails 端负责组装提示所需的参数并发送给 AI 网关。AI 网关负责组装聊天提示,并根据用户的订阅和附加组件选择用户可用的聊天工具。
当 LLM 选择要使用的工具时,该工具会在 Rails 端执行。工具使用不同端点向 AI 网关发起请求。添加新工具时,请考虑到 AI 网关与具有不同版本的多个客户端和 GitLab 应用程序配合工作。这意味着旧版 GitLab 将不了解新工具。若要添加新工具,请联系 Duo Chat 团队。我们正在针对此问题制定长期解决方案 问题 #466247。
AI 网关中的变更
-
在
ai_gateway/chat/tools/gitlab.py中为新工具创建一个类。此类应包含以下属性:- 工具的
name - 工具处理的 GitLab
resource - 工具功能的
description - 问题及期望答案的
example
- 工具的
-
将工具添加到
ai_gateway/chat/tools/gitlab.py中的__all__工具列表中。 -
在
ai_gateway/chat/toolset.py中将工具类添加到DuoChatToolsRegistry中,并附带适当的 Unit Primitive。 -
为你的更改添加测试。
Rails 单体应用中的变更
-
在
ee/lib/gitlab/llm/chain/tools/文件夹中为工具创建文件。可参考现有工具(如issue_reader或epic_reader)作为模板。 -
编写工具类,其中包含关于如何使用该工具收集信息的大语言模型指令——即该工具使用的主要提示语。
-
在工具中实现代码,以解析大语言模型的响应并将其返回给 聊天代理。
-
将新工具名称添加到
ee/lib/gitlab/llm/completions/chat.rb的tools数组中,以便代理了解它。
整体测试
使用对大语言模型发出真实请求的 RSpec 测试来测试和迭代提示语。
关键是要通过提示语和工具描述正确指导大语言模型,保持工具的自足性,并将响应返回给零样本代理。通过一些提示语试验,添加新工具可以扩展 Chat 功能的能力。
有现成的简短 视频 覆盖了这个主题。
使用多线程对话
如果你正在构建与Duo Chat对话交互的功能,你需要理解线程是如何工作的。
Duo Chat支持多个对话。每个对话由一个线程表示,该线程包含多条消息。线程的重要属性包括:
id:回复线程时需要此id。conversation_type:这用于区分不同的Duo Chat对话类型。请参阅thread conversation types list。- 如果你的功能需要自己的对话类型,请联系Duo Chat团队。
如果你的功能需要直接调用GraphQL API,以下查询和变更可用,你必须指定conversation_type。
- Query.aiConversationThreads:列出线程
- Query.aiMessages:列出单个线程的消息。必须指定
threadId。 - Mutation.aiAction:创建一条消息。如果指定了
threadId,则消息将被附加到该线程中。
所有聊天对话都有一个保留期,由管理员控制。默认保留期为最后回复后的30天。
开发者资源
- 示例GraphQL查询 - 请参阅本文档下方的示例
调试
若要收集有关完整请求的更多见解,可使用Gitlab::Llm::Logger文件进行调试日志记录。
生产环境的默认日志级别为INFO,且不得用于记录任何可能包含个人身份信息的数据。
若要跟踪抽象层上与AI请求相关的调试消息,你可以使用:
export LLM_DEBUG=1
gdk start
tail -f log/llm.log生产环境调试
所有与生产和故障排除相关的调试信息都收录在 Duo Chat 值班手册 中。
通过LangSmith追踪
追踪是了解LLM应用程序行为的强大工具。 LangSmith拥有业界领先的追踪能力,并与GitLab Duo Chat集成。追踪可以帮助你排查以下问题:
- 我是GitLab Duo Chat的新手,想了解其内部运作机制。
- 当收到意外答案时,过程具体在哪里失败。
- 哪个过程是延迟的瓶颈。
- 对于模糊的问题使用了哪个工具。
追踪特别适用于对大型数据集运行GitLab Duo Chat评估的场景。 LangSmith集成可与任何工具配合使用,包括Prompt Library。
使用LangSmith进行追踪
追踪仅在开发和测试环境中可用。 在生产环境中不可用。
-
访问LangSmith并创建账户
- 可选:提交访问请求,以添加到LangSmith中的GitLab组织。
-
创建API密钥(注意创建位置——可在个人命名空间或GL命名空间中创建)。
-
在GDK中设置以下环境变量。你可以在
env.runit中定义,或在终端中直接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 # 扩展puma超时以配合Prompt Library作为评估工具使用LangSmith。项目名称可以是LangSmith中现有的项目或新项目。只需在环境变量中输入新名称即可——请求过程中会自动创建项目。
-
重启GDK。
-
向Chat提问任意问题。
-
观察LangSmith页面 > Projects > [项目名称]。“Runs"标签页应包含你最近的请求。
一键评估你的合并请求
若要使用中央评估框架(即CEF)评估你的合并请求,你可以使用评估运行器(仅内部可用)。遵循在合并请求上运行评估的说明。
防止合并请求中的回归问题
当你对Duo Chat或相关组件进行修改时,你应该运行回归评估器,以检测合并请求中出现的质量下降和缺陷。它涵盖任何Duo Chat执行模式,包括工具执行和斜杠命令。
要运行回归评估器,请在合并请求上运行评估,并点击回归评估器的播放按钮。之后,你可以将合并请求的评估结果与主分支进行比较。确保在LangSmith的比较页面中没有出现质量下降和缺陷。
虽然解读比较结果没有严格的指导方针,但以下是一些值得考虑的有用提示:
- 如果退化的分数数量超过改进的分数数量,这可能表明合并请求引入了质量下降。
- 如果任何示例在评估过程中遇到错误,这可能暗示合并请求存在潜在缺陷。
在这两种情况下,我们建议进一步调查:
- 将你的结果与每日评估结果进行比较。例如,查看昨天和前天的每日评估结果。
- 如果你观察到这些每日评估中有类似的模式,那么你的合并请求很可能可以安全合并。然而,如果模式不同,则可能表明你的合并请求引入了意外变更。
我们强烈建议至少在以下环境中运行回归评估器:
| 环境 | 评估流水线名称 |
|---|---|
| GitLab 自托管且广泛采用的自定义模型 | duo-chat regression sm: [bedrock_mistral_8x7b_instruct] |
| GitLab.com 和 GitLab Duo 企业版附加组件 | duo-chat regression .com: [duo_enterprise] |
| GitLab.com 和 GitLab Duo 专业版附加组件 | duo-chat regression .com: [duo_pro] |
此外,你还可以运行其他评估器,例如 gitlab-docs,它在特定范围内有更全面的数据库集。有关更多信息,请参阅可用的评估流水线。
向回归数据集中添加示例
当你引入新功能或收到用户的回归报告时,你应该向回归数据集中添加一个新示例以扩大覆盖范围。要向回归数据集中添加示例,请遵循此章节。
有关更多信息,请参阅回归评估器的指南。
GitLab Duo 聊天 自托管端到端测试
在合并请求(MRs)中,端到端测试通过使用集成有最新版AI网关的GitLab Linux包实例,来演练自托管实例的Duo聊天功能。该AI网关实例配置为返回mock responses。
要查看这些测试的结果,请打开子流水线e2e:test-on-omnibus-ee并查看ai-gateway作业。
ai-gateway作业会激活云许可证,然后在运行测试前为测试用户分配一个Duo Pro席位。
更多信息,参见AiGateway 场景。
GraphQL 订阅
聊天的GraphQL订阅行为略有不同,因为它是面向用户的。用户可能在多个浏览器标签页或IDE中打开聊天。因此我们需要向多个客户端广播消息以保持同步。带有chat操作的aiAction突变的行为如下:
- 所有完整的聊天消息(包括用户的消息)都会以
userId和aiAction: "chat"作为标识符进行广播。 - 流式聊天消息的分块会以突变的
clientSubscriptionId作为标识符进行广播。
Vue组件中的GraphQL订阅示例:
-
完整聊天消息
import aiResponseSubscription from 'ee/graphql_shared/subscriptions/ai_completion_response.subscription.graphql'; [...] apollo: { $subscribe: { aiCompletionResponse: { query: aiResponseSubscription, variables() { return { userId, // 例如 "gid://gitlab/User/1" aiAction: 'CHAT', }; }, result({ data }) { // 处理 data.aiCompletionResponse }, error(err) { // 处理错误 }, }, }, -
流式聊天消息
import aiResponseSubscription from 'ee/graphql_shared/subscriptions/ai_completion_response.subscription.graphql'; [...] apollo: { $subscribe: { aiCompletionResponseStream: { query: aiResponseSubscription, variables() { return { aiAction: 'CHAT', userId, // 例如 "gid://gitlab/User/1" clientSubscriptionId // 每条消息随机生成的标识符 htmlResponse: false, // 重要:避免每分块都处理HTML }; }, result({ data }) { // 处理 data.aiCompletionResponse }, error(err) { // 处理错误 }, }, },
请注意,clientSubscriptionId必须对每个请求唯一。重复使用clientSubscriptionId会在订阅响应中导致多种意外副作用。
Duo 聊天 GraphQL 查询
-
访问GraphQL 探索器。
-
执行
aiAction突变。示例如下:mutation { aiAction( input: { chat: { resourceId: "gid://gitlab/User/1", content: "Hello" } } ){ requestId errors } } -
执行以下查询获取响应:
query { aiMessages { nodes { requestId content role timestamp chunkId errors } } }
如果无法获取响应,请检查graphql_json.log、sidekiq_json.log、llm.log或modelgateway_debug.log是否包含错误信息。
Duo 聊天对话线程 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: "这将创建新的对话线程"
},
conversationType: DUO_CHAT
})
{
requestId
errors
threadId // 此处将包含新创建线程的ID
}
}在现有对话线程中创建新消息
若要在现有线程中添加消息,请在 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 中 将自己设为实例管理员,并且作为管理员,能轻松创建用于测试的有许可的组。
重要测试注意事项
注意:若用户的账户在多个带有不同 Duo 附加组件层级的组中拥有席位,则会在整个实例中获得最高层级的体验。
如果你的测试账户在更高层级的 Duo 附加组件中拥有席位,就无法测试不同 Duo 附加组件之间的功能分离。若要正确测试不同层级,需为每个需要测试的层级创建单独的测试账户。
Staging 测试组
为简化在 staging 上的测试,已创建了多个预配置组,它们配备了相应的许可证和附加组件:
| 组 | Duo 附加组件 | GitLab 许可证 |
|---|---|---|
duo_pro_gitlab_premium |
Pro | Premium |
duo_pro_gitlab_ultimate |
Pro | Ultimate |
duo_enterprise_gitlab_ultimate |
Enterprise | Ultimate |
可在 Slack 的 #g_duo_chat 频道请求将自己添加为这些组的所有者。一旦被添加为所有者,你就可以将你的次要账户以 Developer 角色添加到该组,并为其分配 Duo 附加组件的席位。之后可以以 Developer 用户身份登录,测试对 Duo Chat 的访问控制。
生产环境中 GitLab Duo Chat 的端到端测试
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_historylength_of_questions_in_historytime_since_first_question
- 以下尚未实现:
每个问题类别和详细类别的请求次数与用户数可在 此 Tableau 仪表板 中查看(仅限 GitLab 团队成员)。
access_duo_chat 策略的工作原理
下表描述了在不同场景下,access_duo_chat 策略返回 true 所需的条件。
| GitLab.com | Dedicated 或 GitLab 自托管 | 所有实例 | |
|---|---|---|---|
对于项目或组外的用户(user.can?(:access_duo_chat)) |
用户需属于至少一个开启了 duo_features_enabled 组设置的 Premium 或 Ultimate 层级组 |
- 实例需处于 Premium 或 Ultimate 层级 - 实例需开启 duo_features_enabled 设置 |
|
对于组上下文中的用户(user.can?(:access_duo_chat, group)) |
- 用户需属于至少一个开启了 experiment_and_beta_features 组设置的 Premium 或 Ultimate 层级组- 该组的根祖先组需处于 Premium 或 Ultimate 层级,且该组需开启 duo_features_enabled 设置 |
- 实例需处于 Premium 或 Ultimate 层级 - 实例需开启 duo_features_enabled 设置 |
用户必须至少拥有该组的读取权限 |
对于项目上下文中的用户(user.can?(:access_duo_chat, project)) |
- 用户需属于至少一个开启了 experiment_and_beta_features 组设置的 Premium 或 Ultimate 层级组- 项目的根祖先组需处于 Premium 或 Ultimate 层级,且项目需开启 duo_features_enabled 设置 |
- 实例需处于 Ultimate 层级 - 实例需开启 duo_features_enabled 设置 |
用户必须至少拥有该项目的读取权限 |
运行 GitLab Duo Chat 提示词实验
在合并前,所有针对 GitLab Duo Chat 的提示词或模型变更都应同时满足以下条件:
- 处于功能开关后端 且
- 进行本地评估
所需的本地评估类型取决于变更类型。使用提示词库进行 GitLab Duo Chat 本地评估是衡量对问题和史诗相关问题回答平均正确性的有效方式。
请遵循 提示词库指南 在本地评估 GitLab Duo Chat 变更。提示词库文档是唯一真实来源,应始终是最新的。
观看涵盖完整设置的演示视频(内部链接)。
(已弃用) 问题与史诗实验
此部分已弃用,建议改用 开发种子文件。
如果您想使用评估框架(如 此处 所述),您可以使用以下 Rake 任务导入所需组和项目:
GITLAB_SIMULATE_SAAS=1 bundle exec 'rake gitlab:duo:setup_evaluation[<test-group-name>]'由于我们使用的 Setup 类(位于 ee/lib/gitlab/duo/developments/setup.rb)需要在“saas”模式下创建组(用于导入子组),因此您需要设置 GITLAB_SIMULATE_SAAS=1。这只是为了成功完成导入,之后如果需要可以切换回 GITLAB_SIMULATE_SAAS=0。
(已弃用) 史诗与问题固定装置
此部分已弃用,建议改用 开发种子文件。
固定装置是 GitLab 拥有的项目和组中公开的问题和史诗的副本。采样时排除了内部备注。这些固定装置已被提交到官方 gitlab 仓库中。查看 用于创建固定装置的片段。
聊天提示是如何构建的
所有的聊天请求都通过 GitLab GraphQL API 处理。目前,第三方 LLM 的提示已硬编码到 GitLab 代码库中。
但如果您想修改聊天提示,并不像在单个文件中找到字符串那么简单。聊天提示的构建过程很难跟踪,因为提示是在多个步骤中逐步组合而成的。以下是我们的构建流程:
-
向 GraphQL AI Mutation 发出 API 请求;请求包含用户的聊天输入。 (代码)
-
GraphQL mutation 调用
Llm::ExecuteMethodService#execute(代码) -
Llm::ExecuteMethodService#execute发现 GraphQL API 发送了chat方法,并调用Llm::ChatService#execute(代码) -
Llm::ChatService#execute调用schedule_completion_worker,该方法是定义在Llm::BaseService(ChatService的基类)中的 (代码) -
schedule_completion_worker调用Llm::CompletionWorker.perform_for,该方法异步将任务加入队列 (代码) -
当任务运行时,会调用
Llm::CompletionWorker#perform。它对用户输入和其他消息上下文进行反序列化,并将结果传递给Llm::Internal::CompletionService#execute(代码) -
Llm::Internal::CompletionService#execute调用Gitlab::Llm::CompletionsFactory#completion!,该方法从原始 GraphQL 请求中获取ai_action,初始化新的Gitlab::Llm::Completions::Chat实例并调用其execute方法 (代码) -
Gitlab::Llm::Completions::Chat#execute调用Gitlab::Duo::Chat::ReactExecutor。 (代码) -
Gitlab::Duo::Chat::ReactExecutor#execute调用#step_forward,后者调用Gitlab::Duo::Chat::StepExecutor#step(代码)。 -
Gitlab::Duo::Chat::StepExecutor#step调用Gitlab::Duo::Chat::StepExecutor#perform_agent_request,该方法向 AI Gateway 的/v2/chat/agent/端点发送请求 (代码)。 -
AI Gateway 的
/v2/chat/agent端点在api.v2.agent.chat.agent.chat函数中接收请求 (代码) -
api.v2.agent.chat.agent.chat通过gl_agent_remote_executor_factory创建GLAgentRemoteExecutor(代码)。在创建
GLAgentRemoteExecutor时,会传入以下参数:tools_registry- 所有可用工具的注册表;此参数通过工厂传递 (代码)agent-ReActAgent对象,封装了提示信息,包括选定的 LLM 模型、提示模板等
-
api.v2.agent.chat.agent.chat调用GLAgentRemoteExecutor.on_behalf,该方法提前获取用户工具以尽早抛出异常(若发生错误) (代码)。 -
api.v2.agent.chat.agent.chat调用GLAgentRemoteExecutor.stream(代码)。
1. `GLAgentRemoteExecutor.stream` 调用 `agent`(一个 `ReActAgent` 实例)的 `astream` 方法,传入消息和可用工具列表等参数([代码](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/989ead63fae493efab255180a51786b69a403b49/ai_gateway/chat/executor.py#L92))。
1. `ReActAgent` 构建提示词,将可用工具插入到系统提示模板中([代码](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/989ead63fae493efab255180a51786b69a403b49/ai_gateway/prompts/definitions/chat/react/system/1.0.0.jinja))。
1. `ReActAgent.astream` 向 LLM 模型发送调用请求([代码](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/989ead63fae493efab255180a51786b69a403b49/ai_gateway/chat/agents/react.py#L216))
1. LLM 响应返回给 Rails(代码路径:[`ReActAgent.astream`](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/989ead63fae493efab255180a51786b69a403b49/ai_gateway/chat/agents/react.py#L209) → [`GLAgentRemoteExecutor.stream`](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/989ead63fae493efab255180a51786b69a403b49/ai_gateway/chat/executor.py#L81) → [`api.v2.agent.chat.agent.chat`](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/989ead63fae493efab255180a51786b69a403b49/ai_gateway/api/v2/chat/agent.py#L133) → Rails)
1. 现在我们已经向 AI 网关发出了第一个请求。如果 LLM 表示第一次请求的回答是最终的,Rails 会[解析答案](https://gitlab.com/gitlab-org/gitlab/-/blob/30817374f2feecdaedbd3a0efaad93feaed5e0a0/ee/lib/gitlab/duo/chat/react_executor.rb#L56)并[返回它](https://gitlab.com/gitlab-org/gitlab/-/blob/30817374f2feecdaedbd3a0efaad93feaed5e0a0/ee/lib/gitlab/duo/chat/react_executor.rb#L63),以便由 [`Gitlab::Llm::Completions::Chat`](https://gitlab.com/gitlab-org/gitlab/-/blob/30817374f2feecdaedbd3a0efaad93feaed5e0a0/ee/lib/gitlab/llm/completions/chat.rb#L66) 进行进一步的处理。
1. 如果回答不是最终的,会从第一次 LLM 请求中解析出“思考”和“选择的工具”,然后调用相关的工具类。([代码](https://gitlab.com/gitlab-org/gitlab/-/blob/30817374f2feecdaedbd3a0efaad93feaed5e0a0/ee/lib/gitlab/duo/chat/react_executor.rb#L207) | [示例工具类](https://gitlab.com/gitlab-org/gitlab/-/blob/971d07aa37d9f300b108ed66304505f2d7022841/ee/lib/gitlab/llm/chain/tools/identifier.rb))
1. 工具执行器类包含 `Concerns::AiDependent` 并使用其 `request` 方法。([代码](https://gitlab.com/gitlab-org/gitlab/-/blob/30817374f2feecdaedbd3a0efaad93feaed5e0a0/ee/lib/gitlab/llm/chain/concerns/ai_dependent.rb#L14))
1. `request` 方法使用注入到 `context` 中的 `ai_request` 实例,该实例是在 `Llm::Completions::Chat` 中注入的。对于 Chat 来说,这是 `Gitlab::Llm::Chain::Requests::AiGateway`。([代码](https://gitlab.com/gitlab-org/gitlab/-/blob/971d07aa37d9f300b108ed66304505f2d7022841/ee/lib/gitlab/llm/completions/chat.rb#L42))。
1. 工具指示 `use_ai_gateway_agent_prompt=true`([代码](https://gitlab.com/gitlab-org/gitlab/-/blob/30817374f2feecdaedbd3a0efaad93feaed5e0a0/ee/lib/gitlab/llm/chain/tools/issue_reader/executor.rb#L121))。
这告诉 `ai_request` 将提示词发送到 `/v1/prompts/chat` 端点([代码](https://gitlab.com/gitlab-org/gitlab/-/blob/30817374f2feecdaedbd3a0efaad93feaed5e0a0/ee/lib/gitlab/llm/chain/requests/ai_gateway.rb#L87))。
1. AI 网关 `/v1/prompts/chat` 端点在 `api.v1.prompts.invoke` 上接收请求([代码](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/989ead63fae493efab255180a51786b69a403b49/ai_gateway/api/v1/prompts/invoke.py#L41))。
1. `api.v1.prompts.invoke` 从工具提示注册表中获取正确的工具提示([代码](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/989ead63fae493efab255180a51786b69a403b49/ai_gateway/api/v1/prompts/invoke.py#L49))。
1. 提示词会被作为[流式](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/989ead63fae493efab255180a51786b69a403b49/ai_gateway/api/v1/prompts/invoke.py#L86)或[非流式调用](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/989ead63fae493efab255180a51786b69a403b49/ai_gateway/api/v1/prompts/invoke.py#L96)来调用。
1. 如果工具的回答不是最终的,响应会被添加到 agent_scratchpad 中,并且 `Gitlab::Duo::Chat::ReactExecutor` 中的循环会重新开始,将额外的上下文添加到请求中。它会循环最多 10 次,直到获得最终答案。([代码](https://gitlab.com/gitlab-org/gitlab/-/blob/30817374f2feecdaedbd3a0efaad93feaed5e0a0/ee/lib/gitlab/duo/chat/react_executor.rb#L44))解读 GitLab Duo Chat 错误码
GitLab Duo Chat 有带有指定含义的错误码,以协助调试。
查看 GitLab Duo Chat 故障排除文档 了解所有 GitLab Duo Chat 错误码列表。
在为 GitLab Duo Chat 开发时,返回错误时应包含这些错误码,并记录它们,尤其是面向用户的错误。
错误码格式
错误码遵循以下格式:<层标识符><四位数字系列号>。
例如:
M1001:单体内层的网络通信错误。G2005:AI 网关层的的数据格式化/处理错误。A3010:第三方 API 的认证或数据访问权限错误。
错误码层标识符
| 代码 | 层 |
|---|---|
| M | 单体 |
| G | AI 网关 |
| A | 第三方 API |
错误系列
| 系列 | 类型 |
|---|---|
| 1000 | 网络通信错误 |
| 2000 | 数据格式化/处理错误 |
| 3000 | 认证和/或数据访问权限错误 |
| 4000 | 代码执行异常 |
| 5000 | 配置不良或参数错误 |
| 6000 | 语义或推理错误(模型无法理解或产生幻觉) |