部署DeepSeek模型,进群交流最in玩法!
立即加群
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >让DeepSeek模仿曹操,果然好玩!

让DeepSeek模仿曹操,果然好玩!

原创
作者头像
闫同学
修改2025-03-30 13:28:31
修改2025-03-30 13:28:31
1670
举报
文章被收录于专栏:AI相关AI相关Coding实践

上回说到,在《新三国》中荀彧对曹操说的那句名言,但相比荀彧而言,我觉得曹操的名言会更多,我一想,若能用AI重现这位乱世奸雄曹操,会得到怎样的体验?

于是这篇文章我们将以Go语言为例,展示如何通过LangChain框架调用DeepSeek大模型,重现一代枭雄曹操的独特对话风格。

工具介绍

LangChain 是一个专为构建大语言模型应用设计的开发框架,其核心使命是打通语言模型与真实世界的连接通道。它通过模块化设计将数据处理、记忆管理、工具调用等能力封装为标准化组件,开发者可像搭积木般将这些模块组装成智能应用链。经过一段时间的发展,LangChain不仅支持Python生态快速实现原型验证,也提供Go语言实现满足高并发生产需求。

在Go项目中安装:

代码语言:shell
复制
go get -u github.com/tmc/langchaingo

使用LangChain接入DeepSeek

现在我们写一个最简单的LangChain程序,主要分为以下几个步骤:

1)函数定义和初始化OpenAI客户端

2)创建聊天消息

3)生成内容并流式输出

4)输出推理过程和最终答案

下面是代码:

代码语言:go
复制
func Simple() {
    // 函数定义和初始化OpenAI客户端
    llm, err := openai.New(
        openai.WithBaseURL("https://api.deepseek.com"),
        openai.WithModel("deepseek-chat"),
        openai.WithToken("xxx"), // 填写自己的API Key
    )
    if err != nil {
        log.Fatal(err)
    }
    
    // 创建聊天消息
    content := []llms.MessageContent{
        llms.TextParts(llms.ChatMessageTypeSystem, "你现在模仿曹操,以曹操的口吻和风格回答问题,要展现出曹操的霸气与谋略"),
        llms.TextParts(llms.ChatMessageTypeHuman, "赤壁之战打输了怎么办?"),
    }

    // 生成内容并流式输出
    fmt.Print("曹孟德:")
    completion, err := llm.GenerateContent(
        context.Background(),
        content,
        llms.WithMaxTokens(2000),
        llms.WithTemperature(0.7),
        llms.WithStreamingReasoningFunc(func(ctx context.Context, reasoningChunk []byte, chunk []byte) error {
            contentColor := color.New(color.FgCyan).Add(color.Bold)
            if len(chunk) > 0 {
                _, err := contentColor.Printf("%s", string(chunk))
                if err != nil {
                    return err
                }
            }
            return nil
        }),
    )
    if err != nil {
        log.Fatal(err)
    }

    // 输出推理过程和最终答案
    if len(completion.Choices) > 0 {
        choice := completion.Choices[0]
        fmt.Printf("\nFinal Answer:\n%s\n", choice.Content)
    }
}

当然,如果我们想通过控制台和大模型多轮对话的话可以基于现有程序进行改造:

代码语言:go
复制
func Input() {
    llm, err := openai.New(
        openai.WithBaseURL("https://api.deepseek.com"),
        openai.WithModel("deepseek-chat"),
        openai.WithToken("xxx"),
    )
    if err != nil {
        log.Fatal(err)
    }

    // 初始系统消息
    systemMessage := llms.TextParts(llms.ChatMessageTypeSystem, "你现在模仿曹操,以曹操的口吻和风格回答问题,要展现出曹操的霸气与谋略。")
    content := []llms.MessageContent{systemMessage}

    scanner := bufio.NewScanner(os.Stdin)
    for {
        fmt.Print("闫同学:")
        scanner.Scan()
        question := scanner.Text()

        if question == "exit" {
            break
        }

        // 添加新的用户问题
        userMessage := llms.TextParts(llms.ChatMessageTypeHuman, question)
        content = append(content, userMessage)

        fmt.Print("曹孟德:")
        // Generate content with streaming to see both reasoning and final answer in real-time
        completion, err := llm.GenerateContent(
            context.Background(),
            content,
            llms.WithMaxTokens(2000),
            llms.WithTemperature(0.7),
            llms.WithStreamingReasoningFunc(func(ctx context.Context, reasoningChunk []byte, chunk []byte) error {
                contentColor := color.New(color.FgCyan).Add(color.Bold)
                if len(chunk) > 0 {
                    _, err := contentColor.Printf("%s", string(chunk))
                    if err != nil {
                        return err
                    }
                }
                return nil
            }),
        )
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println()
        // 将回复添加到历史消息中
        if len(completion.Choices) > 0 {
            choice := completion.Choices[0]
            assistantMessage := llms.TextParts(llms.ChatMessageTypeHuman, choice.Content)
            content = append(content, assistantMessage)
        }
    }
}

现在我们来启动调试一下:

重点步骤说明

其实纵观上面的整段代码,我认为在打造自己Agent中,最重要的一步莫过于在与AI对话前的消息组合部分,我们到底该怎样与AI对话才能得到自己想要的结果。

首先是content代码段的作用

