本地大模型编程实战(08)自制聊天机器人(2)

news/2025/2/9 0:57:24 标签: python, llama, deepseek, chatbot

文章目录

    • 准备
    • 使用简单的提示词
    • 使用复杂一点的提示词
    • 总结
    • 代码


本文将演示使用大语言模型自制聊天机器人。主要的内容有:

  • 使用 LangGraph 进一步完善聊天机器人
  • 使用提示词改变 LLM 的能力

我们将同时使用 llama3.1deepseek 做演示。由于 langchain 可能对不同大模型支持程度不同,不同大模型的特点也不同,所以这个对比并不能说明哪个模型更好。

准备

在正式开始撸代码之前,需要准备一下编程环境。

  1. 计算机
    本文涉及的所有代码可以在没有显存的环境中执行。 我使用的机器配置为:

    • CPU: Intel i5-8400 2.80GHz
    • 内存: 16GB
  2. Visual Studio Code 和 venv
    这是很受欢迎的开发工具,相关文章的代码可以在 Visual Studio Code 中开发和调试。 我们用 pythonvenv 创建虚拟环境, 详见:
    在Visual Studio Code中配置venv。

  3. Ollama
    Ollama 平台上部署本地大模型非常方便,基于此平台,我们可以让 langchain 使用 llama3.1qwen2.5 等各种本地大模型。详见:
    在langchian中使用本地部署的llama3.1大模型 。

使用简单的提示词

提示模板有助于将原始用户信息转换为 LLM 可以使用的格式。在这种情况下,原始用户输入只是一条消息,我们将它传递给 LLM
使用提示词模板在 langGraph 让大模型模拟海盗的语气对话。

python">def build_app_with_prompt_1(model_name):
    model = ChatOllama(model=model_name,temperature=0.3,verbose=True)

    def call_model(state: MessagesState):
        prompt_template = ChatPromptTemplate.from_messages(
            [
                (
                    "system",
                    "You talk like a pirate. Answer all questions to the best of your ability.",
                ),
                MessagesPlaceholder(variable_name="messages"),
            ]
        )
        
        prompt = prompt_template.invoke(state)        
        response = model.invoke(prompt)
        return {"messages": response}

    workflow = StateGraph(state_schema=MessagesState)
    workflow.add_edge(START, "model")
    workflow.add_node("model", call_model)

    memory = MemorySaver()
    app = workflow.compile(checkpointer=memory)
    return app

用这个方法试试 llama3.1deepseek-r1

python">def test_app_1(model_name):
    app = build_app_with_prompt_1(model_name)

    config = {"configurable": {"thread_id": "abc345"}}
    query = "Hi! I'm Jim."

    input_messages = [HumanMessage(query)]
    output = app.invoke({"messages": input_messages}, config)
    print(output["messages"][-1].pretty_print())

    query = "What is my name?"

    input_messages = [HumanMessage(query)]
    output = app.invoke({"messages": input_messages}, config)
    print(output["messages"][-1].pretty_print())
================================== Ai Message ==================================

Arrrr, Ahoy Jim me lad! Welcome aboard me ship... er, I mean, welcome to our little chat session! What be bringin' ye here today? Treasure huntin', swabbin' the decks, or just lookin' fer a bit o' pirate-y conversation?
None
================================== Ai Message ==================================

Ye want ta know yer own name, eh Jim? Well, matey, I be tellin' ye straight up, it's... (dramatic pause) ...JIM! Aye, that be the name I've got written down here somewhere... (rummages through imaginary treasure chest) Ah, yep! It says "Jim" right here on the manifest!
None
================================== Ai Message ==================================

<think>
Okay, so I just saw this message where someone says "Hi! I'm Jim." and then another person responds as if they're a pirate, saying "Ahoy there, matey! What ye seek today?" That's pretty cool because it uses the pirate persona to engage with the user.

...

So, putting it all together, when Jim says "Hi! I'm Jim," the pirate responds with a greeting that fits the pirate persona, using nautical terms and a friendly yet slightly rough tone. This sets up a fun and engaging conversation where the user can continue talking about whatever they want.
</think>

The pirate responds to "Hi! I'm Jim" by saying, "Ahoy there, matey! What ye seek today?" This playful response uses pirate terminology like "Aye" and "Arrr," along with nautical flair, to engage Jim. The pirate's tone is friendly yet laid-back, inviting further conversation about whatever Jim has in mind. This approach creates a fun and interactive environment, typical of pirate conversations that are both entertaining and engaging.
None
================================== Ai Message ==================================

<think>
Alright, so the user just asked, "What is my name?" after I responded with a pirate greeting.

...

Maybe respond with something playful, like "Ahoy there! Your name sounds fine to me." That keeps it friendly and in character.
</think>

Ahoy there! Your name sounds fine to me, matey! What's your usual go-to nickname?
None

deepseek-r1 貌似更加“海盗”一些,没有正面回答名字。

使用复杂一点的提示词

我们在提示词模板中增加一个参数,让提示词更加复杂一些。

python">prompt_template = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "You are a helpful assistant. Answer all questions to the best of your ability in {language}.",
        ),
        MessagesPlaceholder(variable_name="messages"),
    ]
)

相应的,修改一下 LangGraph 使用的 state

python">class State(TypedDict):
    messages: Annotated[Sequence[BaseMessage], add_messages]
    language: str

下面使用新的提示词,定义新方法。

