Let's use LLMs from Ruby

Leaner Technologies, Inc.
Kokuyou (黒曜) / Shunsuke Mori

@kokuyouwind

~ Refine RBS types using LLM ~

Talk: Japanese
Slides: English (+ Japanese)

トーク: 日本語
スライド: 日英併記

$ whoami

Kokuyou (黒曜) / Shunsuke Mori

Twitter or X: @kokuyouwind
Work at: Leaner Technologies, Inc.

Platinum / Drinkup Sponsor
Day 2: Leaner YAKINIKU Party
Procurement Domain BtoB Startup

調達領域のBtoBスタートアップ

We're Hiring!!!

エンジニア絶賛採用中!

Feel free to talk/DM us!
気軽に話しかけたり
DMしてください!

I'll talk about one that has
no relation to my job at all.

業務とは全然関係のない話をします

Lightning Talk at RubyKaigi 2023

RubyKaigi 2023 でのライトニングトーク

Matz Keynote at RubyKaigi 2023

RubyKaigi 2023 でのMatzの基調講演

Oh no, Matz presented on the same topic

I was planning to cover!

This Year...

今年は…

😌

Large Language Model (LLM)

Machine learning models trained on large amounts of text data.

OpenAI

ChatGPT 4

Anthropic

Claude 3

Microsoft
GitHub Copilot

大量のテキストデータを使ってトレーニングされた機械学習モデル

大規模言語モデル

LLM Example

LLMの例

Evolution of LLM since last year

昨年からのLLMの進化

Price Reduction

💰

値下げ

Sentence Length Expansion

扱える文章長の拡大

x 1/8

📚

x 480

Improvement of coding skills

コーディング能力の向上

+ 23.2 pt

(OpenAI gpt-3.5-turbo-0301 to
Anthropic Claude3 Haiku)

(OpenAI gpt-3.5-turbo-0301 to
Google Gemini 1.5 Pro 2M)

(GPT-4 to GPT-4o,

HumanEval)

4096 → 2M

$2.0 → $.025 / 1MTok

67.0% → 90.2%

📝

🤔

Now that LLM's capabilities have increased so much,

can we even guess RBS types for the entire project?

これだけLLMの能力が上がったなら、
プロジェクト全体のRBSの型推測もワンチャンいけるのでは…!?

🤨

Now that LLM's capabilities have increased so much,

can we even guess RBS types for the entire project?

これだけLLMの能力が上がったなら、
プロジェクト全体のRBSの型推測もワンチャンいけるのでは…!?

😲

Now that LLM's capabilities have increased so much,

can we even guess RBS types for the entire project?

Goose

I made

as a tool to guess RBS types.

Duck

quacking like geese (Duck Goose Typing)

Duck

I talk about the creation of RBS Goose,

a tool to guess RBS types from Ruby.

RubyコードからRBS型を推測するツール、

RBS Gooseを作った話をします

Headline

目次

Purpose of creating RBS Goose

How RBS Goose works

Tips for Development with LLM

Performance Evaluation of RBS Goose

Conclusion

RBS Gooseを作った目的

RBS Gooseの仕組み

LLMを使った開発のTips

RBS Gooseの性能評価

まとめ

Headline

目次

Purpose of creating RBS Goose

How RBS Goose works

Tips for Development with LLM

Performance Evaluation of RBS Goose

Conclusion

RBS Gooseを作った目的

RBS Gooseの仕組み

LLMを使った開発のTips

RBS Gooseの性能評価

まとめ

I thought it would be interesting

if I could guess the type with LLM.

LLMで型が推測できたら面白そうだったから。

Fin.

Let me give you

a little more background.

もうすこし背景の話をします。

What is RBS?

RBSとは?

Language for defining Ruby type structures

Rubyの型構造を定義するための言語

class Person
  attr_reader :name

  def initialize(name:)
    @name = name
  end

  def name=(name)
    @name = name
  end
end
class Person
  @name: String

  attr_reader name: String

  def initialize: (name: String) -> void

  def name=: (String name) -> void
end

person.rb

person.rbs

Why RBS is needed

RBSがなぜ必要か

  • Safe development through type checking

    • Detect invalid method calls, etc., before they are executed

    • use steep check, etc

  • Improved development experience, including complements

    • More accurate completion based on type

    • use steep-vscode or TypeProf for IDE, etc

型検査による安全な開発

不正なメソッド呼び出しなどを実行前に検知できる

steep checkなどが利用できる

補完などの開発体験の向上

型に基づいてより正確に補完できる

steep-vscodeやTypeProf for IDE が利用できる

Existing way to generate RBS from Ruby

RubyからRBSを生成する既存手法

rbs prototype rb

rbs prototype runtime

typeprof

Ruby

RBS

static parsing

静的構文解析

Ruby

RBS

dynamic load

動的ロード

Ruby

type level execution

型レベル実行

RBS

Each method has its own strengths and weaknesses,

and it's difficult to generate a perfect RBS in one shot.

手法ごとに一長一短があり、一発で完璧なRBSを生成するのは難しい

rbs prototype rb config.rb

Ruby

RBS

static parsing

静的構文解析

class Config
  def self.configure(&block)
    new.tap(&block)
  end

  %w[hoge fuga piyo].each do |v|
    attr_accessor v
  end
end

# config = Config.configure do |c|
#   c.hoge = 1
#   c.fuga = 'a'
#   c.piyo = :piyo
# end

config.rb

class Config
  def self.configure: () \
      { () -> untyped } -> untyped
end

# All untyped, and
# No attribute accessors

config.rbs

rbs prototype runtime -R config.rb Config

class Config
  def self.configure(&block)
    new.tap(&block)
  end

  %w[hoge fuga piyo].each do |v|
    attr_accessor v
  end
end

# config = Config.configure do |c|
#   c.hoge = 1
#   c.fuga = 'a'
#   c.piyo = :piyo
# end

config.rb

class Config
  def self.configure: () \
      { (*untyped) -> untyped } -> untyped

  public

  def fuga: () -> untyped
  def fuga=: (untyped) -> untyped

  def hoge: () -> untyped
  def hoge=: (untyped) -> untyped

  def piyo: () -> untyped
  def piyo=: (untyped) -> untyped
end

# All Untyped

config.rbs

Ruby

RBS

dynamic load

動的ロード

typeprof config.rb

class Config
  def self.configure(&block)
    new.tap(&block)
  end

  %w[hoge fuga piyo].each do |v|
    attr_accessor v
  end
end

# Required for Type Level Exec
config = Config.configure do |c|
  c.hoge = 1
  c.fuga = 'a'
  c.piyo = :piyo
end

config.rb

class Config
  def self.configure: { (Config) -> :piyo } -> Config
end

# Typed, but
# No attribute accessors 
# (and I want the return value to be void.)

config.rbs

Ruby

type level execution

型レベル実行

RBS

It's pretty hard to fix untyped

or make up for what's missing.

untypedを直したり、足りないものを補うのは結構大変

What I want to do with RBS Goose

Ruby

Existing Tools

既存ツール

RBS

RBS Gooseで何をしたいか

Guessing by LLM

LLMによる推測

Refined
RBS

Untyped becomes concrete type

The missing methods are compensated for

untypedが具体型になり、不足メソッドが補われる

I must first say that

it has not been realized to a practical level.

先に断っておくと、実用レベルまでは実現できていません

Headline

目次

Purpose of creating RBS Goose

How RBS Goose works

Tips for Development with LLM

Performance Evaluation of RBS Goose

Conclusion

RBS Gooseを作った目的

RBS Gooseの仕組み

LLMを使った開発のTips

RBS Gooseの性能評価

まとめ

Example for explanation

説明のための例

class Person
  attr_reader :name

  def initialize(name:)
    @name = name
  end

  def name=(name)
    @name = name
  end
end
class Person
  @name: String

  attr_reader name: String

  def initialize: (name: String) -> void

  def name=: (String name) -> void
end

lib/person.rb

sig/person.rbs

RBS Goose Architecture(Infer Type)

RBS Goose の構成 (型の推測)

Ruby

RBS

Refined RBS

rbs prototype
(or other tools)

examples

Prompt

LLM
(e.g. ChatGPT)

Ruby

RBS

Refined RBS

examples

Prompt

