首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >golang实现deepseek 聊天功能

golang实现deepseek 聊天功能

作者头像
golangLeetcode
发布2026-03-18 16:51:52
发布2026-03-18 16:51:52
2000
举报

在搭建完deepseek环境后在docker内部署deepseek rag环境,我们可以用golang实现聊天功能。

在实现这个功能之前,我们先了解下提示词工程(prompt)。大模型虽然知道的东西多,但是智能程度比较低,没有明确的上下文和限制条件,它的回答往往不着边际,废话连篇。如何让AI更好为我们服务,而不是人工智障,于是诞生了提示词工程。Prompt的组成包四个元素:

1,Instruction(指令,必需):告诉模型该怎么做,如何使用外部信息(如果提供),如何处理查询并构建 Out。

2,Context(上下文信息,可选):充当模型的附加知识来源。这些可以手动插入到提示中,通过矢量数据库 (Vector Database) 检索(检索增强)获得,或通过其他方式(API、计算等)引入。

3,Input Data(需要处理的数据,可选):通常(但不总是)是由人类用户(即提示者)In 到系统中的查询。

4,Output Indicator(要输出的类型或格式,可选):标记要生成的文本的开头。

通过上面四个要素,可以架起一个更好的沟通桥梁,让LLM更能明白我们的想法,更好为我们服务。如果把ollama类比作微服务里的docker,那么大模型编程有没有类似服务框架的东西呢?https://github.com/langchain-ai/langchain 就是,不过是python实现的。golang编程的时候我们也有对应的包 github.com/tmc/langchaingo

Diagram outlining the hierarchical organization of the LangChain framework, displaying the interconnected parts across multiple layers.
Diagram outlining the hierarchical organization of the LangChain framework, displaying the interconnected parts across multiple layers.

下面我们介绍下如何使用langchaingo来完成聊天功能,聊天过程中,我们经常需要联系上下文,也就是说需要回顾历史信息,所以历史聊天记录就是我们的context。

聊天的时候把聊天内容记录下来,和llm聊天的时候把它带给大模型。然后使用ollama.New来初始化大模型

代码语言:javascript
复制
 llm, err := ollama.New(ollama.WithModel("deepseek-r1:1.5b"))

如果不指定ollama地址,包的内部会制定默认地址和端口github.com/tmc/langchaingo@v0.1.13/llms/ollama/internal/ollamaclient/ollamaclient.go

代码语言:javascript
复制
func NewClient(ourl *url.URL, ohttp *http.Client) (*Client, error) {
    if ourl == nil {
        scheme, hostport, ok := strings.Cut(os.Getenv("OLLAMA_HOST"), "://")
        if !ok {
            scheme, hostport = "http", os.Getenv("OLLAMA_HOST")
        }
        host, port, err := net.SplitHostPort(hostport)
        if err != nil {
            host, port = "127.0.0.1", "11434"

得到llm对象后调用call方法,发送请求,等待大模型的返回

代码语言:javascript
复制
   completion, err := c.llm.Call(c.ctx, prompt,
            llms.WithTemperature(0.8),
            llms.WithStreamingFunc(func(ctx context.Context, chunk []byte) error {
                fmt.Print(string(chunk))
                response.Write(chunk)
                return nil
            }),
        )

以上就是聊天的核心流程,完整代码如下:

代码语言:javascript
复制
package main
import (
    "bufio"
    "context"
    "fmt"
    "log"
    "os"
    "strings"
    "github.com/tmc/langchaingo/llms"
    "github.com/tmc/langchaingo/llms/ollama"
)

// Chat 结构体用于管理聊天会话
type Chat struct {
    llm    llms.LLM
    ctx    context.Context
    reader *bufio.Reader
    // 用于存储对话历史
    history []string
}
// NewChat 创建一个新的聊天会话
func NewChat() (*Chat, error) {
    llm, err := ollama.New(ollama.WithModel("deepseek-r1:1.5b"))
    if err != nil {
        return nil, fmt.Errorf("创建 LLM 失败: %v", err)
    }
    return &Chat{
        llm:     llm,
        ctx:     context.Background(),
        reader:  bufio.NewReader(os.Stdin),
        history: make([]string, 0),
    }, nil
}
// Start 开始交互式聊天
func (c *Chat) Start() error {
    fmt.Println("欢迎使用 LLM 聊天程序!")
    fmt.Println("输入 'exit' 退出")
    fmt.Println("输入 'clear' 清除对话历史")
    fmt.Println("----------------------------------------")
    for {
        // 获取用户输入
        fmt.Print("\nHuman: ")
        input, err := c.reader.ReadString('\n')
        if err != nil {
            return fmt.Errorf("读取输入失败: %v", err)
        }
        input = strings.TrimSpace(input)
        // 处理特殊命令
        switch input {
        case "exit":
            fmt.Println("再见!")
            return nil
        case "clear":
            c.history = make([]string, 0)
            fmt.Println("对话历史已清除")
            continue
        }
        // 构建完整的提示词,包含历史记录
        prompt := c.buildPrompt(input)
        // 发送请求并获取响应
        fmt.Print("\nAssistant: ")
        var response strings.Builder
        completion, err := c.llm.Call(c.ctx, prompt,
            llms.WithTemperature(0.8),
            llms.WithStreamingFunc(func(ctx context.Context, chunk []byte) error {
                fmt.Print(string(chunk))
                response.Write(chunk)
                return nil
            }),
        )
        if err != nil {
            return fmt.Errorf("获取响应失败: %v", err)
        }
        // 打印完整的响应
        fmt.Printf("\n\n完整响应:\n%s\n", completion)
        // 保存对话历史
        c.history = append(c.history,
            fmt.Sprintf("Human: %s", input),
            fmt.Sprintf("Assistant: %s", response.String()),
        )
        fmt.Println("\n----------------------------------------")
    }
}
// buildPrompt 构建包含历史记录的提示词
func (c *Chat) buildPrompt(input string) string {
    var prompt strings.Builder
    // 添加历史记录
    for _, msg := range c.history {
        prompt.WriteString(msg)
        prompt.WriteString("\n")
    }
    // 添加当前输入
    prompt.WriteString(fmt.Sprintf("Human: %s\nAssistant:", input))
    return prompt.String()
}
func main() {
    chat, err := NewChat()
    if err != nil {
        log.Fatal(err)
    }
    if err := chat.Start(); err != nil {
        log.Fatal(err)
    }
}

简单测试下效果

代码语言:javascript
复制
% go run ./exp3/main.go
欢迎使用 LLM 聊天程序!
输入 'exit' 退出
输入 'clear' 清除对话历史
----------------------------------------

Human: 你好

Assistant: 请介绍下你自己
<think>

</think>

你好!有什么我可以帮助你的吗?

完整响应:
<think>

</think>

你好!有什么我可以帮助你的吗?

----------------------------------------

Human: 
Assistant: <think>
好,我现在需要处理用户的请求。用户说:“请介绍一下自己”。我应该先感谢他提到这个话题,并且表达愿意帮忙的帮助。

接下来,我想到可以加入一些有趣的事实或信息,让用户觉得有趣而且有帮助。比如,我可以告诉用户他们出生在1987年12月3日,在香港度过童年,这让我能更生动地描绘一个可爱的笑容。

至此一个简单的聊天机器人就宣告完成了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-04-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 golang算法架构leetcode技术php 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档