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

Ir para a instalação

Informações da origem

Repositório
reason-machines/ai-agent-skills
Última atividade na origem
11 de junho de 2026 às 14:21
Idioma detectado do SKILL.md
inglês
Estrelas
1
Forks
1

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
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
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub