【LLM】-17-会话存储

news2024/11/25 6:35:31

目录

1、会话存储类型

2、版本代码说明

3、对话缓存存储

3.1、示例代码

3.2、响应response说明

3.3、流式输出

3.4、添加提示词模板

3.5、指定回答语言

4、限制令牌数存储

4.1、trim_messages

4.1.1、自定义tokens计数器

4.1.2、自定义tokens计数器

4.2、完整chatbot代码

4.3、结合RunnableWithMessageHistory 

5、对话摘要存储

5.1、示例代码

5.2、NotImplementedError

5.3.1、问题原因

5.3.2、解决方式


LLM大模型本身并不具备记忆、存储功能,是无状态的;

LangChain 提供了多种储存类型,本质上是将历史的对话内容暂时存储,并在下次一并发送给模型,但这种存储功能,增加了大模型在内容解析、性能资源的消耗。

本文基于Langchain-chat-0.2.x版本 + chatglm3-6b 模型部署使用

1、会话存储类型

  • 对话缓存储存 

即储存了当前为止所有的对话信息

  • 对话缓存窗口储存 

随着对话变得越来越长,所需的内存量也变得非常长。将大量的tokens发送到LLM的成本,也会变得更加昂贵。

对话缓存窗口储存只保留一个窗口大小的对话。它只使用最近的n次交互。这可以用于保持最近交互的滑动窗口,以便缓冲区不会过大。

  • 对话令牌缓存储存 

内存将限制保存的token数量。如果字符数量超出指定数目,它会切掉这个对话的早期部分 以保留与最近的交流相对应的字符数量,但不超过字符限制。

添加对话到Token缓存储存,限制token数量,进行测试

  • 对话摘要缓存储存 

对话摘要缓存储存,使用 LLM 对到目前为止历史对话自动总结摘要,并将其保存下来。

2、版本代码说明

传统的使用 ConversationChain 已经移除, 使用RunnableWithMessageHistory 代替。具体可以参考博文结尾的官方文档

LangChainDeprecationWarning: The class `ConversationChain` was deprecated in LangChain 0.2.7 and will be removed in 1.0. Use RunnableWithMessageHistory: https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.history.RunnableWithMessageHistory.html instead.

在新版的官方示例,基本上完全实现了 openai.OpenAI.chat.completions.create 所需的参数功能

详细示例说明可以通过包 langchain_openai.chat_models.base.py

内部的注释中提供了新旧两种代码,在实现对应功能上的说明

from langchain_openai import ChatOpenAI

     llm = ChatOpenAI(
                model="gpt-4o",
                temperature=0,
                max_tokens=None,
                timeout=None,
                max_retries=2,
                # api_key="...",
                # base_url="...",
                # organization="...",
                # other params...
            )

**NOTE**: Any param which is not explicitly supported will be passed directly to the
    ``openai.OpenAI.chat.completions.create(...)`` API every time to the model is
    invoked. For example:
        .. code-block:: python

            from langchain_openai import ChatOpenAI
            import openai

            ChatOpenAI(..., frequency_penalty=0.2).invoke(...)

            # results in underlying API call of:

            openai.OpenAI(..).chat.completions.create(..., frequency_penalty=0.2)

            # which is also equivalent to:

            ChatOpenAI(...).invoke(..., frequency_penalty=0.2)

    Invoke:
        .. code-block:: python

            messages = [
                (
                    "system",
                    "You are a helpful translator. Translate the user sentence to French.",
                ),
                ("human", "I love programming."),
            ]
            llm.invoke(messages)

        .. code-block:: python

            AIMessage(
                content="J'adore la programmation.",
                response_metadata={
                    "token_usage": {
                        "completion_tokens": 5,
                        "prompt_tokens": 31,
                        "total_tokens": 36,
                    },
                    "model_name": "gpt-4o",
                    "system_fingerprint": "fp_43dfabdef1",
                    "finish_reason": "stop",
                    "logprobs": None,
                },
                id="run-012cffe2-5d3d-424d-83b5-51c6d4a593d1-0",
                usage_metadata={"input_tokens": 31, "output_tokens": 5, "total_tokens": 36},
            )

3、对话缓存存储

使用RunnableWithMessageHistory 类