代码语言:go
复制
content := []llms.MessageContent{
    llms.TextParts(llms.ChatMessageTypeSystem, "你现在模仿曹操,以曹操的口吻和风格回答问题,要展现出曹操的霸气与谋略"),
    llms.TextParts(llms.ChatMessageTypeHuman, "赤壁之战打输了怎么办?"),
}

content 是一个 []llms.MessageContent 类型的切片,用于存储一系列的聊天消息内容。

llms.TextParts是 langchaingo 库中用于创建文本消息内容的函数。它接受两个参数:消息类型和消息内容。

llms.ChatMessageTypeSystem表示系统消息类型。系统消息通常用于给 AI 提供一些额外的指令或上下文信息。在这个例子中,系统消息告知 AI 要模仿曹操的口吻和风格进行回答。

llms.ChatMessageTypeHuman表示人类用户发送的消息类型。这里的消息内容是用户提出的问题“赤壁之战打输了怎么办?”。

ChatMessageType有哪些常量?我们来看下源码:

代码语言:go
复制
// ChatMessageTypeAI is a message sent by an AI.
ChatMessageTypeAI ChatMessageType = "ai"
// ChatMessageTypeHuman is a message sent by a human.
ChatMessageTypeHuman ChatMessageType = "human"
// ChatMessageTypeSystem is a message sent by the system.
ChatMessageTypeSystem ChatMessageType = "system"
// ChatMessageTypeGeneric is a message sent by a generic user.
ChatMessageTypeGeneric ChatMessageType = "generic"
// ChatMessageTypeFunction is a message sent by a function.
ChatMessageTypeFunction ChatMessageType = "function"
// ChatMessageTypeTool is a message sent by a tool.
ChatMessageTypeTool ChatMessageType = "tool"

解释下这些常量分别代表什么:

1)ChatMessageTypeAI:表示由 AI 生成并发送的消息。当 AI 对用户的问题进行回答时,生成的回复消息就属于这种类型。

2)ChatMessageTypeHuman:代表人类用户发送的消息。例如,用户在聊天界面输入的问题、评论等都属于人类消息。

3)ChatMessageTypeSystem:是系统发送的消息,用于设置 AI 的行为、提供指令或者上下文信息。系统消息可以帮助 AI 更好地理解任务和要求。

4)ChatMessageTypeGeneric:表示由通用用户发送的消息。这里的“通用用户”可以是除了明确的人类用户和 AI 之外的其他类型的用户。

5)ChatMessageTypeFunction:表示由函数调用产生的消息。在一些复杂的聊天系统中,AI 可能会调用外部函数来完成某些任务,函数执行的结果会以这种类型的消息返回。

6)ChatMessageTypeTool:表示由工具调用产生的消息。类似于函数调用,工具调用可以帮助 AI 完成更复杂的任务,工具执行的结果会以这种类型的消息呈现。

这些常量的定义有助于在代码中清晰地区分不同类型的聊天消息,方便对消息进行处理和管理。

接入DeepSeek-R1支持深度思考

本篇文章关于DeepSeek的相关文档主要参考deepseek官方文档,这篇文档里我们可以看到DeepSeek的V3模型和R1模型是两个不同的模型标识,即:

model='deepseek-chat' 即可调用 DeepSeek-V3。

model='deepseek-reasoner',即可调用 DeepSeek-R1。

因此在调用R1模型时我们需要改变初始化client的策略,然后在处理回答的时候也需要额外处理思考部分的回答,具体改动的地方如下:

1)初始化使用deepseek-reasoner:

代码语言:go
复制
llm, err := openai.New(
    openai.WithBaseURL("https://api.deepseek.com"),
    openai.WithModel("deepseek-reasoner"),
    openai.WithToken("xxx"),
 )

2)函数处理思考部分

代码语言:go
复制
completion, err := llm.GenerateContent(
    ctx,
    content,
    llms.WithMaxTokens(2000),
    llms.WithTemperature(0.7),
    llms.WithStreamingReasoningFunc(func(ctx context.Context, reasoningChunk []byte, chunk []byte) error {
        contentColor := color.New(color.FgCyan).Add(color.Bold)
        reasoningColor := color.New(color.FgYellow).Add(color.Bold)

        if !isPrint {
            isPrint = true
            fmt.Print("[思考中]")
        }

        // 思考部分
        if len(reasoningChunk) > 0 {
            _, err := reasoningColor.Printf("%s", string(reasoningChunk))
            if err != nil {
                return err
            }
        }
        
        // 回答部分
        if len(chunk) > 0 {
            _, err := contentColor.Printf("%s", string(chunk))
            if err != nil {
                return err
            }
        }
        return nil
    }),
)

基于上面这些改动我们就能使用R1模型进行接入了。

小总结

这篇文章可以说展示了LangChain对接大模型的最基本功能,也是搭建我们自己Agent的第一步,如果真的想要搭建一个完整的AI Agent,那么还需要有很多地方进行补充和优化,比如:

  • 上下文记忆:添加会话历史管理
  • 风格校验:构建古汉语词库验证
  • 多模态扩展:结合人物画像生成

本篇文章到这里就结束啦~

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 工具介绍
  • 使用LangChain接入DeepSeek
  • 重点步骤说明
  • 接入DeepSeek-R1支持深度思考
  • 小总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档