The file includes a header comment showing how to use the class to qil your user prompts before sending them to the LLM.
QIL+LLM simplifies prompt augmentation with a single, elegant function call.
The system automatically detects matching utterances in user prompts and replaces them with pre-computed function outputs, eliminating unnecessary LLM requests.
An important optimization: if QIL handles the entire prompt, bypass the LLM entirely and return the result directly to the user.
After loading, _QIL_REGISTRY becomes a dictionary mapping utterances to function objects.
Depending on your needs, you could load the configuration as needed or per user session.
๐ช Sentence Splitting
Sentence splitting is deceptively tricky.
Real user prompts often lack punctuation, contain runโons, or mix multiple intents in a single line.
The goal here isnโt perfection.
itโs reliability without involving an LLM.
The following approach uses regexโbased heuristics to segment text into meaningful units:
import re
def sentence_splitter(text):
starters = ["i", "what", "show", "get", "is", "can", "please", "summarize", "list"]
starters_regex = "|".join(starters)
# We wrap the punctuation part in () so it's included in the split result
# We use a non-capturing group for the 'and/also' logic
# Move (?i) to the very start
pattern = rf"(?i)([\.\!\?\n]+|(?<=\s)(?:and|also|then)(?=\s+(?:{starters_regex})\b))"
# re.split with a capturing group returns: [text, delim, text, delim...]
parts = re.split(pattern, text)
sentences = []
# Loop through and merge the text with its following delimiter
for i in range(0, len(parts)-1, 2):
combined = (parts[i] + parts[i+1]).strip()
if len(combined) > 1:
sentences.append(combined)
# Catch any trailing text that didn't have a delimiter
if len(parts) % 2 != 0 and len(parts[-1].strip()) > 1:
sentences.append(parts[-1].strip())
return sentences
You provide a prompt, and you get back a list of sentences. Simple, predictable, and fast.
๐ Calling a Function
Suppose you have a match.
You need to call a function.
This is easiest to do with a function calling function.
def execute_qil_function(func_name, extracted_value=None):
# Get the function object from the global namespace
# Note: Ensure your tool functions (get_balance, etc.) are imported or defined here
func = globals().get(func_name)
if not func:
print(f"Error: Function {func_name} not found.")
return None
try:
if extracted_value:
# Requirements: var name must be lowercase in call
# We assume the parameter name is 'customerid' for [CUSTOMERID]
# This logic can be made more generic if you have multiple variables
return func(customerid=extracted_value)
else:
return func()
except Exception as e:
print(f"Execution Error in {func_name}: {e}")
return None
This purposely returns None on failure.
That indicates that the original sentence should not be replaced with function output.
Keep it in the original prompt for the LLM.
๐ ๏ธ Processing the Prompt
Now we can use QIL to handle prompt queries without sending them to the LLM.
There are many ways to compare an utterance to a sentence.
import re
def qil(user_prompt, config_path="lib/qil.conf"):
"""
Main functional entry point.
Returns (augmented_prompt, all_replaced_boolean)
"""
# Load config if not already loaded or if a custom path is provided
global _CONFIG_LOADED
if not _CONFIG_LOADED or config_path != "lib/qil.conf":
_load_config(config_path)
sentences = _sentence_splitter(user_prompt)
untagged_count = len(sentences)
final_output = user_prompt
templates = list(_REGISTRY.keys())
for sentence in sentences:
# Normalize the sentence for matching
lsentence = re.sub(r'[^\w\s]', '', sentence.lower())
# Use MEWF similarity to find the best matching utterance
best_utterance, score = find_best_utterance(lsentence, templates, threshold=95)
if best_utterance:
func_tuple = _REGISTRY[best_utterance]
extracted_val = None
# Extract wildcard values if template contains brackets
if "[" in best_utterance:
val_match = re.search(r'\b\d{3,}\b', sentence)
if val_match:
extracted_val = val_match.group(0)
result_string = _execute_tool(func_tuple, extracted_val)
if result_string is not None:
final_output = final_output.replace(sentence, str(result_string) + "\n")
untagged_count -= 1
return (final_output, untagged_count == 0)
This splits the prompt into sentences.
Then, it finds the best matching utterance for every sentence.
For each match, it calls the associated function.
If the function call returns a value, the original sentence is replaced with the function's output.
The updated prompt is returned.
I include a Boolean value that is True if every sentance was replaced.
๐ Finding a Match
I rally wanted to use a well-known common library to matching sentences to templates.
For a while, RapidFuzz worked well, but a close examination showed that the window of false-positives and false-negatives was far too wide.
I wrote the following function to mix concepts of Levenshtein distance and Monge-Elkan distance into a single function heavily customized for this project.
The accompanying function is a wrapper that returns the best match and score.
import Levenshtein
def similarity(user_query, utterance):
"""
This function calculates similarity between a user query and an utterance template.
It is based on existing algorithms for Levenshtein distance and Monge-Elkan similarity.
The function returns a similarity score between 0 and 100.
"""
# Normalize inputs as requested
def normalize(text, keep_brackets=False):
text = text.lower()
if keep_brackets:
text = re.sub(r'[^a-z0-9\s\[\]]', '', text)
else:
text = re.sub(r'[^a-z0-9\s]', '', text)
return re.sub(r'\s+', ' ', text).strip()
u_raw = normalize(user_query, keep_brackets=False)
t_raw = normalize(utterance, keep_brackets=True)
u_len = len(u_raw)
t_len = len(t_raw)
if u_len == 0 and t_len == 0:
return 100.0
if u_len == 0 or t_len == 0:
return 0.0
u_tokens = u_raw.split()
t_tokens = t_raw.split()
# 1. Remove Exact Matches (case-sensitive after normalization)
# Use list() to avoid modification during iteration
common = []
for token in list(u_tokens):
if token in t_tokens:
common.append(token)
for token in common:
if token in u_tokens and token in t_tokens:
u_tokens.remove(token)
t_tokens.remove(token)
# 2. Separate Wildcards from Static Template Words
wildcards = [t for t in t_tokens if t.startswith('[') and t.endswith(']')]
static_templates = [t for t in t_tokens if t not in wildcards]
total_cost = 0
# 3. Match Static Template words to closest User words (Greedy Pairing)
# Continue until we run out of static template words OR user words
while static_templates and u_tokens:
# Find the pair with minimum Levenshtein distance
min_cost = float('inf')
best_t_idx = -1
best_u_idx = -1
for t_idx, t_word in enumerate(static_templates):
for u_idx, u_word in enumerate(u_tokens):
cost = Levenshtein.distance(t_word, u_word)
if cost < min_cost:
min_cost = cost
best_t_idx = t_idx
best_u_idx = u_idx
total_cost += min_cost
static_templates.pop(best_t_idx)
u_tokens.pop(best_u_idx)
# 4. Wildcard Fulfillment
# Wildcards consume remaining user tokens at 0 cost
while wildcards and u_tokens:
wildcards.pop()
u_tokens.pop(0)
# 5. Penalties for unmatched words
# Remaining user words
total_cost += sum(len(u) for u in u_tokens)
# Remaining static template words (already handled above, but kept for clarity)
total_cost += sum(len(t) for t in static_templates)
# Remaining wildcards (couldn't be matched)
total_cost += sum(len(w) for w in wildcards)
# 6. Normalize Score (0-100)
score = 100 * (u_len + t_len - total_cost) / (u_len + t_len)
return max(0.0, score) # Ensure non-negative
def find_best_utterance(user_query, utterances, threshold=90):
""" Find the best matching utterance for a user query using MEWF similarity. """
if not utterances:
return (None, 0)
best_utterance = None
best_score = 0
for utterance in utterances:
score = similarity(user_query, utterance)
if score > best_score:
best_score = score
best_utterance = utterance
if best_score >= threshold:
return (best_utterance, best_score)
else:
return (None, best_score)
๐ License
This project is open source and available under the MIT License.