guidance-ai / guidance

A guidance language for controlling large language models.
MIT License
18.58k stars 1.03k forks source link

Generation of `select` fails on OpenAI chat mode, depending on possible options. #232

Open jprafael opened 1 year ago

jprafael commented 1 year ago

The bug

Generation of select fails on OpenAI chat mode, depending on possible options. It seems to be related with common prefixes between two options.

To Reproduce

This works:

llm = guidance.llms.OpenAI('gpt-3.5-turbo')

experts = guidance('''
{{#assistant~}}
{{#select 'name'}}John{{or}}Jane Doe{{/select}}
{{~/assistant}}
''', llm=llm)

x = experts()
x.variables()

But this doesn't:

llm = guidance.llms.OpenAI('gpt-3.5-turbo')

experts = guidance('''
{{#assistant~}}
{{#select 'name'}}John{{or}}John Doe{{/select}}
{{~/assistant}}
''', llm=llm)

x = experts()
x.variables()

It fails with When calling OpenAI chat models you must generate only directly inside the assistant role! The OpenAI API does not currently support partial assistant prompting.

This also fails, even though one answer is not a complete prefix of the other:

# this fails
program = guidance(
"""
{{#assistant~}}
{{#select 'help'}}No I need support{{or}}No I am not ok{{/select}}
{{~/assistant}}
""",
llm=llm
)

result = program()

System info (please complete the following information):

jprafael commented 1 year ago

The problem is indeed related to prefixes. When running the John/John Doe example, guidance extracts the common prefix \n <|im_start|>assistant\nJohn and asks OpenAI for the next most-likely tokens, either {{ or Doe. Because the prompt doesn't end with <|im_start|>assistant (e.g. has \nJohn in it it fails. However it also seems wierd that one of the next tokens to be predicted is {{ (which is the start of the finishing assistant tag) and not <| for <|im_end|>

AI-Ahmed commented 1 year ago

@jprafael Did you find a solution for this?

Thank you!

AI-Ahmed commented 1 year ago

I think you may want to test this new syntax format:

{{select 'name' options=["John", "John Doe"]}}
jprafael commented 1 year ago

I think you may want to test this new syntax format:

{{select 'name' options=["John", "John Doe"]}}

The issue is present regardless ot method.

@jprafael Did you find a solution for this?

I did not find a good solution for this. The issue is that to support select guidance does the following under the scenes:

The work around that I found was to create the prompt in a way that avoids prefixes, but still gives enough context to the LLM so that choices are valid:


experts = guidance('''
{{#user~}}
What is your name:
1. John
2. John Doe
{{~/user}}

{{#assistant~}}
{{#select 'name'}}1. John{{or}}2. John Doe{{/select}}
{{~/assistant}}
''', llm=llm)

This way, the longest common prefix is empty, and one of the two options can be selected directly from the first token emited by the LLM. In this case, we need to write the list of allowed values into the context, to add some meaning to the `1` and `2` tokens, but that was something I was doing already.