Skip to content

Commit d19b80f

Browse files
committed
Show the trace ID inline with messages
1 parent d10a6b4 commit d19b80f

File tree

4 files changed

+96
-31
lines changed

4 files changed

+96
-31
lines changed

instrumentation-genai/opentelemetry-instrumentation-vertexai/examples/langgraph-chatbot-demo/run_streamlit.py.lock

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ wheels = [
331331

332332
[[package]]
333333
name = "google-cloud-aiplatform"
334-
version = "1.79.0"
334+
version = "1.80.0"
335335
source = { registry = "https://pypi.org/simple" }
336336
dependencies = [
337337
{ name = "docstring-parser" },
@@ -347,9 +347,9 @@ dependencies = [
347347
{ name = "shapely" },
348348
{ name = "typing-extensions" },
349349
]
350-
sdist = { url = "https://files.pythonhosted.org/packages/a5/8e/93e9f5a7059883c21a82adf8687248c6615d4b833b3bf665631a768b8ebd/google_cloud_aiplatform-1.79.0.tar.gz", hash = "sha256:362bfd16716dcfb6c131736f25246790002b29c99a246fcf4c08a7c71bd2301f", size = 8455732 }
350+
sdist = { url = "https://files.pythonhosted.org/packages/f0/88/d36384280cc4653e190a4a30025e66b285fbaef06024f68a4264cc588a33/google_cloud_aiplatform-1.80.0.tar.gz", hash = "sha256:bcaa4570a6fb56d3d29cb6b8f92588d4d1a1931de5f90cf07761853dab4c76fd", size = 8459480 }
351351
wheels = [
352-
{ url = "https://files.pythonhosted.org/packages/d9/df/a7629fc1c405ead82249a70903068992932cc5a8c494c396e22995b4429d/google_cloud_aiplatform-1.79.0-py2.py3-none-any.whl", hash = "sha256:e52d518c386ce2b4ce57f1b73b46c57531d9a6ccd70c21a37b349f428bfc1c3f", size = 7086167 },
352+
{ url = "https://files.pythonhosted.org/packages/b5/57/5e761e7a8b03efc8e7faa4c0b2775991177bbd4dae7a6656a60dfd092ca8/google_cloud_aiplatform-1.80.0-py2.py3-none-any.whl", hash = "sha256:45d2a170f22431dae977551eccb740400bdb899807d0c8d4c16c53b2c1dbc6a5", size = 7089949 },
353353
]
354354

355355
[[package]]
@@ -818,7 +818,7 @@ wheels = [
818818
[[package]]
819819
name = "langgraph-chatbot-demo"
820820
version = "0.1.0"
821-
source = { git = "https://github.com/aabmass/opentelemetry-python-contrib.git?subdirectory=instrumentation-genai%2Fopentelemetry-instrumentation-vertexai%2Fexamples%2Flanggraph-chatbot-demo&branch=vertex-langgraph#441d9f6440e895957ebb982fd5fc1ae6d2731f46" }
821+
source = { git = "https://github.com/aabmass/opentelemetry-python-contrib.git?subdirectory=instrumentation-genai%2Fopentelemetry-instrumentation-vertexai%2Fexamples%2Flanggraph-chatbot-demo&branch=vertex-langgraph#833be299733a585349eca5bbc3f4977a6760e0be" }
822822
dependencies = [
823823
{ name = "duckduckgo-search" },
824824
{ name = "langchain-community" },
@@ -1268,7 +1268,7 @@ wheels = [
12681268
[[package]]
12691269
name = "opentelemetry-instrumentation-vertexai"
12701270
version = "2.1b0.dev0"
1271-
source = { git = "https://github.com/aabmass/opentelemetry-python-contrib.git?subdirectory=instrumentation-genai%2Fopentelemetry-instrumentation-vertexai&branch=vertex-langgraph#441d9f6440e895957ebb982fd5fc1ae6d2731f46" }
1271+
source = { git = "https://github.com/aabmass/opentelemetry-python-contrib.git?subdirectory=instrumentation-genai%2Fopentelemetry-instrumentation-vertexai&branch=vertex-langgraph#833be299733a585349eca5bbc3f4977a6760e0be" }
12721272
dependencies = [
12731273
{ name = "opentelemetry-api" },
12741274
{ name = "opentelemetry-instrumentation" },

instrumentation-genai/opentelemetry-instrumentation-vertexai/examples/langgraph-chatbot-demo/src/langgraph_chatbot_demo/_streamlit_helpers.py

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
1+
from __future__ import annotations
2+
13
from textwrap import dedent
24

35
import google.auth
46
import pandas as pd
57
import streamlit as st
8+
from langchain_core.messages.base import BaseMessage
69
from langgraph.checkpoint.memory import InMemorySaver
710
from sqlalchemy import Engine, inspect
811

912

13+
@st.cache_data
14+
def _get_project_id() -> str:
15+
project_id: str = google.auth.default()[1] # type: ignore
16+
return project_id
17+
18+
1019
def render_intro() -> None:
1120
st.markdown("""\
1221
This demo allows you to chat with an Agent that has full access to an
@@ -90,8 +99,41 @@ def on_create() -> None:
9099
on_change=on_create,
91100
)
92101

93-
_, project_id = google.auth.default() # type: ignore
94102
st.link_button(
95103
"View in Google Cloud Trace",
96-
f"https://console.cloud.google.com/traces/explorer;query=%7B%22plotType%22:%22HEATMAP%22,%22targetAxis%22:%22Y1%22,%22traceQuery%22:%7B%22resourceContainer%22:%22projects%2F{project_id}%2Flocations%2Fglobal%2FtraceScopes%2F_Default%22,%22spanDataValue%22:%22SPAN_DURATION%22,%22spanFilters%22:%7B%22attributes%22:%5B%5D,%22displayNames%22:%5B%22chain%20invoke%22%5D,%22isRootSpan%22:true,%22kinds%22:%5B%5D,%22maxDuration%22:%22%22,%22minDuration%22:%22%22,%22services%22:%5B%5D,%22status%22:%5B%5D%7D%7D%7D;duration=PT30M",
104+
_trace_url(),
105+
icon=":material/account_tree:",
97106
)
107+
108+
109+
def styles() -> None:
110+
st.html("""\
111+
<style>
112+
.stChatMessage { padding: 16px; }
113+
.stChatMessage .stLinkButton { text-align: right; }
114+
</style>
115+
""")
116+
117+
118+
def render_message(message: BaseMessage, trace_id: str | None) -> None:
119+
# Filter out tool calls
120+
if not (message.type in ("human", "ai") and message.content):
121+
return
122+
123+
with st.chat_message(message.type):
124+
col1, col2 = st.columns([0.9, 0.1])
125+
col1.markdown(message.content)
126+
if trace_id:
127+
col2.link_button(
128+
"",
129+
_trace_url(trace_id),
130+
icon=":material/account_tree:",
131+
help="Open in Cloud Trace",
132+
)
133+
134+
135+
def _trace_url(trace_id: str | None = None) -> str:
136+
url = f"https://console.cloud.google.com/traces/explorer;query=%7B%22plotType%22:%22HEATMAP%22,%22targetAxis%22:%22Y1%22,%22traceQuery%22:%7B%22resourceContainer%22:%22projects%2F{_get_project_id()}%2Flocations%2Fglobal%2FtraceScopes%2F_Default%22,%22spanDataValue%22:%22SPAN_DURATION%22,%22spanFilters%22:%7B%22attributes%22:%5B%5D,%22displayNames%22:%5B%22chain%20invoke%22%5D,%22isRootSpan%22:true,%22kinds%22:%5B%5D,%22maxDuration%22:%22%22,%22minDuration%22:%22%22,%22services%22:%5B%5D,%22status%22:%5B%5D%7D%7D%7D;duration=PT30M"
137+
if not trace_id:
138+
return url
139+
return f"{url};traceId={trace_id}"

instrumentation-genai/opentelemetry-instrumentation-vertexai/examples/langgraph-chatbot-demo/src/langgraph_chatbot_demo/langchain_history.py

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
"""Adapted from https://github.com/langchain-ai/streamlit-agent/blob/main/streamlit_agent/basic_memory.py"""
22

3+
import sqlite3
34
import tempfile
45
from os import environ
56
from random import getrandbits
67

78
import streamlit as st
89
from langchain_community.agent_toolkits.sql.toolkit import SQLDatabaseToolkit
910
from langchain_community.utilities.sql_database import SQLDatabase
10-
from langchain_core.messages import SystemMessage
11+
from langchain_core.messages import HumanMessage, SystemMessage
1112
from langchain_core.messages.base import BaseMessage
1213
from langchain_core.runnables.config import (
1314
RunnableConfig,
@@ -35,6 +36,7 @@
3536
title = "LangGraph SQL Agent Demo"
3637
st.set_page_config(page_title=title, page_icon="📖", layout="wide")
3738
st.title(title)
39+
_streamlit_helpers.styles()
3840

3941

4042
model = ChatVertexAI(
@@ -75,12 +77,19 @@ def search(query: str):
7577

7678

7779
system_prompt = SystemMessage(
78-
content="You are a helpful AI assistant with a mastery of database management and querying. You have "
79-
"access to an ephemeral sqlite database that you can query and modify through some tools. Help "
80-
"answer questions and perform actions."
81-
"\n"
82-
"Make sure you always use QuerySQLCheckerTool to validate queries before running them! If you "
83-
"make a mistake, try to recover."
80+
content=f"""\
81+
You are a careful and helpful AI assistant with a mastery of database design and querying. You
82+
have access to an ephemeral sqlite3 database that you can query and modify through some tools.
83+
Help answer questions and perform actions. Follow these rules:
84+
85+
- Make sure you always use sql_db_query_checker to validate SQL statements **before** running
86+
them! In pseudocode: `checked_query = sql_db_query_checker(query);
87+
sql_db_query(checked_query)`.
88+
- The sqlite version is {sqlite3.sqlite_version} which supports multiple row inserts.
89+
- Always prefer to insert multiple rows in a single call to the sql_db_query tool, if possible.
90+
- You may request to execute multiple sql_db_query tool calls which will be run in parallel.
91+
92+
If you make a mistake, try to recover."""
8493
)
8594

8695

@@ -119,35 +128,49 @@ def get_db(thread_id: str) -> SQLDatabase:
119128
else:
120129
messages = []
121130

131+
132+
@st.cache_resource
133+
def get_trace_ids(thread_id: str) -> "dict[str, str]":
134+
# Stores the trace IDs. Unfortunately I can't find a way to easily retrieve this from the
135+
# checkpointer, so just store it separately.
136+
return {}
137+
138+
139+
trace_ids = get_trace_ids(st.query_params.thread_id)
140+
122141
col1, col2 = st.columns([0.6, 0.4])
123142
with col1:
124143
_streamlit_helpers.render_intro()
125144
st.divider()
126145

127146
# Add system message
128-
st.chat_message(
129-
"human", avatar=":material/precision_manufacturing:"
130-
).markdown(f"**System Instructions**\n> {system_prompt.content}")
147+
st.expander(
148+
"System Instructions", icon=":material/precision_manufacturing:"
149+
).markdown(system_prompt.content)
131150

132151
# Render current messages
133-
for msg in messages:
134-
# Filter out tool calls
135-
if msg.type in ("human", "ai") and msg.content:
136-
st.chat_message(msg.type).write(msg.content)
152+
for message in messages:
153+
trace_id = trace_ids.get(message.id or "")
154+
_streamlit_helpers.render_message(message, trace_id)
137155

138156
# If user inputs a new prompt, generate and draw a new response
139157
if prompt := st.chat_input():
158+
message = HumanMessage(prompt)
140159
with col1:
141-
st.chat_message("human").write(prompt)
142160
with tracer.start_as_current_span(
143161
"chain invoke",
144162
attributes={"thread_id": st.query_params.thread_id},
145-
) as span, st.spinner("Thinking..."):
146-
st.toast(
147-
f"Trace ID {format_trace_id(span.get_span_context().trace_id)}"
148-
)
163+
) as span:
164+
trace_id = format_trace_id(span.get_span_context().trace_id)
165+
_streamlit_helpers.render_message(message, trace_id=trace_id)
166+
149167
# Invoke the agent
150-
app.invoke({"messages": [prompt]}, config=config)
168+
with st.spinner("Thinking..."):
169+
res = app.invoke({"messages": [message]}, config=config)
170+
171+
# Store trace ID for rendering
172+
trace_ids[message.id or ""] = trace_id
173+
trace_ids[res["messages"][-1].id] = trace_id
151174

152175
st.rerun()
153176

@@ -160,6 +183,3 @@ def get_db(thread_id: str) -> SQLDatabase:
160183

161184
with st.expander("View the message contents in session state"):
162185
st.json(messages)
163-
164-
# https://pantheon.corp.google.com/traces/explorer;traceId=8a69802b84077b162277f175e0f15276;duration=PT30M?project=otlp-test-deleteme
165-
# https://pantheon.corp.google.com/traces/explorer;query=%7B%22plotType%22:%22HEATMAP%22,%22targetAxis%22:%22Y1%22,%22traceQuery%22:%7B%22resourceContainer%22:%22projects%2Fotlp-test-deleteme%2Flocations%2Fglobal%2FtraceScopes%2F_Default%22,%22spanDataValue%22:%22SPAN_DURATION%22,%22spanFilters%22:%7B%22attributes%22:%5B%5D,%22displayNames%22:%5B%22chain%20invoke%22%5D,%22isRootSpan%22:true,%22kinds%22:%5B%5D,%22maxDuration%22:%22%22,%22minDuration%22:%22%22,%22services%22:%5B%5D,%22status%22:%5B%5D%7D%7D%7D;traceId=8a69802b84077b162277f175e0f15276;duration=PT30M

instrumentation-genai/opentelemetry-instrumentation-vertexai/examples/langgraph-chatbot-demo/src/langgraph_chatbot_demo/run_streamlit.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ def run_streamlit() -> None:
3535
setenv_default("OTEL_RESOURCE_ATTRIBUTES", f"gcp.project_id={project_id}")
3636

3737
# Hide metadata and token refreshes
38-
setenv_default("OTEL_PYTHON_EXCLUDED_URLS", "computeMetadata")
38+
setenv_default(
39+
"OTEL_PYTHON_EXCLUDED_URLS",
40+
"computeMetadata,oauth2.googleapis.com",
41+
)
3942

4043
langchain_app_spec = importlib.util.find_spec(
4144
"langgraph_chatbot_demo.langchain_history"

0 commit comments

Comments
 (0)