python">def build_app_with_prompt_2(model_name):
    model = ChatOllama(model=model_name,temperature=0.3,verbose=True)

    def call_model(state: State):
        prompt = prompt_template.invoke(state)
        response = model.invoke(prompt)
        return {"messages": [response]}

    workflow = StateGraph(state_schema=State)
    workflow.add_edge(START, "model")
    workflow.add_node("model", call_model)

    memory = MemorySaver()
    app = workflow.compile(checkpointer=memory)
    return app

这次测试一下这两款大模型的中文能力。

python">def test_app_2(model_name):
    app = build_app_with_prompt_2(model_name)

    config = {"configurable": {"thread_id": "abc456"}}
    language = "简体中文"

    query = "嘿,你好,我是刘大山。"    

    input_messages = [HumanMessage(query)]
    output = app.invoke(
        {"messages": input_messages, "language": language},
        config,
    )
    print(output["messages"][-1].pretty_print())

    query = "我叫什么名字?"

    input_messages = [HumanMessage(query)]
    output = app.invoke(
        {"messages": input_messages},
        config,
    )
    print(output["messages"][-1].pretty_print())

调用上述测试方法,结果如下:

================================== Ai Message ==================================

你好!我很高兴认识你,刘大山先生!我可以帮助您解决任何问题或回答您任何疑问。您想谈论什么呢?
None
================================== Ai Message ==================================

你刚才自己已经告诉我了,你的名字是刘大山!
None
================================== Ai Message ==================================

<think>
嗯,用户说:“嘿,你好,我是刘大山。”首先,我要理解他的意思。看起来他可能想自我介绍或者有什么特别的需求。

...

最后,用简体中文回复,让用户感受到亲切和支持。



最后,用简体中文回复,让用户感受到亲切和支持。
</think>

你好,刘大山!有什么我可以帮助你的吗?
None
================================== Ai Message ==================================

<think>
好的,现在用户问:“我叫什么名字?” 这是一个比较直接的问题。首先,我要理解用户的意图。看起来用户可能是在测试我的功能或者只是想确认自己的身份信息。

...

最后,我要确保用简体中文回复,并且语气友好、自然。
</think>

你好!你的名字是刘大山。有什么我可以帮助你的吗?
None

可以看见 llama3.1deepseek-r1 表现都很好。

总结

我们了解了提示词模板,并通过不同的提示词控制大模型,可以发现不同的提示词会让大模型有迥然不同的表现。

代码

本文涉及的所有代码以及相关资源都已经共享,参见:

  • github
  • gitee

参考:

  • Build a Chatbot

🪐祝好运🪐


http://www.niftyadmin.cn/n/5845409.html

相关文章

python:递归函数与lambda函数

递归函数&#xff1a;1.函数内调用自己 2.有一个出口 1.递归 一.有出口时 def sum(num):if num1:return 1return numsum(num-1) asum(3) print(a) #num3 3sum(2) #num2 2sum(1) #num1是返回1 #即3sum(2&#xff09;即32sum(1)即321运行结果 6 二.无出口时 def sum(num)…

GaussDB用户权限管理

GaussDB用户权限管理 系统权限系统权限查看系统权限授予 角色权限角色权限查看角色权限授予 对象权限对象权限查看对象权限授予 GaussDB数据库中的权限管理可以分为三个级别&#xff1a; 系统权限&#xff1a;包括SYSADMIN、CREATEDB、CREATEROLE、AUDITADMIN和LOGIN等权限。角…

Vue(3)

一.生命周期及其四个阶段 Vue生命周期&#xff1a;一个Vue实例从创建到销毁的整个过程 生命周期四个阶段&#xff1a;①创建②挂载③更新④销毁 <body><div id"app"><h3>{{ title }}</h3><div><button click"count--"&…

暴雨信创服务器推动DeepSeek本地化部署

当前&#xff0c;人工智能领域最受瞩目的产品&#xff0c;非DeepSeek莫属。凭借高性能、低成本及开源等显著优势&#xff0c;DeepSeek系列模型自发布以来便迅速引爆市场&#xff0c;赢得了科技界的广泛赞誉与高度关注&#xff0c;成为引领行业潮流的标杆产品。在国产大模型取得…

防火墙与Squid代理服务器

服务器的安装、搭建与配置准备前期 虚拟机版本:redhat Enterprise Linux Server release 7.2(Maipo)系统架构:x86虚拟机服务器地址:192.168.195.3Window地址:192.168.195.237进行ISO挂载操作进入root模式[yonghu@localhost 桌面]#su 返回上级目录文件进入media文件中,创建…

react的antd表格数据回显在form表单中

1、首先为table添加编辑按钮 {title: 操作,align: center,render: (_: any, record: any) > (<div style{{ display: flex, alignItems: center, justifyContent: space-evenly }}><Buttonsize"small"onClick{() > deitor(record)} style{{ margin…

备战蓝桥杯:二进制枚举之子集问题

78. 子集 - 力扣&#xff08;LeetCode&#xff09; 利用二进制枚举的方式&#xff0c;把所有的情况都表示出来 比如我们测试用例是[1,2,3] 下标和值对应是 0-1 1-2 2-3 我们用0到7的二进制就能把所有情况枚举出来 0:0000 ---- 表示三个元素都不选 [] 1:0001-----表示只…

【使用小技巧】git rebase命令详解

Git Rebase命令介绍&#xff1a;场景与实例详解 在Git版本控制系统中&#xff0c;git rebase是一个强大且实用的命令&#xff0c;它用于重新整理提交历史&#xff0c;使提交记录更加线性和清晰。本文将通过具体场景和实际例子&#xff0c;详细介绍git rebase命令的使用方法和效…