Skip to content

Commit a70cdf1

Browse files
first commit
1 parent b6f0474 commit a70cdf1

20 files changed

Lines changed: 1514 additions & 1 deletion

File tree

.env.example

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Galileo Configuration
2+
GALILEO_API_KEY="<galileo-api-key-goes-here>"
3+
GALILEO_CONSOLE_URL="<do-not-set-this-if-using-saas-galileo-instance>"
4+
GALILEO_PROJECT_NAME="<your-project-name-goes-here>"
5+
GALILEO_LOG_STREAM="<your-log-stream-name-goes-here>"
6+
7+
# OpenAI Configuration
8+
OPENAI_API_KEY="<your-openai-api-key-goes-here>"

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ __pycache__/
66
# C extensions
77
*.so
88

9+
# Mac
10+
.DS_Store
11+
912
# Distribution / packaging
1013
.Python
1114
build/
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
"""
2+
Log Streams with Galileo — Sample Application
3+
4+
Demonstrates how to send traces to a Galileo Log Stream using the
5+
Galileo OpenAI wrapper. All LLM calls are automatically logged —
6+
no manual instrumentation needed.
7+
8+
This script runs a few different prompts; open your Galileo dashboard
9+
to see the traces appear in your Log Stream.
10+
11+
This script assumes the .env file is located
12+
in the parent directory, and it's properly configured.
13+
14+
Setup:
15+
1. review the .env configuration file
16+
2. pip install -r requirements.txt
17+
3. python 01_sample_app.py
18+
"""
19+
20+
import os
21+
from dotenv import load_dotenv
22+
from galileo.openai import openai
23+
from galileo import galileo_context
24+
25+
load_dotenv("../.env")
26+
project=os.environ.get("GALILEO_PROJECT_NAME")
27+
log_stream=os.environ.get("GALILEO_LOG_STREAM")
28+
29+
# Confirm that environment variables are properly mapped
30+
print(f"Loaded env variables: galileo console: {os.environ.get("GALILEO_CONSOLE_URL")} | Project: {project} | Log Stream: {log_stream}")
31+
32+
# Galileo wraps the OpenAI client automatically.
33+
# Traces are sent to the project and log stream set in your .env file.
34+
client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
35+
36+
37+
def ask(question: str) -> str:
38+
"""Send a question to the model and return the response."""
39+
response = client.chat.completions.create(
40+
model="gpt-5.2",
41+
messages=[
42+
{"role": "system", "content": "You are a helpful assistant."},
43+
{"role": "user", "content": question},
44+
],
45+
)
46+
answer = response.choices[0].message.content
47+
print(f"Q: {question}")
48+
print(f"A: {answer}\n")
49+
return answer
50+
51+
52+
if __name__ == "__main__":
53+
# Run a few sample prompts — each becomes a trace in your Log Stream
54+
with galileo_context(project=project, log_stream=log_stream):
55+
galileo_context.start_session(name="Lab 01 - Why Agent Observability Matters")
56+
ask("Summarize the impact of rising interest rates on technology sector and how it might affect valuations and investor sentiment in the short term.")
57+
ask("What are the best growth stocks to invest in?")
58+
ask("What would be the impact of rising interest rages?")
59+
60+
print("✓ Done — open your Galileo dashboard to see the traces.")
61+
print(f" Project: {os.environ.get('GALILEO_PROJECT')}")
62+
print(f" Log Stream: {os.environ.get('GALILEO_LOG_STREAM')}")
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
galileo[openai]
2+
openai
3+
python-dotenv

