【LLM】-17-会话存储

目录

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文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宣晨光

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值