暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

golang实现deepseek 聊天功能

        在搭建完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
          下面我们介绍下如何使用langchaingo来完成聊天功能,聊天过程中,我们经常需要联系上下文,也就是说需要回顾历史信息,所以历史聊天记录就是我们的context。
        聊天的时候把聊天内容记录下来,和llm聊天的时候把它带给大模型。然后使用ollama.New来初始化大模型
     llm, err := ollama.New(ollama.WithModel("deepseek-r1:1.5b"))
    复制
    如果不指定ollama地址,包的内部会制定默认地址和端口github.com/tmc/langchaingo@v0.1.13/llms/ollama/internal/ollamaclient/ollamaclient.go
      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方法,发送请求,等待大模型的返回
           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
                    }),
                )
        复制
        以上就是聊天的核心流程,完整代码如下:
          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([]string0),
              }, 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([]string0)
                      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 stringstring {
              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)
              }
          }
          复制
                  简单测试下效果
            % go run ./exp3/main.go
            欢迎使用 LLM 聊天程序!
            输入 'exit' 退出
            输入 'clear' 清除对话历史
            ----------------------------------------


            Human: 你好


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


            </think>


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


            完整响应:
            <think>


            </think>


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


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


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


            接下来,我想到可以加入一些有趣的事实或信息,让用户觉得有趣而且有帮助。比如,我可以告诉用户他们出生在1987年12月3日,在香港度过童年,这让我能更生动地描绘一个可爱的笑容。
            复制
                    至此一个简单的聊天机器人就宣告完成了。

            文章转载自golang算法架构leetcode技术php,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

            评论