1)通过创建全局对象store,存储所有历史记录

2)通过定义config中的id,区分不同用户的记录 config = {"configurable": {"session_id": "abc2"}},不同用户之间信息不共享

3.1、示例代码

from langchain_core.chat_history import (
    BaseChatMessageHistory,
    InMemoryChatMessageHistory,
)
from langchain_core.messages import HumanMessage
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.runnables import ConfigurableField
from langchain_openai import ChatOpenAI

import os

store = {}



os.environ.setdefault("OPENAI_API_KEY", "EMPTY")
os.environ.setdefault("OPENAI_API_BASE", "http://192.168.1.1:20000/v1")

# 创建模型API对象
model = ChatOpenAI(model='chatglm3-6b',max_tokens=20).configurable_fields(
    max_tokens=ConfigurableField(
        id="output_token_number",
        name="Max tokens in the output",
        description="The maximum number of tokens in the output",
    )
)

# 构建全局对象,存储所有历史记录
def get_session_history(session_id: str) -> BaseChatMessageHistory:
    if session_id not in store:
        store[session_id] = InMemoryChatMessageHistory()
    return store[session_id]


with_message_history = RunnableWithMessageHistory(model, get_session_history)

# 设置session id
config = {"configurable": {"session_id": "abc2"}}

# 通过message_history 发送消息
response = with_message_history.invoke(
    [HumanMessage(content="你好, 我叫宣晨光")],
    config=config,
)

# response 对象 包含了 token的使用量、sessionId
# print(response)
print(response.content)

response = with_message_history.invoke(
    [HumanMessage(content="你知道我的名字吗")],
    config=config,
)

print(response.content)


你好,宣晨光先生!很高兴能为您服务。请问有什么我可以为您解答
当然知道,您叫宣晨光。请问有什么我可以帮助您的吗?

在打印store 对象时,我们可以看出,store 存储了所有消息的输入与输出,

因此在实现滑动窗口类型的存储会话,可以对 InMemoryChatMessageHistory中的messages数组做截取操作,从而保持数组固定大小。

3.2、响应response说明

content='你好,宣晨光先生!很高兴能为您服务。请问有什么我可以为您解答'

response_metadata=

        {

                'token_usage':

                        {'completion_tokens': 20, 'prompt_tokens': 14, 'total_tokens': 34},

                'model_name': 'chatglm3-6b',

                'system_fingerprint': None,

                'finish_reason': 'stop',

                'logprobs': None

        }

id='run-d0c37edb-d83f-4852-b7fd-3f023ade9f9b-0'

usage_metadata={'input_tokens': 14, 'output_tokens': 20, 'total_tokens': 34}

3.3、流式输出

stream = model.stream("你知道我叫什么名字吗")
full = next(stream)
for chunk in stream:
    full += chunk
    print(full.content)

3.4、添加提示词模板

使用ChatPromptTemplate.from_messages 创建系统提示词

在invoke调用时,使用HumanMessage 传入用户输入

from langchain_core.chat_history import BaseChatMessageHistory, InMemoryChatMessageHistory
from langchain_core.messages import HumanMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import ConfigurableField, RunnableWithMessageHistory
from langchain_openai import ChatOpenAI


import os

os.environ.setdefault("OPENAI_API_KEY", "EMPTY")
os.environ.setdefault("OPENAI_API_BASE", "http://192.168.1.1:20000/v1")

model = ChatOpenAI(model='chatglm3-6b', max_tokens=1024).configurable_fields(
    max_tokens=ConfigurableField(
        id="output_token_number",
        name="Max tokens in the output",
        description="The maximum number of tokens in the output",
    )
)

# 添加提示词模板,完善LLM回答
prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "需要真实、准确的回答问题。不可以胡乱编造假的回答。如果是你不知道的问题,你可以回答不知道。",
        ),
        # 占位符
        MessagesPlaceholder(variable_name="messages"),
    ]
)

chain = prompt | model

# 未使用消息存储
response = chain.invoke({"messages": [HumanMessage(content="我是宣晨光")]})
print(response.content)
response = chain.invoke({"messages": [HumanMessage(content="你知道我的名字吗")]})
print(response.content)
print('\n')


