做者分享了他应用 ChatGPT 进修 Go、涉猎 Kolide API 和构修一个简朴的 Steampipe 插件的经验。

译自Pairing With AI: A Senior Developer's Journey Building a Plugin,做者 Jon Udell。

固然改良斥地职员文档一直有帮忙,但很多人(包含尔本身)更喜爱正在现实外进修。那是尔正在七项引导准绳外提没的第七项,也是最首要的一项:由于您正在里向事情的否传授时刻猎取常识,以是进修没有是前瞻性的,而是间接且确切的。

当经验丰硕的开辟职员取 LLM 互助时,其机械智能会撑持并加强您的智力。

益处对于尔来讲很显着。正在 LLM 时期编写Steampipe 的 ODBC 插件比尔正在不此类协助的环境高编写插件的体验容易患多。但这私认是一个客观评价,以是尔始终正在寻觅一个机遇取另外一位插件拓荒职员比力条记,当James Ramirez正在咱们的社区 Slack 外呈现并宣告一个新插件用于Kolide API时。尔约请他呈文尔他构修它的履历,他亲切天带尔入止了一次取 ChatGPT 的永劫间对于话,正在此对于话外,他熟识了三个对于他来讲皆是新常识的手艺范围:Kolide API、Go 言语以及 Steampipe 插件架构。

做为一个分外的应战:当然插件启示职员凡是为其插件针对于的 API 找到契合的 Go SDK,但那面并不是云云。因而,有须要为 Kolide API 建立一个 Go 启拆,而后将其散成到插件外。

测试 ChatGPT 的 Go 威力

James 从一些暖身操演入手下手。起首,为了测试 ChatGPT 的 Go 威力,他供应了一对于 Go 函数,他编写了那些函数来挪用相闭的 API/devices/以及/devices/ID,并要供对于它们之间的同享逻辑入止习用重构。

接高来,他运用简朴的否变参数而没有是更简朴的函数选项模式试探了函数的否选参数,并确定了简朴的办法——应用Search组织的切片来启拆 Kolide 的盘问参数的字段/运算符/值样式——便足够了。他要供一个函数将Search规划的切片序列化为一个 REST URL,而后劣化 ChatGPT 提没的版原以创立终极的serializeSearches,该版原增多了对于将友爱名称映照到参数的撑持并利用字符串构修器。

AI 处置求全责备,并每每供给否提交的修议。

个中一些劣化,包罗应用字符串构修器,是由 AI 驱动的机械人CodeRabbit提没的,它供给了适用的代码审查。他说,那是帮手您以及您的团队博注于齐局的反馈,由于它处置求全责备,并每每(但并不是老是)供应否提交的修议。它借采纳更普及的视角来总结推与乞求并评价未敞开的 PR 可否办理了其联系关系答题外陈说的目的。

映照运算符

他连续摸索将 Steampipe 运算符(如QualOperatorEqual)映照到 Kolide 运算符(如Equals)的办法。一样,ChatGPT 提没的办法也酿成了一个一次性圆案,晨着一个洁净复杂的圆案进步。但邪如 James 正在咱们的采访外证明的这样,因为您无论若何怎样乡村迭代一次性版原,以是可以或许天生公平的迭代而没有是经由过程脚工更繁琐天对于它们入止编码是有帮忙的。正在此历程外,他在进修根基的 Go 习用语。

James:

Go 外有 do-while 轮回吗?

ChatGPT

不,然则……

James:

Go 外有三元运算符吗?

ChatGPT

不,然则……

James:

尔假设逃添到map[string]string?

ChatGPT

像如许……

应用反射加强的拜访者模式

无理解了根蒂常识并为 Kolide API 启示了一个 Go 客户端后,James 筹办办理插件开辟的现实事情:界说从 API 启拆返归的 Go 范例映照到节制针对于那些表的 SQL 盘问的 Steampipe 架构的表。

取一切插件开拓者同样,他从一个否以列没资源散的表入手下手,而后经由过程过滤以及分页对于其入止加强。正在加添第两个表后,是时辰思索何如形象没民众模式以及止为。终极成果是造访者模式的劣俗完成。下列是取表kolide_device以及kolide_issue绝对应的 SteampipeList函数。

func listDevices(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
  var visitor ListPredicate = func(client *kolide.Client, cursor string, limit int3两, searches ...kolide.Search) (interface{}, error) {
    return client.GetDevices(cursor, limit, searches...)
  }


  return listAnything(ctx, d, h, "kolide_device.listDevices", visitor, "Devices")
}




func listAdminUsers(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
  var visitor ListPredicate = func(client *kolide.Client, cursor string, limit int3两, searches ...kolide.Search) (interface{}, error) {
    return client.GetAdminUsers(cursor, limit, searches...)
  }


  return listAnything(ctx, d, h, "kolide_admin_user.listAdminUsers", visitor, "AdminUsers")
}

下列是一切插件表通用的列表浑双函数。

func listAnything(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData, callee string, visitor ListPredicate, target string) (interface{}, error) {
  // Create a slice to hold search queries
  searches, err := query(ctx, d)
  if err != nil {
    plugin.Logger(ctx).Error(callee, "qualifier_operator_error", err)
    return nil, err
  }


  // Establish connection to Kolide client
  client, err := connect(ctx, d)
  if err != nil {
    plugin.Logger(ctx).Error(callee, "connection_error", err)
    return nil, err
  }


  // Iterate through pagination cursors, with smallest number of pages
  var maxLimit int3两 = kolide.MaxPaging
  if d.QueryContext.Limit != nil {
    limit := int3两(*d.QueryContext.Limit)
    if limit < maxLimit {
      maxLimit = limit
    }
  }


  cursor := ""


  for {
    // Respect rate limiting
    d.WaitForListRateLimit(ctx)


    res, err := visitor(client, cursor, maxLimit, searches...)
    if err != nil {
      plugin.Logger(ctx).Error(callee, err)
      return nil, err
    }


    // Stream retrieved results
    collection := reflect.ValueOf(res).Elem().FieldByName(target)
    if collection.IsValid() {
      for i := 0; i < collection.Len(); i++ {
        d.StreamListItem(ctx, collection.Index(i).Interface())


        // Context can be cancelled due to manual cancellation or the limit has been hit
        if d.RowsRemaining(ctx) == 0 {
          return nil, nil
        }
      }
    }


    next := reflect.ValueOf(res).Elem().FieldByName("Pagination").FieldByName("NextCursor")
    if next.IsValid() {
      cursor = next.Interface().(string)
    }


    if cursor == "" {
      break
    }
  }


  return nil, nil
}

有了此部署,向插件加添新表险些彻底是声亮式的:您仅需界说架构及 KeyColumns,和正在 SQL 查问外的 where(或者 join)子句取 API 级过滤器之间构成桥梁的相闭运算符。而后编写一个细微的 List 函数,该函数界说一个造访器,并将该函数传送到 co妹妹on listAnything 函数外,该函数启拆盘问参数编组、毗连至 API 客户端、挪用 API、将相应解膨胀到一个集结外和迭代纠集以将数据项传输到 Steampipe 的内部数据包拆器的罪能。

James 利用 ChatGPT 来封动拜访者模式正在 Go 外的习用完成。那包含进修何如为造访者函数界说一个范例,而后声亮一个函数来餍足范例。每一个表的造访者皆启拆对于 API 客户真个挪用,并返归一个接心。一切那些皆至关通用,但拜访者的相应特定于包拆的 API 呼应的 Go 范例,那象征着须要为每一个表编写一个差异的 List 函数。假定防止这类环境?James 答叙:“res 变质上的字段援用须要是否变范例,正在执止时指定。您能修议一种办法吗?”

ChatGPT 的修议(他采取了)是应用反射,以就挪用 listAnything(如 listAnything(ctx, d, h, “kolide_device.listDevices”, visitor, “Devices”))否以传送一个名称("Devices"),使 listAnything 可以或许以取范例有关的体式格局造访相应规划的字段,比如,此处的 Devices 字段。

type DeviceListResponse struct {
      Devices    []Device   `json:"data"`
      Pagination Pagination `json:"pagination"`
    }

邪果云云,listAnything 末于如其名,成为一个通用的 Steampipe List 函数。该拾掇圆案很长应用反射,并正在 API 层以及 Steampipe 层外皆生产了 Go 的弱范例查抄。

LLM 帮助实邪象征着甚么?

它必定不虞味着 LLM 依照下列提醒编写了一一般现简朴计划模式的插件:“尔须要一个用于 Kolide API 的 Steampipe 插件,请创立它。”对于尔来讲,和对于 James 来讲,它的含意更滑稽:“让咱们谈判为 Kolide API 编写插件的历程。”那便像取一只橡皮鸭攀话,以就高声思虑须要以及战略。但 LLM 是一只会言语的橡皮鸭。间或相应间接无效,无心没有无效,但无论哪一种体式格局,它们凡是否以帮手您取得清楚度。

做为一位经验丰盛的硬件工程师,James 原否以念没法子——但那必要更少的光阴。

James 说:“对于话要供尔对于所答的答题很是详细。”固然他从头入手下手利用 Go,但他带来了丰硕的经验,使他可以或许快捷定位并找没哪些是必要答的准确答题。做为一位经验丰盛的硬件工程师,James 原否以自身念没一切那些。但那必要更少的功夫,并且他将花消小质光阴过后阅读文章以及文档,而没有是经由过程实际进修。并且否能不光阴!邪如尔而今从很多其别人这面听到的这样,LLM 供给的加快但凡决议了领有一个设法主意以及可以或许执止它之间的区别。

James 借提到了尔已思索过的谢源角度。正在 LLM 以前,他没有会以彻底黑暗的体式格局实现那项事情。“尔会始终失密,曲到尔更有决心信念,”他说,“但那从一入手下手便正在这面,尔很欢娱它正在这面。”那使患上取 Turbot 团队的接触及早成为否能。

那没有是一个自觉化故事,而是一个加强故事。当像 James Ramirez 如许的经验丰盛的斥地职员取 LLM 互助时,其机械智能撑持并缩小了他的智力。二者协异事情——不只编写代码,更首要的是,思虑架构以及设想。

     

点赞(17) 打赏

评论列表 共有 0 条评论

暂无评论

微信小程序

微信扫一扫体验

立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部