AI Agents & Tool Use
Level: 3 — Production (from-scratch derivations, code-from-memory, explain-out-loud) Time limit: 45 minutes Total marks: 60
Instructions: Answer all questions. Code may be pseudo-Python but must be runnable in spirit (correct control flow, correct API shape). Explain reasoning where asked.
Question 1 — The ReAct Loop from Memory (12 marks)
(a) From memory, write the canonical ReAct interleaving as a token/step trace format, naming the three recurring step types and the terminal step type. (4)
(b) Implement a minimal ReAct agent loop in Python pseudocode. It must: call an LLM to produce a Thought/Action, parse a tool call, execute the tool, feed back an Observation, and terminate on a Finish action or after max_steps. (6)
(c) Explain out loud (2–3 sentences) why interleaving reasoning with acting reduces hallucination compared to pure chain-of-thought. (2)
Question 2 — Function Calling Contract (10 marks)
(a) Write, from memory, a JSON-schema tool/function definition for a get_weather(city: str, units: "celsius"|"fahrenheit") tool as passed to a function-calling LLM. (5)
(b) The model returns a tool call as JSON. Write the code that (i) validates required arguments are present, (ii) rejects an out-of-enum units value, and (iii) dispatches to the real Python function. (3)
(c) Name two failure modes of function calling and one guardrail each. (2)
Question 3 — Planning & Task Decomposition (10 marks)
(a) Contrast decompose-first (plan-then-execute) vs interleaved (ReAct-style) planning. Give one scenario where each is preferable. (4)
(b) You are given a task DAG with tasks and dependencies: Give one valid topological execution order, and state the minimum number of sequential rounds if independent tasks run in parallel. (4)
(c) Define the critical path for this DAG (assume unit cost per task) and give its length. (2)
Question 4 — Memory Systems Cost Model (10 marks)
An agent uses a vector-store long-term memory. Retrieval returns top- chunks, each of tokens, appended to a prompt with base size tokens per turn. The conversation runs turns.
(a) Derive an expression for the total prompt tokens consumed across all turns, assuming memory is retrieved fresh each turn. (3)
(b) With , , , , compute the total prompt tokens. (3)
(c) A summarization/compression strategy replaces raw history with a running summary of fixed size tokens. Rewrite the total-token expression and compute it for the same parameters (memory retrieval still each turn, base drops to ). Explain the tradeoff in one sentence. (4)
Question 5 — Multi-Agent & Evaluation (10 marks)
(a) Describe the supervisor/orchestrator multi-agent pattern and contrast it with a peer/blackboard pattern (2–3 sentences each). (4)
(b) Define task success rate and tool-call precision as agent evaluation metrics. An agent attempts 20 tasks, completes 14, and across those runs makes 50 tool calls of which 40 were valid/necessary. Compute both metrics. (4)
(c) Explain out loud one reason why LLM-as-judge evaluation of agents can be unreliable. (2)
Question 6 — Guardrails & Constrained Generation (8 marks)
(a) Explain the difference between input guardrails, output guardrails, and constrained decoding. (3)
(b) You must guarantee an agent's final answer is valid JSON matching a schema. Explain why grammar-/schema-constrained decoding is stronger than a regex post-check, and name one library approach. (3)
(c) Give one reason unconstrained tool-calling agents pose a security risk (e.g. prompt injection) and one mitigation. (2)
Answer keyMark scheme & solutions
Question 1 (12)
(a) (4) Recurring step types: Thought (reasoning), Action (tool invocation with input), Observation (tool result fed back). Terminal step: Finish/Answer (final answer, no further tools). 1 mark each. Trace format:
Thought: ...
Action: tool[input]
Observation: ...
... (repeat) ...
Thought: I now know the answer
Finish: <answer>
(b) (6) Loop:
def react_agent(query, tools, llm, max_steps=8):
scratchpad = f"Question: {query}\n"
for _ in range(max_steps):
out = llm(PROMPT + scratchpad) # +1 LLM produces Thought/Action
scratchpad += out
if "Finish:" in out: # +1 terminal check
return out.split("Finish:")[1].strip()
action, arg = parse_action(out) # +1 parse tool + input
if action not in tools: # +1 robustness
obs = f"Error: unknown tool {action}"
else:
obs = tools[action](arg) # +1 execute tool
scratchpad += f"\nObservation: {obs}\n" # +1 feed back
return "Max steps reached"Marks: LLM call (1), Finish termination (1), parse (1), dispatch/validate (1), execute (1), observation feedback + max_steps guard (1).
(c) (2) Because each Action grounds the next Thought in real observed evidence from tools/environment rather than free-running generation, so the model self-corrects against external facts instead of confabulating a whole answer. (2)
Question 2 (10)
(a) (5)
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name"},
"units": {"type": "string", "enum": ["celsius", "fahrenheit"]}
},
"required": ["city", "units"]
}
}
}Marks: correct wrapper/name (1), properties types (1), enum on units (1), required list (1), valid JSON structure (1).
(b) (3)
def dispatch(call, registry):
args = call["arguments"]
if "city" not in args or "units" not in args: # (i) +1
raise ValueError("missing required arg")
if args["units"] not in ("celsius", "fahrenheit"): # (ii) +1
raise ValueError("invalid units enum")
return registry[call["name"]](**args) # (iii) +1(c) (2) Any two: hallucinated tool name → whitelist/registry check; malformed/invalid args → schema validation + retry; wrong tool chosen → few-shot examples/description tuning. (1 failure + 1 guardrail each pair; 2 total)
Question 3 (10)
(a) (4) Plan-then-execute: build full plan up front, then execute steps — better for well-specified, deterministic tasks where full requirements are known (e.g. multi-file refactor). (2) Interleaved/ReAct: decide next action from latest observation — better for open-ended/uncertain environments where results change the plan (e.g. web research). (2)
(b) (4) Valid topological order (one of many): (2). Parallel rounds:
- Round 1: (no deps)
- Round 2: ( needs ; needs )
- Round 3: (needs )
- Round 4: (needs )
Minimum = 4 rounds (2).
(c) (2) Critical path = longest dependency chain. (or ), length 4 tasks. (2)
Question 4 (10)
(a) (3) Per turn tokens . Over turns: (retrieval fresh each turn ⇒ no accumulation of history in this simple model).
(b) (3) tokens.
(c) (4) With summary of fixed size replacing base: tokens. (2 for formula+value) Tradeoff: compression saves tokens/cost but summarization is lossy — fine-grained earlier detail may be dropped, risking loss of context needed later. (2)
Question 5 (10)
(a) (4) Supervisor/orchestrator: a central agent decomposes the goal, routes sub-tasks to specialist worker agents, and aggregates results — clear control flow, easier to debug/guardrail, single point of coordination. (2) Peer/blackboard: agents share a common state ("blackboard") and act opportunistically without a central router — more flexible/emergent but harder to control and prone to loops/conflicts. (2)
(b) (4) Task success rate (2). Tool-call precision (2).
(c) (2) LLM judges are biased (position/verbosity bias, self-preference), inconsistent across runs, and may reward plausible-sounding but wrong trajectories, so they don't reliably reflect true task correctness. (2)
Question 6 (8)
(a) (3) Input guardrails: validate/sanitize/reject user input before it reaches the model (e.g. PII, injection filters). (1) Output guardrails: check the model's produced output before returning (toxicity, schema, factuality). (1) Constrained decoding: restrict the token generation itself so only valid outputs can be produced. (1)
(b) (3) Regex post-check can only reject after generation (may fail every time, wasting calls) and can't guarantee syntactic validity for nested structures. (1) Constrained/grammar decoding masks the logits at each step so only tokens allowed by the grammar are sampled, making invalid JSON impossible by construction. (1) Library: Outlines / Guidance / JSON-schema constrained decoding / GBNF (llama.cpp). (1)
(c) (2) Risk: prompt injection — malicious content in a tool result/webpage can hijack the agent into calling dangerous tools (data exfiltration, file deletion). (1) Mitigation: least-privilege tool permissions / human-in-the-loop confirmation / sandboxing / treating tool output as untrusted. (1)
[
{"claim": "Q4b total tokens = 15000", "code": "b,k,c,n=500,5,200,10; result = (n*(b+k*c))==15000"},
{"claim": "Q4c compressed total = 13000", "code": "s,k,c,n=300,5,200,10; result = (n*(s+k*c))==13000"},
{"claim": "Q5b success rate 0.7 and precision 0.8", "code": "result = (Rational(14,20)==Rational(7,10)) and (Rational(40,50)==Rational(4,5))"},
{"claim": "Q3b parallel rounds = 4 (longest chain length)", "code": "chain=4; result = chain==4"}
]