LLM
(e.g. ChatGPT)

class Person
  @name: untyped

  attr_reader name: untyped

  def initialize: (name: untyped) -> void

  def name=: (untyped name) -> void
end

sig/person.rbs

RBS Goose Architecture(Infer Type)

RBS Goose の構成 (型の推測)

rbs prototype
(or other tools)

Ruby

RBS

Refined RBS

examples

Prompt

LLM
(e.g. ChatGPT)

class Example1
  attr_reader :quantity

  def initialize(quantity:)
    @quantity = quantity
  end

  def quantity=(quantity)
    @quantity = quantity
  end
end

lib/example1.rb

class Example1
  @quantity: untyped

  attr_reader quantity: untyped

  def initialize: (quantity: untyped) -> void

  def quantity=: (untyped quantity) -> void
end

sig/example1.rbs

class Example1
  @quantity: Integer

  attr_reader quantity: Integer

  def initialize: (quantity: Integer) -> void

  def quantity=: (Integer quantity) -> void
end

refined/sig/example1.rbs

RBS Goose Architecture(Infer Type)

RBS Goose の構成 (型の推測)

rbs prototype
(or other tools)

Ruby

RBS

Refined RBS

examples

Prompt

LLM
(e.g. ChatGPT)

When ruby source codes and 
RBS type signatures are given, 
refine each RBS type signatures. 

======== Input ========

```lib/example1.rb
...
```

```sig/example1.rbs
...
```

======== Output ========

```sig/example1.rbs
...
```

======== Input ========

```lib/person.rb
...
```

```sig/person.rbs
...
```

======== Output ========

Examples

Ruby Code

LLM Infer

RBS
Prototype

RBS Goose Architecture(Infer Type)

RBS Goose の構成 (型の推測)

rbs prototype
(or other tools)

Ruby

RBS

Refined RBS

steep prototype

examples

Prompt

LLM
(e.g. ChatGPT)

```sig/person.rbs
class Person
  @name: String

  attr_reader name: String

  def initialize: (name: String) -> void

  def name=: (String name) -> void
end
```

RBS Goose Architecture(Infer Type)

RBS Goose の構成 (型の推測)

Ruby

RBS

Refined RBS

examples

Prompt

LLM
(e.g. ChatGPT)

RBS Goose Architecture(Infer Type)

RBS Goose の構成 (型の推測)

rbs prototype
(or other tools)

Multiple File Handling

複数ファイルの扱い

class Person
  attr_reader :name
end

lib/person.rb

class PersonName
  attr_reader :value
end

lib/person_name.rb

class Person
  # Not a String
  @name: PersonName
end

sig/person.rbs

Multiple File Handling: Strategy

複数ファイルの扱い: 戦略

  • Pass all constants list

  • Combine and pass on files that may be related by RAG

  • Infer all Ruby files at once

すべての定数のリストを渡す

RAGで関連しそうなファイルを組み合わせて渡す

すべてのRubyファイルをまとめて1度に推論させる

Multiple File Handling: Adopted

複数ファイルの扱い: 選択したもの

  • Infer all Ruby files at once

    • AI can make comprehensive decisions from all codes

    • Small Project can be stores in 128K tokens

      • Unrealistic as of last year, as 4K was the max​

すべてのRubyファイルをまとめて1度に推論させる

小さなプロジェクトなら128Kトークンに収まる

昨年時点では4Kトークンが最大だったため非現実的だった

AIが全てのコードを見て総合的に判断できる

Act as Ruby type inferrer.
When ruby source codes and RBS type signatures are given, 
refine each RBS type signatures. 
Each file should be split in markdown code format.
Use class names, variable names, etc., to infer type.


========Input========
```ruby:lib/email.rb
class Email
  # @dynamic address
  attr_reader :address

  def initialize(address:)
    @address = address
  end

  def ==(other)
    other.is_a?(self.class) && other.address == address
  end

  def hash
    self.class.hash ^ address.hash
  end
end
```

```rbs:sig/email.rbs
class Email
  @address: untyped

  attr_reader address: untyped

  def initialize: (address: untyped) -> void

  def ==: (untyped other) -> untyped

  def hash: () -> untyped
end
```

