Tool Filter API Reference¶
The tool filter subsystem implements Anthropic's Tool Search pattern for reducing token usage by dynamically filtering tools per request based on semantic similarity to the user's query. Instead of sending every registered tool to the LLM on each call, only the most relevant tools are included.
The subsystem lives in holodeck.lib.tool_filter and exposes four public symbols:
ToolMetadata, ToolFilterConfig, ToolIndex, and ToolFilterManager.
Configuration¶
ToolFilterConfig is the Pydantic model that controls filtering behavior.
It is typically embedded in an agent's YAML configuration.
tool_filter:
enabled: true
top_k: 5
similarity_threshold: 0.3
search_method: hybrid # semantic | bm25 | hybrid
always_include:
- get_user_context
always_include_top_n_used: 3
ToolFilterConfig
¶
Bases: BaseModel
Configuration for automatic tool filtering.
Defines how tools are filtered per request to reduce token usage. When enabled, only the most relevant tools (based on semantic similarity to the user query) are included in each LLM call.
Attributes:
| Name | Type | Description |
|---|---|---|
enabled |
bool
|
Enable or disable tool filtering globally. |
top_k |
int
|
Maximum number of tools to include per request. |
similarity_threshold |
float
|
Minimum similarity score for tool inclusion. |
always_include |
list[str]
|
Tool names that are always included regardless of score. |
always_include_top_n_used |
int
|
Number of most-used tools to always include. |
search_method |
Literal['semantic', 'bm25', 'hybrid']
|
Method for tool search (semantic, bm25, or hybrid). |
validate_always_include(v)
classmethod
¶
Validate always_include entries are non-empty strings.
Source code in src/holodeck/lib/tool_filter/models.py
131 132 133 134 135 136 137 138 | |
Tool Metadata¶
ToolMetadata represents a single tool inside the index. It is created
automatically by ToolIndex.build_from_kernel and carries the embedding
vector (when available), parameter descriptions, and runtime usage counts.
ToolMetadata
¶
Bases: BaseModel
Metadata for a single tool used in semantic search and filtering.
Stores information about tools extracted from the Semantic Kernel, including embeddings for semantic search and usage statistics for adaptive optimization.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Tool function name (e.g., "search", "get_user"). |
plugin_name |
str
|
Plugin namespace (e.g., "vectorstore", "mcp_weather"). |
full_name |
str
|
Combined identifier as "plugin_name-function_name". |
description |
str
|
Human-readable description for semantic search. |
parameters |
list[str]
|
List of parameter descriptions for enhanced matching. |
defer_loading |
bool
|
If True, exclude from initial context (load on-demand). |
embedding |
list[float] | None
|
Pre-computed embedding vector for semantic search. |
usage_count |
int
|
Number of times this tool has been invoked. |
validate_description(v)
classmethod
¶
Validate description is not empty.
Source code in src/holodeck/lib/tool_filter/models.py
68 69 70 71 72 73 74 | |
validate_full_name(v)
classmethod
¶
Validate full_name is not empty.
Source code in src/holodeck/lib/tool_filter/models.py
60 61 62 63 64 65 66 | |
validate_name(v)
classmethod
¶
Validate name is not empty.
Source code in src/holodeck/lib/tool_filter/models.py
52 53 54 55 56 57 58 | |
validate_usage_count(v)
classmethod
¶
Validate usage_count is non-negative.
Source code in src/holodeck/lib/tool_filter/models.py
76 77 78 79 80 81 82 | |
Tool Index¶
ToolIndex is the in-memory search index that holds all ToolMetadata
entries and supports three search strategies:
| Method | Description |
|---|---|
semantic |
Cosine similarity over embedding vectors |
bm25 |
Classic BM25 keyword scoring (no embeddings required) |
hybrid |
Reciprocal Rank Fusion of semantic and BM25 results |
When the embedding service is unavailable, semantic search automatically falls back to BM25.
ToolIndex()
¶
In-memory index for fast tool searching.
Maintains a collection of ToolMetadata objects and supports multiple search methods for finding relevant tools based on user queries.
Attributes:
| Name | Type | Description |
|---|---|---|
tools |
dict[str, ToolMetadata]
|
Dictionary mapping full_name to ToolMetadata. |
_idf_cache |
dict[str, float]
|
Cached IDF values for BM25 search. |
_doc_lengths |
dict[str, int]
|
Document lengths for BM25 normalization. |
_avg_doc_length |
float
|
Average document length for BM25. |
Initialize an empty tool index.
Source code in src/holodeck/lib/tool_filter/index.py
92 93 94 95 96 97 | |
build_from_kernel(kernel, embedding_service=None, defer_loading_map=None)
async
¶
Build index from Semantic Kernel plugins.
Extracts all registered functions from the kernel's plugins and creates ToolMetadata entries with optional embeddings.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
kernel
|
Kernel
|
Semantic Kernel with registered plugins. |
required |
embedding_service
|
EmbeddingGeneratorBase | None
|
Optional TextEmbedding service for generating embeddings. |
None
|
defer_loading_map
|
dict[str, bool] | None
|
Optional mapping of tool names to defer_loading flags. Defaults to True for all tools if not provided. |
None
|
Source code in src/holodeck/lib/tool_filter/index.py
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | |
get_all_tool_names()
¶
Get all tool full names in the index.
Returns:
| Type | Description |
|---|---|
list[str]
|
List of all tool full names. |
Source code in src/holodeck/lib/tool_filter/index.py
543 544 545 546 547 548 549 | |
get_tool(full_name)
¶
Get a tool by its full name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
full_name
|
str
|
Tool's full name (plugin_name-function_name). |
required |
Returns:
| Type | Description |
|---|---|
ToolMetadata | None
|
ToolMetadata if found, None otherwise. |
Source code in src/holodeck/lib/tool_filter/index.py
532 533 534 535 536 537 538 539 540 541 | |
get_top_n_used(n)
¶
Get the N most frequently used tools.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n
|
int
|
Number of top tools to return. |
required |
Returns:
| Type | Description |
|---|---|
list[ToolMetadata]
|
List of ToolMetadata sorted by usage_count descending. |
Source code in src/holodeck/lib/tool_filter/index.py
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 | |
search(query, top_k, method='semantic', threshold=0.0, embedding_service=None)
async
¶
Search for relevant tools based on query.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
str
|
User query to match against tools. |
required |
top_k
|
int
|
Maximum number of results to return. |
required |
method
|
str
|
Search method (semantic, bm25, or hybrid). |
'semantic'
|
threshold
|
float
|
Minimum score threshold for inclusion. |
0.0
|
embedding_service
|
EmbeddingGeneratorBase | None
|
TextEmbedding service (required for semantic search). |
None
|
Returns:
| Type | Description |
|---|---|
list[tuple[ToolMetadata, float]]
|
List of (ToolMetadata, score) tuples sorted by relevance. |
Source code in src/holodeck/lib/tool_filter/index.py
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | |
update_usage(tool_name)
¶
Increment usage count for a tool.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tool_name
|
str
|
Full name of the tool that was used. |
required |
Source code in src/holodeck/lib/tool_filter/index.py
503 504 505 506 507 508 509 510 511 512 513 | |
Tool Filter Manager¶
ToolFilterManager is the main orchestrator. It wires together the
ToolIndex, the embedding service, and Semantic Kernel's
FunctionChoiceBehavior to transparently reduce the tool set on every
agent invocation.
Typical lifecycle¶
from holodeck.lib.tool_filter import ToolFilterConfig, ToolFilterManager
config = ToolFilterConfig(
enabled=True,
top_k=5,
similarity_threshold=0.3,
search_method="hybrid",
)
manager = ToolFilterManager(config, kernel, embedding_service)
await manager.initialize()
# Per-request filtering
filtered_tool_names = await manager.filter_tools("What's the weather?")
# Or apply directly to execution settings
settings = await manager.prepare_execution_settings(query, base_settings)
# After execution, record which tools the model actually called
manager.record_tool_usage(result.tool_calls)
ToolFilterManager(config, kernel, embedding_service=None)
¶
Manages tool filtering for agent invocations.
Coordinates between the ToolIndex (for semantic search) and Semantic Kernel's FunctionChoiceBehavior (for tool filtering) to reduce token usage by only including relevant tools.
Attributes:
| Name | Type | Description |
|---|---|---|
config |
ToolFilterConfig with filtering parameters. |
|
kernel |
Semantic Kernel with registered plugins. |
|
embedding_service |
TextEmbedding service for semantic search. |
|
index |
ToolIndex for fast tool searching. |
|
_initialized |
Whether the manager has been initialized. |
Initialize the tool filter manager.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
ToolFilterConfig
|
Tool filtering configuration. |
required |
kernel
|
Kernel
|
Semantic Kernel with registered plugins. |
required |
embedding_service
|
EmbeddingGeneratorBase | None
|
Optional TextEmbedding service for semantic search. |
None
|
Source code in src/holodeck/lib/tool_filter/manager.py
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | |
create_function_choice_behavior(filtered_tools)
¶
Create FunctionChoiceBehavior with filtered tool list.
Uses Semantic Kernel's native filtering mechanism to restrict which functions are available to the LLM.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filtered_tools
|
list[str]
|
List of tool full_names to include. |
required |
Returns:
| Type | Description |
|---|---|
FunctionChoiceBehavior
|
FunctionChoiceBehavior configured with the filtered tool list. |
Source code in src/holodeck/lib/tool_filter/manager.py
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | |
filter_tools(query)
async
¶
Filter tools based on query relevance.
Returns a list of tool names that should be included in the LLM call based on semantic similarity to the query.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
str
|
User query for filtering. |
required |
Returns:
| Type | Description |
|---|---|
list[str]
|
List of tool full_names to include in the request. |
Source code in src/holodeck/lib/tool_filter/manager.py
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | |
get_filter_stats()
¶
Get statistics about tool filtering.
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Dictionary with filtering statistics. |
Source code in src/holodeck/lib/tool_filter/manager.py
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | |
initialize(defer_loading_map=None)
async
¶
Initialize the tool index from kernel plugins.
Must be called after all tools are registered on the kernel and before any filtering operations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
defer_loading_map
|
dict[str, bool] | None
|
Optional mapping of tool names to defer_loading flags. |
None
|
Source code in src/holodeck/lib/tool_filter/manager.py
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | |
prepare_execution_settings(query, base_settings)
async
¶
Prepare execution settings with filtered tools.
Filters tools based on the query and creates new execution settings with the appropriate FunctionChoiceBehavior.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
str
|
User query for filtering. |
required |
base_settings
|
PromptExecutionSettings | dict[str, PromptExecutionSettings]
|
Base execution settings to modify. |
required |
Returns:
| Type | Description |
|---|---|
PromptExecutionSettings | dict[str, PromptExecutionSettings]
|
Modified execution settings with filtered function choice behavior. |
Source code in src/holodeck/lib/tool_filter/manager.py
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | |
record_tool_usage(tool_calls)
¶
Record tool usage for adaptive optimization.
Updates usage counts in the index based on which tools were actually called during agent execution.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tool_calls
|
list[dict[str, Any]]
|
List of tool call dicts with 'name' key. |
required |
Source code in src/holodeck/lib/tool_filter/manager.py
247 248 249 250 251 252 253 254 255 256 257 258 259 | |
Module-Level Helpers¶
The index module also exposes two private helper functions used
internally by ToolIndex. They are not part of the public API but are
documented here for completeness.
_cosine_similarity(vec_a, vec_b)
¶
Compute cosine similarity between two vectors.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vec_a
|
list[float]
|
First embedding vector. |
required |
vec_b
|
list[float]
|
Second embedding vector. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Cosine similarity score between -1.0 and 1.0. |
Source code in src/holodeck/lib/tool_filter/index.py
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | |
_tokenize(text)
¶
Simple tokenizer for BM25 search.
Splits text on non-alphanumeric characters INCLUDING underscores, so that tool names like "brave_web_search" become ["brave", "web", "search"]. This enables matching individual terms like "web" against tool names.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Input text to tokenize. |
required |
Returns:
| Type | Description |
|---|---|
list[str]
|
List of lowercase tokens. |
Source code in src/holodeck/lib/tool_filter/index.py
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | |