Enrich agents with domain-specific knowledge to make AI smarter (Ontology, Skills, RAG, Tool…
Finding new ways to expand an AI agent’s knowledge is a fascinating challenge. Last year I focused on using comprehensive “ontologies”…
Enrich agents with domain-specific knowledge to make AI smarter (Ontology, Skills, RAG, Tool Calling)
Finding new ways to expand an AI agent’s knowledge is a fascinating challenge. Last year I focused on using comprehensive “ontologies” (structured maps of data) . Then this year’s trend — pushed by companies like Anthropic — is focusing on Agent Skills.
Yet I still use RAG when the AI needs to “read” and summarize vast amounts of information. It acts like an automated librarian that is best for searching through internal documents, conducting market research, analyzing news, and answering questions based on specific files.
More frequently I use Tool Calling when the AI needs to “do” something or access live, structured data. It acts more like a specialized technician. Which is best for querying databases, performing secure data tasks, following strict rules (type-validation), maintaining audit trails, and interacting with other software through APIs.

figure: Enrich Agent Knowledge Approaches
Table of Contents
- Tool Calling (Function Calling) Approach
- RAG Approach
- Agent Skills vs. Ontology: Two Ways to Make AI Smarter
- Ontology Approach (BambooAI)
- Agent Skills Approach (Anthropic)
- Pros and Cons
- Comparison of Ontology,Skills,RAG, Tool Calling
- Token Efficiency Ranking
- Flexibility Ranking
- Safety Ranking
- Use Cases
- Summary
While Agent Skills are great for standard tasks, an Ontology approach — which maps out how different concepts relate to one another.
- Complex Finances: Understanding deep relationships in banking or investment data.
- Connecting Data: Merging information from many different sources into one clear picture.
- Smart Reasoning: Helping the AI “read between the lines” to make logical connections.
Here is a simple code example to show how these four methods work.
Scenario: Agent analyzes company financials
Using Different Approaches:
- Ontology Approach:
# Ontology defines: IncomeStatement, BalanceSheet, CashFlow relationships
# Agent generates code:
df.merge(income_stmt, balance_sheet, on='company_id')
.groupby('sector')['revenue'].sum()
- Skills Approach:
# Skill teaches: "Use Company.financials() for statements"
# Agent generates code:
company = Company("AAPL")
income = company.financials().income_statement
- RAG Approach:
# RAG retrieves: "Apple's revenue was $394B in 2023"
# Agent responds: "Apple's revenue was $394B in 2023"
# (No code execution)
- Tool Calling Approach:
# Tool defined: get_financials(ticker, statement_type)
# Agent calls: get_financials("AAPL", "income")
# Returns: Predefined data structure
Essentially, Agent Skills teaches AI agents how to use APIs and “Tool Calling” to access data securely. The distinction is simple: agents use tools for tasks that require safe, predictable results, while they use skills when they need to write flexible, custom code on the fly.
The main objective of the Ontology and Anthropic Skill frameworks is to teach these agents how to generate their own code effectively.
Let’s dive into the details of each approach.
Tool Calling (Function Calling) Approach
How it works
User Query → LLM Decides Tool → Generate Parameters → Execute Function → Return Result
The main characteristics of this approach are following:
- Knowledge storage: Function definitions
- Retrieval: LLM selects tool
- Agent action: Call predefined functions
- Token usage: Low (just function signatures)
- Best for: Structured operations, API calls, database queries
For example: Agent needs to analyze Apple’s financial statements
Knowledge Provided:
- Tool: get_financials(ticker, statement_type, period)
- Parameters: ticker (string), statement_type (enum), period (int)
- Returns: Structured JSON with financial data
Agent Process:
User: "Get Apple's income statement"
↓
LLM decides to call tool
↓
Generates parameters:
{
"ticker": "AAPL",
"statement_type": "income",
"period": "annual"
}
↓
Executes Function:
# Predefined function (not generated)
def get_financials(ticker, statement_type, period):
# Validated, type-safe operation
data = api.fetch_financials(ticker, statement_type, period)
return {
"revenue": data.revenue,
"net_income": data.net_income,
"eps": data.eps
}
Result:
- ✅ Type-safe, predictable, auditable
- ✅ Very low token cost: 100 tokens
- ✅ Easy to secure and monitor
- ❌ Limited to predefined operations
- ❌ No composability (can’t chain easily)
Tool Definition Sample
# Define tool
tools = [{
"name": "get_stock_price",
"description": "Get current stock price",
"parameters": {
"ticker": {"type": "string", "description": "Stock ticker"}
}
}]
# LLM decides to call tool
response = llm.chat(messages, tools=tools)
if response.tool_calls:
result = get_stock_price(ticker=response.tool_calls[0].arguments["ticker"])
RAG Approach
How it works
User Query → Vector Search → Retrieve Relevant Docs → Inject into Prompt → LLM Response
Example: Agent needs to analyze Apple’s financial statements
Knowledge Provided:
- Vector DB contains: Annual reports, earnings transcripts
- Documents: “Apple’s revenue was $394B in 2023”
- Context: “Revenue grew 8% YoY”
Agent Process:
User: "What was Apple's revenue in 2023?"
↓
Query embedding → Vector search
↓
Retrieves: "Apple reported $394.3B revenue in FY2023,
up 8% from $365.8B in FY2022"
↓
Generates Response:
Apple's revenue in 2023 was $394.3 billion, representing
an 8% increase from the previous year's $365.8 billion.
Result:
- ✅ Quick answer, no code needed
- ✅ Works with unstructured documents
- ❌ Can’t perform calculations or data manipulation
- ❌ High token cost: 2,000 tokens
- ❌ Retrieval quality varies
So the key characteristics in this approach are following:
- Knowledge storage: Vector database
- Retrieval: Semantic search
- Agent action: Generate text response (not code)
- Token usage: High (retrieved docs in prompt)
- Best for: Q&A, documentation search, knowledge retrieval
Knowledge store in a specialized database that helps the AI find the right answers by searching for meaning, not just matching words. This allows the system to instantly connect your questions with the most relevant knowledge. see code example below for reference:
User asks: "What's the return policy?"
query_embedding = embed("return policy")
docs = vector_db.search(query_embedding, top_k=5)
prompt = f"Context: {docs}\n\nQuestion: What's the return policy?" response = llm.generate(prompt)
Agent Skills vs. Ontology: Two Ways to Make AI Smarter
The more interesting thing here is talk about “enriching” an AI agent, by giving it a specialized education so it can handle complex tasks. There are two primary ways to do this: Ontology and Skills.
1. BambooAI: The “Librarian” Approach (Ontology)
BambooAI uses Ontologies, specifically OWL/RDF formats (often stored as .ttl files).
- How it works: Think of this as a highly detailed map or a dictionary of relationships. It tells the AI exactly how different pieces of data relate to one another.
- The Goal: To give the agent a deep “semantic” understanding of a specific field so it doesn’t get confused by complex data structures.
2. Anthropic: The “Technician” Approach (Skills)
Anthropic uses Skills, which are defined using YAML (a simple, readable coding language) or a simple Markdown file.
- How it works: These are like “how-to” manuals. They teach the agent specific patterns for using APIs (tools that let software talk to other software) and best practices for completing tasks.
- The Goal: To give the agent a specific set of abilities or “muscles” to perform actions efficiently.
Next, let’s deep dive on each approach to understand how it works and usage.
Ontology Approach (BambooAI)
Currently the BambooAI framework is the library I found that implemented the Ontology approach. See link here: https://github.com/pgalko/BambooAI.

figure: BambooAI
What Problem Does It Solve?
- Data Structure Understanding: Agent knows what columns exist, their types, units, and relationships
- Semantic Relationships: Understands how datasets link (foreign keys, join conditions)
- Available Operations: Knows which functions can be applied to which data
- Domain Vocabulary: Uses correct terminology (e.g., “activity_id” not “id”)
- Derivation Logic: Understands how computed fields are calculated
How does it work?
Let’s go over an example about a Financial Analysis Agent.
Scenario: Agent needs to analyze Apple’s financial statements
Agent Processing Flow
User Query → BambooAI Agent → Ontology Inspector Agent → LLM
↓
Ontology File (.ttl)
↓
Structured Data Model (YAML)
↓
Code Generator → Python Code
Two-Stage Processing
Stage 1: Ontology Inspection
User Query + Ontology + Data Preview
↓
Ontology Inspector Agent (LLM)
↓
Structured Data Model (YAML)
Stage 2: Code Generation
User Query + Data Model
↓
Code Generator Agent (LLM)
↓
Python Code
Knowledge Representation
BambooAI: Formal Ontology
Formal semantics: OWL provides logical inference
Relationship modeling: Object properties define connections
Type hierarchy: Classes and subclasses
Constraint validation: Domain/range restrictions
Interoperability: RDF standard enables data exchange
Ontology File Structure
(Sports_Data_Ontology.ttl) sample
# Object Properties (Relationships)
:containsActivity rdf:type owl:ObjectProperty ;
rdfs:domain :ActivityDataframe ;
rdfs:range :Activity .
:hasUniqueIdentifier rdf:type owl:ObjectProperty ;
rdfs:domain :DataObjects ;
rdfs:range :Key .
# Data Properties (Attributes)
:measuredInUnits rdf:type owl:DatatypeProperty ;
rdfs:domain :Measurement ;
rdfs:range xsd:string .
:isPresentInDataset rdf:type owl:DatatypeProperty ;
rdfs:domain :Key ;
rdfs:range xsd:boolean .
# Classes (Entities)
:Activity rdf:type owl:Class ;
rdfs:subClassOf :Timeseries ;
rdfs:comment "A single activity session with measurements." .
:ActivityDataframe rdf:type owl:Class ;
rdfs:subClassOf :Dataframe ;
rdfs:comment "Container for multiple activities." .
:heart_rate rdf:type :Measurement ;
rdfs:subClassOf :Metabolic ;
:measuredInUnits "bpm" ;
:recordedWithFrequency "per_second" ;
:isPresentInDataset true .
:compute_average_heart_rate rdf:type :Function ;
:functionRequiresMeasurements :heart_rate ;
:applicableToDataObject :ActivityDataframe .
Inference:
- If heart_rate is a Metabolic measurement
- And Metabolic is a subclass of MeasurementCategory
- Then heart_rate is a MeasurementCategory
Ontology Processing Flow
File: bambooai/utils.py — inspect_dataframe() function
def inspect_dataframe(df, df_ontology=None, ...): # 1. Read ontology file ontology = "" if df_ontology and isinstance(df_ontology, str): with open(df_ontology, 'r') as file: ontology = file.read()
# 2. Generate dataframe preview
primary_df_head = dataframe_to_string(df)
auxiliary_datasets_heads = aux_datasets_to_string(file_paths)
# 3. Inject into prompt template
prompt = inject_content(
prompt_manager.dataframe_inspector_user,
ontology=ontology,
dataframe_preview=primary_df_head,
auxiliary_datasets=auxiliary_datasets_heads,
task=query
)
# 4. LLM extracts structured data model
llm_response = models.llm_stream(prompt)
return llm_response # YAML-formatted data model
Prompt Template
File: `bambooai/messages/default_prompts.yaml
dataframe_inspector_user: |
You are an AI Ontologist tasked with extracting and structuring
information from the dataframe ontology relevant to the given task.
The user provided the following ontology describing the dataframe
structure, relationships, and functions.
DATAFRAME ONTOLOGY:
<< ontology >>
DATAFRAME PREVIEW:
<< dataframe_preview >>
AUXILIARY DATASETS:
<< auxiliary_datasets >>
TASK:
<< task >>
Your job is to extract and structure the relevant information from
the ontology AND the dataset previews to address the task.
Output a YAML structure with:
- datasets: List of data containers with source identifiers
- keys: Unique identifiers and grouping columns
- measurements: Metrics with units, frequency, derivation formulas
- functions: Available operations from ontology
- relationships: How datasets link together
Generated Data Model (Output)
The LLM generates a structured YAML model:
datasets:
name: ActivityDataframe dataset_source_identifier: PrimaryActivityData type: Dataframe description: Container for multiple activities
keys:
name: activity_id dataset_source_identifier: PrimaryActivityData role_in_grouping: unique_identifier isPresentInDataset: true
measurements:
name: heart_rate category: Metabolic units: bpm recording_frequency: per_second isPresentInDataset: true
functions:
name: compute_average_heart_rate definition: "Calculate mean heart rate for activity" applicable_to: ActivityDataframe requires_measurements: [heart_rate]
relationships:
source_key: activity_id target_key: activity_id condition: "Join on activity_id"
Usage Code
from bambooai import BambooAI
# Initialize with ontology
bamboo = BambooAI(
df=activity_dataframe,
df_ontology="path/to/Sports_Data_Ontology.ttl"
)
# Agent uses ontology to understand data structure
bamboo.pd_agent_converse("What's the average heart rate per activity type?")
Example Scenario: Agent needs to analyze Apple’s financial statements
Knowledge Provided:
- Ontology defines: IncomeStatement, BalanceSheet, CashFlow
- Relationships: company_id links statements
- Functions: compute_revenue_growth, compute_profit_margin
Agent Process:
User: "Compare Apple's revenue across quarters"
↓
Agent reads ontology → Understands data structure
↓
Knows: revenue is in IncomeStatement
quarter is a grouping key
Can merge with company metadata
↓
Generates Code:
# Agent-generated code
income_stmt = df[df['statement_type'] == 'income']
apple_data = income_stmt[income_stmt['company_id'] == 'AAPL']
quarterly_revenue = apple_data.groupby('quarter')['revenue'].sum()
print(quarterly_revenue)
Result:
- ✅ Flexible code, handles complex data relationships
- ✅ Can perform complex joins and aggregations
- ❌ High token cost: 3,650 tokens
- ❌ Requires OWL/RDF expertise
Token Usage
Per Query:
- Ontology file: ~2,000 tokens (full .ttl file)
- Data preview: ~500 tokens
- Auxiliary datasets: ~300 tokens
- Prompt template: ~800 tokens’
- User query: ~50 tokens
Total: ~3,650 tokens per query
Optimization:
- Cache data model after first extraction
- Reuse model for subsequent queries
- Reduces to ~1,000 tokens per query after caching
Agent Skills Approach (Anthropic)
Anthropic Skills are specialized, reusable sets of instructions that teach Claude how to handle specific tasks. Think of them as “skill packages” that contain the prompts and resources Claude needs to perform complex or repetitive jobs with better accuracy and consistency.
By using these skills, you can automate your workflows across Claude.ai and Claude Code without having to re-explain your preferences every time.

figure: Anthropic Agent Skills
The primary focus is teaching agents to generate code with the knowledge to process user requests.
What Problem Does It Solve?
- API Learning Curve: Teaches correct usage patterns (find() vs manual construction)
- Error Prevention: Documents common pitfalls (None checks, pagination)
- Best Practices: Shows idiomatic code (filing.search() vs regex)
- Progressive Disclosure: 4-tier documentation (skill → sharp-edges → validations → collaboration)
- Context Efficiency: Minimal token usage (YAML is compact)
- Code Execution: Agent writes Python code directly (no protocol overhead)
Anthropic’s Skills Implementation Markdown or YAML
Anthropic references agentskills.io as the emerging standard for skills across different AI systems, suggesting this approach is becoming industry-wide.
See link here: Repository: https://github.com/anthropics/skills where skills format (SKILL.md) is used a simple markdown format with YAML frontmatter:
---
name: my-skill-name
description: A clear description of what this skill does and when to use it
---
# My Skill Name
[Add your instructions here that Claude will follow when this skill is active]
## Examples
- Example usage 1
- Example usage 2
## Guidelines
- Guideline 1
- Guideline 2
Required fields:
name: Unique identifier (lowercase, hyphens)
description: What the skill does and when to use it
How It Works
- Skills are folders with SKILL.md files
- Claude discovers them through the description field
- No central catalog, no manual wiring
- Claude loads them dynamically
- Claude reads instructions and generates code
The ‘catch’ is that you have to link it up with Claude Code or use an API to make it work with other software
Claude Code (CLI):
Add marketplace
/plugin marketplace add anthropics/skills
Install skills
/plugin install document-skills@anthropic-agent-skills
Claude.ai:
Skills already available to paid plans
Can upload custom skills
Claude API:
Skills API available
Can upload custom skills programmatically
Skills: Single-Stage Pattern Application
Agent Startup (One-Time)
Load Skills from ~/.claude/skills/
↓
Agent Memory (Patterns + Examples)
Runtime (Per Query)
User Query
↓
Agent Recalls Relevant Patterns
↓
Generate Python Code
↓
Execute Code
Pattern-Based Documentation
- Concrete examples: Shows actual code
- Contextual guidance: “when” conditions for pattern selection
- Anti-patterns: Documents what NOT to do
- Progressive disclosure: 4-tier documentation depth
- Executable: Code can be copied directly
Example Skill File:
- name: Search Filing Content
when: Find text/topics within a filing
code: |
results = filing.search("executive compensation")
for match in results[:5]:
print(match.score, str(match)[:200])
note: |
ALWAYS use filing.search() - returns ranked results.
Never use doc.text() + regex.
Pattern Matching:
Agent sees "find text in filing"
Recalls "Search Filing Content" pattern
Applies code template
Adapts to specific query
Usage Example
Scenario: Agent needs to analyze Apple’s financial statements
Knowledge Provided:
- Pattern: “Use Company.financials() for statements”
- Example: company = Company(“AAPL”)
- Note: “Always check for None”
Agent Process:
User: "Get Apple's income statement"
↓
Agent recalls "Company-First Lookup" pattern
↓
Knows: Use Company("AAPL")
Then .financials()
Then .income_statement
↓
Generates Code:
# Agent-generated code
from edgar import Company
company = Company("AAPL")
financials = company.financials()
if financials:
income = financials.income_statement
print(income)
else:
print("No financial data available")
Result:
- ✅ Clean API usage, error handling included
- ✅ Low token cost: 250 tokens
- ✅ Easy to maintain and update
- ❌ No formal semantic understanding
Token Usage
Startup (One-Time):
All skill files: ~5,000 tokens (loaded once)
Per Query:
- User query: ~50 tokens
- Relevant patterns: ~200 tokens (agent recalls)
- Total: ~250 tokens per query
Efficiency:
- 15x more efficient per query
- Skills loaded once at startup
- Agent recalls only relevant patterns
Now that we’ve looked at both approaches, let’s take a look at their pros and cons.
Pros and Cons
BambooAI Ontology Approach
Pros
- Formal Semantics
- OWL provides logical inference capabilities
- Can reason about relationships automatically
- Validates consistency of knowledge
2. Rich Relationship Modeling
- Object properties define complex connections
- Supports transitive, symmetric, inverse relationships
- Can model hierarchies and taxonomies
3. Domain Knowledge Capture
- Captures expert knowledge in structured form
- Documents data structure comprehensively
- Enables knowledge reuse across projects
4. Interoperability
- RDF is a W3C standard
- Can integrate with other ontologies
- Supports SPARQL queries
5. Explicit Constraints
- Domain/range restrictions
- Cardinality constraints
- Data type validation
6. Separation of Concerns
- Data model separate from code generation
- Can cache and reuse data model
- Different agents for different stages
Cons
- High Complexity
- Requires OWL/RDF expertise
- Steep learning curve for developers
- Complex tooling (Protégé, reasoners)
2. Token Overhead
- Full ontology in every prompt (~2,000 tokens)
- Higher cost per query
- Slower response times
3. Two-Stage Processing
- Ontology inspection + code generation
- Two LLM calls per query
- Higher latency
4. Maintenance Burden
- Ontology evolution is complex
- Must maintain consistency
- Breaking changes affect all queries
5. Limited to Data Understanding
- Doesn’t teach API usage patterns
- Doesn’t document error handling
- No anti-pattern guidance
6. Overkill for Simple Cases
- Not needed for well-documented APIs
- Adds complexity without clear benefit
- Better suited for complex data domains
Anthropics Skills Approach
Pros
- Simplicity
- YAML is easy to read/write
- No special tooling required
- Low learning curve
2. Token Efficiency
- Skills loaded once at startup
- Only relevant patterns recalled (~250 tokens/query)
- 15x more efficient than ontology approach
3. Direct Code Examples
- Shows actual working code
- Copy-paste ready
- Contextual guidance
4. Comprehensive Coverage
- API patterns
- Error handling
- Anti-patterns
- Best practices
5. Progressive Disclosure
- 4-tier documentation (skill → sharp-edges → validations → collaboration)
- Agent can dive deeper as needed
- Balances brevity and completeness
6. Easy Maintenance
- Simple YAML editing
- Incremental additions
- No formal validation needed
7. Single-Stage Processing
- One LLM call per query
- Lower latency
- Simpler pipeline
Cons
- No Formal Semantics
- No logical inference
- No automatic reasoning
- Pattern matching is implicit
2. Limited to API Usage
- Doesn’t model data structures
- Doesn’t capture domain relationships
- Focused on “how” not “what”
3. No Interoperability
- Custom YAML format
- Not a standard
- Can’t integrate with other systems
4. Manual Pattern Selection
- Agent must recognize relevant patterns
- No automatic constraint checking
- Relies on LLM’s pattern matching
5. Duplication Risk
- Similar patterns across skills
- No inheritance mechanism
- Manual consistency maintenance
6. Limited Validation
- No formal validation of patterns
- Errors caught at runtime
- Relies on testing
Comparison


figure: comparison approach use cases

figure: comparison approach metrics
Token Efficiency Ranking
- Tool Calling: ~100 tokens/query (Most efficient)
- Skills: ~250 tokens/query
- RAG: ~2,000 tokens/query
- Ontology: ~3,650 tokens/query (Least efficient)
Flexibility Ranking
- Ontology: Full Python + semantic reasoning (Most flexible)
- Skills: Full Python + patterns
- RAG: Text generation only
- Tool Calling: Predefined functions only (Least flexible)
Safety Ranking
- Tool Calling: Type-safe, controlled (Safest)
- RAG: Text only, no execution
- Skills: Code generation, taught patterns
- Ontology: Code generation, complex logic (Least safe)
Use Cases
When to Use Each Approach
Use Ontology When:
- ✅ Complex multi-dataset domains
- ✅ Semantic relationships critical
- ✅ Need formal knowledge representation
- ❌ Simple APIs
- ❌ Performance critical
Use Skills When:
- ✅ Teaching API usage
- ✅ Code generation needed
- ✅ Token efficiency important
- ✅ Rapid development
- ❌ Need type safety
- ❌ Audit requirements
Use RAG When:
- ✅ Large knowledge bases (docs, wikis)
- ✅ Q&A over documents
- ✅ Frequently updated content
- ✅ Text-based responses sufficient
- ❌ Need code execution
- ❌ Token budget limited
Use Tool Calling When:
- ✅ Structured operations (API calls, DB queries)
- ✅ Type safety required
- ✅ Audit trail needed
- ✅ Predictable behavior critical
- ❌ Need composability
- ❌ Complex workflows
Summary
In my opinion, pick the most effective approach for the use case.
- Ontologies excel at “what” — describing data structures and relationships
- Skills excel at “how” — teaching API usage and best practices
- Token efficiency matters — Skills are 15x more efficient per query
- Complexity has costs — Ontologies require expertise and tooling
- Context is king — Choose based on your specific needs
- All approaches generate code — They teach agents to write Python, not call tools
Anthropic’s approach is to treat every AI agent as a coder. By allowing the AI to write its own code on the fly, it becomes more flexible and reliable — as long as it follows strict safety rules which enriches the Ai agent with knowledge.
Thanks for reading, have a nice day!
/MC
References:
BambooAI
- Repository: https://github.com/pgalko/BambooAI
- Ontology: web_app/ontologies/Sports_Data_Ontology.ttl
- Implementation: bambooai/utils.py — inspect_dataframe()
Anthropic Skills
- Repository: https://github.com/anthropics/skills (88.7k stars)
- Official implementation: Agent Skills standard
- Documentation: https://support.claude.com/en/articles/12512198-creating-custom-skills
- Standard: https://agentskills.io
Standards
- OWL: https://www.w3.org/OWL/
- RDF: https://www.w3.org/RDF/
- Turtle: https://www.w3.org/TR/turtle/
- YAML: https://yaml.org/
- Agent Skills: https://agentskills.io
메타데이터
- post_id
- 3fa5ee20e52c
- slug
- enrich-agents-with-domain-specific-knowledge-to-make-ai-smarter-ontology-skills-rag-tool-3fa5ee20e52c
- url
- https://medium.com/@mychen76/enrich-agents-with-domain-specific-knowledge-to-make-ai-smarter-ontology-skills-rag-tool-3fa5ee20e52c
- canonical_url
- https://medium.com/@mychen76/enrich-agents-with-domain-specific-knowledge-to-make-ai-smarter-ontology-skills-rag-tool-3fa5ee20e52c
- author_url
- https://medium.com/@mychen76
- status
- ok
- fetched_at
- 2026-06-23 17:05:31