开发个人Go-ChatGPT--5 模型管理 (一)

开发个人Go-ChatGPT--5 模型管理 (一)

背景

开发一个chatGPT的网站,后端服务如何实现与大模型的对话?是整个项目中开发困难较大的点。

如何实现上图的聊天对话功能?在开发后端的时候,如何实现stream的响应呢?本文就先介绍后端的原理,逐步攻克这个课题。

环境部署

  • 启动ollamadocker run -d -p 3000:8080 -p 11434:11434 -v ollama:/root/.ollama -v open-webui:/app/backend/data --name open-webui --restart always ollama/ollama

  • ollama 下载对话模型: docker exec -it open-webui ollama run gemma:2b

    bash 复制代码
    pulling manifest 
    pulling c1864a5eb193... 100% ▕████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▏ 1.7 GB                         
    pulling 097a36493f71... 100% ▕████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▏ 8.4 KB                         
    pulling 109037bec39c... 100% ▕████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▏  136 B                         
    pulling 22a838ceb7fb... 100% ▕████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▏   84 B                         
    pulling 887433b89a90... 100% ▕████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▏  483 B                         
    verifying sha256 digest 
    writing manifest 
    removing any unused layers 
    success

Stream reponse

前端

svelte 复制代码
        ....
        const [res, controller] = await generateChatCompletion(localStorage.token, {
            model: model,
            messages: messagesBody,
            options: {
                ...($settings.options ?? {})
            },
            format: $settings.requestFormat ?? undefined,
            keep_alive: $settings.keepAlive ?? undefined,
            docs: docs.length > 0 ? docs : undefined
        });

        if (res && res.ok) {
            console.log('controller', controller);

            const reader = res.body
                .pipeThrough(new TextDecoderStream())
                .pipeThrough(splitStream('\n'))
                .getReader();
        ...

ollamaopen-webui 前端项目实现和人类一样沟通的方法,使用的是stream监听 messages事件收到的响应,保持长连接的状态,逐渐将收到的消息显示到前端,直到后端响应结束。

后端

  • gin.Stream
go 复制代码
...
    c.Stream(func(w io.Writer) bool {
        select {
        case msg, ok := <-msgChan:
            if !ok {
                // 如果msgChan被关闭,则结束流式传输
                return false
            }
            fmt.Print(msg)
            // 流式响应,发送给 messages 事件,和前端进行交互
            c.SSEvent("messages", msg)
            return true
        case <-c.Done():
            // 如果客户端连接关闭,则结束流式传输
            return false
        }
    })
...
  • ollama 响应
go 复制代码
...
    // llms.WithStreamingFunc 将ollama api 的响应内容逐渐返回,而不是一次性全部返回
    callOp := llms.WithStreamingFunc(func(ctx context.Context, chunk []byte) error {
        select {
        case msgChan <- string(chunk):
        case <-ctx.Done():
            return ctx.Err() // 返回上下文的错误
        }
        return nil
    })

    _, err := llaClient.Call(context.Background(), prompt, callOp)
    if err != nil {
        log.Fatalf("Call failed: %v", err) // 处理错误,而不是 panic
    }
...
  • 完整代码
go 复制代码
package main

import (
    "context"
    "fmt"
    "io"
    "log"
    "net/http"

    "github.com/gin-gonic/gin"
    "github.com/tmc/langchaingo/llms"
    "github.com/tmc/langchaingo/llms/ollama"
)

func main() {
    router := gin.Default()

    router.GET("/ping", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{
            "message": "OK",
        })
    })

    router.POST("/chat", chat)

    router.Run(":8083")
}

type Prompt struct {
    Text string `json:"text"`
}

func chat(c *gin.Context) {
    var prompt Prompt
    if err := c.BindJSON(&prompt); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return


    }

    var msgChan = make(chan string)
    // 通过chan 将ollama 响应返回给前端
    go Generate(prompt.Text, msgChan)

    c.Stream(func(w io.Writer) bool {
        select {
        case msg, ok := <-msgChan:
            if !ok {
                // 如果msgChan被关闭,则结束流式传输
                return false
            }
            // fmt.Print(msg)
            c.SSEvent("messages", msg)
            return true
        case <-c.Done():
            // 如果客户端连接关闭,则结束流式传输
            return false
        }
    })
}

var llaClient *ollama.LLM

func init() {
    // Create a new Ollama instance
    // The model is set to "gemma:2b"
    // remote url is set to "http://ollama-ip:11434"
    url := ollama.WithServerURL("http://ollama-ip:11434")
    lla, err := ollama.New(ollama.WithModel("gemma:2b"), url)
    if err != nil {
        panic(err)
    }

    llaClient = lla

    fmt.Println("connect to ollama server successfully")
}

func Generate(prompt string, msgChan chan string) {
    // ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) // 设置超时
    // defer cancel()                                                          // 确保在函数结束时取消上下文

    callOp := llms.WithStreamingFunc(func(ctx context.Context, chunk []byte) error {
        select {
        case msgChan <- string(chunk):
        case <-ctx.Done():
            return ctx.Err() // 返回上下文的错误
        }
        return nil
    })

    _, err := llaClient.Call(context.Background(), prompt, callOp)
    if err != nil {
        log.Fatalf("Call failed: %v", err) // 处理错误,而不是 panic
    }

    // 确保在所有数据处理完毕后关闭 msgChan
    close(msgChan)
}

项目地址

jackwillsmith/openui-svelte-build (github.com)

GitHub - jackwillsmith/openui-backend-go: openui-backend-go

相关推荐
Narutolxy2 小时前
大模型数据分析破局之路20250512
人工智能·chatgpt·数据分析
AIWritePaper智能写作探索14 小时前
高质量学术引言如何妙用ChatGPT?如何写提示词?
人工智能·chatgpt·prompt·智能写作·aiwritepaper·引言
陌尘(MoCheeen)16 小时前
技术书籍推荐(002)
java·javascript·c++·python·go
江鸟199820 小时前
AI日报 · 2025年05月11日|传闻 OpenAI 考虑推出 ChatGPT “永久”订阅模式
人工智能·gpt·ai·chatgpt·github
知来者逆21 小时前
AI 在模仿历史语言方面面临挑战:大型语言模型在生成历史风格文本时的困境与研究进展
人工智能·深度学习·语言模型·自然语言处理·chatgpt
AI Echoes2 天前
大模型(LLMs)强化学习——RLHF及其变种
人工智能·深度学习·算法·机器学习·chatgpt
白泽来了2 天前
字节大模型应用开发框架 Eino 全解(一)|结合 RAG 知识库案例分析框架生态
开源·go·大模型应用开发
没有梦想的咸鱼185-1037-16633 天前
【大语言模型ChatGPT4/4o 】“AI大模型+”多技术融合:赋能自然科学暨ChatGPT在地学、GIS、气象、农业、生态与环境领域中的应用
人工智能·python·机器学习·arcgis·语言模型·chatgpt·数据分析
yibuapi_com3 天前
Embedding 的数学特性与可视化解析
chatgpt·架构·langchain·embedding·claude·向量数据库·中转api
致于数据科学家的小陈3 天前
Go 层级菜单树转 json 处理
python·go·json·菜单树·菜单权限·children