02_log_streams/02_sample_app.py

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
"""
2+
Agent Observability with Galileo — Sample Application
3+
Topic: Log Streams
4+
5+
This script demonstrates a simple tool-using agent instrumented with Galileo.
6+
Galileo captures every LLM call, tool invocation, and span so you can see
7+
exactly what the agent did, why, and where things went wrong.
8+
9+
This script assumes the .env file is located
10+
in the parent directory, and it's properly configured.
11+
12+
Setup:
13+
1. review the .env configuration file
14+
2. pip install -r requirements.txt
15+
3. python 02_sample_app.py
16+
"""
17+
18+
import os
19+
import json
20+
from dotenv import load_dotenv
21+
from galileo import log, galileo_context
22+
from galileo.openai import OpenAI
23+
24+
25+
load_dotenv("../.env")
26+
project=os.environ.get("GALILEO_PROJECT_NAME")
27+
log_stream=os.environ.get("GALILEO_LOG_STREAM")
28+
29+
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
30+
31+
# Confirm that environment variables are properly mapped
32+
print(f"Loaded env variables: galileo console: {os.environ.get("GALILEO_CONSOLE_URL")} | Project: {project} | Log Stream: {log_stream}")
33+
34+
35+
# --- Simple tools the agent can call ---
36+
37+
@log(span_type="tool")
38+
def get_account_balance(account_id: str) -> dict:
39+
"""Simulated tool: fetch account balance."""
40+
# Simulated data — in a real app this would call your backend
41+
balances = {
42+
"ACC-001": {"balance": 4200.00, "currency": "USD"},
43+
"ACC-002": {"balance": 150.75, "currency": "USD"},
44+
}
45+
return balances.get(account_id, {"error": f"Account {account_id} not found"})
46+
47+
@log(span_type="tool")
48+
def check_loan_eligibility(account_id: str, loan_amount: float) -> dict:
49+
"""Simulated tool: check if an account is eligible for a loan."""
50+
balance = get_account_balance(account_id).get("balance", 0)
51+
eligible = balance >= loan_amount * 0.2 # Simple rule: need 20% of loan as balance
52+
return {
53+
"eligible": eligible,
54+
"account_id": account_id,
55+
"requested_amount": loan_amount,
56+
"reason": "Sufficient balance" if eligible else "Insufficient balance for loan",
57+
}
58+
59+
60+
# --- Tool definitions for the LLM ---
61+
62+
TOOLS = [
63+
{
64+
"type": "function",
65+
"function": {
66+
"name": "get_account_balance",
67+
"description": "Get the current balance for a bank account",
68+
"parameters": {
69+
"type": "object",
70+
"properties": {
71+
"account_id": {
72+
"type": "string",
73+
"description": "The account ID, e.g. ACC-001",
74+
}
75+
},
76+
"required": ["account_id"],
77+
},
78+
},
79+
},
80+
{
81+
"type": "function",
82+
"function": {
83+
"name": "check_loan_eligibility",
84+
"description": "Check if an account is eligible for a loan of a given amount",
85+
"parameters": {
86+
"type": "object",
87+
"properties": {
88+
"account_id": {
89+
"type": "string",
90+
"description": "The account ID",
91+
},
92+
"loan_amount": {
93+
"type": "number",
94+
"description": "The requested loan amount in USD",
95+
},
96+
},
97+
"required": ["account_id", "loan_amount"],
98+
},
99+
},
100+
},
101+
]
102+
103+
TOOL_MAP = {
104+
"get_account_balance": get_account_balance,
105+
"check_loan_eligibility": check_loan_eligibility,
106+
}
107+
108+
109+
# --- Agent loop instrumented with Galileo ---
110+
111+
@log(span_type="agent", name="Agent Workflow")
112+
def run_agent(user_query: str):
113+
"""
114+
Run a simple tool-using agent and log every step to Galileo.
115+
This demonstrates agent observability: every LLM call, tool call,
116+
and final response is captured as a trace with spans.
117+
"""
118+
119+
120+
print(f"\n{'='*60}")
121+
print(f"User query: {user_query}")
122+
print(f"{'='*60}")
123+
124+
messages = [
125+
{
126+
"role": "system",
127+
"content": (
128+
"You are a helpful banking assistant. "
129+
"Use the available tools to answer questions about accounts and loans. "
130+
"Always use the exact account ID provided by the user."
131+
),
132+
},
133+
{"role": "user", "content": user_query},
134+
]
135+
136+
# Agentic loop — runs until the model stops calling tools
137+
max_steps = 5
138+
for step in range(max_steps):
139+
print(f"\n[Step {step + 1}] Calling LLM...")
140+
141+
response = client.chat.completions.create(
142+
model="gpt-4o-mini",
143+
messages=messages,
144+
tools=TOOLS,
145+
tool_choice="auto",
146+
)
147+
148+
message = response.choices[0].message
149+
150+
151+
# If no tool calls, we're done
152+
if not message.tool_calls:
153+
print(f"\nFinal answer: {message.content}")
154+
break
155+
156+
# Otherwise, process each tool call
157+
messages.append(message)
158+
for tool_call in message.tool_calls:
159+
fn_name = tool_call.function.name
160+
fn_args = json.loads(tool_call.function.arguments)
161+
162+
print(f" -> Tool call: {fn_name}({fn_args})")
163+
164+
# Execute the tool
165+
result = TOOL_MAP[fn_name](**fn_args)
166+
print(f" <- Tool result: {result}")
167+
168+
169+
# Append tool result to message history
170+
messages.append({
171+
"role": "tool",
172+
"tool_call_id": tool_call.id,
173+
"content": json.dumps(result),
174+
})
175+
176+
177+
178+
# --- Run sample queries ---
179+
180+
if __name__ == "__main__":
181+
with galileo_context(project=project, log_stream=log_stream):
182+
galileo_context.start_session(name="Lab 02 - Log Streams")
183+
184+
# Query 1: Normal flow — should work fine
185+
run_agent("What is the balance for account ACC-001?")
186+
187+
# Query 2: Loan eligibility check
188+
run_agent("Can account ACC-002 get a loan of $5000?")
189+
190+
# Query 3: Ambiguous query — watch how the agent handles it
191+
run_agent("Can I get a loan?")
192+
193+
print("\n\nOpen your Galileo dashboard to see the traces for these 3 runs.")
194+
print("Look for differences in tool selection quality and context adherence across the queries.")

02_log_streams/requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
galileo[openai]
2+
openai
3+
python-dotenv

0 commit comments

Comments
 (0)