# 添加历史消息记录
store = {}

def get_session_history(session_id: str) -> BaseChatMessageHistory:
    if session_id not in store:
        store[session_id] = InMemoryChatMessageHistory()
    return store[session_id]

with_message_history = RunnableWithMessageHistory(chain, get_session_history)

# 定义用户session
config = {"configurable": {"session_id": "abc2"}}
response = with_message_history.invoke( [HumanMessage(content="我是宣晨光")], config=config,)
print(response.content)

response = with_message_history.invoke( [HumanMessage(content="你知道我的名字吗")], config=config,)
print(response.content)

3.5、指定回答语言

针对不同的用户,采取不同的提示词模板策略。

1)在使用ChatPromptTemplate.from_messages 定义占位符的参数 {language}

2)在RunnableWithMessageHistory 中定义 input_messages_key="messages",

3)在invoke发送消息时,重新构造入参对象,并传入指定的language参数

  {"messages": [HumanMessage(content="我是宣晨光")], "language": "英语"}, 

from langchain_core.chat_history import BaseChatMessageHistory, InMemoryChatMessageHistory
from langchain_core.messages import HumanMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import ConfigurableField, RunnableWithMessageHistory
from langchain_openai import ChatOpenAI


import os

os.environ.setdefault("OPENAI_API_KEY", "EMPTY")
os.environ.setdefault("OPENAI_API_BASE", "http://192.168.1.1:20000/v1")

model = ChatOpenAI(model='chatglm3-6b', max_tokens=1024).configurable_fields(
    max_tokens=ConfigurableField(
        id="output_token_number",
        name="Max tokens in the output",
        description="The maximum number of tokens in the output",
    )
)

# 添加提示词模板,完善LLM回答
prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "回答必须使用指定的语言:{language} 回答问题。",
        ),
        # 占位符
        MessagesPlaceholder(variable_name="messages"),
    ]
)

chain = prompt | model

# 添加历史消息记录
store = {}

def get_session_history(session_id: str) -> BaseChatMessageHistory:
    if session_id not in store:
        store[session_id] = InMemoryChatMessageHistory()
    return store[session_id]

with_message_history = RunnableWithMessageHistory(
     chain,
     get_session_history,
     input_messages_key="messages",)

# 定义用户session
config = {"configurable": {"session_id": "abc2"}}
response = with_message_history.invoke(
    {"messages": [HumanMessage(content="我是宣晨光")], "language": "英语"}, config=config )
print(response.content)

response = with_message_history.invoke(
    {"messages": [HumanMessage(content="你知道我的名字?")], "language": "中文"}, config=config )
print(response.content)

4、限制令牌数存储

4.1、trim_messages

限定存储消息的最大tokens值

1)使用trim_messages 对 已发送的所有消息进行截断

2)最终的trimmer 则是最终存储的历史消息列表

3)有新的消息,需要 重新创建 trim_messages

参数说明

  • max_tokens=50 
  • token_counter=dummy_token_counter   自定义统计器
  • start_on="human"  #从第一条human消息开始,默认可以不指定
  • strategy="last"  #保留策略,first=从开始消息保存  last=保留最近的消息
  • include_system  #默认False
from typing import List
from langchain_core.messages import trim_messages, AIMessage, BaseMessage, HumanMessage, SystemMessage

messages = [
    SystemMessage(content="你现在是一个优秀的助手"),
    HumanMessage(content="你好,我叫宣晨光"),
    AIMessage(content="你好!"),
    HumanMessage(content="我喜欢看唱歌"),
    AIMessage(content="很不错"),
    HumanMessage(content="2 + 2 应该等于几"),
    AIMessage(content="4"),
    HumanMessage(content="谢谢"),
    AIMessage(content="不客气"),
    HumanMessage(content="你很高兴吗"),
    AIMessage(content="是的!"),
]

def dummy_token_counter(messages: List[BaseMessage]) -> int:
    # 对待每条消息,就像它在开始时添加了3个默认令牌
    # 消息和消息的末尾。3 + 4 + 3 = 10个tokens
    default_content_len = 4
    default_msg_prefix_len = 3
    default_msg_suffix_len = 3

    count = 0
    for msg in messages:
        if isinstance(msg.content, str):
            count += default_msg_prefix_len + default_content_len + default_msg_suffix_len
        if isinstance(msg.content, list):
            count += default_msg_prefix_len + len(msg.content) *  default_content_len + default_msg_suffix_len
    return count


trimmer = trim_messages(messages, max_tokens=50, token_counter=dummy_token_counter,start_on="human", strategy="last")
print(trimmer)

[HumanMessage(content='谢谢'), AIMessage(content='不客气'), HumanMessage(content='你很高兴吗'), AIMessage(content='是的!')]

4.1.1、自定义tokens计数器

def dummy_token_counter(messages: List[BaseMessage]) -> int:
    # 对待每条消息,就像它在开始时添加了3个默认令牌
    # 消息和消息的末尾。3 + 4 + 3 = 10个tokens
    default_content_len = 4
    default_msg_prefix_len = 3
    default_msg_suffix_len = 3

    count = 0
    for msg in messages:
        if isinstance(msg.content, str):
            count += default_msg_prefix_len + default_content_len + default_msg_suffix_len
        if isinstance(msg.content, list):
            count += default_msg_prefix_len + len(msg.content) *  default_content_len + default_msg_suffix_len
    return count

4.1.2、自定义tokens计数器

from typing import List

# pip install tiktoken
import tiktoken
from langchain_core.messages import BaseMessage, ToolMessage


def str_token_counter(text: str) -> int:
    enc = tiktoken.get_encoding("o200k_base")
    return len(enc.encode(text))


def tiktoken_counter(messages: List[BaseMessage]) -> int:
    """Approximately reproduce https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb

    For simplicity only supports str Message.contents.
    """
    num_tokens = 3  # every reply is primed with <|start|>assistant<|message|>
    tokens_per_message = 3
    tokens_per_name = 1
    for msg in messages:
        if isinstance(msg, HumanMessage):
            role = "user"
        elif isinstance(msg, AIMessage):
            role = "assistant"
        elif isinstance(msg, ToolMessage):
            role = "tool"
        elif isinstance(msg, SystemMessage):
            role = "system"
        else:
            raise ValueError(f"Unsupported messages type {msg.__class__}")
        num_tokens += (
            tokens_per_message
            + str_token_counter(role)
            + str_token_counter(msg.content)
        )
        if msg.name:
            num_tokens += tokens_per_name + str_token_counter(msg.name)
    return num_tokens


trim_messages(
    messages,
    max_tokens=45,
    strategy="last",
    token_counter=tiktoken_counter,
)

4.2、完整chatbot代码

通过限定 trim_messages中的max_tokens值,对最大tokens值存储能力的测试(100、150)

from operator import itemgetter
from typing import List

from langchain_core.chat_history import BaseChatMessageHistory, InMemoryChatMessageHistory
from langchain_core.messages import trim_messages, HumanMessage, SystemMessage, AIMessage, BaseMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai import ChatOpenAI

from langchain_core.runnables import RunnablePassthrough, RunnableWithMessageHistory

import os

os.environ.setdefault("OPENAI_API_KEY", "EMPTY")
os.environ.setdefault("OPENAI_API_BASE", "http://192.168.1.1:20000/v1")

model = ChatOpenAI(model='chatglm3-6b', max_tokens=1024)

# 添加提示词模板,完善LLM回答
prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "你是一个回答准确的助手,必须使用指定的{language}语言回答问题",
        ),
        # 占位符
        MessagesPlaceholder(variable_name="messages"),
    ]
)

messages = [
    SystemMessage(content="you're a good assistant"),
    HumanMessage(content="hi! I'm bob"),
    AIMessage(content="hi!"),
    HumanMessage(content="I like vanilla ice cream"),
    AIMessage(content="nice"),
    HumanMessage(content="whats 2 + 2"),
    AIMessage(content="4"),
    HumanMessage(content="thanks"),
    AIMessage(content="no problem!"),
    HumanMessage(content="having fun?"),
    AIMessage(content="yes!"),
]


def dummy_token_counter(messages: List[BaseMessage]) -> int:
    # 对待每条消息,就像它在开始时添加了3个默认令牌
    # 消息和消息的末尾。3 + 4 + 3 = 10个tokens
    default_content_len = 4
    default_msg_prefix_len = 3
    default_msg_suffix_len = 3

    count = 0
    for msg in messages:
        if isinstance(msg.content, str):
            count += default_msg_prefix_len + default_content_len + default_msg_suffix_len
        if isinstance(msg.content, list):
            count += default_msg_prefix_len + len(msg.content) *  default_content_len + default_msg_suffix_len
    return count

trimmer = trim_messages(max_tokens=100, token_counter=dummy_token_counter,start_on="human", strategy="last")

chain = (
        RunnablePassthrough.assign(messages=itemgetter("messages") | trimmer)
        | prompt
        | model
)

# max_tokens = 150
response = chain.invoke(
    {
        "messages": messages + [HumanMessage(content="你知道我的名字吗?")],
        "language": "中文",
    }
)
print(response.content)

# max_tokens = 100
response = chain.invoke(
    {
        "messages": messages + [HumanMessage(content="你知道,我上一次询问的数学问题是什么")],
        "language": "中文",
    }
)
print(response.content)

很抱歉,我只是一个计算机程序,无法知道你的个人信息。但是,如果你愿意告诉我,我很乐意与你交流并回答你的问题。

您问的是"2 + 2等于什么?"。我回答是"4"。

4.3、结合RunnableWithMessageHistory 

1)全局对象store 记录了完整的历史对话

2)将多个函数通过管道命令组织形成的chain 

chain = (
        RunnablePassthrough.assign(messages=itemgetter("messages") | trimmer)
        | prompt
        | model
)

3)第一次的  with_message_history.invoke 需要发送历史记录messages数组对象

4)max_tokens = 100,所以第一个问题LLM并不清楚。

from operator import itemgetter
from typing import List

from langchain_core.chat_history import BaseChatMessageHistory, InMemoryChatMessageHistory
from langchain_core.messages import trim_messages, HumanMessage, SystemMessage, AIMessage, BaseMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai import ChatOpenAI

from langchain_core.runnables import RunnablePassthrough, RunnableWithMessageHistory

import os

os.environ.setdefault("OPENAI_API_KEY", "EMPTY")
os.environ.setdefault("OPENAI_API_BASE", "http://192.168.1.1:20000/v1")

model = ChatOpenAI(model='chatglm3-6b', max_tokens=1024)

# 添加提示词模板,完善LLM回答
prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "必须使用指定的国家语言:{language}回答问题",
        ),
        # 占位符
        MessagesPlaceholder(variable_name="messages"),
    ]
)

messages = [
    SystemMessage(content="you're a good assistant"),
    HumanMessage(content="hi! I'm bob"),
    AIMessage(content="hi!"),
    HumanMessage(content="I like vanilla ice cream"),
    AIMessage(content="nice"),
    HumanMessage(content="whats 2 + 2"),
    AIMessage(content="4"),
    HumanMessage(content="thanks"),
    AIMessage(content="no problem!"),
    HumanMessage(content="having fun?"),
    AIMessage(content="yes!"),
]


def dummy_token_counter(messages: List[BaseMessage]) -> int:
    # 对待每条消息,就像它在开始时添加了3个默认令牌
    # 消息和消息的末尾。3 + 4 + 3 = 10个tokens
    default_content_len = 4
    default_msg_prefix_len = 3
    default_msg_suffix_len = 3

    count = 0
    for msg in messages:
        if isinstance(msg.content, str):
            count += default_msg_prefix_len + default_content_len + default_msg_suffix_len
        if isinstance(msg.content, list):
            count += default_msg_prefix_len + len(msg.content) *  default_content_len + default_msg_suffix_len
    return count

trimmer = trim_messages(max_tokens=100, token_counter=dummy_token_counter,start_on="human", strategy="last")

chain = (
        RunnablePassthrough.assign(messages=itemgetter("messages") | trimmer)
        | prompt
        | model
)

# 添加历史消息记录
store = {}

def get_session_history(session_id: str) -> BaseChatMessageHistory:
    if session_id not in store:
        store[session_id] = InMemoryChatMessageHistory()
    return store[session_id]

with_message_history = RunnableWithMessageHistory(
    chain,
    get_session_history,
    input_messages_key="messages",
)

