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

Feat/llm responses #376

Open
wants to merge 169 commits into
base: dev
Choose a base branch
from
Open

Feat/llm responses #376

wants to merge 169 commits into from

Conversation

NotBioWaste905
Copy link
Collaborator

@NotBioWaste905 NotBioWaste905 commented Jul 24, 2024

Description

Added functionality for calling LLMs via langchain API for utilizing them in responses and conditions.

Checklist

  • I have performed a self-review of the changes

List here tasks to complete in order to mark this PR as ready for review.

To Consider

  • Add tests
  • Update API reference / tutorials / guides
  • Update CONTRIBUTING.md

@NotBioWaste905 NotBioWaste905 requested a review from RLKRo July 24, 2024 12:22
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears this PR is a release PR (change its base from master if that is not the case).

Here's a release checklist:

  • Update package version
  • Update poetry.lock
  • Change PR merge option
  • Update template repo
  • Search for objects to be deprecated

@NotBioWaste905 NotBioWaste905 changed the base branch from master to dev July 24, 2024 12:22
chatsky/llm/methods.py Outdated Show resolved Hide resolved
chatsky/llm/methods.py Outdated Show resolved Hide resolved
chatsky/llm/filters.py Outdated Show resolved Hide resolved
chatsky/llm/wrapper.py Outdated Show resolved Hide resolved
chatsky/llm/wrapper.py Outdated Show resolved Hide resolved
chatsky/llm/wrapper.py Outdated Show resolved Hide resolved
chatsky/llm/wrapper.py Outdated Show resolved Hide resolved
tests/llm/test_model_response.py Outdated Show resolved Hide resolved
tests/llm/test_model_response.py Outdated Show resolved Hide resolved
tests/llm/test_model_response.py Outdated Show resolved Hide resolved
@RLKRo
Copy link
Member

RLKRo commented Aug 8, 2024

I got an idea for more complex prompts: we can allow passing responses as prompts instead of just strings.

And then it'd be possible to incorporate slots into a prompt:

model = LLM_API(prompt=rsp.slots.FilledTemplate("You are an experienced barista in a local coffeshop."
"Answer your customers questions about coffee and barista work.\n"
"Customer data:\nAge {person.age}\nGender: {person.gender}\nFavorite drink: {person.habits.drink}"
))

Copy link
Member

@RLKRo RLKRo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've marked all resolved conversations as resolved (don't forget to put correct commit hash!).
There are still 25 unresolved conversations.
I've edited 9 of them with PROMPT REWORK or POSTPONED prefixes: the first ones are for me to resolve, the latter -- to be resolved in a later PR.

Please respond to the other 16 comments (plus the ones from this review): either with a commit hash of a commit that resolves it or with your comments regarding the suggestion.

raise NotImplemented

