Replace structured JSON function calling with natural-language YES/NO grids. Instead of serializing tool schemas on every call and asking the model to emit JSON, NLT asks the model a question it is good at: "Do you need this tool? YES or NO." — then extracts arguments in a second, equally plain exchange.
Validated across 14 models and 8,560 trials: +14.9pp selection accuracy, 93% fewer errors, 25.2% token savings versus structured function calling — with the gap widest on small and open models.
Zero core dependencies (stdlib only). You bring the LLM.
import nlt
tools = [
nlt.ToolSpec(
name="search",
description="Search the web for information.",
parameters={
"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"],
},
),
]
def my_llm(user_prompt: str, system_prompt: str) -> str:
... # call any model; return its text
selected = nlt.select_tools("Find articles about climate change", tools, call_llm=my_llm)
for tool in selected:
print(tool.name, tool.args)Two phases, both plain text:
- Selection (
nlt.select) — every tool is presented as one row of a YES/NO grid; the parsed answers say which tools are relevant. - Extraction (
nlt.extract_args) — for each selected tool with parameters, one more call extracts the argument values.
nlt.select_tools chains both. NLTConfig controls strategy (nlt,
structured, or hybrid fallback), the per-turn tool cap, and whether
parameterless tools skip extraction.
pip install -e . # core, stdlib only
pip install -e ".[langchain]" # + from_langchain_tools converter
pip install -e ".[openai]" # + OpenAI client adapterfrom nlt.integrations.langchain import from_langchain_tools
specs = from_langchain_tools(my_langchain_tools) # BaseTool -> ToolSpecNLT is the default tool-selection path of the Startr.Team agent framework (spec).
AGPL-3.0-or-later.