FastGPT 是一个基于 LLM 大语言模型的知识库问答系统,提供开箱即用的数据处理、模型调用等能力。同时可以通过 Flow 可视化进行工作流编排,从而实现复杂的问答场景!

背景

在之前使用Gitlab CI进行AI Code Review的时候发现一些痛点,这次为了解决这些问题故在FastGPT平台上进行二次开发

现有痛点

  1. 优化提示词后需要多个项目同步修改

  2. 收集使用反馈困难

  3. 改动较多时候评论太多,影响人工评审

  4. 重试不方便

  5. Review结果不佳

为了解决这些问题从两个角度出发

  1. 将Review任务放到平台上,发起合并请求的时候使用gitlab CI触发该任务(当前二次开发部分)

  2. 维护知识库,提高Review质量

FastGPT技术栈

NextJs + TS + ChakraUI + Mongo + Postgres (Vector 插件)

将项目下载到本地后对关键路径进行分析

  • fastgpt/projects/app/src/service: 存入mongo时的存储内容,相当于表设计

  • fastgpt/projects/app/src/web/core:接口使用

  • fastgpt/projects/app/src/pages:页面路由

  • fastgpt/projects/app/src/pages/api:API路由

功能设计

工程

每个工程都可以选择对应的应用或者提示词来进行代码评审

// projects/app/src/types/mongoSchema.d.ts
export interface ReviewSchema {
  _id: string;
  appName: string;
  projectId: string;
  prompt?: string;
  appId?: string;
  createTime: Date;
  lastUsedTime?: Date;
}

实现增删改查

增加/修改

// 增/改
const { appName, prompt, projectId, appId, _id } = req.body;
if (_id) {
  // 传入了_id则为修改
  response = await Review.updateOne({ _id }, { $set: { appName, prompt, appId, projectId } });
} else {
  // 否则为新增
  response = await Review.create({ appName, prompt, appId, projectId });
}

删除

const { id } = req.query;
await Review.deleteOne({ _id: id });

查看

const { appName, id } = req.query;
let response;
if (appName) {
  response = await Review.find({ appName });
} else if (id) {
  response = await Review.find({ _id: id });
} else {
  response = await Review.find();
}

任务

每次Review都是一次任务

// projects/app/src/types/mongoSchema.d.ts
export interface ReviewJobSchema {
  _id: string;
  reviewId: string; // 对应ReviewSchema的_id
  projectId: string; // 对应ReviewSchema的projectId
  mrId: string;
  createTime: Date;
}

查看任务

const { projectId } = req.query;
let response = await ReviewJob.find({ projectId }).sort({ createTime: -1 })

结果

每个任务中有多条结果记录

// projects/app/src/types/mongoSchema.d.ts
export interface ReviewResultSchema {
  _id: string;
  jobId: string; // 对应ReviewJobSchema的_id
  newPath?: string;
  newLine?: number;
  oldPath?: string;
  oldLine?: number;
  body: string;
  ref: GitlabDiffRef;
  effective?: string | null;
  createTime: Date;
}

查看结果

const { jobId } = req.query;
let response = await ReviewResult.find({ jobId }).sort({ createTime: -1 });

核心操作

功能实现采用的是【第2924期】如何在 Gitlab 中使用 ChatGPT 进行 CodeReview:https://mp.weixin.qq.com/s/Dyk1cYg63oOs13f9_gf9ug

另外需要打通使用应用库来进行CodeReview的操作

从官方文档可以看出,FastGPT使用API访问时,除域名外其他用法与直接使用Chatgpt一致,所以稍微修改一下原有的 chatgpt.ts 文件即可

这样就有两个执行文件了

import run1 from '@/utils/review/chatgpt';
import run2 from '@/utils/review/fastgpt';

执行任务的时候就是

  1. 根据传参查询指定工程

  2. 判断使用提示词还是应用

  3. 使用提示词则使用run1

  4. 使用的应用则使用run2

其中应用采用的是API访问,如果之前没有创建过,则新建一个,使用.lean()从数据库中拿到API Key来进行操作

let { projectId, mrId, target = /\.(js|jsx|ts|tsx|java)$/} = req.query
let response = await Review.find({ projectId });
let prompt = response[0].prompt;
let appId = response[0].appId;
// 创建review任务
let response1 = await ReviewJob.create({
  reviewId: response[0]._id,
  projectId,
  mrId
});
let jobId = response1._id;
if (appId) {
  // 当有appId时,使用fastgpt
  let res2;
  res2 = await MongoOpenApi.findOne({ appId }).lean();
  if (!res2?.apiKey) {
    let res1 = await MongoUser.findOne({ username: 'root' });
    let userId = res1?._id;
    const nanoid = customAlphabet(
      'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890',
      Math.floor(Math.random() * 14) + 24
    );
    let apiKey = `${global.systemEnv?.openapiPrefix || 'fastgpt'}-${nanoid()}`;
    await MongoOpenApi.create({
      userId,
      apiKey,
      appId,
      name: 'review',
      limit: {
        credit: -1
      }
    });
  }
  res2 = await MongoOpenApi.findOne({ appId }).lean();
  if (!res2?.apiKey) throw new Error('apiKey获取失败');
  run2({
    gitlabConfig: {
      host: 'https://gitlab.qunhequnhe.com',
      token: 'xxx',
      projectId,
      mrIId: mrId,
      target
    },
    fastgptConfig: {
      apikey: res2.apiKey,
      chatId: jobId
    },
    projectId,
    jobId
  });
} else {
  // 当没有appId时,使用chatgpt
  run1({
    gitlabConfig: {
      host: 'https://gitlab.qunhequnhe.com',
      token: 'xxx',
      projectId,
      mrIId: mrId,
      target
    },
    chatgptConfig: {
      model: 'gpt-3.5-turbo-16k',
      prompt,
      language: 'Chinese'
    },
    projectId,
    jobId
  });
}

接口

import { GET, POST, DELETE, PUT } from '@/web/common/api/request';
import { CreateReviewParams } from '@/types/review';

/**
 * 创建一个review工程任务
 */
export const createReviewItem = (data: CreateReviewParams) => POST<string>('/review/create', data);

/**
 * 获取review工程任务列表
 */
export const getReviewList = (appName: string | null, id: string | null) =>
  GET<any>(`/review/list?appName=${appName}&id=${id}`);

/**
 * 删除review工程任务
 */
export const delReviewItem = (_id: string) => DELETE<any>(`/review/del?id=${_id}`);

/**
 * 开始review工程任务
 * */
export const startReviewItem = (projectId: string, mrId: string, target: string) =>
  GET<any>(`/review/work?projectId=${projectId}&mrId=${mrId}&target=${target}`);

/**
 * 查询review结果
 * */
export const getReviewResult = (projectId: string | null, jobId: string | null) =>
  GET<any>(`/review/results?projectId=${projectId}&jobId=${jobId}`);

/**
 * 数据概览
 * */
export const getReviewOverview = () => GET<any>(`/review/overview`);

/**
 * 修改结果是否有效
 * */
export const setEvaluateReviewResult = (_id: string, effective: string) =>
  POST<any>(`/review/evaluateResult?_id=${_id}&effective=${effective}`);

/**
 * 通过jobId获取appId
 * */
export const getAppIdByJobId = (jobId: string) =>
  GET<any>(`/review/getAppIdByJobId?jobId=${jobId}`);

页面部分

页面部分代码略,展示样式

工程新建/编辑

757a827d9a59b9bcf3273e36e41311d9.png

新建

c9512744b53115298b92d1c822084910.png

编辑
工程展示

7045dde11aebd0a45215e1271694f997.png

展示
结果展示

d9c61c677765f0ff0f9b2a94288dd549.png

结果展示
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