|
| 1 | +# Filtering Samples |
| 2 | + |
| 3 | +This directory contains samples demonstrating the Python filter system in Semantic Kernel. |
| 4 | + |
| 5 | +Filters allow you to intercept and modify pipeline execution at specific points. The Python SDK supports three filter types. |
| 6 | + |
| 7 | +## Filter Types |
| 8 | + |
| 9 | +| Filter | Decorator | Purpose | |
| 10 | +|--------|-----------|---------| |
| 11 | +| **Prompt Rendering** | `@kernel.filter(FilterTypes.PROMPT_RENDERING)` | Intercept before/after prompt is rendered | |
| 12 | +| **Function Invocation** | `@kernel.filter(FilterTypes.FUNCTION_INVOCATION)` | Intercept before/after any function call | |
| 13 | +| **Auto Function Invoke** | `@kernel.filter(FilterTypes.AUTO_FUNCTION_INVOCATION)` | Control automatic tool calls | |
| 14 | + |
| 15 | +## Samples |
| 16 | + |
| 17 | +### [prompt_filters.py](./prompt_filters.py) |
| 18 | + |
| 19 | +Basic prompt rendering filter. Demonstrates how to inspect and modify prompts before they're sent to the model. |
| 20 | + |
| 21 | +### [function_invocation_filters.py](./function_invocation_filters.py) |
| 22 | + |
| 23 | +Function invocation filter with logging and exception handling. Shows both `kernel.add_filter()` and `@kernel.filter()` decorator registration. |
| 24 | + |
| 25 | +### [function_invocation_filters_stream.py](./function_invocation_filters_stream.py) |
| 26 | + |
| 27 | +Same as above but for **streaming** responses. Use this when working with streaming chat completions. |
| 28 | + |
| 29 | +### [auto_function_invoke_filters.py](./auto_function_invoke_filters.py) |
| 30 | + |
| 31 | +Controls which automatic tool calls are allowed. Demonstrates `context.terminate = True` to skip specific function calls, and `FunctionResultContent` handling. |
| 32 | + |
| 33 | +### [retry_with_filters.py](./retry_with_filters.py) |
| 34 | + |
| 35 | +Implements automatic retry logic using function invocation filters. Retries on failure with a different model. |
| 36 | + |
| 37 | +### [retry_with_different_model.py](./retry_with_different_model.py) |
| 38 | + |
| 39 | +Similar retry pattern but specifically switches to a fallback model on failure. |
| 40 | + |
| 41 | +## Registration |
| 42 | + |
| 43 | +There are two ways to register a filter: |
| 44 | + |
| 45 | +```python |
| 46 | +# Method 1: Decorator |
| 47 | +@kernel.filter(filter_type=FilterTypes.FUNCTION_INVOCATION) |
| 48 | +async def my_filter(context, next): |
| 49 | + await next(context) |
| 50 | + |
| 51 | +# Method 2: Add function |
| 52 | +kernel.add_filter("function_invocation", my_filter) |
| 53 | +``` |
| 54 | + |
| 55 | +Both are equivalent. Use whichever fits your code style. |
| 56 | + |
| 57 | +## Filter Signature |
| 58 | + |
| 59 | +All filters follow the same signature: |
| 60 | + |
| 61 | +```python |
| 62 | +async def filter_name(context: <ContextType>, next: Callable) -> None: |
| 63 | + # Code before next filter/function runs |
| 64 | + await next(context) |
| 65 | + # Code after next filter/function runs |
| 66 | +``` |
| 67 | + |
| 68 | +The `next` callable passes control to the next filter in the chain, then to the actual function. You can skip execution by not calling `await next(context)`. |
| 69 | + |
| 70 | +## Terminating Auto Function Calls |
| 71 | + |
| 72 | +To prevent an auto-invoked function from executing: |
| 73 | + |
| 74 | +```python |
| 75 | +@kernel.filter(FilterTypes.AUTO_FUNCTION_INVOCATION) |
| 76 | +async def selective_filter(context: AutoFunctionInvocationContext, next): |
| 77 | + if context.function.name == "dangerous_function": |
| 78 | + context.terminate = True # Skip this function call |
| 79 | + return |
| 80 | + await next(context) |
| 81 | +``` |
0 commit comments