> 백엔드 개발 > Golang > Go에서 LangChain 호출하기(1부)

Go에서 LangChain 호출하기(1부)

Mary-Kate Olsen
풀어 주다: 2025-01-02 21:29:40
원래의
842명이 탐색했습니다.

Calling LangChain from Go (Part 1)

동기 부여

Golang 및 LLM 사용에 대한 "휴일" 테스트(이전 게시물…)에 이어 Go에서 LangChain 호출을 구현하는 쉬운 방법을 찾고 있었고 가급적이면 watsonx.ai를 사용하는 것이 좋습니다.

다행히 다음 Github 저장소를 찾았습니다: https://github.com/tmc/langchaingo(Travis Cline https://github.com/tmc에 대한 간략한 설명).

그의 저장소에는 다음 특정 폴더가 있습니다. https://github.com/tmc/langchaingo/blob/main/examples/watsonx-llm-example/watsonx_example.go가 제 관심을 끌었습니다!

그래서 늘 그렇듯이 프로젝트를 하나 만들어서 구현해보기도 했고, 나름의 아이디어도 넣어봤습니다.

구현

평소처럼 환경 변수가 필요하므로 나중에 앱에서 사용할 .env 파일을 설정했습니다.

export WATSONX_API_KEY="your-watsonx-api-key"
export WATSONX_PROJECT_ID="your-watsonx-projectid"
# I used the US-SOUTH, could be any other region of IBM Cloud
export SERVICE_URL="https://us-south.ml.cloud.ibm.com" 
로그인 후 복사

이전 게시물에서 LLM과 주고받은 토큰 수를 계산하는 방법에 대해 언급한 적이 있습니다. 그 작업은 아직 WIP이므로 (가까운 미래에?) 약간의 변경을 가할 생각으로 앱 내부의 "tiktoken-go" 라이브러리를 직접 사용했습니다. 아무튼 현재 진행 상황의 경우에는 실제로 작동하지는 않지만 거기에 있습니다.

앱 자체의 경우 Travis 저장소의 코드를 거의 그대로 사용하고 다음 기능을 추가하고 래핑했습니다.

  • 프롬프트 입력을 위해 대화 상자 사용(? 저는 대화 상자를 좋아합니다 ?)
  • "시도"하여 LLM으로 보내고 받은 "토큰"의 수를 계산합니다. 코드 자체는 다음과 같습니다.
package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "os/exec"
    "runtime"

    "fyne.io/fyne/v2"
    "fyne.io/fyne/v2/app"
    "fyne.io/fyne/v2/container"
    "fyne.io/fyne/v2/dialog"
    "fyne.io/fyne/v2/widget"

    "github.com/joho/godotenv"
    "github.com/pkoukk/tiktoken-go"
    "github.com/tmc/langchaingo/llms"
    "github.com/tmc/langchaingo/llms/watsonx"
)

const (
    _tokenApproximation = 4
)

const (
    _gpt35TurboContextSize   = 4096
    _gpt432KContextSize      = 32768
    _gpt4ContextSize         = 8192
    _textDavinci3ContextSize = 4097
    _textBabbage1ContextSize = 2048
    _textAda1ContextSize     = 2048
    _textCurie1ContextSize   = 2048
    _codeDavinci2ContextSize = 8000
    _codeCushman1ContextSize = 2048
    _textBisonContextSize    = 2048
    _chatBisonContextSize    = 2048
    _defaultContextSize      = 2048
)

// nolint:gochecknoglobals
var modelToContextSize = map[string]int{
    "gpt-3.5-turbo":    _gpt35TurboContextSize,
    "gpt-4-32k":        _gpt432KContextSize,
    "gpt-4":            _gpt4ContextSize,
    "text-davinci-003": _textDavinci3ContextSize,
    "text-curie-001":   _textCurie1ContextSize,
    "text-babbage-001": _textBabbage1ContextSize,
    "text-ada-001":     _textAda1ContextSize,
    "code-davinci-002": _codeDavinci2ContextSize,
    "code-cushman-001": _codeCushman1ContextSize,
}

var tokens int

func runCmd(name string, arg ...string) {
    cmd := exec.Command(name, arg...)
    cmd.Stdout = os.Stdout
    cmd.Run()
}

func ClearTerminal() {
    switch runtime.GOOS {
    case "darwin":
        runCmd("clear")
    case "linux":
        runCmd("clear")
    case "windows":
        runCmd("cmd", "/c", "cls")
    default:
        runCmd("clear")
    }
}

