agentic-ai-patterns / agentic_patterns.py
nguyenthanhasia's picture
Upload agentic_patterns.py with huggingface_hub
43281af verified
"""
Agentic AI Patterns Implementation for Scientific Q&A
Based on 5 proven agentic patterns for better LLM performance
"""
import asyncio
import json
import re
from typing import Dict, List, Any, Optional, Tuple
from openai import OpenAI
import requests
import time
from datetime import datetime
class OpenAlexTool:
"""OpenAlex API integration for scientific literature search"""
def __init__(self):
self.base_url = "https://api.openalex.org"
self.session = requests.Session()
self.session.headers.update({
'User-Agent': 'AgenticAI-ScientificQA/1.0 (mailto:research@university.edu)'
})
def search_papers(self, query: str, max_results: int = 10) -> List[Dict]:
"""Search for scientific papers using OpenAlex"""
try:
url = f"{self.base_url}/works"
params = {
'search': query,
'per-page': min(max_results, 25),
'sort': 'relevance_score:desc'
}
time.sleep(0.1) # Rate limiting
response = self.session.get(url, params=params, timeout=30)
if response.status_code == 200:
data = response.json()
results = []
for work in data.get('results', []):
processed_work = {
'title': work.get('display_name', ''),
'year': work.get('publication_year'),
'citations': work.get('cited_by_count', 0),
'doi': work.get('doi', ''),
'authors': self._extract_authors(work.get('authorships', [])),
'abstract': self._reconstruct_abstract(work.get('abstract_inverted_index', {})),
'url': work.get('id', ''),
'open_access': work.get('open_access', {}).get('is_oa', False)
}
results.append(processed_work)
return results
else:
return []
except Exception as e:
print(f"OpenAlex search error: {e}")
return []
def _extract_authors(self, authorships: List[Dict]) -> List[str]:
"""Extract author names from authorships"""
authors = []
for authorship in authorships[:3]: # First 3 authors
author = authorship.get('author', {})
name = author.get('display_name', 'Unknown')
authors.append(name)
return authors
def _reconstruct_abstract(self, inverted_index: Dict) -> str:
"""Reconstruct abstract from inverted index"""
if not inverted_index:
return ""
word_positions = []
for word, positions in inverted_index.items():
for pos in positions:
word_positions.append((pos, word))
word_positions.sort()
abstract_words = [word for _, word in word_positions]
return ' '.join(abstract_words)[:500] # Limit length
class AgenticPatterns:
"""Implementation of 5 Agentic AI Patterns for Scientific Q&A"""
def __init__(self, api_key: str):
try:
self.client = OpenAI(api_key=api_key)
except Exception as e:
# Fallback for older OpenAI versions
import openai
openai.api_key = api_key
self.client = openai
self.openalex = OpenAlexTool()
async def pure_llm(self, question: str) -> Dict[str, Any]:
"""Pattern 0: Pure LLM without any agentic enhancement"""
start_time = time.time()
try:
response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a helpful scientific assistant. Answer questions clearly and accurately."},
{"role": "user", "content": question}
],
temperature=0.7,
max_tokens=1000
)
answer = response.choices[0].message.content
processing_time = time.time() - start_time
return {
"pattern": "Pure LLM",
"answer": answer,
"processing_time": f"{processing_time:.2f}s",
"steps": ["Direct LLM response"],
"confidence": "N/A",
"sources": []
}
except Exception as e:
return {
"pattern": "Pure LLM",
"answer": f"Error: {str(e)}",
"processing_time": "0s",
"steps": ["Error occurred"],
"confidence": "N/A",
"sources": []
}
async def reflection_pattern(self, question: str) -> Dict[str, Any]:
"""Pattern 1: Reflection - Agent checks its own work"""
start_time = time.time()
steps = []
try:
# Step 1: Initial response
steps.append("Generating initial response")
initial_response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a scientific assistant. Provide a detailed answer to the question."},
{"role": "user", "content": question}
],
temperature=0.7,
max_tokens=800
)
initial_answer = initial_response.choices[0].message.content
# Step 2: Self-reflection and critique
steps.append("Reflecting on initial response")
reflection_prompt = f"""
Review this scientific answer for accuracy, completeness, and clarity:
Question: {question}
Answer: {initial_answer}
Provide:
1. What's good about this answer
2. What could be improved
3. Any potential errors or missing information
4. Confidence score (1-10)
"""
reflection_response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a critical reviewer of scientific content."},
{"role": "user", "content": reflection_prompt}
],
temperature=0.3,
max_tokens=500
)
reflection = reflection_response.choices[0].message.content
# Step 3: Improved response based on reflection
steps.append("Generating improved response")
improvement_prompt = f"""
Based on this reflection, provide an improved answer:
Original Question: {question}
Original Answer: {initial_answer}
Reflection: {reflection}
Provide a refined, more accurate answer:
"""
final_response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a scientific assistant providing refined answers."},
{"role": "user", "content": improvement_prompt}
],
temperature=0.5,
max_tokens=1000
)
final_answer = final_response.choices[0].message.content
# Extract confidence score
confidence_match = re.search(r'confidence.*?(\d+)', reflection.lower())
confidence = confidence_match.group(1) if confidence_match else "7"
processing_time = time.time() - start_time
return {
"pattern": "Reflection",
"answer": final_answer,
"processing_time": f"{processing_time:.2f}s",
"steps": steps,
"confidence": f"{confidence}/10",
"reflection": reflection,
"sources": []
}
except Exception as e:
return {
"pattern": "Reflection",
"answer": f"Error: {str(e)}",
"processing_time": "0s",
"steps": steps,
"confidence": "N/A",
"sources": []
}
async def planning_pattern(self, question: str) -> Dict[str, Any]:
"""Pattern 2: Planning - Agent creates and follows a plan"""
start_time = time.time()
steps = []
try:
# Step 1: Create a plan
steps.append("Creating research plan")
planning_prompt = f"""
Create a step-by-step research plan to answer this scientific question:
{question}
Provide a numbered list of 3-5 specific steps to thoroughly research and answer this question.
Each step should be actionable and specific.
"""
plan_response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a research planner. Create systematic research plans."},
{"role": "user", "content": planning_prompt}
],
temperature=0.3,
max_tokens=400
)
plan = plan_response.choices[0].message.content
# Step 2: Execute the plan
steps.append("Executing research plan")
execution_prompt = f"""
Follow this research plan to answer the question:
Question: {question}
Plan: {plan}
Execute each step systematically and provide a comprehensive answer based on your planned approach.
"""
execution_response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a systematic researcher following a detailed plan."},
{"role": "user", "content": execution_prompt}
],
temperature=0.6,
max_tokens=1200
)
answer = execution_response.choices[0].message.content
processing_time = time.time() - start_time
return {
"pattern": "Planning",
"answer": answer,
"processing_time": f"{processing_time:.2f}s",
"steps": steps,
"plan": plan,
"confidence": "8/10",
"sources": []
}
except Exception as e:
return {
"pattern": "Planning",
"answer": f"Error: {str(e)}",
"processing_time": "0s",
"steps": steps,
"confidence": "N/A",
"sources": []
}
async def tool_use_pattern(self, question: str) -> Dict[str, Any]:
"""Pattern 3: Tool Use - Agent uses OpenAlex to find relevant papers"""
start_time = time.time()
steps = []
try:
# Step 1: Analyze question for search terms
steps.append("Extracting search terms")
search_prompt = f"""
Extract 2-3 key scientific search terms from this question for academic paper search:
{question}
Provide only the search terms, separated by spaces, optimized for finding relevant scientific papers.
"""
search_response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You extract optimal search terms for scientific literature."},
{"role": "user", "content": search_prompt}
],
temperature=0.2,
max_tokens=50
)
search_terms = search_response.choices[0].message.content.strip()
# Step 2: Search for relevant papers
steps.append(f"Searching papers with: '{search_terms}'")
papers = self.openalex.search_papers(search_terms, max_results=5)
# Step 3: Synthesize answer with paper evidence
steps.append("Synthesizing answer with literature evidence")
papers_context = ""
if papers:
papers_context = "\n\nRelevant Research Papers:\n"
for i, paper in enumerate(papers[:3], 1):
papers_context += f"{i}. {paper['title']} ({paper['year']}) - {paper['citations']} citations\n"
if paper['abstract']:
papers_context += f" Abstract: {paper['abstract'][:200]}...\n"
synthesis_prompt = f"""
Answer this scientific question using the provided research papers as evidence:
Question: {question}
{papers_context}
Provide a comprehensive answer that:
1. Directly addresses the question
2. References relevant findings from the papers
3. Acknowledges any limitations in current research
"""
synthesis_response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a scientific researcher synthesizing evidence from literature."},
{"role": "user", "content": synthesis_prompt}
],
temperature=0.6,
max_tokens=1200
)
answer = synthesis_response.choices[0].message.content
processing_time = time.time() - start_time
return {
"pattern": "Tool Use (OpenAlex)",
"answer": answer,
"processing_time": f"{processing_time:.2f}s",
"steps": steps,
"search_terms": search_terms,
"papers_found": len(papers),
"confidence": "9/10" if papers else "6/10",
"sources": [{"title": p["title"], "year": p["year"], "citations": p["citations"]} for p in papers[:3]]
}
except Exception as e:
return {
"pattern": "Tool Use (OpenAlex)",
"answer": f"Error: {str(e)}",
"processing_time": "0s",
"steps": steps,
"confidence": "N/A",
"sources": []
}
async def multi_agent_pattern(self, question: str) -> Dict[str, Any]:
"""Pattern 4: Multi-Agent - Multiple specialized agents collaborate"""
start_time = time.time()
steps = []
try:
# Agent 1: Research Specialist
steps.append("Research Specialist analyzing question")
research_prompt = f"""
As a Research Specialist, analyze this scientific question and provide:
1. Key research areas involved
2. Important concepts to address
3. Potential methodologies relevant to the question
Question: {question}
"""
research_response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a Research Specialist with expertise in scientific methodology."},
{"role": "user", "content": research_prompt}
],
temperature=0.4,
max_tokens=400
)
research_analysis = research_response.choices[0].message.content
# Agent 2: Domain Expert
steps.append("Domain Expert providing specialized knowledge")
expert_prompt = f"""
As a Domain Expert, provide specialized knowledge for this question:
{question}
Research Analysis: {research_analysis}
Focus on:
1. Current state of knowledge in this area
2. Key findings and established facts
3. Recent developments or controversies
"""
expert_response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a Domain Expert with deep specialized knowledge."},
{"role": "user", "content": expert_prompt}
],
temperature=0.5,
max_tokens=500
)
expert_knowledge = expert_response.choices[0].message.content
# Agent 3: Critical Reviewer
steps.append("Critical Reviewer evaluating perspectives")
reviewer_prompt = f"""
As a Critical Reviewer, evaluate these perspectives on the question:
{question}
Research Analysis: {research_analysis}
Expert Knowledge: {expert_knowledge}
Provide:
1. Strengths of each perspective
2. Potential gaps or limitations
3. Areas of uncertainty
"""
reviewer_response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a Critical Reviewer who evaluates scientific arguments."},
{"role": "user", "content": reviewer_prompt}
],
temperature=0.3,
max_tokens=400
)
critical_review = reviewer_response.choices[0].message.content
# Agent 4: Synthesizer
steps.append("Synthesizer creating final answer")
synthesis_prompt = f"""
Synthesize all agent perspectives into a comprehensive answer:
Question: {question}
Research Specialist: {research_analysis}
Domain Expert: {expert_knowledge}
Critical Reviewer: {critical_review}
Provide a balanced, comprehensive answer that incorporates insights from all agents.
"""
synthesis_response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a Synthesizer who combines multiple expert perspectives."},
{"role": "user", "content": synthesis_prompt}
],
temperature=0.6,
max_tokens=1000
)
final_answer = synthesis_response.choices[0].message.content
processing_time = time.time() - start_time
return {
"pattern": "Multi-Agent",
"answer": final_answer,
"processing_time": f"{processing_time:.2f}s",
"steps": steps,
"agents_used": ["Research Specialist", "Domain Expert", "Critical Reviewer", "Synthesizer"],
"confidence": "9/10",
"sources": []
}
except Exception as e:
return {
"pattern": "Multi-Agent",
"answer": f"Error: {str(e)}",
"processing_time": "0s",
"steps": steps,
"confidence": "N/A",
"sources": []
}
async def chain_of_thought_pattern(self, question: str) -> Dict[str, Any]:
"""Pattern 5: Chain of Thought - Step-by-step reasoning"""
start_time = time.time()
steps = []
try:
steps.append("Breaking down question into reasoning steps")
cot_prompt = f"""
Answer this scientific question using step-by-step reasoning. Show your thinking process clearly.
Question: {question}
Please think through this step by step:
Step 1: Understand what the question is asking
Step 2: Identify the key scientific concepts involved
Step 3: Consider what we know about these concepts
Step 4: Apply logical reasoning to connect the concepts
Step 5: Draw conclusions based on the reasoning
Step 6: Consider any limitations or uncertainties
Show your reasoning for each step, then provide a final answer.
"""
cot_response = self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "You are a scientific reasoner who thinks step-by-step and shows your reasoning process clearly."},
{"role": "user", "content": cot_prompt}
],
temperature=0.4,
max_tokens=1500
)
answer = cot_response.choices[0].message.content
processing_time = time.time() - start_time
return {
"pattern": "Chain of Thought",
"answer": answer,
"processing_time": f"{processing_time:.2f}s",
"steps": steps,
"reasoning_approach": "Step-by-step logical reasoning",
"confidence": "8/10",
"sources": []
}
except Exception as e:
return {
"pattern": "Chain of Thought",
"answer": f"Error: {str(e)}",
"processing_time": "0s",
"steps": steps,
"confidence": "N/A",
"sources": []
}
async def run_all_patterns(self, question: str) -> Dict[str, Any]:
"""Run all patterns simultaneously for comparison"""
start_time = time.time()
# Run all patterns concurrently
tasks = [
self.pure_llm(question),
self.reflection_pattern(question),
self.planning_pattern(question),
self.tool_use_pattern(question),
self.multi_agent_pattern(question),
self.chain_of_thought_pattern(question)
]
results = await asyncio.gather(*tasks)
total_time = time.time() - start_time
return {
"comparison_mode": True,
"total_processing_time": f"{total_time:.2f}s",
"results": {
"pure_llm": results[0],
"reflection": results[1],
"planning": results[2],
"tool_use": results[3],
"multi_agent": results[4],
"chain_of_thought": results[5]
},
"summary": {
"fastest": min(results, key=lambda x: float(x["processing_time"].replace('s', '')) if x["processing_time"] != "0s" else float('inf'))["pattern"],
"highest_confidence": max(results, key=lambda x: int(x["confidence"].split('/')[0]) if x["confidence"] != "N/A" else 0)["pattern"],
"most_sources": max(results, key=lambda x: len(x.get("sources", [])))["pattern"]
}
}
# Example questions for testing
EXAMPLE_QUESTIONS = [
"What are the main mechanisms behind CRISPR-Cas9 gene editing and what are its current limitations?",
"How does climate change affect ocean acidification and marine ecosystems?",
"What is the relationship between gut microbiome diversity and human immune system function?",
"Explain the current understanding of dark matter and dark energy in cosmology.",
"What are the key differences between mRNA vaccines and traditional vaccines in terms of mechanism and efficacy?"
]