## Agentic Tracing The module includes utilities for cost tracking, performance monitoring, and debugging agent behavior. This helps in understanding and optimizing AI agent performance while maintaining transparency in agent operations. #### Supported Tracer Types Choose from the given supported tracer types based on your framework: 1. agentic/langgraph 2. agentic/langchain 3. agentic/smolagents 4. agentic/openai_agents 5. agentic/llamaindex 6. agentic/haystack #### Agentic Tracing Features 1- add span level metrics ```python current_span().add_metrics(name='Accuracy', score=0.5, reasoning='some reasoning') ``` 2- add trace level metrics ```python tracer.add_metrics(name='hallucination_1', score=0.5, reasoning='some reasoning') ``` 3- add gt ```python current_span().add_gt("This is the ground truth") ``` 4- add context ```python current_span().add_context("This is the context") ``` 5- add span level metric execution ```python current_span().execute_metrics( name="Hallucination", model="gpt-4o", provider="openai" ) ``` #### Agentic Tracing example (langgraph) ```python import os import time from langgraph.graph import StateGraph, END from langchain_core.prompts import PromptTemplate from langchain_openai import ChatOpenAI from langchain_community.tools.tavily_search import TavilySearchResults from typing import TypedDict, Annotated, List, Dict, Any, Optional import operator from dotenv import load_dotenv # Load environment variables from .env file load_dotenv() # Import RagaAI Catalyst for tracing from ragaai_catalyst import RagaAICatalyst, init_tracing from ragaai_catalyst.tracers import Tracer # Initialize RagaAI Catalyst def initialize_catalyst(): """Initialize RagaAI Catalyst using environment credentials.""" catalyst = RagaAICatalyst( access_key=os.getenv('CATALYST_ACCESS_KEY'), secret_key=os.getenv('CATALYST_SECRET_KEY'), base_url=os.getenv('CATALYST_BASE_URL') ) tracer = Tracer( project_name=os.environ['PROJECT_NAME'], dataset_name=os.environ['DATASET_NAME'], tracer_type="agentic/langgraph", ) init_tracing(catalyst=catalyst, tracer=tracer) # Initialize language models and tools def initialize_models(model_name: str = "gpt-4o-mini", temperature: float = 0.5, max_results: int = 2): """Initialize the language model and search tool.""" llm = ChatOpenAI(model=model_name, temperature=temperature) tavily_tool = TavilySearchResults(max_results=max_results) return llm, tavily_tool # Initialize default instances initialize_catalyst() llm, tavily_tool = initialize_models() # State structure class ResearchState(TypedDict): topic: str sub_questions: List[str] answers: List[dict] synthesis: str criticism: str iteration: Annotated[int, operator.add] status: str # Nodes def generate_sub_questions(state: ResearchState) -> ResearchState: """Generate sub-questions based on the topic.""" prompt = PromptTemplate( input_variables=["topic"], template="Given the topic '{topic}', generate 3 specific sub-questions to guide research." ) response = llm.invoke(prompt.format(topic=state["topic"])) questions = [q.strip() for q in response.content.split("\n") if q.strip()] return {"sub_questions": questions, "status": "generated_questions"} def research_sub_questions(state: ResearchState) -> ResearchState: """Research each sub-question using Tavily.""" answers = [] for question in state["sub_questions"]: search_results = tavily_tool.invoke(question) prompt = PromptTemplate( input_variables=["question", "search_results"], template="Answer '{question}' concisely based on: {search_results}" ) answer = llm.invoke(prompt.format( question=question, search_results=[r["content"] for r in search_results] )) answers.append({ "question": question, "answer": answer.content, "sources": [r["url"] for r in search_results] }) return {"answers": answers, "status": "researched"} def synthesize_findings(state: ResearchState) -> ResearchState: """Synthesize answers into a cohesive report.""" prompt = PromptTemplate( input_variables=["topic", "answers"], template="Synthesize a 200-word report on '{topic}' using these findings:\n{answers}" ) synthesis = llm.invoke(prompt.format( topic=state["topic"], answers="\n".join([f"Q: {a['question']}\nA: {a['answer']}" for a in state["answers"]]) )) return {"synthesis": synthesis.content, "status": "synthesized"} def critique_synthesis(state: ResearchState) -> ResearchState: """Critique the synthesis for completeness and accuracy.""" prompt = PromptTemplate( input_variables=["topic", "synthesis", "answers"], template="Critique this report on '{topic}':\n{synthesis}\nBased on: {answers}\nReturn 'pass' or issues." ) critique = llm.invoke(prompt.format( topic=state["topic"], synthesis=state["synthesis"], answers="\n".join([f"Q: {a['question']}\nA: {a['answer']}" for a in state["answers"]]) )) return {"criticism": critique.content} def refine_synthesis(state: ResearchState) -> ResearchState: """Refine the synthesis based on critique.""" prompt = PromptTemplate( input_variables=["topic", "synthesis", "critique", "answers"], template="Refine this report on '{topic}':\n{synthesis}\nFix these issues: {critique}\nUsing: {answers}" ) refined = llm.invoke(prompt.format( topic=state["topic"], synthesis=state["synthesis"], critique=state["criticism"], answers="\n".join([f"Q: {a['question']}\nA: {a['answer']}" for a in state["answers"]]) )) return {"synthesis": refined.content, "iteration": state["iteration"] + 1, "status": "refined"} # Conditional logic def should_refine(state: ResearchState) -> str: if "pass" in state["criticism"].lower() or state["iteration"] >= 2: return "end" return "refine" # State graph workflow = StateGraph(ResearchState) workflow.add_node("generate", generate_sub_questions) workflow.add_node("research", research_sub_questions) workflow.add_node("synthesize", synthesize_findings) workflow.add_node("critique", critique_synthesis) workflow.add_node("refine", refine_synthesis) # Workflow workflow.set_entry_point("generate") workflow.add_edge("generate", "research") workflow.add_edge("research", "synthesize") workflow.add_edge("synthesize", "critique") workflow.add_conditional_edges( "critique", should_refine, {"refine": "refine", "end": END} ) workflow.add_edge("refine", "critique") # Compile the workflow app = workflow.compile() def run_research_assistant(topic: str = "Impact of AI on healthcare by 2030", print_results: bool = True) -> Dict[str, Any]: """Run the research assistant workflow with the given topic. Args: topic: The research topic to investigate print_results: Whether to print the results to the console Returns: The final state of the workflow """ # Initialize the state initial_state = { "topic": topic, "sub_questions": [], "answers": [], "synthesis": "", "criticism": "", "iteration": 0, "status": "start" } # Start timing start_time = time.time() # Run the workflow with tracing if print_results: print(f"Starting the Personal Research Assistant for topic: '{topic}'...") result = app.invoke(initial_state) # Calculate duration duration = time.time() - start_time # Print results if requested if print_results: print("\nFinal Research Report:") print(f"Topic: {result['topic']}") print("\nSub-Questions:") for i, question in enumerate(result['sub_questions'], 1): print(f" {i}. {question}") print("\nResearch Findings:") for i, ans in enumerate(result["answers"], 1): print(f"\nQ{i}: {ans['question']}") print(f"A: {ans['answer']}") print(f"Sources: {ans['sources']}") print(f"\nSynthesis:\n{result['synthesis']}") print(f"\nCritique: {result['criticism']}") print(f"Iterations: {result['iteration']}") print(f"Total execution time: {duration:.2f} seconds") return result if __name__ == "__main__": run_research_assistant() ```