生成器#

Generator 是一个面向用户的编排组件,具有简单且统一的接口,用于LLM预测。 它是一个由三个子组件组成的管道。通过切换提示模板、模型客户端和输出解析器,用户可以完全控制和灵活调整。

设计#

AdalFlow generator design

生成器 - 大型语言模型预测的协调者#

Generator 旨在实现以下目标:

  1. 模型无关性:生成器应该能够使用相同的提示调用任何LLM模型。

  2. 统一接口:它管理从提示(输入)-> 模型调用 -> 输出解析的管道,同时仍然让用户完全控制每个部分。

  3. 统一输出:这将使得记录和保存所有LLM预测的结果变得容易。

  4. 与优化器一起工作:它应该能够与优化器一起工作以优化提示。

前三个目标同样适用于其他协调器组件,如RetrieverEmbedderAgent(大部分情况下)。

一个协调器#

它协调三个组件:

  • 提示: 通过接收 template (字符串) 和 prompt_kwargs (字典) 在初始化时格式化提示。 当未提供 template 时,默认使用 DEFAULT_ADALFLOW_SYSTEM_PROMPT

  • ModelClient: 通过接收一个已经实例化的 model_clientmodel_kwargs 来调用模型。 切换模型客户端允许你使用相同的提示和输出解析来调用任何LLM模型。

  • output_processors: 一个单独的组件或通过Sequential链接的组件,用于将原始响应处理为所需的格式。 如果没有提供输出处理器,则由模型客户端决定,通常返回原始字符串响应(来自第一个响应消息)。

调用和参数

Generator 支持 call (__call__) 和 acall 方法。 它们接受两个可选参数:

  • prompt_kwargs (字典): 这与初始 Prompt 组件中的 prompt_kwargs 结合使用,用于格式化提示。

  • model_kwargs (dict): 这与初始模型客户端中的 model_kwargs 结合,并与 ModelType.LLM 一起传递给 ModelClient。 ModelClient 会将所有输入解释为特定于每个模型 API 提供者的 api_kwargs

注意

这也意味着任何希望与Generator兼容的ModelClient都应该接受model_kwargsmodel_type作为参数。

生成器输出#

与其他组件不同,我们不能总是强制LLM遵循输出格式。ModelClientoutput_processors可能会失败。

注意

每当发生错误时,我们不会引发错误并强制程序停止。 相反,Generator 将始终返回一个输出记录。 我们做出这个设计选择是因为它对于记录训练/评估集中的各种失败案例非常有帮助,以便进一步调查和改进。

特别是,我们创建了GeneratorOutput来捕获重要信息。

  • data (object) : 存储管道中所有三个组件处理后的最终响应,表示success

  • error (str): 如果管道中的三个组件中的任何一个失败,则包含错误消息。当此值不为None时,表示failure

  • raw_response (str): 用于参考任何LLM预测的原始字符串响应。目前,它是来自第一个响应消息的字符串。[这可能会在未来发生变化并有所不同]

  • metadata (dict): 存储任何额外的信息

  • usage: 保留用于跟踪LLM预测的使用情况。

是否在发生错误时进行进一步处理或终止管道,从现在起由用户决定。

生成器实战#

我们将创建一个简单的单轮聊天机器人来演示如何使用生成器。

最小示例#

在代码中启动生成器的最小设置:

from adalflow.core import Generator
from adalflow.components.model_client import GroqAPIClient

generator = Generator(
    model_client=GroqAPIClient(),
    model_kwargs={"model": "llama3-8b-8192"},
)
print(generator)

