Self-Discovery: Choose The Strategy Before Solving
Some failures are not about inability. They are about using the wrong strategy. For a rainy easy-walking food trip, the assistant may first need modules like decompose constraints, verify route, and check walking effort.
Self-Discovery asks the model to choose strategy modules first, then solve using those modules.
One Sentence
Self-Discovery turns direct solving into select strategy modules, then solve, so the model commits to a method before details.
What Breaks Without It
| Problem | What it looks like | Risk |
|---|---|---|
| Direct answer | Fast | Wrong strategy |
| Strategies live in prompt | Comprehensive | Model may ignore them |
| Module library is huge | Flexible | Selection becomes random |
What This Pattern Changes
| Who | Owns |
|---|---|
| Module library | Provides reusable strategies |
| Model | Selects modules for this task |
| Solver | Answers using selected modules |
| Python | Validates module names and traces selection |
Modules should be checklists, not slogans.
Walk Through One Trace
| Stage | Output |
|---|---|
| Available modules | decompose, verify, analogy |
| Selection | decompose, verify |
| Solve | Answer using decompose+verify |
For travel, modules might be: decompose constraints, check weather fit, check walking load.
Flow
flowchart TD
T["Task"] --> L["Read module library"]
L --> S["Select modules"]
S --> V["Validate module names"]
V --> A["Solve using modules"]
A --> O["Answer"]
Code Walk
result = self_discovery(
model,
task="Solve something.",
available_modules=["decompose", "verify", "analogy"],
tracer=tracer,
)
Full example:
from __future__ import annotations
from pathlib import Path
from agent_patterns_lab.patterns.self_discovery import self_discovery
from agent_patterns_lab.runtime import MockLLM, Tracer
def main() -> None:
tracer = Tracer()
model = MockLLM(['{"modules":["decompose","verify"]}', "Answer using decompose+verify"])
result = self_discovery(
model,
task="Solve something.",
available_modules=["decompose", "verify", "analogy"],
tracer=tracer,
)
print(result.answer)
trace_path = tracer.export_jsonl(Path(".traces") / "55_self_discovery.jsonl")
print(f"[trace] {trace_path}")
if __name__ == "__main__":
main()
Run:
UV_CACHE_DIR=.uv_cache PYTHONPATH=src uv run --no-sync python examples/55_self_discovery.py
Nearby Patterns
| Pattern | Who decides next | Use when |
|---|---|---|
| Plan & Solve | Model writes steps | Task needs decomposition |
| Self-Discovery | Model selects strategy modules | Task needs the right method |
| LATS | Search compares candidates | Multiple solutions need scoring |
| Routing | Route selects external flow | Inputs need different pipelines |
When To Use It
- You have a small clear module library.
- The model often fails from wrong strategy.
- Strategy selection is cheaper than search.
- You want consistency across similar tasks.
When Not To Use It
- Module descriptions are vague.
- There are too many modules.
- The task is simple.
- Selected modules have no required checkpoints.
Costs And Common Failures
| Failure | Symptom | Fix |
|---|---|---|
| Slogan modules | "Be logical" | Define input/output/checklist |
| Selects but ignores | Strategy theater | Bind checkpoints to each module |
| Too many modules | Selection drift | Limit library and max selected |
| Wrong module | Bad direction | Allow reselect after quick check |
What To Read Next
Self-Discovery fits choosing a method first.
For task steps, read Plan & Solve. For candidate search, read LATS.