def __call__(self, ctx, request, response, model_name):
return self.call(ctx, request, model_name) + self.call(ctx, response, model_name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs to be bitwise or:

Suggested change
return self.call(ctx, request, model_name) + self.call(ctx, response, model_name)
return self.call(ctx, request, model_name) | self.call(ctx, response, model_name)

Add tests. They did not catch this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 68 to 71
if request is not None and request.misc is not None and request.misc.get("important", None):
return self.Return.Request
if response is not None and response.misc is not None and response.misc.get("important", None):
return self.Return.Response
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If both contain "important" this will return Request instead of Turn.
Implement this as MessageFilter.

Same for FromModel.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
return ExtractedGroupSlot(**res)

def __flatten_llm_group_slot(self, slot, parent_key=""):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You missed at least one in

            if isinstance(value, LLMGroupSlot):
                items.update(self.__flatten_llm_group_slot(value, new_key))

Add tests that use nested LLMGroupSlots.

raise ValueError

async def condition(
self, ctx: Context, prompt: str, method: BaseMethod, return_schema: Optional[BaseModel] = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does condition not support context history?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

result.annotations = {"__generated_by_model__": self.name}
return result

async def condition(self, prompt: str, method: BaseMethod, return_schema=None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it not possible to use message schema with log probs?

chatsky/llm/utils.py Outdated Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some lines are clearly not covered by the tests:
Slots are not tested at all.

Run poe quick_test_coverage to generate html reports in htmlcov directory.
You can then view them (by opening htmlcov/index.html) to see which lines are not covered.

it will be reused across all the nodes and therefore it will store all dialogue history.
This is not advised if you are short on tokens or if you do not need to store all dialogue history.
Alternatively you can instantiate model object inside of RESPONSE field in the nodes you need.
Via `history` parameter you can set number of dialogue _turns_ that the model will use as the history. Default value is `5`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is out of place.
This should be in filtering_history or as a comment near the line where LLMResponse is initialized with history=0.

},
"tell": {
RESPONSE: rsp.FilledTemplate(
"So you are {person.username} and your occupation is {person.job}, right?"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

person group slot does not allow partial extraction.
Add the flag, mention it, link to partial extraction tutorial.


# %% [markdown]
"""
Chatsky enables you to use more complex prompts then a simple string if need be.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Chatsky enables you to use more complex prompts then a simple string if need be.
Chatsky enables you to use more complex prompts than a simple string if needed.

"""
Chatsky enables you to use more complex prompts then a simple string if need be.
In this example we create a VacantPlaces class, that can dynamically retrieve
some external data and put them into the prompt.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
some external data and put them into the prompt.
some external data and put it into the prompt.

toy_script = {
GLOBAL: {
MISC: {
# this prompt will be overwritten with
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# this prompt will be overwritten with
# this prompt will be overwritten in

GLOBAL: {
MISC: {
# this prompt will be overwritten with
# every node with `prompt` key in it
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# every node with `prompt` key in it
# every node by the `prompt` key in it


# %% [markdown]
"""
Let's create a simple script to demonstrate this. Note, that prompts should go
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Let's create a simple script to demonstrate this. Note, that prompts should go
Let's create a simple script to demonstrate this. Note that prompts should go into

Inside `MISC` they can be stored under the `prompt`,
`global_prompt` or `local_prompt` keys.
Please note, that `MISC` is just a dictionary and its fields can be overwritten
in any node, if given the same key. You can utilize this in your project,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
in any node, if given the same key. You can utilize this in your project,

`global_prompt` or `local_prompt` keys.
Please note, that `MISC` is just a dictionary and its fields can be overwritten
in any node, if given the same key. You can utilize this in your project,
but below we present the intended way of
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
but below we present the intended way of
Below we present the intended way of

If you want to take the messages that meet your particular criteria and pass
them to the LLMs context you can use the `LLMResponse`s `filter_func` parameter.
It must be a function that takes a single `Message`
object and returns a boolean.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be an old description. Shouldn't it be like this?

It must be a class, whose call method takes the following args: context, request, response, and model_name

@@ -75,6 +75,7 @@ opentelemetry-instrumentation = { version = "*", optional = true }
sqlalchemy = { version = "*", extras = ["asyncio"], optional = true }
opentelemetry-exporter-otlp = { version = ">=1.20.0", optional = true } # log body serialization is required
pyyaml = { version = "*", optional = true }
langchain = { version = "*", optional = true }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about langchain-openai? it doesn't seem to be installed by default and I got import errors until I added it manually

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error

INFO:chatsky.core.script_parsing:Loaded file /home/rami1996/ui/my_project/bot/scripts/build.yaml
INFO:chatsky.messengers.common.interface:Attachments directory for LongpollingInterface messenger interface is None, so will be set to tempdir and attachment data won't be cached locally!
Exception: [ModuleNotFoundError("No module named 'langchain_openai'")]

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/rami1996/ui/my_project/./app.py", line 19, in <module>
    main()
  File "/home/rami1996/.cache/pypoetry/virtualenvs/chatsky-ui-Yhfmz2Co-py3.10/lib/python3.10/site-packages/click/core.py", line 1161, in __call__
    return self.main(*args, **kwargs)
  File "/home/rami1996/.cache/pypoetry/virtualenvs/chatsky-ui-Yhfmz2Co-py3.10/lib/python3.10/site-packages/click/core.py", line 1082, in main
    rv = self.invoke(ctx)
  File "/home/rami1996/.cache/pypoetry/virtualenvs/chatsky-ui-Yhfmz2Co-py3.10/lib/python3.10/site-packages/click/core.py", line 1443, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/rami1996/.cache/pypoetry/virtualenvs/chatsky-ui-Yhfmz2Co-py3.10/lib/python3.10/site-packages/click/core.py", line 788, in invoke
    return __callback(*args, **kwargs)
  File "/home/rami1996/ui/my_project/./app.py", line 14, in main
    pipeline = Pipeline.from_file(file = script_path, custom_dir = Path(script_path).parent.parent / "custom")
  File "/home/rami1996/.cache/pypoetry/virtualenvs/chatsky-ui-Yhfmz2Co-py3.10/lib/python3.10/site-packages/chatsky/core/pipeline.py", line 182, in from_file
    pipeline = JSONImporter(custom_dir=custom_dir).import_pipeline_file(file)
  File "/home/rami1996/.cache/pypoetry/virtualenvs/chatsky-ui-Yhfmz2Co-py3.10/lib/python3.10/site-packages/chatsky/core/script_parsing.py", line 263, in import_pipeline_file
    return self.replace_resolvable_objects(pipeline)
  File "/home/rami1996/.cache/pypoetry/virtualenvs/chatsky-ui-Yhfmz2Co-py3.10/lib/python3.10/site-packages/chatsky/core/script_parsing.py", line 232, in replace_resolvable_objects
    return {k: (self.replace_resolvable_objects(v)) for k, v in obj.items()}
  File "/home/rami1996/.cache/pypoetry/virtualenvs/chatsky-ui-Yhfmz2Co-py3.10/lib/python3.10/site-packages/chatsky/core/script_parsing.py", line 232, in <dictcomp>
    return {k: (self.replace_resolvable_objects(v)) for k, v in obj.items()}
  File "/home/rami1996/.cache/pypoetry/virtualenvs/chatsky-ui-Yhfmz2Co-py3.10/lib/python3.10/site-packages/chatsky/core/script_parsing.py", line 232, in replace_resolvable_objects
    return {k: (self.replace_resolvable_objects(v)) for k, v in obj.items()}
  File "/home/rami1996/.cache/pypoetry/virtualenvs/chatsky-ui-Yhfmz2Co-py3.10/lib/python3.10/site-packages/chatsky/core/script_parsing.py", line 232, in <dictcomp>
    return {k: (self.replace_resolvable_objects(v)) for k, v in obj.items()}
  File "/home/rami1996/.cache/pypoetry/virtualenvs/chatsky-ui-Yhfmz2Co-py3.10/lib/python3.10/site-packages/chatsky/core/script_parsing.py", line 229, in replace_resolvable_objects
    args, kwargs = self.parse_args(obj[key])
  File "/home/rami1996/.cache/pypoetry/virtualenvs/chatsky-ui-Yhfmz2Co-py3.10/lib/python3.10/site-packages/chatsky/core/script_parsing.py", line 196, in parse_args
    value = self.replace_resolvable_objects(value)
  File "/home/rami1996/.cache/pypoetry/virtualenvs/chatsky-ui-Yhfmz2Co-py3.10/lib/python3.10/site-packages/chatsky/core/script_parsing.py", line 232, in replace_resolvable_objects
    return {k: (self.replace_resolvable_objects(v)) for k, v in obj.items()}
  File "/home/rami1996/.cache/pypoetry/virtualenvs/chatsky-ui-Yhfmz2Co-py3.10/lib/python3.10/site-packages/chatsky/core/script_parsing.py", line 232, in <dictcomp>
    return {k: (self.replace_resolvable_objects(v)) for k, v in obj.items()}
  File "/home/rami1996/.cache/pypoetry/virtualenvs/chatsky-ui-Yhfmz2Co-py3.10/lib/python3.10/site-packages/chatsky/core/script_parsing.py", line 230, in replace_resolvable_objects
    return self.resolve_string_reference(key)(*args, **kwargs)
  File "/home/rami1996/.cache/pypoetry/virtualenvs/chatsky-ui-Yhfmz2Co-py3.10/lib/python3.10/site-packages/chatsky/core/script_parsing.py", line 181, in resolve_string_reference
    raise JSONImportError(f"Could not import {obj}") from Exception(exceptions)
chatsky.core.script_parsing.JSONImportError: Could not import langchain_openai.ChatOpenAI
Read the guide on Pipeline import from file: https://deeppavlov.github.io/chatsky/user_guides/pipeline_import.html

Copy link
Collaborator Author

@NotBioWaste905 NotBioWaste905 Dec 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not include langchain-<provider> packages by default to prevent dependencies versions mismatch. As it is shown in tutorials you need to install them by yourself like so pip install chatsky[llm] langchain-openai

especially when using smaller models.

Note that we are passing the name of the model
from pipeline.models dictionary to LLMGroupSlot.model field.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't get it! pipeline.models and LLMGrouptSlot.model seem not to be mentioned elsewhere

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

Successfully merging this pull request may close these issues.

4 participants