Skip to content

Researcher (single agent)

A single research agent with one stub web-search tool — the LazyBridge equivalent of CrewAI's "single-agent crew" quickstart. Demonstrates that you don't need a multi-agent crew, decorators, or YAML configs to get a researcher up and running.

Source

"""CrewAI quickstart (single researcher) — ported to LazyBridge.

Original (CrewAI quickstart):

    # config/agents.yaml
    researcher:
      role: "{topic} Senior Data Researcher"
      goal: "Uncover cutting-edge developments in {topic}"
      backstory: "You're a seasoned researcher..."

    # config/tasks.yaml
    research_task:
      description: "Conduct thorough research about {topic}..."
      expected_output: "A markdown report with clear sections..."
      agent: researcher
      output_file: output/report.md

    # content_crew.py
    @CrewBase
    class ResearchCrew:
        agents_config = "config/agents.yaml"
        tasks_config = "config/tasks.yaml"

        @agent
        def researcher(self) -> Agent:
            return Agent(config=self.agents_config["researcher"],
                         verbose=True, tools=[SerperDevTool()])

        @task
        def research_task(self) -> Task: ...

        @crew
        def crew(self) -> Crew:
            return Crew(agents=self.agents, tasks=self.tasks,
                        process=Process.sequential, verbose=True)

    # Plus a Flow class with @start / @listen decorators that calls
    # ResearchCrew().crew().kickoff(inputs={"topic": "AI Agents"}) and writes
    # report.md.

LazyBridge equivalent: no YAML, no decorators, no @CrewBase / @agent / @task
boilerplate, no separate Crew or Flow. The "agent" is an :class:`Agent`,
the "task" is the string passed to it, and the "tool" is just a Python
function. The output file is a one-liner at the end.
"""

from __future__ import annotations

from pathlib import Path

from lazybridge import Agent, LLMEngine

OUTPUT_FILE = Path("output/report.md")


def serper_search(query: str) -> str:
    """Search the web (stub — wire to Serper / Tavily / your search API).

    The CrewAI original uses ``SerperDevTool()``. Replace this body with the
    real call once you have an API key; the rest of the example is unchanged.
    """
    return (
        f"[stub results for {query!r}] "
        "Top sources: latest agent frameworks comparisons, multi-agent "
        "patterns, observability tooling, hosted runtimes."
    )


def build_researcher(topic: str) -> Agent:
    """Mirror of the YAML role/goal/backstory — just three Python strings."""
    role = f"{topic} Senior Data Researcher"
    goal = f"Uncover cutting-edge developments in {topic}"
    backstory = (
        "You're a seasoned researcher with a knack for uncovering the latest "
        f"developments in {topic}. You find the most relevant information and "
        "present it clearly."
    )
    system = f"# Role\n{role}\n\n# Goal\n{goal}\n\n# Backstory\n{backstory}"
    return Agent(
        engine=LLMEngine("claude-opus-4-7", system=system),
        tools=[serper_search],
        name="researcher",
        verbose=True,
    )


def kickoff(topic: str = "AI Agents") -> str:
    researcher = build_researcher(topic)
    task = (
        f"Conduct thorough research about {topic}. Use web search to find "
        "current, credible information. The current year is 2026.\n\n"
        "Expected output: a markdown report with clear sections — key trends, "
        "notable tools or companies, and implications. Aim for 800-1200 words. "
        "Do not wrap the document in fenced code blocks."
    )
    report = researcher(task).text()

    OUTPUT_FILE.parent.mkdir(parents=True, exist_ok=True)
    OUTPUT_FILE.write_text(report, encoding="utf-8")
    print(f"Report written to {OUTPUT_FILE}")
    return report


if __name__ == "__main__":
    kickoff()

Walkthrough

  • No @CrewBase, no YAML. The agent is a plain Agent(engine= LLMEngine(...), tools=[...]) constructor call. The role / goal / backstory live in the system prompt directly.
  • serper_search is a stub function — swap for Serper, Tavily, or any web-search API in production. The signature stays the same because the agent doesn't care about implementation details.
  • output=Path(...)-style file write is plain Python around the result.text() call — there's no framework hook for "write the output to a file"; that's just code you put after the agent runs.

Variations

  • Add a structured output=PydanticModel to validate the report shape (title, bullets, sources) instead of free text.
  • Wrap with verify=judge_agent for a judge-and-retry loop on the output (see verify=).
  • Move to a two-agent pipeline by chaining a reporter agent — see Researcher → reporter.

See also

  • Researcher → reporter — the next rung: add a reporter agent in sequence via Agent.chain.
  • Tool — schema-from-signature semantics for the search function.
  • AgentAgent(engine=...) canonical constructor.