Simple & Reflection Agents
Build single-shot and self-critiquing agents with the unified Agent class — no tools required.
Not every agent needs tools. An Agent with an empty tools list answers in a single pass — that is the "simple agent" pattern — and a well-crafted role plus custom prompt blocks turns the same class into a reflection-style agent that critiques and refines its own output.
The SDK once shipped dedicated SimpleAgent and ReflectionAgent classes; they were merged into the unified Agent class, so all agent behavior is now configured through one API. On the platform, Simple Agent and Reflection Agent still appear as node types used inside other nodes.
Simple agent
Give the agent an LLM and a role, omit tools, and run it. With nothing to act on, the agent answers directly:
from dynamiq import Workflow
from dynamiq.connections import OpenAI as OpenAIConnection
from dynamiq.flows import Flow
from dynamiq.nodes.agents import Agent
from dynamiq.nodes.llms import OpenAI
llm = OpenAI(connection=OpenAIConnection(), model="gpt-4o", temperature=0.3)
agent = Agent(
name="simple-agent",
id="agent",
llm=llm,
role="Helpful assistant with the goal of providing useful information and answering questions.",
)
wf = Workflow(flow=Flow(nodes=[agent]))
result = wf.run(input_data={"input": "What is the capital of France?"})
print(result.output[agent.id]["output"]["content"])Use this pattern instead of a bare LLM node when you want the agent's input schema (user_id, session_id, files, images), memory, and streaming behavior without tool use.
Customizing the prompt with blocks
The agent's system prompt is assembled from named blocks. set_block overrides or adds a block — for example, to enforce an output structure:
agent = Agent(
name="report-writer",
id="report_writer",
llm=llm,
role="Professional writer producing well-structured, informative responses.",
)
agent.set_block(
"instructions",
"""
Use markdown as the main engine.
Use the following structure:
- Title
- Introduction
- Chapter 1
...
- Conclusion
- References
""",
)
result = agent.run(input_data={"input": "Explain how transformers changed NLP."})
print(result.output["content"])Reflection pattern
Reflection — generating an answer, critiquing it, and revising before responding — is expressed through the role. Because the unified agent loops up to max_loops times, instruct it to use its reasoning steps for self-critique:
REFLECTIVE_ROLE = """
You are a meticulous technical writer.
Before giving your final answer:
1. Draft a response.
2. Critique the draft: check factual accuracy, missing caveats, and clarity.
3. Revise the draft to address every critique point.
Only return the revised version as your final answer.
"""
reflection_agent = Agent(
name="reflection-agent",
id="reflection_agent",
llm=llm,
role=REFLECTIVE_ROLE,
max_loops=4,
)
result = reflection_agent.run(
input_data={"input": "How are sin(x) and cos(x) connected in electrodynamics?"}
)
print(result.output["content"])For stronger separation of duties, run a writer agent and a critic agent and let a manager coordinate them — see the manager-led pattern in Orchestrators.
Tracing simple agents
Attach a TracingCallbackHandler to inspect every step the agent took:
from dynamiq.callbacks import TracingCallbackHandler
from dynamiq.runnables import RunnableConfig
tracing = TracingCallbackHandler()
result = wf.run(
input_data={"input": "What is the capital of France?"},
config=RunnableConfig(callbacks=[tracing]),
)
for run in tracing.runs.values():
print(run.to_dict()["name"])To send these traces to the Dynamiq platform instead of keeping them local, see Tracing to Dynamiq.