In this guide, we create a Groq-driven autonomous research assistant that operates entirely through Groq’s free OpenAI-compatible inference API. We set up LangChain’s ChatOpenAI to interface with Groq by configuring the API key and base URL, enabling access to high-speed hosted models like llama-3.3-70b-versatile for reasoning with tools. Next, we integrate the model with essential utilities—web search, webpage retrieval, file operations, Python execution, skill loading, sub-agent task delegation, and persistent memory. By the conclusion of this guide, you’ll have a fully functional Groq-based multi-step agent capable of investigating topics, assigning specialized subtasks, producing structured outputs, and retaining valuable data for future sessions.
import subprocess, sys
def _pip(*a): subprocess.check_call([sys.executable,"-m","pip","install","-q",*a])
_pip("langgraph>=0.2.50", "langchain>=0.3.0", "langchain-openai>=0.2.0",
"langchain-community>=0.3.0", "ddgs", "requests", "beautifulsoup4",
"tiktoken", "pydantic>=2.0")
import os, getpass
if not os.environ.get("GROQ_API_KEY"):
os.environ["GROQ_API_KEY"] = getpass.getpass("GROQ_API_KEY (free at console.groq.com/keys): ")
os.environ["OPENAI_API_KEY"] = os.environ["GROQ_API_KEY"]
os.environ["OPENAI_BASE_URL"] = "https://api.groq.com/openai/v1"
MODEL_NAME = "llama-3.3-70b-versatile"
import json, re, io, contextlib, pathlib
from typing import Annotated, TypedDict, Sequence, Literal, List, Dict, Any
from datetime import datetime, timezone
from langchain_openai import ChatOpenAI
from langchain_core.messages import (
SystemMessage, HumanMessage, AIMessage, ToolMessage, BaseMessage)
from langchain_core.tools import tool
from langgraph.graph import StateGraph, END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNodeWe begin by installing the foundational packages needed to construct the Groq-powered agent pipeline—LangGraph, LangChain, DuckDuckGo search tools, and supporting parsing libraries. We securely prompt for the Groq API key and configure it as an OpenAI-compatible endpoint by assigning the appropriate API key and base URL. Then, we import all necessary modules for handling messages, tools, graph logic, type annotations, file system interactions, and model setup.
SANDBOX = pathlib.Path("/content/deerflow_sandbox").resolve()
for sub in ["uploads","workspace","outputs","skills/public","skills/custom","memory"]:
(SANDBOX/sub).mkdir(parents=True, exist_ok=True)
def _safe(p: str) -> pathlib.Path:
full = (SANDBOX/p.lstrip("/")).resolve()
if not str(full).startswith(str(SANDBOX)):
raise ValueError(f"path escapes sandbox: {p}")
return full
SKILLS: Dict[str, Dict[str,str]] = {}
def register_skill(name, description, content, location="public"):
d = SANDBOX/"skills"/location/name; d.mkdir(parents=True, exist_ok=True)
(d/"SKILL.md").write_text(content)
SKILLS[name] = {"description": description, "content": content,
"path": str(d/"SKILL.md")}
register_skill("research",
"Conduct multi-source web research on a topic and produce structured notes.",
"""# Research Skill
## Workflow
1. Decompose the question into 3-5 sub-questions.
2. For each sub-question call `web_search` and pick 2 authoritative URLs.
3. `web_fetch` those URLs; extract concrete facts, numbers, dates.
4. Cross-reference for consensus vs. disagreement.
5. Append findings to `workspace/research_notes.md`: claim → evidence → URL.
## Best practices
- Prefer primary sources. Note dates. Never fabricate URLs or numbers.""")
register_skill("report-generation",
"Synthesize research notes into a polished markdown report in outputs/.",
"""# Report Generation Skill
## Workflow
1. file_read('workspace/research_notes.md').
2. Outline: exec summary, key findings, analysis, conclusion, sources.
3. file_write('outputs/report.md', ...).
## Structure
- # Title
- ## Executive Summary (3–5 sentences)
- ## Key Findings (bullets)
- ## Detailed Analysis (sections)
- ## Conclusion
- ## Sources (numbered URL list)""")
register_skill("code-execution",
"Run Python in the sandbox for computation, data wrangling, charts.",
"""# Code Execution Skill
1. Plan in plain language first.
2. python_exec the code; persistent artifacts go to /outputs/.
3. Verify before quoting results.""")
MEM = SANDBOX/"memory/long_term.json"
if not MEM.exists():
MEM.write_text(json.dumps({"facts":[],"preferences":{}}, indent=2))
def _load_mem(): return json.loads(MEM.read_text())
def _save_mem(m): MEM.write_text(json.dumps(m, indent=2))We establish a sandboxed directory structure within Colab to neatly organize uploads, workspace files, outputs, skills, and memory in one secure location. We define reusable skill templates for research, report writing, and code execution so the agent can locate and follow standardized procedures. Additionally, we initialize a lightweight long-term memory file in JSON format that preserves facts and user preferences across repeated sessions within the same sandbox environment.
@tool
def list_skills() -> str:
"""List all skills with one-line descriptions. Call this first for complex tasks."""
return "n".join(f"- {n}: {s['description']}" for n,s in SKILLS.items())@tool
def load_skill(name: str) -> str:
"""Load full SKILL.md for `name`. Call before running its workflow."""
if name not in SKILLS: return f"Unknown. Available: {list(SKILLS)}"
return SKILLS[name]["content"]
@tool
def web_search(query: str, max_results: int = 5) -> str:
"""Search the web (DuckDuckGo). Returns titles, URLs, snippets."""
from ddgs import DDGS
out = []
try:
with DDGS() as d:
for r in d.text(query, max_results=max_results):
out.append(f"- {r.get('title','')}n URL: {r.get('href','')}n "
f"{(r.get('body') or '')[:220]}")
except Exception as e:
return f"search error: {e}"
return "n".join(out) or "no results"
@tool
def web_fetch(url: str, max_chars: int = 4000) -> str:
"""Fetch a URL, return cleaned text (scripts/nav stripped)."""
import requests
from bs4 import BeautifulSoup
try:
r = requests.get(url, timeout=15,
headers={"User-Agent":"Mozilla/5.0 DeerFlow-Lite"})
soup = BeautifulSoup(r.text, "html.parser")
for s in soup(["script","style","nav","footer","aside","header"]): s.decompose()
text = re.sub(r"s*ns*", "nn", soup.get_text("n")).strip()
return text[:max_chars] or "(empty page)"
except Exception as e:
return f"fetch error: {e}"
@tool
def file_write(path: str, content: str) -> str:
"""Write content to a sandbox path, e.g. 'workspace/notes.md' or 'outputs/x.md'."""
p = _safe(path); p.parent.mkdir(parents=True, exist_ok=True)
p.write_text(content)
return f"wrote {len(content)} chars → {path}"
@tool
def file_read(path: str) -> str:
"""Read a sandbox file (first 8 KB)."""
p = _safe(path)
return p.read_text()[:8000] if p.exists() else f"not found: {path}"
@tool
def file_list(path: str = "") -> str:
"""List files under a sandbox dir."""
base = _safe(path) if path else SANDBOX
if not base.exists(): return
The code examples above illustrate how the tools for the Groq-driven agent are integrated. These tools enable the agent to list and load skills, perform web searches, fetch web content, read and write files, and execute Python code within a secure sandbox. Additionally, memory functions are included, allowing the agent to store and retrieve important information across sessions.
A sub-agent spawning tool is also defined, enabling the main agent to delegate specific tasks to isolated assistants with restricted tool access. All tools are then compiled, the system prompt is set up, and the LangGraph workflow is constructed to manage the agent's reasoning and tool usage cycle.
The run() function is implemented to initiate tasks, stream the agent's actions, and display the results, including the state of the sandbox and any generated reports. A demonstration task is provided where the agent researches small language models, compiles a briefing, and saves key insights.
In summary, this article presents a streamlined yet powerful Groq-based agent framework, showcasing how Groq's OpenAI-compatible API can effectively support complex LLM workflows. The system leverages LangGraph for agent management, LangChain for tool integration, and custom utilities for enhanced functionality. The framework is designed to be extensible, suitable for various applications such as research assistants and automated briefing systems.