生成器的结构使用print

        
    Generator(
    model_kwargs={'model': 'llama3-8b-8192'},
    (prompt): Prompt(
        template: 
        {# task desc #}
        {% if task_desc_str %}
        {{task_desc_str}}
        {% else %}
        You are a helpful assistant.
        {% endif %}
        {# output format #}
        {% if output_format_str %}
        
        {{output_format_str}}
        
        {% endif %}
        {# tools #}
        {% if tools_str %}
        
        {{tools_str}}
        
        {% endif %}
        {# example #}
        {% if examples_str %}
        
        {{examples_str}}
        
        {% endif %}
        {# chat history #}
        {% if chat_history_str %}
        
        {{chat_history_str}}
        
        {% endif %}
        {#contex#}
        {% if context_str %}
        
        {{context_str}}
        
        {% endif %}
        {# steps #}
        {% if steps_str %}
        
        {{steps_str}}
        
        {% endif %}
        
        {% if input_str %}
        
        {{input_str}}
        
        {% endif %}
        You:
        , prompt_variables: ['input_str', 'tools_str', 'context_str', 'steps_str', 'task_desc_str', 'chat_history_str', 'output_format_str', 'examples_str']
    )
    (model_client): GroqAPIClient()
    )
        
    

显示最终提示

Generatorprint_prompt 方法将简单地中继来自 Prompt 组件的方法:

prompt_kwargs = {"input_str": "What is LLM? Explain in one sentence."}
generator.print_prompt(**prompt_kwargs)

输出将是格式化的提示:

<User>
What is LLM? Explain in one sentence.
</User>
You:

调用生成器

output = generator(
    prompt_kwargs=prompt_kwargs,
)
print(output)

输出将是GeneratorOutput对象:

GeneratorOutput(data='LLM stands for Large Language Model, a type of artificial intelligence that is trained on vast amounts of text data to generate human-like language outputs, such as conversations, text, or summaries.', error=None, usage=None, raw_response='LLM stands for Large Language Model, a type of artificial intelligence that is trained on vast amounts of text data to generate human-like language outputs, such as conversations, text, or summaries.', metadata=None)

使用模板#

在这个例子中,我们将使用一个自定义模板来格式化提示。 我们用一个变量task_desc_str初始化了提示,该变量在提示中进一步与input_str结合。

template = r"""<SYS>{{task_desc_str}}</SYS>
User: {{input_str}}
You:"""
generator = Generator(
    model_client=GroqAPIClient(),
    model_kwargs={"model": "llama3-8b-8192"},
    template=template,
    prompt_kwargs={"task_desc_str": "You are a helpful assistant"},
)

prompt_kwargs = {"input_str": "What is LLM?"}

generator.print_prompt(
    **prompt_kwargs,
)
output = generator(
    prompt_kwargs=prompt_kwargs,
)

最终的提示是:

<SYS>You are a helpful assistant</SYS>
User: What is LLM?
You:

注意

使用任何提示都非常简单。 他们只需要遵循jinja2语法。

使用输出处理器#

在这个例子中,我们将指示LLM输出一个JSON对象作为响应。 我们将使用JsonParser将输出解析回dict对象。

from adalflow.core import Generator
from adalflow.core.types import GeneratorOutput
from adalflow.components.model_client import OpenAIClient
from adalflow.core.string_parser import JsonParser

output_format_str = r"""Your output should be formatted as a standard JSON object with two keys:
{
    "explanation": "A brief explanation of the concept in one sentence.",
    "example": "An example of the concept in a sentence."
}
"""

generator = Generator(
    model_client=OpenAIClient(),
    model_kwargs={"model": "gpt-3.5-turbo"},
    prompt_kwargs={"output_format_str": output_format_str},
    output_processors=JsonParser(),
)

prompt_kwargs = {"input_str": "What is LLM?"}
generator.print_prompt(**prompt_kwargs)

output: GeneratorOutput = generator(prompt_kwargs=prompt_kwargs)
print(type(output.data))
print(output.data)

最终的提示是:

<SYS>
<OUTPUT_FORMAT>
Your output should be formatted as a standard JSON object with two keys:
    {
        "explanation": "A brief explanation of the concept in one sentence.",
        "example": "An example of the concept in a sentence."
    }

</OUTPUT_FORMAT>
</SYS>
<User>
What is LLM?
</User>
You:

上述打印输出是:

<class 'dict'>
{'explanation': 'LLM stands for Large Language Model, which are deep learning models trained on enormous amounts of text data.', 'example': 'An example of a LLM is GPT-3, which can generate human-like text based on the input provided.'}

请参考Parser以获取关于Parser组件的更全面指南。

切换模型客户端#

另外,你是否注意到在上面的例子中我们已经切换到使用OpenAI的模型? 这展示了在生成器中切换model_client是多么容易,使其成为一个真正与模型无关的组件。 我们甚至可以使用ModelClientType来切换模型客户端,而无需处理多个导入。

from adalflow.core.types import ModelClientType

generator = Generator(
    model_client=ModelClientType.OPENAI(),  # or ModelClientType.GROQ()
    model_kwargs={"model": "gpt-3.5-turbo"},
)

获取GeneratorOutput中的错误#

我们将使用一个错误的API密钥故意创建一个错误。 我们仍然会得到一个响应,但它只会包含空的data和一个错误信息。 以下是OpenAI的API密钥错误示例:

GeneratorOutput(data=None, error="Error code: 401 - {'error': {'message': 'Incorrect API key provided: ab. You can find your API key at https://platform.openai.com/account/api-keys.', 'type': 'invalid_request_error', 'param': None, 'code': 'invalid_api_key'}}", usage=None, raw_response=None, metadata=None)

从配置创建#

与所有组件一样,我们可以纯粹从配置中创建生成器。

知道它是一个生成器

在这种情况下,我们知道我们正在创建一个生成器,我们将使用from_config方法,该方法来自Generator类。

from adalflow.core import Generator

config = {
    "model_client": {
        "component_name": "GroqAPIClient",
        "component_config": {},
    },
    "model_kwargs": {
        "model": "llama3-8b-8192",
    },
}

generator: Generator = Generator.from_config(config)
print(generator)

prompt_kwargs = {"input_str": "What is LLM? Explain in one sentence."}
generator.print_prompt(**prompt_kwargs)
output = generator(
    prompt_kwargs=prompt_kwargs,
)
print(output)

仅从配置中

这更加通用。 此方法可用于从配置创建任何组件。 我们只需要遵循配置结构:component_namecomponent_config 对于所有参数。

from adalflow.utils.config import new_component
from adalflow.core import Generator

config = {
    "generator": {
        "component_name": "Generator",
        "component_config": {
            "model_client": {
                "component_name": "GroqAPIClient",
                "component_config": {},
            },
            "model_kwargs": {
                "model": "llama3-8b-8192",
            },
        },
    }
}

generator: Generator = new_component(config["generator"])
print(generator)

prompt_kwargs = {"input_str": "What is LLM? Explain in one sentence."}
generator.print_prompt(**prompt_kwargs)
output = generator(
    prompt_kwargs=prompt_kwargs,
)
print(output)

它的工作方式与前一个示例完全相同。 在这种情况下,我们导入了Generator,只是为了显示类型提示。

注意

请参考配置以获取有关如何从配置创建组件的更多详细信息。

库中的示例#

除了这些例子,LLM就像水一样,即使在我们的库中,我们也有组件将Generator适应于各种其他功能。

  • LLMRetriever 是一个使用生成器调用LLM来检索最相关文档的检索器。

  • DefaultLLMJudge 是一个使用 Generator 调用 LLM 来评估响应质量的评判者。

  • TGDOptimizer 是一个使用生成器调用LLM来优化提示的优化器。

  • ReAct Agent Planner 是一个使用生成器来规划和调用 ReAct Agent 中函数的 LLM 规划器。

追踪#

特别是,我们提供了两种跟踪方法来帮助您开发和改进Generator

  1. 在开发过程中跟踪提示的历史变化(状态)。

  2. 追踪所有失败的LLM预测以进一步改进。

由于本说明已经相当长。请参考tracing了解这两种追踪方法。

训练#

生成器默认支持训练模式。 它需要用户定义Parameter并将其传递给prompt_kwargs