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

Refactor memory layer to be used across flow and chat agent #1707

Conversation

arjunkumargiri
Copy link
Contributor

@arjunkumargiri arjunkumargiri commented Nov 29, 2023

Description

Refactored conversation creation to MLAgentExecutor so that the same memory ID could be used across multiple agents. Generated memory ID will be passed to agents as part of input parameters. Integrated memory with flow agent, with output of the flow agent being appended to additional info field of interaction.

Request:

{
  "parameters": {
    "question": "How many indexes do I have in my cluster?",
    "verbose": false
  }
}

Response:

{
    "inference_results": [
        {
            "output": [
                {
                    "name": "response",
                    "dataAsMap": {
                        "response": "There are 7 indexes in the cluster."
                    }
                },
                {
                    "name": "QuestionSuggestor",
                    "result": " Here are some follow up questions the Human may ask:\n\n[question1: 'How many shards are there per index?',\nquestion2: 'What is the health status of the indexes?',  \nquestion3: 'What are the names of the indexes?']"
                }
            ]
        }
    ]
}

Conversation history:

{
    "interactions": [
        {
            "conversation_id": "EY9sGIwBQ8497oqLl2Np",
            "interaction_id": "Eo9sGIwBQ8497oqLnWMT",
            "create_time": "2023-11-29T00:13:39.188239Z",
            "input": "How many indexes do I have in my cluster?",
            "prompt_template": null,
            "response": "There are 7 indexes in the cluster.",
            "origin": null,
            "additional_info": {
                "LLMResponseGenerator.output": "ModelTensorOutput(mlModelOutputs=[ModelTensors(mlModelTensors=[ModelTensor(name=response, data=null, shape=null, dataType=null, byteBuffer=null, result=null, dataAsMap={response=There are 7 indexes in the cluster.})], statusCode=null)])",
                "QuestionSuggestor.output": " Here are some follow up questions the Human may ask:\n\n[question1: 'How many shards are there per index?',\nquestion2: 'What is the health status of the indexes?',  \nquestion3: 'What are the names of the indexes?']",
                "None": "None"
            }
        }
    ]
}

TODO:

  • Add unit test while merging in main branch
  • Add output of each flow agent step to memory
  • Instead of agent updating final answer, agent executor should update final answer interaction in memory

Issues Resolved

[List any issues this PR will resolve]

Check List

  • New functionality includes testing.
    • All tests pass
  • New functionality has been documented.
    • New functionality has javadoc added
  • Commits are signed per the DCO using --signoff

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

Copy link

codecov bot commented Nov 29, 2023

Codecov Report

Attention: 146 lines in your changes are missing coverage. Please review.

Comparison is base (bb86968) 68.60% compared to head (371b685) 68.94%.
Report is 2 commits behind head on feature/agent_framework_dev.

Files Patch % Lines
...ch/ml/engine/algorithms/agent/MLAgentExecutor.java 0.00% 87 Missing ⚠️
.../ml/engine/algorithms/agent/MLFlowAgentRunner.java 31.25% 18 Missing and 4 partials ⚠️
...nsearch/ml/engine/tools/AbstractRetrieverTool.java 74.19% 14 Missing and 2 partials ⚠️
...a/org/opensearch/ml/engine/tools/VectorDBTool.java 0.00% 11 Missing ⚠️
.../ml/engine/algorithms/agent/MLChatAgentRunner.java 89.13% 4 Missing and 1 partial ⚠️
...g/opensearch/ml/engine/tools/NeuralSparseTool.java 86.48% 3 Missing and 2 partials ⚠️
Additional details and impacted files
@@                        Coverage Diff                        @@
##             feature/agent_framework_dev    #1707      +/-   ##
=================================================================
+ Coverage                          68.60%   68.94%   +0.34%     
- Complexity                          2591     2611      +20     
=================================================================
  Files                                239      241       +2     
  Lines                              12757    12875     +118     
  Branches                            1284     1291       +7     
=================================================================
+ Hits                                8752     8877     +125     
+ Misses                              3404     3392      -12     
- Partials                             601      606       +5     
Flag Coverage Δ
ml-commons 68.94% <48.77%> (+0.34%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@arjunkumargiri arjunkumargiri marked this pull request as ready for review November 29, 2023 00:35
@arjunkumargiri
Copy link
Contributor Author

@jngz-es @ylwu-amzn please review

.getFinalInteractions(memoryId, PREVIOUS_INTERACTION, ActionListener.<List<Interaction>>wrap(interactions -> {
if (interactions.size() == 0) {
throw new IllegalStateException("No existing interactions to update");
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Few questions here

  1. if flow agent don't have conversational agent as its tools, there should not have any interactions behind the memory. Should we throw exception for this case?
  2. Get last 1 interaction may not work when race condition happens, there may have new interaction before previous interaction have final answer

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question:

  1. Will update to create an empty interaction in case there are no existing interaction.
  2. As per my understanding getFinalInteraction will return previous interaction with final answer. @Zhangxunmt please confirm if getFinalInteractions can result in race condition.

Copy link
Collaborator

Choose a reason for hiding this comment

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

getFinalInteractions returns all interactions that are not traces. The final interaction itself is always created when an interaction starts, with an empty response and it waits until all the traces are complete to obtain the final answer. So it's possible that new interaction is created before the previous one receives the final response.

String title = inputDataSet.getParameters().get(QUESTION);

ConversationIndexMemory.Factory conversationIndexMemoryFactory =
(ConversationIndexMemory.Factory) memoryFactoryMap.get(memoryType);
Copy link
Contributor

Choose a reason for hiding this comment

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

does this mean we can only use conversation_index as memory type for all agents?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In my opinion, memory should not be tied to an agent and should be common to all agents. We could have different implementations for memory that could be dynamically chosen but it should reusable across all agents.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This memoryFactoryMap is supposed to support different memory types. Any memory that implements the "Memory" class can be registered in this Map at initialization. So any agent can fetch the memory based on their needs using a memory type. ATM, we only implemented ConversationIndexMemory but there will be more on the way.

Copy link
Contributor

Choose a reason for hiding this comment

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

@jngz-es @ylwu-amzn have question about Memory interface, is memory instance a single memory object or it's a memory container?

BufferedMemory implements like a container for all sessions

ConversationIndexMemory have a property conversation_id associate with it, it's more like a single memory object

Copy link
Collaborator

Choose a reason for hiding this comment

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

Please ignore BufferedMemory for now, we don't use it right now as it is not P0 I think.
Yeah, ConversationIndexMemory is an object which is allocated for each request.

Copy link
Collaborator

@Zhangxunmt Zhangxunmt left a comment

Choose a reason for hiding this comment

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

This PR name is a little confusing. I thought its a big refactor for all the memory layer :).

}
String outputResponse = parseResponse(output);
params.put(outputKey, outputResponse);
additionalInfo.put(outputKey, outputResponse);
Copy link
Contributor

Choose a reason for hiding this comment

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

Using previous step output as chat history may not sufficient for generating suggestions. At least we should include question, that could include in prompt template. Further more, chat history in conversational agent should used.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Parameters field already contains question as part of the map.

Adding historical chat context to flow parameters will be added as part of a different PR.

.updateInteraction(
parentInteractionId,
ImmutableMap.of(AI_RESPONSE_FIELD, finalAnswer1),
ActionListener.<UpdateResponse>wrap(updateResponse -> {
Copy link
Contributor

Choose a reason for hiding this comment

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

why ADDITIONAL_INFO_FIELD, additionalInfo been removed ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Resolved merge conflict

Signed-off-by: Arjun kumar Giri <[email protected]>
@@ -299,17 +298,7 @@ private void runReAct(
String maxIteration = Optional.ofNullable(tmpParameters.get("max_iteration")).orElse("3");

// Create root interaction.
StepListener<CreateInteractionResponse> createRootItListener = new StepListener<>();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Got it, thanks!

@ylwu-amzn ylwu-amzn merged commit fcbfc7e into opensearch-project:feature/agent_framework_dev Dec 6, 2023
4 of 7 checks passed
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.

6 participants