func promptEntryDialog() string {

    var promptEntry string

    // Create a new Fyne application
    myApp := app.New()
    myWindow := myApp.NewWindow("Prompt Entry Dialog")

    // Variable to store user input
    var userInput string

    // Button to show the dialog
    button := widget.NewButton("Click to Enter your prompt's text", func() {
        entry := widget.NewEntry()
        dialog.ShowCustomConfirm("Input Dialog", "OK", "Cancel", entry, func(confirm bool) {
            if confirm {
                userInput = entry.Text
                promptEntry = userInput
                fmt.Println("User Input:", userInput) // Print to the console
                myWindow.Close()
            }
        }, myWindow)
    })

    // Add the button to the window
    myWindow.SetContent(container.NewVBox(
        widget.NewLabel("Click the button below to enter text:"),
        button,
    ))

    // Set the window size and run the application
    myWindow.Resize(fyne.NewSize(400, 200))
    myWindow.ShowAndRun()
    return promptEntry
}

func CountTokens(model, text string, inorout string) int {
    var txtLen int
    e, err := tiktoken.EncodingForModel(model)
    if err != nil {
        e, err = tiktoken.GetEncoding("gpt2")
        if err != nil {
            log.Printf("[WARN] Failed to calculate number of tokens for model, falling back to approximate count")
            txtLen = len([]rune(text))

            fmt.Println("Guessed tokens for the "+inorout+" text:", txtLen/_tokenApproximation)

            return txtLen
        }
    }
    return len(e.Encode(text, nil, nil))
}

func GetModelContextSize(model string) int {
    contextSize, ok := modelToContextSize[model]
    if !ok {
        return _defaultContextSize
    }
    return contextSize
}

func CalculateMaxTokens(model, text string) int {
    return GetModelContextSize(model) - CountTokens(model, text, text)
}

func main() {
    var prompt, model string

    // read the '.env' file
    err := godotenv.Load()
    if err != nil {
        log.Fatal("Error loading .env file")
    }

    ApiKey := os.Getenv("WATSONX_API_KEY")
    if ApiKey == "" {
        log.Fatal("WATSONX_API_KEY environment variable is not set")
    }
    ServiceURL := os.Getenv("SERVICE_URL")
    if ServiceURL == "" {
        log.Fatal("SERVICE_URL environment variable is not set")
    }
    ProjectID := os.Getenv("WATSONX_PROJECT_ID")
    if ProjectID == "" {
        log.Fatal("WATSONX_PROJECT_ID environment variable is not set")
    }

    // LLM from watsonx.ai
    model = "ibm/granite-13b-instruct-v2"
    // model = "meta-llama/llama-3-70b-instruct"

    llm, err := watsonx.New(
        model,
        //// Optional parameters: to be implemented if needed - Not used at this stage but all ready
        // wx.WithWatsonxAPIKey(ApiKey),
        // wx.WithWatsonxProjectID("YOUR WATSONX PROJECT ID"),
    )

    if err != nil {
        log.Fatal(err)
    }
    ctx := context.Background()

    prompt = promptEntryDialog()

    // for the output visibility on the consol - getting rid of system messages
    ClearTerminal()

    // Use the entry variable here
    fmt.Println("Calling the llm with the user's prompt:", prompt)

    tokens = CountTokens(model, prompt, "input")

    completion, err := llms.GenerateFromSinglePrompt(
        ctx,
        llm,
        prompt,
        llms.WithTopK(10),
        llms.WithTopP(0.95),
        llms.WithSeed(25),
    )
    // Check for errors
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(completion)

    tokens = CountTokens(model, completion, "output")

}

로그인 후 복사

아래 출력과 같이 제대로 작동합니다.

Calling the llm with the user's prompt: What is the distance in Kilmometers from Earth to Moon?
2024/12/31 11:08:04 [WARN] Failed to calculate number of tokens for model, falling back to approximate count
Guessed tokens for the input text: 13
The distance from Earth to the Moon is about 384,400 kilometers.
2024/12/31 11:08:04 [WARN] Failed to calculate number of tokens for model, falling back to approximate count
Guessed tokens for the output text: 16

#####


Calling the llm with the user's prompt: What is the name of the capital city of France?
2024/12/31 11:39:28 [WARN] Failed to calculate number of tokens for model, falling back to approximate count
Guessed tokens for the input text: 11
Paris
2024/12/31 11:39:28 [WARN] Failed to calculate number of tokens for model, falling back to approximate count
Guessed tokens for the output text: 1
로그인 후 복사

짜잔!

다음 단계

버전 0.2에서는 다음 기능을 구현하겠습니다.

  • 사용자가 사용하고 싶은 모델을 제안하고,
  • 토큰 개수를 더욱 정확하게 파악하는 방법
  • 실제 LangChain 구현

결론

이것은 Go 애플리케이션에서 LangChain을 호출하는 작업을 매우 간단하게 반영한 것입니다.

앞으로 나올 내용을 계속 지켜봐 주시기 바랍니다.

위 내용은 Go에서 LangChain 호출하기(1부)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