ChatOpenAI调用get_num_tokens_from_messages() is not presently implemented for model qwen-plus

低功耗蓝牙项目,需要一块懂省电的板

思澈 SF32LB52 芯片,BLE 协议栈深度优化,上手即开发

使用langchain做历史会话管理时报错,代码及报错如下:

from langchain_openai import ChatOpenAI

model = ChatOpenAI(
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    api_key="sk-ba5d2f5624d144c98fb196f4013b0e3d",
    model="qwen-plus",
)

from langchain_core.messages import HumanMessage, SystemMessage ,AIMessage
from langchain_core.messages import SystemMessage, trim_messages

trimmer = trim_messages(
    max_tokens=65,
    strategy="last",
    token_counter=model,
    include_system=True,
    allow_partial=False,
    start_on="human",
)

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!"),
]

trimmer.invoke(messages)


报错



NotImplementedError: get_num_tokens_from_messages() is not presently implemented for model qwen-plus. See https://platform.openai.com/docs/guides/text-generation/managing-tokens for information on how messages are converted to tokens.

原因
根本原因是:LangChain 的 ChatOpenAI 类在使用非 OpenAI 官方模型(比如阿里云的 Qwen 系列)时,默认无法准确计算 token 数量,因为 get_num_tokens_from_messages() 方法依赖于 OpenAI 的 tokenizer。而像 qwen-plus 这样的第三方兼容模型,并没有被 LangChain 内置支持用于 token 计算

解决方法

如果你使用的是较新版本的 LangChain(>=0.2),可以考虑直接使用 Tongyi 官方提供的 LangChain 集成,而不是通过 OpenAI 兼容模式

pip install langchain-community
pip install dashscope --upgrade
pip install transformers

修改后代码

tongyi_model = ChatTongyi(
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    api_key="sk-ba5d2f5624d144c98fb196f4013b0e3d",
    model="qwen-plus",
)


trimmer = trim_messages(
    max_tokens=65,
    strategy="last",
    token_counter=tongyi_model,
    include_system=True,
    allow_partial=False,
    start_on="human",
)

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!"),
]

trimmer.invoke(messages)

运行后,有警告

/home/runUser/anaconda3/envs/langchain/lib/python3.12/site-packages/langchain_core/language_models/base.py:328: UserWarning: Using fallback GPT-2 tokenizer for token counting. Token counts may be inaccurate for non-GPT-2 models. For accurate counts, use a model-specific method if available.
  return len(self.get_token_ids(text))

表明 ChatTongyi 虽然被用作 token_counter,但其底层 没有实现准确的 token 计数方法(或未正确注册 Qwen 的 tokenizer),于是 LangChain 回退到 GPT-2 的 tokenizer(对中文和 Qwen 模型不准确)
ChatTongyi 的 get_num_tokens_from_messages 方法仍未被正确实现(或依赖未安装的 tokenizer 包),导致它无法准确计算 Qwen 系列模型的 token 数量,只能回退到不合适的 GPT-2 tokenizer。
🔍 验证:Qwen 模型使用的是 基于 tiktoken 的 cl100k_base 编码(和 GPT-3.5/4 相同),不是 GPT-2 的 gpt2 编码。用 GPT-2 tokenizer 会严重低估 token 数(尤其对英文标点、空格等处理不同)。

处理方法:
增加自定义的计数方法实现准确计数,调整后代码如下:
from langchain_core.messages import SystemMessage, trim_messages
import tiktoken

✅ 准确的 token 计数函数(适用于 Qwen / GPT-3.5 / GPT-4)

def count_tokens_in_messages(messages):

    """估算 messages 的总 token 数(参考 OpenAI 官方方式)"""
    encoding = tiktoken.get_encoding("cl100k_base")  # Qwen 使用此编码
    tokens_per_message = 4  # 每条消息的固定开销(role + 分隔符等)
    tokens_per_name = -1    # Qwen 不支持 name 字段,可忽略

    num_tokens = 0
    for message in messages:
        num_tokens += tokens_per_message
        num_tokens += len(encoding.encode(message.content))
        num_tokens += len(encoding.encode(message.type))  # 'system', 'user', 'assistant'
        # 注意:Qwen 不支持 'name',所以跳过
    num_tokens += 3  # 每轮对话的额外开销(如 <|im_start|> 等)
    return num_tokens

trimmer = trim_messages(
    max_tokens=65,
    strategy="last",
    token_counter=count_tokens_in_messages,
    include_system=True,
    allow_partial=False,
    start_on="human",
)

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!"),
]

trimmer.invoke(messages)

需要提醒的是Qwen的行为更“上下文驱动”而非“指令驱动”。它会优先模仿最近的语言风格,而不是严格遵行system规则

低功耗蓝牙项目,需要一块懂省电的板

思澈 SF32LB52 芯片,BLE 协议栈深度优化,上手即开发

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

natide

觉得有帮助就好

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

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

打赏作者

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

抵扣说明:

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

余额充值