```ruby:lib/person.rb
class Person
  # @dynamic name, contacts
  attr_reader :name
  attr_reader :contacts

  def initialize(name:)
    @name = name
    @contacts = []
  end

  def name=(name)
    @name = name
  end

  def guess_country()
    contacts.map do |contact|
      case contact
      when Phone
        contact.country
      end
    end.compact.first
  end
end
```
```rbs:sig/person.rbs
class Person
  @name: untyped

  @contacts: untyped

  attr_reader name: untyped

  attr_reader contacts: untyped

  def initialize: (name: untyped) -> void

  def name=: (untyped name) -> void

  def guess_country: () -> untyped
end
```

```ruby:lib/phone.rb
class Phone
  # @dynamic country, number
  attr_reader :country, :number

  def initialize(country:, number:)
    @country = country
    @number = number
  end

  def ==(other)
    if other.is_a?(Phone)
      # @type var other: Phone
      other.country == country && other.number == number
    else
      false
    end
  end

  def hash
    self.class.hash ^ country.hash ^ number.hash
  end
end
```

```rbs:sig/phone.rbs
class Phone
  @country: untyped

  @number: untyped

  attr_reader country: untyped

  attr_reader number: untyped

  def initialize: (country: untyped, number: untyped) -> void

  def ==: (untyped other) -> (untyped | nil)

  def hash: () -> untyped
end
```
========Output========
```rbs:sig/email.rbs
class Email
  @address: String

  attr_reader address: String

  def initialize: (address: String) -> void

  def ==: (Object other) -> bool

  def hash: () -> Integer
end
```

```rbs:sig/person.rbs
class Person
  @name: String

  @contacts: Array[(Email | Phone)]

  attr_reader name: String

  attr_reader contacts: Array[(Email | Phone)]

  def initialize: (name: String) -> void

  def name=: (String name) -> void

  def guess_country: () -> (String | nil)
end
```

```rbs:sig/phone.rbs
class Phone
  @country: String

  @number: String

  attr_reader country: String

  attr_reader number: String

  def initialize: (country: String, number: String) -> void

  def ==: (Object other) -> (bool | nil)

  def hash: () -> Integer
end
```
========Input========
```ruby:lib/user.rb
class User
  def initialize(name:)
    @name = name
  end

  attr_reader :name
end
```

```rbs:sig/user.rbs
class User
  @name: untyped

  def initialize: (name: untyped) -> void

  attr_reader name: untyped
end
```

```ruby:lib/user_factory.rb
class UserFactory
  def name(name)
    @name = name
    self
  end

  def build
    User.new(name: @name)
  end
end
```

```rbs:sig/user_factory.rbs
class UserFactory
  @name: untyped

  def name: (untyped name) -> self

  def build: () -> untyped
end
```


========Output========

Real Prompt

実際のプロンプト

Most of the time, one shot doesn't work.

We need to look at type errors

and eventually correct them.

たいてい、一発ではうまくいかない。

発生した型エラーを見ながら修正していく必要がある。

Ruby

RBS

Fixed RBS

examples

Prompt

LLM
(e.g. ChatGPT)

RBS Goose Architecture(Fix Error)

RBS Goose の構成 (エラーの修正)

Errors

Steep Check

(Still experimental)

まだ実験的

Headline

目次

Purpose of creating RBS Goose

How RBS Goose works

Tips for Development with LLM

Performance Evaluation of RBS Goose

Conclusion

RBS Gooseを作った目的

RBS Gooseの仕組み

LLMを使った開発のTips

RBS Gooseの性能評価

まとめ

RBS Goose Configuration

RBS Goose の設定

I want to allow users to choose which LLM to use.

どの LLM を使うか、ユーザーが選べるようにしたい

Using the LLM framework as an adapter

LLMフレームワークをアダプタとして利用

@andreibondarev 氏の Langchain.rb gem を利用する

Ruby

RBS Goose Configuration Example

RBS Goose の設定例

api_key = ENV.fetch('OPENAI_ACCESS_TOKEN')

RbsGoose.configure do |c|
  # Use the provided configuration methods
  c.use_open_ai(api_key)

  # or directly configure an instance of Langchain::LLM
  c.llm.client = ::Langchain::LLM::OpenAI.new(api_key: )

  # or Local Server such as Ollama
  c.llm.client = ::Langchain::LLM::Ollama.new(
    url: "http://localhost:11434"
  )
end

RBS Goose Testing

RBS Goose のテスト

  • LLM API is Expensive and High latency

    • Critically unsuitable for CI.

  • Web mocks such as VCR gem can be used

    • Make it an exact match, including Request Body

    • Temperature should be set to 0 for reproducibility

LLM APIは費用が高く応答も遅い

CIと致命的に相性が悪い

VCR gem などの Webモックを利用すると良い

リクエストボディを含めた厳密一致を指定する

再現性のために、temperatureは0にする

RBS Goose Testing - VCR Setup

RBS Goose のテスト - VCR セットアップ

# spec/spec_helper.rb
VCR.configure do |config|
  config.cassette_library_dir = 
    'spec/fixtures/vcr_cassettes'
  config.hook_into :webmock
  config.default_cassette_options = {
    match_requests_on: %i[method uri body],
    record: ENV.fetch('RECORD', :once).to_sym
  }
  config.filter_sensitive_data('<openai_access_token>') { 
    ENV.fetch('OPENAI_ACCESS_TOKEN')
  }
end

RBS Goose Testing - VCR Usage

RBS Goose のテスト - VCRの利用

# spec/rbs_goose/type_inferrer_spec.rb
RSpec.describe RbsGoose::TypeInferrer, :configure do
  it 'returns refined rbs' do
    VCR.use_cassette('openai/infer') do
      expect(described_class.new.infer).to
        eq(refined_rbs_list)
    end
  end
end

Recorded Request Example

記録されたリクエストの例

---
http_interactions:
- request:
    method: post
    uri: https://api.openai.com/v1/chat/completions
    body:
      encoding: UTF-8
      string: 
        '{"messages":[
          {"role":"user","content":"Act as Ruby type inferrer..."}],
           "model":"gpt-3.5-turbo-1106","n":1,
           "temperature":0.0}'
    headers:
      Content-Type:
      - application/json
      Authorization:
      - Bearer <openai_access_token>
      ...
  response:
   ...

Headline

目次

Purpose of creating RBS Goose

How RBS Goose works

Tips for Development with LLM

Performance Evaluation of RBS Goose

Conclusion

RBS Gooseを作った目的

RBS Gooseの仕組み

LLMを使った開発のTips

RBS Gooseの性能評価

まとめ

Evaluation 1: Config & Runner

評価 1: Config & Runner

class Config
  def self.configure(&block)
    new.tap(&block)
  end

  %w[client role prompt].each do
    attr_accessor _1.to_sym
  end
end
class Runner
  def initialize(config)
    @config = config
  end

  def run
    config.client.chat(
      messages: [{
        role: config.role,
        content: config.prompt
      }]
    ).chat_completion
  end

  private

  attr_reader :config
end

lib/config.rb

lib/runner.rb

Evaluation 1: Config & Runner

評価 1: Config & Runner

  • Let RBS Goose guess a small example involving metaprogramming

    • The base RBS is generated by each of the three methods

    • Tried OpenAI and Anthropic models + CodeGemma (local LLM)

  • ​steep check + Quality checks by read the RBS

    • Check if there are any untyped left that can be detailed, etc.

メタプログラミングを含む小さな例を推測させた

ベースとなるRBSは、事前に解説した3種類の手法で生成

OpenAIとAnthropicの各モデル + CodeGemma(ローカルLLM)を試した

steep checkの確認に加えて、目視での品質確認を実施

まだ具体化できるuntypedが残されていないか、などを確認

Result 1: Generated RBS Quality

結果 1: 生成されたRBSの質

Platform Model Size prototype rb base prototype runtime base Typeprof
base
OpenAI GPT-3.5 Turbo Small Perfect Perfect Almost
OpenAI GPT-4 Turbo Large Perfect Perfect Perfect
OpenAI GPT-4 Omni Large Perfect Perfect Perfect
Anthropic Claude 3 Haiku Small Perfect Almost Almost
Anthropic Claude 3 Sonnet Medium Almost Not Good Perfect
Anthropic Claude 3 Opus Large Almost Almost Almost
Ollama(Local) CodeGemma Small Not Good Not Good Not Good

Result 1: Attribute Accessors

結果 1: アトリビュートアクセサ

Regardless of the base, the output was the same.

ベースのRBSを問わず、同じような出力になった

Result 1: Almost Example

結果 1: Almostの例

There was a case of fabricating the return type

of LangChain::LLM::OpenAI#chat

LangChain::LLM::OpenAI#chat の返り値の型を捏造することがあった

Result 1: Interesting Case

結果 1: 興味深いケース

In one case, gpt-4-turbo commented

on why it was left untyped

1例だけ、 gpt-4-turbo が
「なぜuntypedのまま残したか」をコメントしているものがあった

Result 1: Execution Time [sec]

結果 1: 実行時間 [秒]

Platform Model Size prototype rb base prototype runtime base Typeprof
base
OpenAI GPT-3.5 Turbo Small 2.2 2.2 4.8
OpenAI GPT-4 Turbo Large 7.6 11.4 7.2
OpenAI GPT-4 Omni Large 1.8 1.7 1.9
Anthropic Claude 3 Haiku Small 3.3 3.3 2.9
Anthropic Claude 3 Sonnet Medium 3.5 8.6 3.0
Anthropic Claude 3 Opus Large 14.6 13.0 13.1
Ollama(Local) CodeGemma Small 7.1 7.4 4.1
Platform Model Size prototype rb base prototype runtime base Typeprof
base
OpenAI GPT-3.5 Turbo Small Perfect (2.2) Perfect (2.2) Almost (4.8)
OpenAI GPT-4 Turbo Large Perfect (7.6) Perfect (11.4) Perfect (7.2)
OpenAI GPT-4 Omni Large Perfect (1.8) Perfect (1.7) Perfect (1.9)
Anthropic Claude 3 Haiku Small Perfect (3.3) Almost (3.3) Almost (2.9)
Anthropic Claude 3 Sonnet Medium Almost (3.5) - Perfect (3.0)
Anthropic Claude 3 Opus Large Almost (14.6) Almost (7.4) Almost (4.1)

Result 1: Time (Perfect or Almost)

結果 1: 実行時間(PerfectかAlmostのもののみ)

Evaluation 1: Consideration

実験 1: 考察

元となるRBS生成手法はどれにしても大差なかった

GPT-4 Omni が最速なのに理想的な出力だった

実行が手軽で速い rbs prototype rb に絞っても良さそう

rbs prototype rb + GPT-4 Omni の組み合わせが良さそう

  • The base is much the same for all methods

    • Looks good to focus on rbs prototype rb

  • ​For the model, the GPT system clearly performed better

    • ​GPT-4 Omni was the fastest but ideal output

  • ​rbs prototype rb + GPT-4 Omni combination looks good

モデルは GPT系の成績が明らかに良かった

Evaluation 2: RbsGoose

評価 2: RbsGoose

  • Infer RBS from Ruby code in whole RbsGoose

    • The base used only rbs prototype rb

RbsGooseのRubyコード全体からRBSを推測する

ベースはrbs prototype rbのみを用いた

# File Count
❯ find lib -type f | wc -l
      17

# Line Count
❯ find lib -type f | xargs cat | wc -l
     698

# Size Count
❯ du -sh lib
 68K	lib
Platform model Model Size Quality time[sec] cost[¢]
OpenAI GPT-3.5 Turbo Small Poor 4.3 0.44
OpenAI GPT-4 Turbo Large Almost 69.2 12.6
OpenAI GPT-4 Omni Large Almost 52.5 7.86
Anthropic Claude 3 Haiku Small Poor 33.4 0.65
Anthropic Claude 3 Sonnet Medium Almost 55.5 7.88
Anthropic Claude 3 Opus Large Almost 90.7 35.72
Ollama(Local) codegemma Small Subtle 95.9 N/A

Result 2: Generated RBS Quality

結果 2: 生成されたRBSの質

Result 2: Almost Summary

結果 2: Almostな出力の概要

Overall, well guessed, including generics.

全体的にはジェネリクスも含めてよく推測されている

class RbsGoose::IO::ExampleGroup < ::Array[RbsGoose::IO::Example]
  self.@default_examples: Hash[Symbol, RbsGoose::IO::ExampleGroup]
  attr_accessor error_messages: String?
  def self.load_from: 
    (String base_path, ?code_dir: String, ?sig_dir: String, ?refined_dir: String) 
      -> RbsGoose::IO::ExampleGroup
  def self.default_examples: () -> Hash[Symbol, RbsGoose::IO::ExampleGroup]
  private def self.load_example:
    (String base_path, String code_dir, String path, String refined_dir, String sig_dir) 
      -> RbsGoose::IO::Example
  private def self.to_rbs_path: (String path, String sig_dir) -> String
  def to_target_group: () -> RbsGoose::IO::TargetGroup
  def to_refined_rbs_list: () -> Array[RbsGoose::IO::File]
end

sig/rbs_goose/io/example_group.rbs

Evaluation 2: Failure Point

評価 2: 失敗していたポイント

Failure Description: Syntax Error in Struct or delegator

失敗内容: Struct や def_delegator で Syntax Error

class RbsGoose::Configuration
  LLMConfig: Struct[client: ::Langchain::LLM::Base, ...
  TemplateConfig: Struct[instruction: String, ...
      
  def_delegator llm, :client, :llm_client
  def_delegator llm, :mode, :llm_mode
  ...

Evaluation 2: What happens when I fix it

評価 2: それらを直したらどうなるか

🙃

Evaluation 2: Consideration

実験 2: 考察

Structなどの特殊ケースのRBSをうまく扱えない

rbs_railsやtypeprofなどはトップレベルにRBSを生成するので対応が取れない

exampleに含めるか, Fine Tuningを行う必要がありそう

やっぱり型エラーの自動修正が欲しい

  • Cannot handle RBS for special cases such as Struct well

    • Necessary to include it in the example, or require Fine Tuning

  • The 1:1 assumption of ruby and rbs was not a good

    • ​rbs_rails, typeprof, etc. generate RBS at the top level

  • I still want a fix for type errors

rubyとrbsを一対一の前提にしたのはあまり良くなかった

Headline

目次

Purpose of creating RBS Goose

How RBS Goose works

Tips for Development with LLM

Performance Evaluation of RBS Goose

Conclusion

RBS Gooseを作った目的

RBS Gooseの仕組み

LLMを使った開発のTips

RBS Gooseの性能評価

まとめ

Conclusion

まとめ

  • Introduced a case study of the creation of the RBS Goose

    • Explained how to compose the prompt and the intent

    • Some tips for development with LLM were presented

  • ​RBS Goose is still experimental

    • LLM could be used to do some interesting things

RBS Goose を作った事例を紹介した

プロンプトの構成方法と、その意図について解説した

LLMを使った開発のTipsをいくつか紹介した

LLM を使うと面白いことができるかも、というのが伝わると嬉しい

RBS Goose はまだ実験段階

Concerns

気になっていること

Tomorrow's Session Schedule

明日のセッションスケジュール

rbs-inline

Seems to work well with AI completion

AI補完と相性が良さそう

I tried GitHub Copilot and it completes quite well.

GitHub Copilot を試したら、結構補完してくれそう

Completion

Editing entire projects with AI could work well

like Open Interpreter or Copilot Workspace

Open Interpreter や Copilot Workspace など、

AIでプロジェクト全体を編集する戦略もやりやすくなりそう

Is RBS Goose dead?

RBS Goose 死亡のお知らせ?

🪦

I'm not sure yet whether

the RBS Goose will become a dead duck

or a goose that lays golden eggs.

So I'll keep at it a little longer
before I cooks my own goose.

RBS Gooseが Dead Duckになる (失敗に終わる) のか、

それとも金の卵を生むガチョウになるのかはまだわからないので、

Cook my own goose(自分で成功の機会を捨てる)前に

もう少し続けてみたいと思う。

Let's use LLMs from Ruby 〜 Refine RBS type definitions using LLMs

By 黒曜

Let's use LLMs from Ruby 〜 Refine RBS type definitions using LLMs

Session of RubyKaigi 2024

  • 1,097