This documentation page is also available as an interactive notebook. You can launch the notebook in
Kaggle or Colab, or download it for use with an IDE or local Jupyter installation, by clicking one of the
above links.
Two popular taxonomies describe the building blocks of agentic AI
systems:
- Cognitive / reasoning-oriented (Taxonomy 1): Reflection, Tool Use,
ReAct, Planning, Multi-Agent — asks “how does the agent think?”
- Architectural / system-design-oriented (Taxonomy 2): Prompt
Chaining, Routing, Parallelization, Tool Use, Evaluator-Optimizer,
Orchestrator-Worker — asks “how do you wire LLM calls together?”
(See OpenAI’s Practical Guide to Building
Agents,
Anthropic’s multi-agent research
system,
and Pydantic AI’s multi-agent
delegation.)
Mapping them against each other reveals:
The cleanest framing: six architectural patterns that describe how
you structure LLM calls, plus two cross-cutting reasoning strategies
(ReAct and Planning) that can be layered inside any of them.
This cookbook implements all eight in Pixeltable, where your agent is
a table:
Setup
Created directory ‘agentic_patterns’.
<pixeltable.catalog.dir.Dir at 0x32639cb90>
Pattern 1: Prompt Chaining
Break a complex task into sequential steps, where each step’s output
feeds the next.
Imperative approach: a chain of function calls or an explicit
pipeline object. Pixeltable approach: each step is a computed
column. The engine resolves dependencies automatically.
input → step 1 (outline) → step 2 (draft) → step 3 (polish) → output
Created table ‘chain’.
Added 0 column values with 0 errors in 0.00 s
Added 0 column values with 0 errors in 0.01 s
No rows affected.
Added 0 column values with 0 errors in 0.01 s
Added 0 column values with 0 errors in 0.01 s
No rows affected.
Added 0 column values with 0 errors in 0.01 s
Added 0 column values with 0 errors in 0.01 s
No rows affected.
Inserted 1 row with 0 errors in 14.58 s (0.07 rows/s)
Every intermediate result (outline, draft, final_article) is
persisted in the table. Inserting another topic reuses the same pipeline
— no code changes needed. If the same topic is inserted again, cached
results are returned instantly.
Pattern 2: Routing
Classify an input and route it to a specialized handler. This is the
agent equivalent of a switch/case statement.
Imperative approach: a triage agent that performs handoffs to
specialized agents. Pixeltable approach: one computed column
classifies; a UDF selects the prompt; a second LLM call generates the
response.
input → classify intent → select specialized prompt → generate response
Created table ‘router’.
Added 0 column values with 0 errors in 0.01 s
Added 0 column values with 0 errors in 0.01 s
No rows affected.
Added 0 column values with 0 errors in 0.01 s
No rows affected.
Added 0 column values with 0 errors in 0.00 s
Added 0 column values with 0 errors in 0.01 s
No rows affected.
Inserted 3 rows with 0 errors in 6.93 s (0.43 rows/s)
Each query was classified and then handled by a specialized system
prompt. The intent column is inspectable for every row, making it easy
to audit routing decisions.
Pattern 3: Parallelization
Run multiple independent LLM calls on the same input simultaneously,
then combine the results.
Imperative approach: asyncio.gather or thread pools. Pixeltable
approach: add independent computed columns. The engine parallelizes
them automatically because they share no dependencies.
┌→ sentiment ─┐
input ──┼→ entities ──┼→ merge → combined output
└→ summary ─┘
Created table ‘parallel’.
Added 0 column values with 0 errors in 0.01 s
Added 0 column values with 0 errors in 0.01 s
Added 0 column values with 0 errors in 0.00 s
Added 0 column values with 0 errors in 0.01 s
Added 0 column values with 0 errors in 0.00 s
Added 0 column values with 0 errors in 0.01 s
No rows affected.
Added 0 column values with 0 errors in 0.01 s
No rows affected.
The three LLM calls (sentiment, entities, summary) have no
dependency on each other, so Pixeltable dispatches them concurrently.
The merge_analysis UDF waits for all three before combining the
results. No async code required.
Give an LLM access to external functions it can call to gather
information or take action.
Imperative approach: @function_tool decorator, tool loop that
re-prompts until the LLM stops requesting tools. Pixeltable
approach: pxt.tools() bundles UDFs into tool definitions;
invoke_tools() executes the LLM’s choices — both as computed columns.
input → LLM (with tools) → invoke_tools() → results
For a deeper walkthrough including MCP servers, see Use tool calling
with
LLMs.
Created table ‘tool_agent’.
Added 0 column values with 0 errors in 0.01 s
Added 0 column values with 0 errors in 0.01 s
No rows affected.
The LLM chose which tools to invoke (including multiple tools for the
last query). invoke_tools() executed them and stored results. The full
LLM response is also persisted in the response column for debugging.
Pattern 5: Evaluator-Optimizer
One LLM generates output, a second LLM evaluates it, and the results are
used to decide whether to refine. This is the architectural cousin of
the Reflection pattern from Taxonomy 1 — an agent critiques its own
output and iteratively improves it.
Imperative approach: a while-loop that re-prompts until a quality
threshold is met (see Pixelagent’s reflection
example).
Pixeltable approach: chained computed columns — generate, evaluate,
then conditionally refine. The evaluation score is stored alongside the
content for analysis.
input → generate → evaluate (score + feedback) → refine if needed → output
Created table ‘evaluator’.
Added 0 column values with 0 errors in 0.00 s
Added 0 column values with 0 errors in 0.01 s
No rows affected.
Added 0 column values with 0 errors in 0.01 s
Added 0 column values with 0 errors in 0.01 s
No rows affected.
Added 0 column values with 0 errors in 0.01 s
Added 0 column values with 0 errors in 0.01 s
No rows affected.
Inserted 2 rows with 0 errors in 2.95 s (0.68 rows/s)
Both the first draft and the refined version are stored side-by-side
with the evaluation. This makes it straightforward to compare outputs,
audit the judge’s reasoning, or filter rows where the score fell below a
threshold.
Pattern 6: Orchestrator-Worker
A central agent decomposes a task, delegates sub-tasks to specialized
worker agents, and synthesizes the results. This is the architectural
cousin of the Multi-Agent pattern from Taxonomy 1, and the same
structure Anthropic uses in their multi-agent research
system
— a lead agent coordinates parallel subagents, each with their own
context and tools.
Imperative approach: an orchestrator agent class that spawns worker
agent instances and collects their outputs. Pixeltable approach:
each worker is a table with computed columns, wrapped as a callable
function via pxt.udf(table, return_value=...). The orchestrator table
calls these functions as computed columns.
input → decompose → worker A (summarizer) ─┐
→ worker B (fact-checker) ─┼→ synthesize → output
For more on table UDFs, see Use a table pipeline as a reusable
function.
Build worker agents as tables
Created table ‘summarizer’.
Added 0 column values with 0 errors in 0.10 s
Added 0 column values with 0 errors in 0.06 s
Created table ‘checker’.
Added 0 column values with 0 errors in 0.01 s
Added 0 column values with 0 errors in 0.02 s
Build the orchestrator
Created table ‘orchestrator’.
Added 0 column values with 0 errors in 0.01 s
Added 0 column values with 0 errors in 0.01 s
No rows affected.
Added 0 column values with 0 errors in 0.02 s
Added 0 column values with 0 errors in 0.01 s
No rows affected.
Inserted 1 row with 0 errors in 4.69 s (0.21 rows/s)
The orchestrator table called two independent worker pipelines
(summarize and fact_check), each backed by their own table with full
intermediate-result persistence. The synthesis step consumed both
outputs to produce the final briefing. Adding a new worker (e.g., a tone
analyzer) requires only creating another table, wrapping it with
pxt.udf(), and adding one more computed column to the orchestrator.
Strategy A: ReAct
ReAct is not a wiring pattern — it is a reasoning strategy that can
be applied inside any of the six patterns above. The agent alternates
between reasoning about the next step and acting on it (typically via
tools), observing the result before deciding what to do next.
Imperative approach: a while-loop that parses the LLM’s
THOUGHT/ACTION output, calls tools, and feeds observations back (see
Pixelagent’s ReAct
example).
Pixeltable approach: the reasoning loop lives in a UDF that inserts
rows into a tool-calling table and reads back results. The table stores
every thought-action-observation triple for full observability.
question → [THOUGHT → ACTION → OBSERVATION] × N → final answer
Created table ‘react_steps’.
Added 0 column values with 0 errors in 0.00 s
Added 0 column values with 0 errors in 0.01 s
Added 0 column values with 0 errors in 0.00 s
No rows affected.
Every thought, action, and observation is persisted as a row in the
react_steps table. The loop itself is plain Python; the LLM calls and
tool execution happen declaratively via computed columns. This makes the
reasoning trace fully queryable after the fact — useful for debugging or
evaluation.
Strategy B: Planning
Planning is the second cross-cutting reasoning strategy. Instead of
acting step-by-step (ReAct), the agent first generates a complete plan,
then executes each step. This is especially effective for complex tasks
where the structure of the solution can be determined upfront.
Imperative approach: an LLM generates a plan as structured JSON,
then a loop executes each step (see Pixelagent’s planning
example).
Pixeltable approach: a prompt-chaining pipeline where the first
column generates the plan and a UDF parses it into executable steps.
Each step then feeds into subsequent computed columns.
question → generate plan → execute step 1 → execute step 2 → … → synthesize
Created table ‘planner’.
Added 0 column values with 0 errors in 0.00 s
Added 0 column values with 0 errors in 0.01 s
No rows affected.
Added 0 column values with 0 errors in 0.01 s
No rows affected.
Added 0 column values with 0 errors in 0.01 s
Added 0 column values with 0 errors in 0.01 s
Added 0 column values with 0 errors in 0.01 s
No rows affected.
The plan (stored in plan_steps) is fully inspectable. The execution
step answers all sub-questions in a single LLM call, but this could also
use parallelization (Pattern 3) to answer each sub-question
independently and merge the results. Planning and ReAct compose
naturally with any of the six architectural patterns.
Choosing a Pattern
Six architectural patterns
Two cross-cutting reasoning strategies
Patterns compose naturally. An orchestrator-worker system might use
routing in the orchestrator, tool use within a worker, and ReAct
reasoning inside the tool-calling loop. Because each pattern is just a
set of computed columns on a table, combining them requires no special
glue code.
See Also
Pixeltable cookbooks:
Pixelagent examples (imperative implementations of the same
patterns):
External references: