从零开始学 Dify ,本文教你如何避免 LLM 上下文长度超限错误,零基础小白建议收藏!!

前言

在构建基于大语言模型(LLM)的应用时,context_length_exceeded 错误是最常见且令人头疼的问题之一。当输入提示(包括对话历史、系统指令和当前查询)加上预期输出 Token 数超过模型的最大上下文窗口时,就会发生这种错误。

接下来将深入剖析 Dify 内部的 Token 计算和上下文管理逻辑。学习如何优雅地解决了这个问题。

Token"。一个 Token 可以是一个单词、单词的一部分或标点符号。每个模型都有一个硬性限制,即单次请求能处理的 Token 数量,这被称为上下文窗口。例如,OpenAI 的 gpt-4-turbo 的上下文窗口为 128,000 个 Token,而 Anthropic 的 Claude 3.5 Sonnet 的上下文窗口为 200,000 个 Token 。

如果应用程序发送的请求过大,提供商的 API 会拒绝该请求。因此,一个健壮的应用程序必须在发送请求之前计算 Token,并智能地管理其上下文以保持在限制范围内。

二、Dify 的 Token 管理流程

Dify 充当用户和 LLM 提供商之间的智能中介。它确保发送给模型的最终负载始终有效。下图展示了这个过程:

图片

逻辑详解

  1. 配置收集:当请求开始时,Dify 加载所选模型的配置。这包括两个关键数字:

    • 模型最大上下文(context_size):模型支持的理论最大 token 数(如 128,000)。
    • 用户定义的输出 Token(max_tokens):开发者在 Dify 界面中设置的值,为模型的答案保留一部分上下文窗口。
  2. 预算计算:Dify 使用简单公式计算提示的可用预算:可用提示 Token 数 = 模型最大上下文 - 用户定义的输出 Token 数

  3. Token 化和计数:这是实现的核心。Dify 使用 OpenAI 的 tiktoken 库进行精确的 Token 计算。

  4. 上下文截断:如果当前上下文的 Token 计数超过可用提示 Token 数,Dify 会智能地截断它。对于聊天应用,这通常涉及从对话历史中删除最旧的消息,直到总 Token 计数适合预算。

  5. 最终 API 调用:只有在验证和潜在截断之后,Dify 才会将负载发送给 LLM 提供商,确保请求有效并避免 context_length_exceeded 错误。

三、与提供商模型配置的关系

Dify 的 Token 计算逻辑与提供商模型配置中的参数有着密切的关系,在 Dify 中,每个模型都有以下关键配置参数:

# 模型配置示例
model_config = {
    "context_size": 128000,        # 模型的最大上下文窗口
    "max_tokens": 4096,            # 用户设置的最大输出 token 数
    "model_name": "gpt-4-turbo",   # 模型名称,用于选择正确的 tokenizer
    "provider": "openai"           # 提供商,决定使用哪种 token 化方法
}

Dify 的 Token 计算流程

图片

四、代码分析:核心实现

1. 预先计算剩余 Token

base_app_runner.py 中,get_pre_calculate_rest_tokens 方法负责计算可用的 Token 预算:

def get_pre_calculate_rest_tokens(self, app_record, model_config, prompt_template_entity, inputs, files, query):
    # 获取模型实例
    model_instance = ModelInstance(
        provider_model_bundle=model_config.provider_model_bundle, model=model_config.model
    )

    # 获取模型最大上下文 token 数
    model_context_tokens = model_config.model_schema.model_properties.get(ModelPropertyKey.CONTEXT_SIZE)

    # 获取用户定义的输出 max_tokens
    max_tokens = 0
    for parameter_rule in model_config.model_schema.parameter_rules:
        if parameter_rule.name == "max_tokens"or (
            parameter_rule.use_template and parameter_rule.use_template == "max_tokens"
        ):
            max_tokens = (
                model_config.parameters.get(parameter_rule.name)
                or model_config.parameters.get(parameter_rule.use_template or"")
            ) or0

    # 获取不包含记忆和上下文的提示消息
    prompt_messages, stop = self.organize_prompt_messages(
        app_record=app_record,
        model_config=model_config,
        prompt_template_entity=prompt_template_entity,
        inputs=inputs,
        files=files,
        query=query,
    )

    # 计算当前提示消息的 token 数
    prompt_tokens = model_instance.get_llm_num_tokens(prompt_messages)

    # 计算剩余可用 token 数
    rest_tokens: int = model_context_tokens - max_tokens - prompt_tokens
    if rest_tokens < 0:
        raise InvokeBadRequestError(
            "Query or prefix prompt is too long, you can reduce the prefix prompt, "
            "or shrink the max token, or switch to a llm with a larger token limit size."
        )

    return rest_tokens

2. 重新计算最大 Token 数

如果提示 Token 数加上最大输出 Token 数超过模型上下文限制,Dify 会自动调整 max_tokens 参数:

def recalc_llm_max_tokens(self, model_config, prompt_messages):
    # 获取模型实例
    model_instance = ModelInstance(
        provider_model_bundle=model_config.provider_model_bundle, model=model_config.model
    )

    # 获取模型最大上下文 token 数
    model_context_tokens = model_config.model_schema.model_properties.get(ModelPropertyKey.CONTEXT_SIZE)

    # 获取用户定义的输出 max_tokens
    max_tokens = 0
    for parameter_rule in model_config.model_schema.parameter_rules:
        if parameter_rule.name == "max_tokens"or (
            parameter_rule.use_template and parameter_rule.use_template == "max_tokens"
        ):
            max_tokens = (
                model_config.parameters.get(parameter_rule.name)
                or model_config.parameters.get(parameter_rule.use_template or"")
            ) or0

    # 计算当前提示消息的 token 数
    prompt_tokens = model_instance.get_llm_num_tokens(prompt_messages)

    # 如果提示 token 数加上最大输出 token 数超过模型上下文限制,则调整 max_tokens
    if prompt_tokens + max_tokens > model_context_tokens:
        max_tokens = max(model_context_tokens - prompt_tokens, 16)

        for parameter_rule in model_config.model_schema.parameter_rules:
            if parameter_rule.name == "max_tokens"or (
                parameter_rule.use_template and parameter_rule.use_template == "max_tokens"
            ):
                model_config.parameters[parameter_rule.name] = max_tokens

3. 计算剩余 Token

prompt_transform.py 中,_calculate_rest_token 方法负责计算剩余可用的 Token 数:

def _calculate_rest_token(self, prompt_messages, model_config):
    rest_tokens = 2000

    model_context_tokens = model_config.model_schema.model_properties.get(ModelPropertyKey.CONTEXT_SIZE)
    if model_context_tokens:
        model_instance = ModelInstance(
            provider_model_bundle=model_config.provider_model_bundle, model=model_config.model
        )

        curr_message_tokens = model_instance.get_llm_num_tokens(prompt_messages)

        max_tokens = 0
        for parameter_rule in model_config.model_schema.parameter_rules:
            if parameter_rule.name == "max_tokens"or (
                parameter_rule.use_template and parameter_rule.use_template == "max_tokens"
            ):
                max_tokens = (
                    model_config.parameters.get(parameter_rule.name)
                    or model_config.parameters.get(parameter_rule.use_template or"")
                ) or0

        rest_tokens = model_context_tokens - max_tokens - curr_message_tokens
        rest_tokens = max(rest_tokens, 0)

    return rest_tokens

4. 管理对话历史

上下文管理的智能策略,分层截断策略。

图片

token_buffer_memory.py 中,get_history_prompt_messages 方法负责获取对话历史,并在必要时进行截断:

def get_history_prompt_messages(self, max_token_limit=2000, message_limit=None):
    # 获取对话历史消息
    messages = query.limit(message_limit).all()
    thread_messages = extract_thread_messages(messages)
    messages = list(reversed(thread_messages))

    prompt_messages = []
    # 将消息转换为提示消息
    for message in messages:
        # 处理消息内容和文件
        # ...

    # 如果提示消息的 token 数超过最大限制,则进行截断
    curr_message_tokens = self.model_instance.get_llm_num_tokens(prompt_messages)
    if curr_message_tokens > max_token_limit:
        pruned_memory = []
        while curr_message_tokens > max_token_limit and len(prompt_messages) > 1:
            pruned_memory.append(prompt_messages.pop(0))
            curr_message_tokens = self.model_instance.get_llm_num_tokens(prompt_messages)

    return prompt_messages

5. Token 计算的核心:tiktoken

Dify 使用 OpenAI 的 tiktoken 库进行精确的 Token 计算。这是一个快速的 BPE(Byte Pair Encoding)tokenizer,专为 OpenAI 模型设计。

large_language_model.py 中,get_num_tokens 方法负责获取提示消息的 Token 数:

def get_num_tokens(self, model, credentials, prompt_messages, tools=None):
    if dify_config.PLUGIN_BASED_TOKEN_COUNTING_ENABLED:
        plugin_model_manager = PluginModelClient()
        return plugin_model_manager.get_llm_num_tokens(
            tenant_id=self.tenant_id,
            user_id="unknown",
            plugin_id=self.plugin_id,
            provider=self.provider_name,
            model_type=self.model_type.value,
            model=model,
            credentials=credentials,
            prompt_messages=prompt_messages,
            tools=tools,
        )
    return0

五、模型配置与 Token 计算的关系

Dify 中的模型配置参数直接影响 Token 计算和限制处理:

  1. ModelPropertyKey.CONTEXT_SIZE:定义模型的最大上下文窗口大小,如 GPT-4 的 128,000 或 Claude 的 200,000。
  2. max_tokens 参数:用户在 Dify 界面中设置的值,为模型的回答保留一部分上下文窗口。
  3. 模型名称:决定使用哪种 tokenizer,因为不同模型使用不同的 token 化规则。
  4. 提供商:不同提供商(如 OpenAI、Anthropic)的模型可能有不同的 token 化方法和限制。

六、总结:Dify 的 Token 管理优势

Dify 的 Token 管理机制提供了几个关键优势:

  1. 自动化处理:开发者无需手动计算 Token 或担心上下文限制。
  2. 智能截断:当上下文过长时,Dify 会自动截断历史消息,确保请求有效。
  3. 适应性调整:如果提示 Token 数加上最大输出 Token 数超过模型上下文限制,Dify 会自动调整 max_tokens 参数。
  4. 多模型支持:Dify 支持多种 LLM 提供商和模型,并为每个模型使用正确的 tokenizer。
  5. 错误预防:通过预先计算和验证 Token 数,Dify 有效防止了 context_length_exceeded 错误。

通过这种方式,Dify 为开发者提供了一个无缝的体验,使他们能够专注于构建应用程序,而不必担心底层的 Token 管理复杂性。这种抽象层次的提升是 Dify 作为 LLM 应用开发平台的核心优势之一。

最后

为什么要学AI大模型

当下,⼈⼯智能市场迎来了爆发期,并逐渐进⼊以⼈⼯通⽤智能(AGI)为主导的新时代。企业纷纷官宣“ AI+ ”战略,为新兴技术⼈才创造丰富的就业机会,⼈才缺⼝将达 400 万!

DeepSeek问世以来,生成式AI和大模型技术爆发式增长,让很多岗位重新成了炙手可热的新星,岗位薪资远超很多后端岗位,在程序员中稳居前列。

在这里插入图片描述

与此同时AI与各行各业深度融合,飞速发展,成为炙手可热的新风口,企业非常需要了解AI、懂AI、会用AI的员工,纷纷开出高薪招聘AI大模型相关岗位。
在这里插入图片描述
最近很多程序员朋友都已经学习或者准备学习 AI 大模型,后台也经常会有小伙伴咨询学习路线和学习资料,我特别拜托北京清华大学学士和美国加州理工学院博士学位的鲁为民老师给大家这里给大家准备了一份涵盖了AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频 全系列的学习资料,这些学习资料不仅深入浅出,而且非常实用,让大家系统而高效地掌握AI大模型的各个知识点。

这份完整版的大模型 AI 学习资料已经上传优快云,朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费

AI大模型系统学习路线

在面对AI大模型开发领域的复杂与深入,精准学习显得尤为重要。一份系统的技术路线图,不仅能够帮助开发者清晰地了解从入门到精通所需掌握的知识点,还能提供一条高效、有序的学习路径。

img

但知道是一回事,做又是另一回事,初学者最常遇到的问题主要是理论知识缺乏、资源和工具的限制、模型理解和调试的复杂性,在这基础上,找到高质量的学习资源,不浪费时间、不走弯路,又是重中之重。

AI大模型入门到实战的视频教程+项目包

看视频学习是一种高效、直观、灵活且富有吸引力的学习方式,可以更直观地展示过程,能有效提升学习兴趣和理解力,是现在获取知识的重要途径

在这里插入图片描述
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
在这里插入图片描述

海量AI大模型必读的经典书籍(PDF)

阅读AI大模型经典书籍可以帮助读者提高技术水平,开拓视野,掌握核心技术,提高解决问题的能力,同时也可以借鉴他人的经验。对于想要深入学习AI大模型开发的读者来说,阅读经典书籍是非常有必要的。
在这里插入图片描述

600+AI大模型报告(实时更新)

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。
在这里插入图片描述

AI大模型面试真题+答案解析

我们学习AI大模型必然是想找到高薪的工作,下面这些面试题都是总结当前最新、最热、最高频的面试题,并且每道题都有详细的答案,面试前刷完这套面试题资料,小小offer,不在话下
在这里插入图片描述

在这里插入图片描述

这份完整版的大模型 AI 学习资料已经上传优快云,朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值