Course Content
LangChain Mastery
7 sections · 109 lessons
How do you implement a LangChain agent with tool prioritization?
What you need to know
Soft priority versus hard priority
Soft: tell the model
- Order stated in the system prompt
- "Use when / do not use when" in docstrings
- Cheap, flexible
- The model can still ignore it
Hard: enforce in code
- Filter tools per step with middleware
- Force the first call with
tool_choice - Remove forbidden tools entirely
- Guaranteed, but less flexible
Use soft priority for preferences ("usually try X first") and hard priority for rules that must hold ("never search the web before the internal KB", "no refund tool for unverified users").
Soft: prompt and descriptions
1SYSTEM = """Answer support questions for our broadband service.2Tool order:31. search_help_centre — always try this first.42. get_account — only for questions about this customer's own plan or bills.53. web_search — only if the help centre has no answer, and never for prices."""Also write each docstring to point at the others: web_search's says "Use only after search_help_centre returned nothing relevant."
Hard: middleware that gates tools
1from langchain.agents import create_agent2from langchain.agents.middleware import wrap_model_call34@wrap_model_call5def help_centre_first(request, handler):6 used = {m.name for m in request.state["messages"] if m.type == "tool"}7 if "search_help_centre" not in used:8 # First step: only the help centre is available, and it must be called.9 kb = [t for t in request.tools if t.name == "search_help_centre"]10 request = request.override(tools=kb, tool_choice="search_help_centre")11 elif not request.runtime.context.verified:12 request = request.override(13 tools=[t for t in request.tools if t.name != "get_account"])14 return handler(request)1516agent = create_agent(model, tools=[search_help_centre, get_account, web_search],17 system_prompt=SYSTEM, middleware=[help_centre_first],18 context_schema=SupportContext)The model cannot choose a tool it cannot see. On the first step it sees only search_help_centre and is forced to call it. After that it sees the other tools, except get_account when the user is not verified. request.runtime.context holds values your backend passes at invoke time, such as context=SupportContext(verified=False).
Other options
- Route before the agent. A cheap classifier chooses a tool group ("billing" or "technical") and the agent only sees that group.
LLMToolSelectorMiddlewarewithalways_include=["search_help_centre"]keeps the priority tool present while a small model picks the rest.ToolCallLimitMiddlewareon expensive tools, such asweb_searchwithrun_limit=1, makes them a last resort in practice.
A real-life example
A broadband company's help-centre support bot had three tools. The team noticed the bot answering "How do I reset my router?" with steps from a web search — for a different brand of router — about 8% of the time, even though the help centre had the correct article.
A stronger system-prompt rule brought this down to 3%. The help_centre_first middleware brought it to zero, because the web search tool is not visible until the help centre has been searched. Web search calls fell by 70%, and the cost per conversation fell with them. The eval set now includes 40 questions whose expected first tool is search_help_centre.
Follow-up questions to expect
- "What does
tool_choicedo?" — It tells the model it must call a tool (a specific one, or any); forcing it on every step would stop the agent from ever answering, so apply it only to the first step. - "How do you handle permissions?" — Remove the tool for that user in middleware, and also check permissions inside the tool itself; never rely on a prompt instruction.
- "How do you test priorities?" — An eval set with the expected first tool or tool sequence, run on every prompt or model change.