config = {"configurable": {"session_id": "abc20"}}


# 第一步加载所有的历史消息
response = with_message_history.invoke(
    {
        "messages": messages + [HumanMessage(content="我的名字是?")],
        "language": "中文",
    },
    config=config,
)
print(response.content)

response = with_message_history.invoke(
    {
        "messages": [HumanMessage(content="我问了什么数学题?")],
        "language": "中文",
    },
    config=config,
)
print(response.content)

I'm sorry, I don't know your name. Can you tell me?
你问了 "2 + 2" 这个问题。

5、对话摘要存储

5.1、示例代码

多次的memory.save_context 只会在最后调用一次模型,生成新的摘要信息

from typing import List

from langchain_core.messages import BaseMessage
from langchain_openai import ChatOpenAI
from langchain.memory import ConversationSummaryBufferMemory
import os

from langchain_openai.chat_models.base import BaseChatOpenAI

os.environ.setdefault("OPENAI_API_KEY", "EMPTY")
os.environ.setdefault("OPENAI_API_BASE", "http://192.168.1.1:20000/v1")

class ChildChatOpenAI(ChatOpenAI):
    def get_num_tokens_from_messages(self, messages: List[BaseMessage]) -> int:
        model, encoding = self._get_encoding_model()
        if model.startswith("cl100k_base"):
            return super(BaseChatOpenAI, self).get_num_tokens_from_messages(messages)
        else:
            return super().get_num_tokens_from_messages(messages)

schedule = "在八点你和你的产品团队有一个会议。 \
你需要做一个PPT。 \
上午9点到12点你需要忙于LangChain。\
Langchain是一个有用的工具,因此你的项目进展的非常快。\
中午,在意大利餐厅与一位开车来的顾客共进午餐 \
走了一个多小时的路程与你见面,只为了解最新的 AI。 \
确保你带了笔记本电脑可以展示最新的 LLM 样例."

llm = ChildChatOpenAI(model='chatglm3-6b')

memory = ConversationSummaryBufferMemory(llm=llm,  max_token_limit=100)
# 对每一组输入、输出存储
memory.save_context({"input": "你好,我叫皮皮鲁"}, {"output": "你好啊,我叫鲁西西"})
memory.save_context({"input": "很高兴和你成为朋友!"}, {"output": "是的,让我们一起去冒险吧!"})
memory.save_context({"input": "今天的日程安排是什么?"}, {"output": f"{schedule}"})

print(memory.load_memory_variables({})['history'])

System: 当前的对话如下:

人类:你好,我叫皮皮鲁。
AI:你好啊,我叫鲁西西。
人类:很高兴和你成为朋友!
AI:是的,让我们一起去冒险吧!
人类:今天的日程安排是什么?
AI:在八点你和你的产品团队有一个会议。 你需要做一个PPT。 上午9点到12点你需要忙于LangChain。LangChain是一个有用的工具,因此你的项目进展的非常快。中午,在意大利餐厅与一位开车来的顾客共进午餐 走了一个多小时的路程与你见面,只为了解最新的 AI。 确保你带了笔记本电脑可以展示最新的 LLM 样例。

新的摘要:
今天,人类与AI讨论了许多话题,包括人工智能的潜力。AI认为人工智能可以人类发挥其全部潜力,并且帮助人类进步。此外,他们讨论了日程安排,包括一个与产品团队的会议,一个忙碌的LangChain项目,以及与一位开车来的顾客共进午餐的计划。

"POST /v1/chat/completions HTTP/1.1"

5.2、NotImplementedError

5.3.1、问题原因

在使用时,存在如下错误,不支持的模型计算tokens值

NotImplementedError: get_num_tokens_from_messages() is not presently implemented for model cl100k_base

代码位置

5.3.2、解决方式

1)使用类的继承方式,覆盖。定义子类class ChildChatOpenAI(ChatOpenAI)  ,并重写get_num_tokens_from_messages函数

from langchain_core.messages import BaseMessage
from langchain_openai import ChatOpenAI

