Source code for optim.text_grad.llm_text_loss
"""Implementation of TextGrad: Automatic “Differentiation” via Text"""
from typing import Union, TYPE_CHECKING
if TYPE_CHECKING:
from adalflow.core import ModelClient
from ..parameter import Parameter
from adalflow.optim.loss_component import LossComponent
from typing import Dict
from copy import deepcopy
import logging
log = logging.getLogger(__name__)
TEXT_LOSS_TEMPLATE = r"""<START_OF_SYSTEM_PROMPT>
{{eval_system_prompt}}
<END_OF_SYSTEM_PROMPT>
<USER>
{{eval_user_prompt}}
</USER>
"""
[docs]
class LLMAsTextLoss(LossComponent):
__doc__ = r"""Evaluate the final RAG response using an LLM judge.
The LLM judge will have:
- eval_system_prompt: The system prompt to evaluate the response.
- y_hat: The response to evaluate.
- Optional: y: The correct response to compare against.
The loss will be a Parameter with the evaluation result and can be used to compute gradients.
This loss use LLM/Generator as the computation/transformation operator, so it's gradient will be
found from the Generator's backward method.
"""
def __init__(
self,
prompt_kwargs: Dict[str, Union[str, "Parameter"]],
model_client: "ModelClient",
model_kwargs: Dict[str, object],
):
from adalflow.core.generator import Generator
from adalflow.optim.parameter import Parameter
super().__init__()
prompt_kwargs = deepcopy(prompt_kwargs)
# TODO: do we really need to convert str to Parameter? what if not?
for key, value in prompt_kwargs.items():
if isinstance(value, str):
prompt_kwargs[key] = Parameter(
data=value, requires_opt=False, role_desc=key
)
self.prompt_kwargs = prompt_kwargs
# this is llm as judge (loss) to get the loss
self.loss_llm = Generator(
name="llm_judge",
model_client=model_client,
model_kwargs=model_kwargs,
template=TEXT_LOSS_TEMPLATE,
prompt_kwargs=prompt_kwargs,
)
# def __call__(self, *args, **kwargs):
# return self.forward(*args, **kwargs)
[docs]
def forward(self, *args, **kwargs) -> "Parameter":
return self.loss_llm.forward(*args, **kwargs)