@@ -144,10 +144,10 @@ def llm_attrs(model: str, prompt, completion, usage: dict) -> dict:
144144 `usage` keys map under gen_ai.usage.* (input_tokens, output_tokens, etc.).
145145 """
146146 attrs = {
147- "gen_ai.system" : "openai" , # -> provider
148- "gen_ai.request.model" : model , # -> model, forces span type = llm
149- "input" : prompt , # -> input
150- "output" : completion , # -> output
147+ "gen_ai.system" : "openai" , # -> provider
148+ "gen_ai.request.model" : model , # -> model, forces span type = llm
149+ "input" : prompt , # -> input
150+ "output" : completion , # -> output
151151 }
152152 for token_type , count in usage .items ():
153153 attrs [f"gen_ai.usage.{ token_type } " ] = count
@@ -167,32 +167,50 @@ def backend_request_1(session_id: str, user_prompt: str) -> dict:
167167 then dispatches it to the UI/external service (out of process).
168168 """
169169 trace_id = new_id ()
170- s_orchestrator = new_id () # root span (closes last, in finalize())
170+ s_orchestrator = new_id () # root span (closes last, in finalize())
171171 s_routing = new_id ()
172172 s_agent = new_id ()
173173 s_llm1 = new_id ()
174- s_dispatch = new_id () # tool_dispatch: tool result must nest UNDER this
175-
176- emit_span ("routing.invoke" , trace_id = trace_id , span_id = s_routing ,
177- parent_span_id = s_orchestrator , duration_s = 0.1 )
178- emit_span ("routing.generic_agent" , trace_id = trace_id , span_id = s_agent ,
179- parent_span_id = s_routing , duration_s = 0.1 )
180- emit_span ("llm.request" , trace_id = trace_id , span_id = s_llm1 , parent_span_id = s_agent ,
181- duration_s = 0.3 ,
182- attributes = llm_attrs (
183- model = "gpt-4o" ,
184- prompt = [{"role" : "user" , "content" : user_prompt }],
185- completion = [{"role" : "assistant" , "tool_calls" : [
186- {"id" : "call_1" , "name" : "web_search" , "arguments" : {"query" : user_prompt }}]}],
187- usage = {"input_tokens" : 412 , "output_tokens" : 37 },
188- ))
189- emit_span ("tool_dispatch" , trace_id = trace_id , span_id = s_dispatch ,
190- parent_span_id = s_llm1 , duration_s = 0.02 ,
191- attributes = {
192- "gen_ai.tool.name" : "web_search" ,
193- "gen_ai.tool.call.id" : "call_1" ,
194- "input" : {"query" : user_prompt },
195- })
174+ s_dispatch = new_id () # tool_dispatch: tool result must nest UNDER this
175+
176+ emit_span (
177+ "routing.invoke" , trace_id = trace_id , span_id = s_routing , parent_span_id = s_orchestrator , duration_s = 0.1
178+ )
179+ emit_span (
180+ "routing.generic_agent" , trace_id = trace_id , span_id = s_agent , parent_span_id = s_routing , duration_s = 0.1
181+ )
182+ emit_span (
183+ "llm.request" ,
184+ trace_id = trace_id ,
185+ span_id = s_llm1 ,
186+ parent_span_id = s_agent ,
187+ duration_s = 0.3 ,
188+ attributes = llm_attrs (
189+ model = "gpt-4o" ,
190+ prompt = [{"role" : "user" , "content" : user_prompt }],
191+ completion = [
192+ {
193+ "role" : "assistant" ,
194+ "tool_calls" : [
195+ {"id" : "call_1" , "name" : "web_search" , "arguments" : {"query" : user_prompt }}
196+ ],
197+ }
198+ ],
199+ usage = {"input_tokens" : 412 , "output_tokens" : 37 },
200+ ),
201+ )
202+ emit_span (
203+ "tool_dispatch" ,
204+ trace_id = trace_id ,
205+ span_id = s_dispatch ,
206+ parent_span_id = s_llm1 ,
207+ duration_s = 0.02 ,
208+ attributes = {
209+ "gen_ai.tool.name" : "web_search" ,
210+ "gen_ai.tool.call.id" : "call_1" ,
211+ "input" : {"query" : user_prompt },
212+ },
213+ )
196214
197215 # Persist the two ids the second request needs to stitch the trace correctly.
198216 SESSION_STORE [session_id ] = {
@@ -221,28 +239,42 @@ def backend_request_2(session_id: str, tool_result: dict) -> str:
221239
222240 # THE KEY LINE: parent is the dispatch span id from request 1 — no longer a
223241 # disconnected root.
224- emit_span ("tool_execution" , trace_id = trace_id , span_id = s_tool ,
225- parent_span_id = ctx ["dispatch_span_id" ], duration_s = 0.2 ,
226- attributes = {
227- "gen_ai.tool.name" : "web_search" ,
228- "gen_ai.tool.call.id" : "call_1" ,
229- "input" : ctx ["user_prompt" ],
230- "output" : tool_result ,
231- })
232- emit_span ("routing.invoke" , trace_id = trace_id , span_id = s_routing2 ,
233- parent_span_id = s_tool , duration_s = 0.1 )
234- emit_span ("routing.generic_agent" , trace_id = trace_id , span_id = s_agent2 ,
235- parent_span_id = s_routing2 , duration_s = 0.1 )
242+ emit_span (
243+ "tool_execution" ,
244+ trace_id = trace_id ,
245+ span_id = s_tool ,
246+ parent_span_id = ctx ["dispatch_span_id" ],
247+ duration_s = 0.2 ,
248+ attributes = {
249+ "gen_ai.tool.name" : "web_search" ,
250+ "gen_ai.tool.call.id" : "call_1" ,
251+ "input" : ctx ["user_prompt" ],
252+ "output" : tool_result ,
253+ },
254+ )
255+ emit_span ("routing.invoke" , trace_id = trace_id , span_id = s_routing2 , parent_span_id = s_tool , duration_s = 0.1 )
256+ emit_span (
257+ "routing.generic_agent" ,
258+ trace_id = trace_id ,
259+ span_id = s_agent2 ,
260+ parent_span_id = s_routing2 ,
261+ duration_s = 0.1 ,
262+ )
236263
237264 final_answer = "The capital of France is Paris."
238- emit_span ("llm.request" , trace_id = trace_id , span_id = s_llm2 , parent_span_id = s_agent2 ,
239- duration_s = 0.3 ,
240- attributes = llm_attrs (
241- model = "gpt-4o" ,
242- prompt = [{"role" : "tool" , "content" : tool_result }],
243- completion = [{"role" : "assistant" , "content" : final_answer }],
244- usage = {"input_tokens" : 690 , "output_tokens" : 122 },
245- ))
265+ emit_span (
266+ "llm.request" ,
267+ trace_id = trace_id ,
268+ span_id = s_llm2 ,
269+ parent_span_id = s_agent2 ,
270+ duration_s = 0.3 ,
271+ attributes = llm_attrs (
272+ model = "gpt-4o" ,
273+ prompt = [{"role" : "tool" , "content" : tool_result }],
274+ completion = [{"role" : "assistant" , "content" : final_answer }],
275+ usage = {"input_tokens" : 690 , "output_tokens" : 122 },
276+ ),
277+ )
246278
247279 ctx ["final_answer" ] = final_answer
248280 return final_answer
@@ -254,14 +286,19 @@ def finalize(session_id: str) -> None:
254286 thread_id groups the trace into a conversation thread in Opik.
255287 """
256288 ctx = SESSION_STORE [session_id ]
257- emit_span ("orchestrator_request" , trace_id = ctx ["trace_id" ],
258- span_id = ctx ["orchestrator_span_id" ], parent_span_id = None , duration_s = 0.05 ,
259- attributes = {
260- "thread_id" : session_id , # -> Opik thread grouping
261- "input" : ctx ["user_prompt" ], # -> trace input
262- "output" : ctx ["final_answer" ], # -> trace output
263- "opik.tags" : ["tool-call" , "distributed" , "demo" ],
264- })
289+ emit_span (
290+ "orchestrator_request" ,
291+ trace_id = ctx ["trace_id" ],
292+ span_id = ctx ["orchestrator_span_id" ],
293+ parent_span_id = None ,
294+ duration_s = 0.05 ,
295+ attributes = {
296+ "thread_id" : session_id , # -> Opik thread grouping
297+ "input" : ctx ["user_prompt" ], # -> trace input
298+ "output" : ctx ["final_answer" ], # -> trace output
299+ "opik.tags" : ["tool-call" , "distributed" , "demo" ],
300+ },
301+ )
265302
266303
267304def print_tree () -> None :
0 commit comments