-
Notifications
You must be signed in to change notification settings - Fork 168
Plan-Execute-Reflect Agent Tracing #3964
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
base: feature/agent-tracing
Are you sure you want to change the base?
Plan-Execute-Reflect Agent Tracing #3964
Conversation
Signed-off-by: chrislai <chrlaii@amazon.com>
|
||
if ("aws.bedrock".equalsIgnoreCase(provider)) { | ||
// Bedrock/Claude format: input_tokens, output_tokens (or inputTokens, outputTokens) | ||
if (usage.containsKey("input_tokens")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wondering if you check on contains "input_tokens", but if the usage has "input_tokens_meta_data" but no "input_tokens", this will through key not found exception or getting null while toString(), can you verify this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed by adding fallback
if (tensors != null && !tensors.isEmpty()) { | ||
var tensor = tensors.get(0); | ||
// Try result | ||
if (tensor.getResult() != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did you test it with local model output, even though most of the users should use remote model, but what if a users accidentally passed over a local model output, what would happen here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, very good point. addressed as well by adding fallback for local model
Signed-off-by: chrislai <chrlaii@amazon.com>
"version": 1, | ||
"template": { | ||
"mappings": { | ||
"date_detection": false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious, what is this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Disables automatic date detection in OpenSearch to ensure no field gets automatically mapped to date if we don't want it to
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if a cluster with this index name already exists? do you think we should give a setting to configure this index?
} | ||
} | ||
}, | ||
"serviceName": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
snake case for consistency
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately it conflicts with OTel format, so must keep the standard of camel case
Map<String, String> agentAttributes = MLAgentTracer.createAgentTaskAttributes(mlAgent.getName(), apiParams.get(QUESTION_FIELD)); | ||
Span agentTaskSpan = MLAgentTracer.getInstance().startSpan(MLAgentTracer.AGENT_TASK_PER_SPAN, agentAttributes, null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since attributes depend on the type of span, can we have methods like startTaskSpan? What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, fixed
Double inputTokens = planResultInfo.usage != null && planResultInfo.usage.get("inputTokens") instanceof Number | ||
? ((Number) planResultInfo.usage.get("inputTokens")).doubleValue() | ||
: null; | ||
Double outputTokens = planResultInfo.usage != null && planResultInfo.usage.get("outputTokens") instanceof Number | ||
? ((Number) planResultInfo.usage.get("outputTokens")).doubleValue() | ||
: null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move attribute creation/setting into methods, keep each method small and reusable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed
phaseInputTokens.set(0.0); | ||
phaseOutputTokens.set(0.0); | ||
phaseTotalTokens.set(0.0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we use a "reset" method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, good point, addressed
// if (!allParams.containsKey(LLM_RESPONSE_FILTER) || allParams.get(LLM_RESPONSE_FILTER).isEmpty()) { | ||
// throw new IllegalArgumentException("llm_response_filter not found. Please provide the path to the model output."); | ||
// } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why has this been commented out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch
Map<String, String> spanContextMap = new HashMap<>(); | ||
MLAgentTracer.getInstance().injectSpanContext(executeStepSpan, spanContextMap); | ||
reactParams.putAll(spanContextMap); | ||
log.info("[AGENT_TRACE] PER Agent - Injected parent SpanContext: {}", spanContextMap); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use debug logs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed
Signed-off-by: chrislai <chrlaii@amazon.com>
|
||
newSpan.addAttribute("thread.name", Thread.currentThread().getName()); | ||
} catch (Exception e) { | ||
log.warn("Failed to create root span, falling back to normal span creation", e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is the consequence if it failed to create root span and become a normal span? is it we lost the relationship of a root span?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but the opposite actually. If we fail to create a root span, the span will still be created except it will show to have a parent span, but that span doesn't exist.
@@ -0,0 +1,182 @@ | |||
package org.opensearch.ml.engine.algorithms.agent.tracing; | |||
|
|||
import static org.junit.Assert.*; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
avoid import *
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, addressed
private Tracer mockTracer; | ||
private MLFeatureEnabledSetting mockFeatureSetting; | ||
|
||
@Before |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add proper java doc for you class and test method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right, thanks. done
@@ -0,0 +1,180 @@ | |||
package org.opensearch.ml.engine.algorithms.agent.tracing; | |||
|
|||
import static org.junit.Assert.*; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
avoid *
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed
package org.opensearch.ml.engine.algorithms.agent.tracing; | ||
|
||
import static org.junit.Assert.*; | ||
import static org.mockito.Mockito.*; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed
import org.opensearch.ml.common.output.model.ModelTensors; | ||
import org.opensearch.telemetry.tracing.Span; | ||
|
||
public class MLAgentTracerStaticUtilsTests { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
java doc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@SuppressWarnings("unchecked") | ||
Map<String, Object> usage = (Map<String, Object>) usageObj; | ||
|
||
if ("aws.bedrock".equalsIgnoreCase(provider)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are using equalsIgnoreCase for "aws.bedrock" but you are not getting "aws.bedrock".
I think "aws.bedrock" would be better to be "containsKey"
but the rest of the key that you are actually getting, for example, "input_tokens" and "prompt_tokens", before you are getting the keys, it makes more sense to check equalsIgnoreCase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, very good point. fixed
Signed-off-by: chrislai <chrlaii@amazon.com>
Description
Adds tracing to the Plan-Execute-Reflect agent. Uses custom index mapping for storage. Basic connection with Conversational agent. Also re-structures the tracing class to be more flexible for non-agent tracing.
Related Issues
Resolves #3971
Check List
--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.