class ChildChatOpenAI(ChatOpenAI):
    def get_num_tokens_from_messages(self, messages: List[BaseMessage]) -> int:
        model, encoding = self._get_encoding_model()
        # 此处的model名称并不是传入的chatglm3-6b
        if model.startswith("cl100k_base"):
            # 调用祖父类的函数
            return super(BaseChatOpenAI, self).get_num_tokens_from_messages(messages)
        else:
            return super().get_num_tokens_from_messages(messages)

llm = ChildChatOpenAI(model='chatglm3-6b',temperature=0.0)

2)直接修改对应源码,对else部分,采用super 父类计算函数

return super().get_num_tokens_from_messages(messages)
            # raise NotImplementedError(
            #     f"get_num_tokens_from_messages() is not presently implemented "
            #     f"for model {model}. See "
            #     "https://platform.openai.com/docs/guides/text-generation/managing-tokens"  # noqa: E501
            #     " for information on how messages are converted to tokens."
            # )

参考文档:

Migrating to LangChain v0.2 | 🦜️🔗 LangChain

面向开发者的LLM入门教程

RunnableWithMessageHistory — 🦜🔗 LangChain 0.2.12

LangChain-0.2.x 官方API文档

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1992690.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HookNet- 用于病理全切片图像的多分辨率语义分割模型|顶刊精析·24-08-08

小罗碎碎念 今天分享的这篇文章是关于一种名为HookNet的新型语义分割模型&#xff0c;它专为病理学全切片图像设计&#xff0c;于2021年发表于《Med Image Anal》&#xff0c;目前IF10.7。 作者角色姓名单位&#xff08;中文翻译&#xff09;第一作者Mart van Rijthoven荷兰Ra…

Spring-boot 集成 SocketIO(看这一篇就够了)

1 前言 1.1 什么是 SocketIO ? Socket.IO 是一个可以在浏览器与服务器之间实现实时、双向、基于事件的通信的工具库。 Socket.IO 能够在任何平台、浏览器或设备上运行,可靠性和速度同样出色。 1.2 websocket和socket.io区别&#xff1f; websocket a&#xff1a;一种让客户…

video标签,去除上下默认边距

不知道为什么&#xff0c;video标签上下会有空白 清除方法 style"width 100%; height100%; object-fit: fill"

校园二手物品交易网站/校园闲置物品交易系统

摘 要 本文论述了校园二手物品交易网站的设计和实现&#xff0c;该网站从实际运用的角度出发&#xff0c;运用了计算机网站设计、数据库等相关知识&#xff0c;网络和JSP技术、SSM框架Mysql数据库设计来实现的&#xff0c;网站主要包括学生注册、学生登录、浏览商品、搜索商品…

Vue+Element Plus后台管理主界面搭建实现

​ 续接Django REST Framework&#xff0c;使用Vite构建Vue3的前端项目 1. 后台管理系统主界面框架搭建 后台系统主界面搭建 新建后台管理文件目录 完成后台整体布局 // 1.主界面 index.vue<script setup lang"ts"></script><template><el-…

应用层HTTP协议

文章目录 应用层HTTP协议1、HTTP协议概念2、URL&#xff08;统一资源定位符&#xff09;2.1、URL的encode&#xff08;编码&#xff09;和decode&#xff08;解码&#xff09; 3、HTTP请求和响应报头格式3.1、请求报头3.2、响应报头 4、HTTP的方法4.1、GET方法4.2、POST方法4.3…

生成模型VAE

VAE likelihood-basedELBOVAESGVB估计器和AEVB算法重参数化 likelihood-based likelihood-based generative models是生成模型的一类范式&#xff0c;通过最大化所有观测数据的似然函数来学习模型参数。 该怎么去理解likelihood-based&#xff0c;基于似然的生成模型&#xf…

互联网重构“规则制定权”,周期性谋咒开始轮转!

周期“魔咒”又开始轮转了。 产业趋势叠加资本周期&#xff0c;使得任何产业都有其周期性规律&#xff0c;传统资源产业是如此&#xff0c;科技产业亦非例外。 刚刚迎来30周年庆的中国互联网赛道就正处于新一轮小周期的节点。随着移动用户量逐渐被开发利用至阶段性顶峰&#…

学习c语言第24天(练习)

