Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Control LLM output with regex and grammars, guarantee valid JSON/XML/code generation, enforce structured formats, and build multi-step workflows with Guidance - Microsoft Research's constrained generation framework
.claude/skills/openlair-guidance/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-06 | ✗→✓ | ▲ Improved | 104% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 311% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 167% | 0% |
| case-19 | ✗→✓ | ▲ Improved | 282% | 0% |
| case-21 | ✗→✓ | ▲ Improved | 219% | 0% |
Use Guidance when you need to:
GitHub Stars: 18,000+ | From: Microsoft Research
bash# Base installation pip install guidance # With specific backends pip install guidance[transformers] # Hugging Face models pip install guidance[llama_cpp] # llama.cpp models
pythonfrom guidance import models, gen # Load model (supports OpenAI, Transformers, llama.cpp) lm = models.OpenAI("gpt-4") # Generate with constraints result = lm + "The capital of France is " + gen("capital", max_tokens=5) print(result["capital"]) # "Paris"
pythonfrom guidance import models, gen, system, user, assistant # Configure Claude lm = models.Anthropic("claude-sonnet-4-5-20250929") # Use context managers for chat format with system(): lm += "You are a helpful assistant." with user(): lm += "What is the capital of France?" with assistant(): lm += gen(max_tokens=20)
Guidance uses Pythonic context managers for chat-style interactions.
pythonfrom guidance import system, user, assistant, gen lm = models.Anthropic("claude-sonnet-4-5-20250929") # System message with system(): lm += "You are a JSON generation expert." # User message with user(): lm += "Generate a person object with name and age." # Assistant response with assistant(): lm += gen("response", max_tokens=100) print(lm["response"])
Benefits:
Guidance ensures outputs match specified patterns using regex or grammars.
pythonfrom guidance import models, gen lm = models.Anthropic("claude-sonnet-4-5-20250929") # Constrain to valid email format lm += "Email: " + gen("email", regex=r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}") # Constrain to date format (YYYY-MM-DD) lm += "Date: " + gen("date", regex=r"\d{4}-\d{2}-\d{2}") # Constrain to phone number lm += "Phone: " + gen("phone", regex=r"\d{3}-\d{3}-\d{4}") print(lm["email"]) # Guaranteed valid email print(lm["date"]) # Guaranteed YYYY-MM-DD format
How it works:
pythonfrom guidance import models, gen, select lm = models.Anthropic("claude-sonnet-4-5-20250929") # Constrain to specific choices lm += "Sentiment: " + select(["positive", "negative", "neutral"], name="sentiment") # Multiple-choice selection lm += "Best answer: " + select( ["A) Paris", "B) London", "C) Berlin", "D) Madrid"], name="answer" ) print(lm["sentiment"]) # One of: positive, negative, neutral print(lm["answer"]) # One of: A, B, C, or D
Guidance automatically "heals" token boundaries between prompt and generation.
Problem: Tokenization creates unnatural boundaries.
python# Without token healing prompt = "The capital of France is " # Last token: " is " # First generated token might be " Par" (with leading space) # Result: "The capital of France is Paris" (double space!)
Solution: Guidance backs up one token and regenerates.
pythonfrom guidance import models, gen lm = models.Anthropic("claude-sonnet-4-5-20250929") # Token healing enabled by default lm += "The capital of France is " + gen("capital", max_tokens=5) # Result: "The capital of France is Paris" (correct spacing)
Benefits:
Define complex structures using context-free grammars.
pythonfrom guidance import models, gen lm = models.Anthropic("claude-sonnet-4-5-20250929") # JSON grammar (simplified) json_grammar = """ { "name": <gen name regex="[A-Za-z ]+" max_tokens=20>, "age": <gen age regex="[0-9]+" max_tokens=3>, "email": <gen email regex="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}" max_tokens=50> } """ # Generate valid JSON lm += gen("person", grammar=json_grammar) print(lm["person"]) # Guaranteed valid JSON structure
Use cases:
Create reusable generation patterns with the @guidance decorator.
pythonfrom guidance import guidance, gen, models @guidance def generate_person(lm): """Generate a person with name and age.""" lm += "Name: " + gen("name", max_tokens=20, stop="\n") lm += "\nAge: " + gen("age", regex=r"[0-9]+", max_tokens=3) return lm # Use the function lm = models.Anthropic("claude-sonnet-4-5-20250929") lm = generate_person(lm) print(lm["name"]) print(lm["age"])
Stateful Functions:
python@guidance(stateless=False) def react_agent(lm, question, tools, max_rounds=5): """ReAct agent with tool use.""" lm += f"Question: {question}\n\n" for i in range(max_rounds): # Thought lm += f"Thought {i+1}: " + gen("thought", stop="\n") # Action lm += "\nAction: " + select(list(tools.keys()), name="action") # Execute tool tool_result = tools[lm["action"]]() lm += f"\nObservation: {tool_result}\n\n" # Check if done lm += "Done? " + select(["Yes", "No"], name="done") if lm["done"] == "Yes": break # Final answer lm += "\nFinal Answer: " + gen("answer", max_tokens=100) return lm
pythonfrom guidance import models lm = models.Anthropic( model="claude-sonnet-4-5-20250929", api_key="your-api-key" # Or set ANTHROPIC_API_KEY env var )
pythonlm = models.OpenAI( model="gpt-4o-mini", api_key="your-api-key" # Or set OPENAI_API_KEY env var )
pythonfrom guidance.models import Transformers lm = Transformers( "microsoft/Phi-4-mini-instruct", device="cuda" # Or "cpu" )
pythonfrom guidance.models import LlamaCpp lm = LlamaCpp( model_path="/path/to/model.gguf", n_ctx=4096, n_gpu_layers=35 )
pythonfrom guidance import models, gen, system, user, assistant lm = models.Anthropic("claude-sonnet-4-5-20250929") with system(): lm += "You generate valid JSON." with user(): lm += "Generate a user profile with name, age, and email." with assistant(): lm += """{ "name": """ + gen("name", regex=r'"[A-Za-z ]+"', max_tokens=30) + """, "age": """ + gen("age", regex=r"[0-9]+", max_tokens=3) + """, "email": """ + gen("email", regex=r'"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"', max_tokens=50) + """ }""" print(lm) # Valid JSON guaranteed
pythonfrom guidance import models, gen, select lm = models.Anthropic("claude-sonnet-4-5-20250929") text = "This product is amazing! I love it." lm += f"Text: {text}\n" lm += "Sentiment: " + select(["positive", "negative", "neutral"], name="sentiment") lm += "\nConfidence: " + gen("confidence", regex=r"[0-9]+", max_tokens=3) + "%" print(f"Sentiment: {lm['sentiment']}") print(f"Confidence: {lm['confidence']}%")
pythonfrom guidance import models, gen, guidance @guidance def chain_of_thought(lm, question): """Generate answer with step-by-step reasoning.""" lm += f"Question: {question}\n\n" # Generate multiple reasoning steps for i in range(3): lm += f"Step {i+1}: " + gen(f"step_{i+1}", stop="\n", max_tokens=100) + "\n" # Final answer lm += "\nTherefore, the answer is: " + gen("answer", max_tokens=50) return lm lm = models.Anthropic("claude-sonnet-4-5-20250929") lm = chain_of_thought(lm, "What is 15% of 200?") print(lm["answer"])
pythonfrom guidance import models, gen, select, guidance @guidance(stateless=False) def react_agent(lm, question): """ReAct agent with tool use.""" tools = { "calculator": lambda expr: eval(expr), "search": lambda query: f"Search results for: {query}", } lm += f"Question: {question}\n\n" for round in range(5): # Thought lm += f"Thought: " + gen("thought", stop="\n") + "\n" # Action selection lm += "Action: " + select(["calculator", "search", "answer"], name="action") if lm["action"] == "answer": lm += "\nFinal Answer: " + gen("answer", max_tokens=100) break # Action input lm += "\nAction Input: " + gen("action_input", stop="\n") + "\n" # Execute tool if lm["action"] in tools: result = tools[lm["action"]](lm["action_input"]) lm += f"Observation: {result}\n\n" return lm lm = models.Anthropic("claude-sonnet-4-5-20250929") lm = react_agent(lm, "What is 25 * 4 + 10?") print(lm["answer"])
pythonfrom guidance import models, gen, guidance @guidance def extract_entities(lm, text): """Extract structured entities from text.""" lm += f"Text: {text}\n\n" # Extract person lm += "Person: " + gen("person", stop="\n", max_tokens=30) + "\n" # Extract organization lm += "Organization: " + gen("organization", stop="\n", max_tokens=30) + "\n" # Extract date lm += "Date: " + gen("date", regex=r"\d{4}-\d{2}-\d{2}", max_tokens=10) + "\n" # Extract location lm += "Location: " + gen("location", stop="\n", max_tokens=30) + "\n" return lm text = "Tim Cook announced at Apple Park on 2024-09-15 in Cupertino." lm = models.Anthropic("claude-sonnet-4-5-20250929") lm = extract_entities(lm, text) print(f"Person: {lm['person']}") print(f"Organization: {lm['organization']}") print(f"Date: {lm['date']}") print(f"Location: {lm['location']}")
python# ✅ Good: Regex ensures valid format lm += "Email: " + gen("email", regex=r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}") # ❌ Bad: Free generation may produce invalid emails lm += "Email: " + gen("email", max_tokens=50)
python# ✅ Good: Guaranteed valid category lm += "Status: " + select(["pending", "approved", "rejected"], name="status") # ❌ Bad: May generate typos or invalid values lm += "Status: " + gen("status", max_tokens=20)
python# Token healing is enabled by default # No special action needed - just concatenate naturally lm += "The capital is " + gen("capital") # Automatic healing
python# ✅ Good: Stop at newline for single-line outputs lm += "Name: " + gen("name", stop="\n") # ❌ Bad: May generate multiple lines lm += "Name: " + gen("name", max_tokens=50)
python# ✅ Good: Reusable pattern @guidance def generate_person(lm): lm += "Name: " + gen("name", stop="\n") lm += "\nAge: " + gen("age", regex=r"[0-9]+") return lm # Use multiple times lm = generate_person(lm) lm += "\n\n" lm = generate_person(lm)
python# ✅ Good: Reasonable constraints lm += gen("name", regex=r"[A-Za-z ]+", max_tokens=30) # ❌ Too strict: May fail or be very slow lm += gen("name", regex=r"^(John|Jane)$", max_tokens=10)
| Feature | Guidance | Instructor | Outlines | LMQL | |---------|----------|------------|----------|------| | Regex Constraints | ✅ Yes | ❌ No | ✅ Yes | ✅ Yes | | Grammar Support | ✅ CFG | ❌ No | ✅ CFG | ✅ CFG | | Pydantic Validation | ❌ No | ✅ Yes | ✅ Yes | ❌ No | | Token Healing | ✅ Yes | ❌ No | ✅ Yes | ❌ No | | Local Models | ✅ Yes | ⚠️ Limited | ✅ Yes | ✅ Yes | | API Models | ✅ Yes | ✅ Yes | ⚠️ Limited | ✅ Yes | | Pythonic Syntax | ✅ Yes | ✅ Yes | ✅ Yes | ❌ SQL-like | | Learning Curve | Low | Low | Medium | High |
When to choose Guidance:
When to choose alternatives:
Latency Reduction:
Memory Usage:
Token Efficiency:
references/constraints.md - Comprehensive regex and grammar patternsreferences/backends.md - Backend-specific configurationreferences/examples.md - Production-ready examples| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 10,353 | 6,201 | -40% | 1 | 1 | 0% | 1,778 | 5,509 | +210% | 0 | 0 | — |
case-02 | pass→pass | 10,524 | 3,945 | -63% | 1 | 1 | 0% | 1,871 | 5,042 | +169% | 0 | 0 | — |
case-03 | pass→pass | 8,169 | 4,998 | -39% | 1 | 1 | 0% | 1,471 | 5,311 | +261% | 0 | 0 | — |
case-04 | fail→fail | 13,166 | 9,185 | -30% | 1 | 1 | 0% | 2,159 | 5,818 | +169% | 0 | 0 | — |
case-05 | pass→pass | 4,673 | 3,381 | -28% | 1 | 1 | 0% | 866 | 4,948 | +471% | 0 | 0 | — |
case-06 | fail→pass | 15,318 | 8,294 | -46% | 1 | 1 | 0% | 2,838 | 5,779 | +104% | 0 | 0 | — |
case-07 | pass→pass | 4,514 | 2,746 | -39% | 1 | 1 | 0% | 865 | 4,880 | +464% | 0 | 0 | — |
case-08 | fail→pass | 5,787 | 2,572 | -56% | 1 | 1 | 0% | 1,160 | 4,768 | +311% | 0 | 0 | — |
case-09 | pass→pass | 6,564 | 2,948 | -55% | 1 | 1 | 0% | 1,372 | 4,874 | +255% | 0 | 0 | — |
case-10 | pass→pass | 8,760 | 4,793 | -45% | 1 | 1 | 0% | 1,518 | 5,215 | +244% | 0 | 0 | — |
case-11 | pass→pass | 8,268 | 6,353 | -23% | 1 | 1 | 0% | 1,588 | 5,538 | +249% | 0 | 0 | — |
case-12 | pass→pass | 11,418 | 7,471 | -35% | 1 | 1 | 0% | 1,941 | 5,714 | +194% | 0 | 0 | — |
case-13 | fail→pass | 13,805 | 12,425 | -10% | 1 | 1 | 0% | 2,455 | 6,545 | +167% | 0 | 0 | — |
case-14 | pass→pass | 14,759 | 7,657 | -48% | 1 | 1 | 0% | 2,372 | 5,647 | +138% | 0 | 0 | — |
case-15 | pass→pass | 11,382 | 6,676 | -41% | 1 | 1 | 0% | 2,018 | 5,669 | +181% | 0 | 0 | — |
case-16 | pass→pass | 7,278 | 5,016 | -31% | 1 | 1 | 0% | 1,372 | 5,298 | +286% | 0 | 0 | — |
case-17 | pass→pass | 5,089 | 2,516 | -51% | 1 | 1 | 0% | 999 | 4,731 | +374% | 0 | 0 | — |
case-18 | pass→pass | 6,890 | 6,886 | -0% | 1 | 1 | 0% | 1,217 | 5,677 | +366% | 0 | 0 | — |
case-19 | fail→pass | 6,731 | 2,050 | -70% | 1 | 1 | 0% | 1,186 | 4,527 | +282% | 0 | 0 | — |
case-20 | pass→pass | 10,522 | 7,404 | -30% | 1 | 1 | 0% | 1,936 | 5,712 | +195% | 0 | 0 | — |
case-21 | fail→pass | 10,342 | 6,473 | -37% | 1 | 1 | 0% | 1,714 | 5,467 | +219% | 0 | 0 | — |
case-22 | pass→pass | 7,144 | 5,907 | -17% | 1 | 1 | 0% | 1,346 | 5,363 | +298% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +23 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.