首页 > 后端开发 > Golang > Go 调用 LangChain(一)

Go 调用 LangChain(一)

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 引起了我的注意!

所以像往常一样,我建立了一个项目并尝试实现它,并提出了我自己的想法(à ma酱?)。

执行

像往常一样需要环境变量,我设置了一个 .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" 
登录后复制

在上一篇文章中,我提到尝试计算法学硕士发送和接收的代币数量。这项工作仍在进行中,因此我直接在应用程序中使用了“tiktoken-go”库,并打算对其进行一些更改(在不久的将来?)。无论如何,就我目前的进度而言,它并没有真正起作用,但它就在那里。

对于应用程序本身,我几乎按原样使用了 Travis 存储库中的代码,并添加和包装了以下功能;

  • 使用对话框进行提示输入(?我喜欢对话框?)
  • 尝试”计算发送给法学硕士和从法学硕士收到的“令牌”数量。 代码本身如下;
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(一)的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板