编程题 第一题 最大公约数最小公倍数求和 //求最大公约数和最小公倍数之和 //暴力求解 //int main() //{ // int n 0; // int m 0; // while (scanf("%d %d", &n, &m)2) // { // int min n < m ? n : m; // int max n > m ? n : m; //…

原神4.8版本角色数据

<!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>原神4.8版本角色数据</title><style>…

【浏览器插件】Chrome扩展V3版本

前言&#xff1a;Chrome从2022年6月开始&#xff0c;新发布插件只接受V3版。2024年V2版已从应用商店下架。 浏览器扩展插件开发API文档 chrome官网&#xff08;要翻墙&#xff09;&#xff1a; https://developer.chrome.com/docs/extensions/mv3 MDN中文&#xff1a;https:/…

gitee拉取项目,提交代码

1&#xff0c;安装git 2&#xff0c;gitee配置成员仓库权限 3&#xff0c;克隆项目 git clone gitgitee.com:sky474775788/Python_API_AUTO.git 4&#xff0c;配置用户信息 git config --global user.name 林俊xxx git config --global user.email ohnxxxsee1xxx.com 5&…

机器学习·L2W4-决策树

决策树 从根节点的所有示例开始计算所有可能特征的分割信息增益&#xff0c;并选择信息增益最高的特征根据所选特征分割数据集&#xff0c;并创建树的左分支和右分支不断重复分割过程&#xff0c;直到满足停止条件 信息增益 也可以理解为信息熵的减少 p p p是结果为positive…

住宅代理和数据中心代理:指纹浏览器用哪个更安全?

在当今的数字时代&#xff0c;确保您的在线安全至关重要。这就是住宅和数据中心代理发挥作用的地方&#xff0c;它们可以保护您的身份和个人信息。指纹浏览器解决了账号所在环境指纹参数隔离的安全问题&#xff0c;而IP解决环境的定位与隔离问题&#xff0c;就像Maskfog中提供的…

洛伦兹微分方程与混沌理论

前言 这一段时间在看书中关于深度学习与神经网络的内容&#xff0c;其中有一节介绍神经网络用于预测洛伦兹微分方程的数值解&#xff0c;还提到了“吸引子”这一概念&#xff0c;当时也没太理解是什么&#xff0c;下午搜集了一本书上关于混沌理论的介绍——《混沌的本质》。 这…

【线性回归】——解决运筹优化类问题

目录 文章目录 前言 一、模型原理 1.线性规划模型的三要素 &#x1f60f;&#x1f60f;&#x1f60f; 2.模型特点 3.线性规划的表现形式 二、模型建立步骤 1.找决策变量 2.确定目标函数 3.找到约束条件 4.运用Matlab中的Linprog函数 总结 前言 在实际生活应用中&#xff0c;我…

Unity入门5——材质

创建材质 点击Assets → Create → Material&#xff0c;得到一个默认材质球的副本。 使用材质 直接把材质球拖拽到物体上&#xff0c;或设置mesh renderer组件下的Materials 数组中第一个元素

etcd高可用集群部署

文章目录 一、环境准备二、安装部署2.1 下载安装包2.2 将etcd和etcdctl复制到/usr/local/bin中2.3 创建目录并赋予权限2.4 修改节点配置2.4.1 配置etcd.conf文件2.4.2 配置/etc/systemd/system/etcd.service文件 2.5 启动ectd服务2.6 查看集群成员信息2.7 查看集群状态 在生产环…

【PyQt5】PyQt5 信号和槽

基于GUI的应用程序是事件驱动的。函数或方法按照用户的操作&#xff08;例如点击按钮、从集合中选择项目或点击鼠标等&#xff09;来执行&#xff0c;这些操作被称为 事件 。用于构建GUI界面的小部件充当这些事件的来源。每个PyQt小部件都是从QObject类派生而来&#xff0c;设计…

《Redis设计与实现》读书笔记-复制

目录 1.概述 2.复制命令 3.部分重同步过程 4.部分重同步实现 4.1复制偏移量 4.2复制积压缓冲区 4.3服务器运行ID 5.总结 1.概述 在redis 通过向从服务器发送命令&#xff1a;SLAVE OF&#xff0c;让从服务器复制主服务器&#xff0c;成为复制。 复制的目的 让从服务器…