| name | langchain-agent-skills |
| description | Implement the LangChain agent skills pattern — packaging specialized prompts and domain knowledge as on-demand loadable skills via tool calling. Use when building agents that need many specializations without overwhelming context, distributing development across teams, or implementing progressive disclosure of prompts, schemas, and documentation. Covers basic load_skill pattern, dynamic tool registration, hierarchical skills, and reference-aware skills. |
Documentation Index
Fetch the complete documentation index at: https://docs.langchain.com/llms.txt
Use this file to discover all available pages before exploring further.
LangChain Agent Skills Pattern
A single agent loads specialized prompts and domain knowledge on-demand via tool calls, rather than loading everything upfront. The agent stays in control while skills augment its behavior.
Use when: one agent needs many specializations, constraints between skills aren't needed, or different teams own different capabilities.
Don't use when: you need strong isolation between domains (use subagents) or strict sequential constraints (use handoffs).
Basic Implementation
from langchain.tools import tool
from langchain.agents import create_agent
SKILLS = {
"write_sql": """You are a SQL expert.
Write efficient, safe queries. Always use parameterized queries.
Prefer CTEs over nested subqueries for readability.""",
"review_legal": """You are a legal document reviewer.
Check for ambiguous liability clauses, missing termination conditions,
and jurisdiction conflicts.""",
}
@tool
def load_skill(skill_name: str) -> str:
"""Load a specialized skill prompt.
Available skills:
- write_sql: SQL query writing expert
- review_legal: Legal document reviewer
Returns the skill's prompt and context.
"""
return SKILLS.get(skill_name, f"Unknown skill: {skill_name}")
agent = create_agent(
model="gpt-5.4",
tools=[load_skill],
system_prompt=(
"You are a helpful assistant. "
"Available skills: write_sql, review_legal. "
"Use load_skill before specialized tasks."
),
)
Extension Patterns
Dynamic tool registration
Loading a skill also unlocks new tools — capabilities are hidden until the relevant skill is loaded.
from langchain.agents import AgentState
from langchain.tools import tool, ToolRuntime
from langgraph.types import Command
class MyState(AgentState):
active_skills: list[str] = []
available_tools: list[str] = ["load_skill"]
DB_TOOLS = {"db_backup": db_backup_tool, "db_migrate": db_migrate_tool}
@tool
def load_skill(skill_name: str, runtime: ToolRuntime[None, MyState]) -> Command:
"""Load a skill and unlock its tools."""
prompt = SKILLS[skill_name]
new_tools = SKILL_TOOLS.get(skill_name, [])
return Command(update={
"active_skills": runtime.state["active_skills"] + [skill_name],
"available_tools": runtime.state["available_tools"] + [t.name for t in new_tools],
"messages": [ToolMessage(content=prompt, tool_call_id=runtime.tool_call_id)],
})
Hierarchical skills
A skill's prompt lists its sub-skills, enabling nested progressive disclosure.
SKILLS = {
"data_science": """You are a data science expert.
Sub-skills available for specialized tasks:
- pandas_expert: DataFrame operations and data wrangling
- visualization: matplotlib/seaborn charts and plots
- statistical_analysis: hypothesis testing, distributions
Use load_skill to access any sub-skill when needed.""",
"pandas_expert": """You are a pandas expert.
Prefer vectorized operations over loops.
Use .loc for label-based indexing, .iloc for positional.
...""",
}
Reference awareness
Skill prompts point to files/assets the agent should read when relevant — keeps the context window lean.
SKILLS = {
"api_integration": """You are an API integration specialist.
Available resources (read these when relevant):
- API schema: /docs/api/openapi.yaml
- Auth examples: /docs/api/auth-examples.md
- Rate limit rules: /docs/api/rate-limits.md
Only read files relevant to the current task.""",
}
Loading from files (production pattern)
For team-distributed skills, load from the filesystem instead of hardcoding:
import pathlib
SKILLS_DIR = pathlib.Path("skills/")
@tool
def load_skill(skill_name: str) -> str:
"""Load a skill from the skills directory."""
skill_file = SKILLS_DIR / f"{skill_name}.md"
if not skill_file.exists():
return f"Skill '{skill_name}' not found."
return skill_file.read_text()
@tool
def list_skills() -> str:
"""List all available skills."""
skills = [f.stem for f in SKILLS_DIR.glob("*.md")]
return "\n".join(f"- {s}" for s in sorted(skills))
Key Rules
- Skill descriptions are prompting levers — the
load_skill docstring listing available skills is what the agent uses to decide when to load; make them specific
- Skills accumulate in context — once loaded, each skill's prompt stays in the conversation; token cost grows with loaded skills; use subagents if context isolation is needed
- For large registries, add a
list_skills discovery tool instead of enumerating in the load_skill docstring
- Reference-aware prompts reduce upfront token cost — point to files rather than inlining large schemas/docs
- Hierarchical skills work best when sub-skills are genuinely independent; avoid deeply nested trees
Related Resources