Skip to main content

agentic-ai-research-agent

Build and deploy reflective research agents with FastAPI, Postgres, and multi-step planning workflows using Tavily, arXiv, and Wikipedia tools

Aller à l'installation

Informations de source

Dépôt
reason-machines/ai-agent-skills
Dernière activité de la source
11 juin 2026 à 14:21
Langue détectée de SKILL.md
anglais
Étoiles
1
Forks
1

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
agentic-ai-research-agent
description
Build and deploy reflective research agents with FastAPI, Postgres, and multi-step planning workflows using Tavily, arXiv, and Wikipedia tools
triggers
["create a research agent with planning workflow","build agentic AI research system","set up reflective research agent with FastAPI","implement multi-step agent workflow with tools","deploy research agent with Postgres backend","use planning agent with research tools","build agentic workflow with Tavily and arXiv","create task-based research agent API"]
# Agentic AI Research Agent > Skill by [ara.so](https://ara.so) — AI Agent Skills collection. ## Overview The Agentic AI Research Agent is a FastAPI-based service that implements a reflective, multi-step research workflow. It uses planning agents to break down research tasks, executes specialized agents (research, writer, editor) with external tools (Tavily search, arXiv papers, Wikipedia), and stores task state/results in Postgres. The system provides real-time progress tracking and generates comprehensive research reports. **Key Features:** - Multi-step agent planning and execution - Tool-using agents with Tavily, arXiv, Wikipedia integration - Postgres-backed task state and result storage - Real-time progress tracking via REST API - Web UI for launching research tasks - Single-container Docker deployment with embedded Postgres ## Installation ### Prerequisites - Docker (Desktop or Engine) - OpenAI API key - Tavily API key (for web search) ### Environment Setup Create a `.env` file in the project root: ```bash # Required API keys OPENAI_API_KEY=sk-... TAVILY_API_KEY=tvly-... # Optional: Override database settings # POSTGRES_USER=app # POSTGRES_PASSWORD=local # POSTGRES_DB=appdb # DATABASE_URL=postgresql://app:local@127.0.0.1:5432/appdb ``` ### Docker Build and Run ```bash # Build the image docker build -t fastapi-postgres-service . # Run the container (foreground with logs) docker run --rm -it \ -p 8000:8000 \ -p 5432:5432 \ --name fpsvc \ --env-file .env \ fastapi-postgres-service # Run in detached mode docker run -d \ -p 8000:8000 \ -p 5432:5432 \ --name fpsvc \ --env-file .env \ fastapi-postgres-service ``` ### Access Points - Web UI: http://localhost:8000/ - API Docs: http://localhost:8000/docs - Database: `postgresql://app:local@localhost:5432/appdb` ## Project Structure ``` . ├─ main.py # FastAPI app with endpoints ├─ src/ │ ├─ planning_agent.py # Planner and executor agents │ ├─ agents.py # Research, writer, editor agents │ └─ research_tools.py # Tavily, arXiv, Wikipedia tools ├─ templates/ │ └─ index.html # Web UI template ├─ static/ # CSS/JS assets ├─ docker/ │ └─ entrypoint.sh # Postgres + Uvicorn startup ├─ requirements.txt ├─ Dockerfile └─ README.md ``` ## Core API Endpoints ### Generate Research Report ```python # POST /generate_report import requests response = requests.post( "http://localhost:8000/generate_report", json={ "prompt": "Large Language Models for scientific discovery", "model": "openai:gpt-4o" } ) task_id = response.json()["task_id"] print(f"Task ID: {task_id}") ``` ### Poll Task Progress ```python # GET /task_progress/{task_id} import requests import time def poll_progress(task_id): while True: response = requests.get(f"http://localhost:8000/task_progress/{task_id}") data = response.json() print(f"Status: {data['status']}") print(f"Current step: {data.get('current_step', 'N/A')}") print(f"Progress: {data.get('progress_pct', 0)}%") if data["status"] in ["completed", "failed"]: break time.sleep(2) return data progress = poll_progress(task_id) ``` ### Get Final Report ```python # GET /task_status/{task_id} import requests response = requests.get(f"http://localhost:8000/task_status/{task_id}") result = response.json() if result["status"] == "completed": print("Final Report:") print(result["final_output"]) else: print(f"Task failed: {result.get('error')}") ``` ## Building Custom Agents ### Creating a Research Tool ```python # src/research_tools.py import os import requests def tavily_search_tool(query: str, max_results: int = 5) -> dict: """Search the web using Tavily API.""" api_key = os.getenv("TAVILY_API_KEY") if not api_key: return {"error": "TAVILY_API_KEY not set"} url = "https://api.tavily.com/search" payload = { "api_key": api_key, "query": query, "max_results": max_results } try: response = requests.post(url, json=payload, timeout=30) response.raise_for_status() return response.json() except Exception as e: return {"error": str(e)} def arxiv_search_tool(query: str, max_results: int = 5) -> list: """Search arXiv for research papers.""" import arxiv try: search = arxiv.Search( query=query, max_results=max_results, sort_by=arxiv.SortCriterion.Relevance ) results = [] for paper in search.results(): results.append({ "title": paper.title, "authors": [a.name for a in paper.authors], "summary": paper.summary, "published": paper.published.isoformat(), "pdf_url": paper.pdf_url }) return results except Exception as e: return [{"error": str(e)}] def wikipedia_search_tool(query: str) -> dict: """Search Wikipedia and return summary.""" import wikipedia try: # Search for the topic search_results = wikipedia.search(query, results=3) if not search_results: return {"error": "No results found"} # Get the first page page = wikipedia.page(search_results[0], auto_suggest=False) return { "title": page.title, "summary": page.summary, "url": page.url } except wikipedia.exceptions.DisambiguationError as e: return {"error": f"Disambiguation: {e.options[:5]}"} except Exception as e: return {"error": str(e)} ``` ### Implementing a Research Agent ```python # src/agents.py import os from src.research_tools import tavily_search_tool, arxiv_search_tool, wikipedia_search_tool def research_agent(query: str, tools: list = None) -> dict: """ Research agent that gathers information using multiple tools. """ if tools is None: tools = ["tavily", "arxiv", "wikipedia"] results = { "query": query, "sources": [] } # Use Tavily for web search if "tavily" in tools: tavily_results = tavily_search_tool(query, max_results=5) if "error" not in tavily_results: results["sources"].append({ "tool": "tavily", "data": tavily_results }) # Use arXiv for academic papers if "arxiv" in tools: arxiv_results = arxiv_search_tool(query, max_results=5) results["sources"].append({ "tool": "arxiv", "data": arxiv_results }) # Use Wikipedia for general knowledge if "wikipedia" in tools: wiki_results = wikipedia_search_tool(query) results["sources"].append({ "tool": "wikipedia", "data": wiki_results }) return results def writer_agent(research_data: dict, style: str = "academic") -> str: """ Writer agent that creates content from research data. """ # This would typically use an LLM to synthesize the research # into a coherent report. Example structure: import aisuite as ai client = ai.Client() prompt = f""" Based on the following research data, write a {style} report: {research_data} Structure the report with: 1. Executive Summary 2. Key Findings 3. Detailed Analysis 4. Conclusions """ messages = [{"role": "user", "content": prompt}] response = client.chat.completions.create( model="openai:gpt-4o", messages=messages ) return response.choices[0].message.content def editor_agent(draft: str, feedback: str = None) -> str: """ Editor agent that refines and improves the draft. """ import aisuite as ai client = ai.Client() prompt = f""" Edit and improve the following draft. Focus on: - Clarity and conciseness - Logical flow - Grammar and style - Factual accuracy {f'Specific feedback to address: {feedback}' if feedback else ''} Draft: {draft} """ messages = [{"role": "user", "content": prompt}] response = client.chat.completions.create( model="openai:gpt-4o", messages=messages ) return response.choices[0].message.content ``` ### Planning Agent Implementation ```python # src/planning_agent.py import json from typing import List, Dict def planner_agent(user_prompt: str, model: str = "openai:gpt-4o") -> List[Dict]: """ Plans a multi-step research workflow based on user prompt. Returns a list of steps with agent assignments and parameters. """ import aisuite as ai client = ai.Client() planning_prompt = f""" Create a step-by-step research plan for the following task: "{user_prompt}" Break it into concrete steps. For each step, specify: - step_id: unique identifier - agent: which agent to use (research_agent, writer_agent, editor_agent) - action: brief description - parameters: dict of parameters for the agent - dependencies: list of step_ids this step depends on Return ONLY a JSON array of steps. """ messages = [{"role": "user", "content": planning_prompt}] response = client.chat.completions.create( model=model, messages=messages, temperature=0.3 ) # Parse the plan plan_text = response.choices[0].message.content try: # Extract JSON from markdown code blocks if present if "```json" in plan_text: plan_text = plan_text.split("```json")[1].split("```")[0] elif "```" in plan_text: plan_text = plan_text.split("```")[1].split("```")[0] plan = json.loads(plan_text.strip()) return plan except json.JSONDecodeError: # Fallback: create a simple default plan return [ { "step_id": "research", "agent": "research_agent", "action": "Gather information", "parameters": {"query": user_prompt, "tools": ["tavily", "arxiv", "wikipedia"]}, "dependencies": [] }, { "step_id": "write", "agent": "writer_agent", "action": "Write initial draft", "parameters": {"style": "academic"}, "dependencies": ["research"] }, { "step_id": "edit", "agent": "editor_agent", "action": "Edit and refine", "parameters": {}, "dependencies": ["write"] } ] def executor_agent_step(step: Dict, step_results: Dict) -> any: """ Execute a single step in the plan. Uses step_results to access outputs from dependency steps. """ from src.agents import research_agent, writer_agent, editor_agent agent_name = step["agent"] parameters = step.get("parameters", {}) dependencies = step.get("dependencies", []) # Inject dependency results into parameters for dep_id in dependencies: if dep_id in step_results: parameters[f"{dep_id}_output"] = step_results[dep_id] # Execute the appropriate agent if agent_name == "research_agent": return research_agent(**parameters) elif agent_name == "writer_agent": # Use research output if available research_data = parameters.get("research_output", {}) return writer_agent(research_data, style=parameters.get("style", "academic")) elif agent_name == "editor_agent": # Use writer output if available draft = parameters.get("write_output", "") return editor_agent(draft, feedback=parameters.get("feedback")) else: raise ValueError(f"Unknown agent: {agent_name}") ``` ## Database Models and Task Management ### SQLAlchemy Models ```python # main.py or models.py from sqlalchemy import Column, String, Text, DateTime, Float, JSON, create_engine
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub