Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I start enforcing schema only after a keyword is hit during inference? #120

Open
accupham opened this issue Jul 11, 2024 · 3 comments

Comments

@accupham
Copy link

For example, sometimes during chain of reasoning, it is helpful to have the model reason about the answer in free-form, then output the JSON. So perhaps inference could start without enforcement, then when “‘’’\n{“ is encountered, then start enforcement.

@noamgat
Copy link
Owner

noamgat commented Jul 13, 2024

Interesting. It should be possible to chain several parsers, for example something like (this is pseudocode for the LM Format Enforcer)

SequenceParser
      element 1: Regex Parser <regex for anything except ```\n{>```\n{    # any string that ends with your json prefix
      element 2: JsonSchemaParser (schema).add_character('{')  # adding the { character to start at the json parsing state in which the regex already reached

RegexParser, SequenceParser and JsonSchemaParser are all existing classes.
I did not try this, but in theory it should work.
However, In reality, I would expect better results in a multiturn scenario:

User: Please do xxxxx. Share your chain of thought reasoning as well.
Assistant: .....
User: Based on the arugments above, output your answer in JSON in the following schema: <schema>
Assistant: <LMFE Json Schema Parser active here>

As in this way, it is mandatory to start the json output at a specific point, where it makes sense conversation wise. In the first scenario, the LLM might want to end the response, and LMFE won't let it (because it didn't output json yet), causing hallucinations.

@accupham
Copy link
Author

accupham commented Jul 13, 2024

With regards to the first scenario, what if you did something like this:

SequenceParser:
    element 1:
        UnionParser:
             element 1: RegexParser
             element 2: ForceStopParser
    element 2:
        JSONSchemaParser

I think I would have to modify Sequence parser can_end so it could stop on any, instead of all here:

return all([parser.can_end() for parser in self.parsers])

But then now the LLM can end the conversation if it encounters an EOS or stopword before JSON is emitted if the conversation is appropriate, avoiding nasty hallucinations.

I would like to open a PR by adding a new parser that does effectively this with one-shot. Is this the right direction or am I overcomplicating things?

@noamgat
Copy link
Owner

noamgat commented Jul 16, 2024

I'm not sure it warrants a PR, its OK if your code has classes from the LMFE hierarchy. Maybe it could be a sample.
Alternatively, create a UnionParser from the two options (one with the json and one without).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants