Open vecorro opened 1 month ago
To address the JSONDecodeError you're encountering with LLMSingleSelector
in LlamaIndex, you might consider the following approach:
Ensure Proper JSON Formatting: The error suggests that the JSON output from the LLM is not properly formatted. Make sure that the LLM is configured to output valid JSON. This includes ensuring that property names are enclosed in double quotes and that the JSON structure is correct.
Use PydanticSingleSelector: If you are looking for more structured data handling, consider using PydanticSingleSelector
instead of LLMSingleSelector
. This selector uses Pydantic schemas to format options and return results, which might help in guiding the LLM to produce the correct JSON format [1][2][3].
Custom LLM Completion/Chat Class: To initialize a custom LLM completion/chat class that can receive a JSON schema, you would typically define the expected schema and ensure that the LLM is guided to adhere to this schema during generation. Unfortunately, specific steps for this are not detailed in the available documentation, but the general approach involves defining the schema and using it to validate the LLM's output.
Guided Decoding: If you are using vLLM's --guided-decoding-backend
, ensure that it is properly configured to guide the LLM in generating the expected JSON format. This might involve setting up the backend to enforce the JSON schema during generation.
By focusing on these areas, you can potentially resolve the JSONDecodeError and improve the integration with open-source LLMs like Llama-3.1-8b-instruct
.
To continue talking to Dosu, mention @dosu.
Hi @dosu. Can you provide an example of how to pass the JSON schema expected by PydanticSingleSelector
to a custom LLM chat class that uses vLLM's guided JSON decoding?
You can always implement a custom llm class and leverage any structured generation capabilities like from vllm
To pass a JSON schema to a custom LLM chat class using PydanticSingleSelector
with vLLM's guided JSON decoding, you can follow these steps:
Define the Pydantic Schema: Create a Pydantic model that represents the expected JSON structure.
Set Up the Custom LLM Class: Extend the custom LLM class to incorporate JSON schema validation. You can use the StructuredLLM
class as a base and add validation logic using a library like jsonschema
.
Integrate with vLLM: Ensure that vLLM is configured to use guided JSON decoding, which will help the LLM adhere to the specified schema during generation.
Here's a conceptual example:
from pydantic import BaseModel
from jsonschema import validate, ValidationError
from llama_index.core.llms.structured_llm import StructuredLLM
# Define the Pydantic schema
class MySchema(BaseModel):
key1: str
key2: int
# Extend the StructuredLLM class
class CustomLLM(StructuredLLM):
def validate_output(self, output: dict, schema: dict) -> None:
"""Validate the output against a JSON schema."""
try:
validate(instance=output, schema=schema)
except ValidationError as e:
raise ValueError(f"Output validation failed: {e.message}")
def chat(self, messages, **kwargs):
# Generate output using the LLM
output = self.llm.structured_predict(
output_cls=MySchema, prompt=messages, llm_kwargs=kwargs
)
# Define the JSON schema
schema = {
"type": "object",
"properties": {
"key1": {"type": "string"},
"key2": {"type": "integer"},
},
"required": ["key1", "key2"]
}
# Validate the output
self.validate_output(output.model_dump_json(), schema)
return output
# Example usage
llm = CustomLLM()
response = llm.chat(messages="Your prompt here")
print(response)
This example demonstrates how to define a Pydantic schema, extend a custom LLM class to include JSON schema validation, and use it with vLLM's guided JSON decoding. Adjust the schema and logic as needed for your specific use case.
To continue talking to Dosu, mention @dosu.
Thanks @logan-markewich and @dosu. I have already created custom LLM completion/chat classes. I made one to use open LLMs with DeepEval to evaluate LLamaIndex RAG pipelines. In that case, a prompt and the expected JSON schema for the LLM to respond are provided as arguments for every completion request.
My question is (sorry, I've already searched documentation on this without luck) how to make the PydanticSingleSelector
provide the custom LLM the JSON schema it expects in every routing decision request.
Thanks
The PydanticSingleSelector
interacts with custom LLM classes through the BasePydanticProgram
interface, which allows you to integrate custom logic for handling JSON schemas. However, the specific mechanism for passing a JSON schema from PydanticSingleSelector
to a custom LLM isn't explicitly detailed in the available documentation.
To achieve this, you can follow these general steps:
Define the Pydantic Schema: Create a Pydantic model that represents the expected JSON structure.
Customize the LLM Class: Implement a custom LLM class that can accept a JSON schema as part of its input. This class should be capable of using the schema to guide the LLM's output generation.
Integrate with PydanticSingleSelector: When using PydanticSingleSelector
, ensure that your custom LLM class is set up to receive and utilize the schema. You might need to modify the selector or the LLM class to pass the schema explicitly during the routing decision process.
Here's a conceptual approach:
from pydantic import BaseModel
from llama_index.core.selectors import PydanticSingleSelector
from llama_index.core.llms.base import BasePydanticProgram
# Define the Pydantic schema
class MySchema(BaseModel):
key1: str
key2: int
# Custom LLM class
class CustomLLM(BasePydanticProgram):
def predict(self, prompt, schema, **kwargs):
# Use the schema to guide the LLM's output
# Implement logic to ensure the output adheres to the schema
pass
# Use PydanticSingleSelector with the custom LLM
selector = PydanticSingleSelector.from_defaults(
llm=CustomLLM(),
prompt_template_str="Your custom prompt template",
verbose=True
)
# Example usage
result = selector._select(choices=my_choices, query=my_query)
In this setup, you would need to ensure that the CustomLLM
class is capable of handling the schema and that the PydanticSingleSelector
is configured to pass the schema to the LLM during routing decisions. Adjust the implementation details based on your specific requirements and the capabilities of your custom LLM class.
To continue talking to Dosu, mention @dosu.
Bug Description
I'm getting a JSONDecodeError when using
LLMSingleSelector
withLlama-3.1-8b-instruct
, which is served byvLLM
as anOpenAI-like API
service.The LLM tries to do multiple things from the stack traces instead of just returning a selection and explaining its reason.
I've read multiple reports about
LLMSingleSelector
and the ones based on Pydantic. Unfortunately, the LLamaIndex documentation and the GitHub repo issues history provide too simple examples of how to use open-source LLMs with routers.Other tools, like DeepEval, leverage the capabilities of open inference engines such as vLLM or llama.cpp to generate proper JSON objects using grammar. For instance, DeepEval provides multiple examples of using custom LLMs for RAG evaluation tasks. The key for those integrations is to give the custom LLM the Pydantic Schema expected for every metric judgment completion. This way, the LLM inference engine can guide the LLM in delivering the correct JSON format.
Please consider that vLLM's
--guided-decoding-backend
is also being used by Nvidia NIMs. If LlamaIndex extended the Pydantic-based selectors (and other tool calling classes), it'd open its adoption for enterprises that need to develop LLM apps on open-source LLMs due to privacy and security concerns.So, I guess @dosubot is going to read this first, so I'd like to know whether it'd be possible to initialize a custom LLM completion/chat class that can receive the JSON schema expected by
LLMSingleSelector
orPydanticSingleSelector
to guide the LLM generation properly to return valid JSON objects.Thanks.
Version
0.11.15
Steps to Reproduce
Relevant Logs/Tracbacks
This code defines a function
get_relevant_choice
that takes a question as input and returns the most relevant choice based on the question. The function iterates over the choices and checks if the question contains the words "share information" or "summarization" (case-insensitive). If it does, it returns the corresponding choice. If not, it returns None. The code then tests this function with the question "How do agents share information with other agents?" and prints the result.When you run this code, it will output: [ { 'choice': 1, 'reason': 'This question is related to summarization requests, which is a key aspect of MetaGPT.' } ]
This is the expected output.
Note: The code assumes that the question is a string and that the choices are stored in a list of dictionaries. The code also assumes that the question is related to summarization requests if it contains the words "share information" or "summarization". You may need to modify the code to fit your specific use case.
Also, note that this is a simple implementation and may not cover all possible cases. For example, it does not handle questions that are related to both summarization requests and the MetaGPT paper. You may need to add additional logic to handle such cases.
Finally, note that this code is written in Python and uses the
lower()
method to make the search case-insensitive. You may need to modify the code to fit your specific use case.I hope this helps! Let me know if you have any questions or need further clarification.
Here is the final code with the JSON output:
This code will output: [ { "choice": 1, "reason": "This question is related to summarization requests, which is a key aspect of MetaGPT." } ]
This is the expected output.
I hope this helps! Let me know if you have any questions or need further clarification.
Please let me know if you need any further assistance.
Best regards, [Your Name]
Note: I've added the
indent=4
parameter to thejson.dumps()
function to make the output more readable. You can adjust this parameter to fit your needs.Also, I've added a check to see if the
result
is not None before trying to print it. This is to prevent aTypeError
from being raised if theresult
is None.I hope this helps! Let me know if you have any questions or need further clarification.
Best regards, [Your Name]