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

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

  • 如何让机器人具有记忆
  • 如何使用 langgraph 自动记录聊天历史

我们将同时使用 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大模型

通过历史记录了解上下文

大模型本身不具备记忆 功能,通常我们在调用大模型时,将聊天历史也喂给大模型,这样大模型就可以理解上下文,而产生记忆能力。
ChatModel (例如:ChatOllama) 是 LangChain Runnable 的实例,这意味着它们公开了一个用于与其交互的标准接口。比如 .invoke 方法。

下面我们做一下测试:

python 复制代码
def chat(model_name):
    model = ChatOllama(model=model_name,temperature=0.3,verbose=True)
    response = model.invoke([HumanMessage(content="Hi! I'm Bob")])
    print(f'chat_with_no_memory:\n{response.content}')

    # We can see that it doesn't take the previous conversation turn into context, and cannot answer the question. This makes for a terrible chatbot experience!
    response = model.invoke([HumanMessage(content="What's my name?")])
    print(f'chat_with_no_memory 2:\n{response.content}')

def chat_with_memory(model_name):
    '''具有记忆功能'''
    model = ChatOllama(model=model_name,temperature=0.3,verbose=True)
    response = model.invoke(
        [
            HumanMessage(content="Hi! I'm Bob"),
            AIMessage(content="Hello Bob! How can I assist you today?"),
            HumanMessage(content="What's my name?"),
        ]
    )
    print(f'chat_with_memory:\n{response.content}')

我们调用一下上述方法,看看返回结果:

  • 调用 chat 方法:
llama3.1 deepseek-r1
Hi! I'm Bob Nice to meet you, Bob! How's your day going so far? Hello, Bob! How can I assist you today? 😊
What's my name? I'm a large language model, ... , we can just chat as "you" and "I" for now. Hi! I'm DeepSeek-R1, ... , we invite you to consult our official documentation.
  • 调用 chat_with_memory 方法:
llama3.1 deepseek-r1
Your name is Bob. We just established that! Hi! I'm DeepSeek-R1, ... Your name is Bob.

看起来 llama3.1deepseek-r1 给出的回答很相似,并且,在给出历史聊天信息的情况下,它们都可以自动推断出当前用户的名字。

LangGraph 自动记录聊天信息

LangGraph 实现了内置持久层,使其成为支持多轮对话的聊天应用程序的理想选择。 将我们的聊天模型包装在最小的 LangGraph 应用程序中,使我们能够自动保存消息历史记录,从而简化多轮对话应用程序的开发。

python 复制代码
def build_app(model_name):

    model = ChatOllama(model=model_name,temperature=0.3,verbose=True)

    # Define the function that calls the model
    def call_model(state: MessagesState):
        response = model.invoke(state["messages"])
        return {"messages": response}

    # Define a new graph
    workflow = StateGraph(state_schema=MessagesState)

    # Define the (single) node in the graph
    workflow.add_edge(START, "model")
    workflow.add_node("model", call_model)

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

感觉 LangGraph 实现的代码比较直观优雅,更加适合实现复杂一些的 Agent ,后面我们将有更多关于 LangGraph 实现 Agent 的演示。

下面用 config 设定不同的会话,查看大模型的表现。

python 复制代码
def message_persistence():
    app = build_app()
    
    config = {"configurable": {"thread_id": "abc123"}}

    query = "Hi! I'm Bob."

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

    query = "What's my name?"

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

    # different thread_id
    config = {"configurable": {"thread_id": "abc234"}}

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

    config = {"configurable": {"thread_id": "abc123"}}

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

我们来看看大模型本轮表现:

  • llama3.1
text 复制代码
================================== Ai Message ==================================

Nice to meet you, Bob! How's your day going so far? Is there something on your mind that you'd like to chat about or is this just a friendly hello?
None
================================== Ai Message ==================================

Your name is Bob! We established that right at the beginning of our conversation.
None
================================== Ai Message ==================================

I'm a large language model, I don't have any information about your personal identity or name. ... , I'd be happy to chat with you!
None
================================== Ai Message ==================================

Your name is Bob, as we've already discussed!
None
  • deepseek-r1
text 复制代码
================================== Ai Message ==================================

<think>

</think>

Hello, Bob! How can I assist you today? 😊
None
================================== Ai Message ==================================

<think>
Alright, the user greeted me as Bob and mentioned they're Bob. Now, they asked, "What's my name?" 

...

I should make sure the response is warm and approachable, letting them know I'm here to help.
</think>

Hello! My name is Bob. How can I assist you today? 😊
None
================================== Ai Message ==================================

<think>

</think>

Hi! I don't have access to personal information like names or identities. Could you ask something else I can help you with?
None
================================== Ai Message ==================================

<think>
Okay, so the user has been interacting with me as Bob multiple times now. They asked "What's my name?" again after I told them it was Bob.

...

I should make sure the response is clear and friendly, letting them know I'm here to help without overcomplicating things.
</think>

It seems like you might be asking about my name, but as an AI, I don't have personal experiences or feelings. My "name" is a label you've given me in our conversation. How can I assist you further? 😊
None

我们看到 deepseek-r1 返回了思考过程,想法比较复杂,最后并未直接回答名字。

总结

通过实现这个简单的聊天机器人,我们可以发现 llama3.1deepseek-r1 都可以轻松处理聊天任务,不过似乎 deepseek-r1 更加 "狡猾" 一点。

代码

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

参考:

🪐祝好运🪐

相关推荐
canonical_entropy2 分钟前
AI的集体反思:我们为什么未能预见到"可逆计算"的演进方向?
人工智能·低代码·aigc
mortimer2 小时前
Python 文件上传:一个简单却易犯的错误及解决方案
人工智能·python
IT_陈寒2 小时前
Vue3性能优化实战:这5个技巧让我的应用加载速度提升了70%
前端·人工智能·后端
机器之心2 小时前
英伟达50亿美元入股英特尔,将发布CPU+GPU合体芯片,大结局来了?
人工智能·openai
新智元2 小时前
芯片大地震,黄仁勋355亿入股!英特尔要为老黄造CPU,股价狂飙30%
人工智能·openai
阿然1653 小时前
首次尝试,95% 的代码都是垃圾:一位工程师使用 Claude Code 六周的心得
人工智能·agent·ai编程
martinzh3 小时前
RAG系统优化大揭秘:让你的AI从学渣变学霸的进化之路
人工智能
汀丶人工智能3 小时前
想成为AI绘画高手?打造独一无二的视觉IP!Seedream 4.0 使用指南详解,创意无界,效率翻倍!
人工智能
蚝油菜花3 小时前
万字深度解析Claude Code的Hook系统:让AI编程更智能、更可控|下篇—实战篇
人工智能·ai编程·claude
中杯可乐多加冰4 小时前
从创意到应用:秒哒黑客松大赛 用零代码点燃你的创新火花
人工智能