Repository navigation
LangChain Agents 2 · Tools, routing, and the failure you have to handle #10
Replies: 10 comments
from typing import Any, List
from langchain_core.language_models.chat_models import BaseChatModel
from langchain_core.messages import AIMessage
from langchain_core.outputs import ChatResult, ChatGeneration
from langchain.agents import create_agent
from langchain.tools import tool
class ScriptedChatModel(BaseChatModel):
'''Deterministic stand-in. Real framework, scripted replies, no credentials.'''
responses: List[Any]
idx: int = 0
@property
def _llm_type(self) -> str:
return "scripted"
def _generate(self, messages, stop=None, run_manager=None, **kwargs):
reply = self.responses[min(self.idx, len(self.responses) - 1)]
object.__setattr__(self, "idx", self.idx + 1)
return ChatResult(generations=[ChatGeneration(message=reply)])
def bind_tools(self, tools, **kwargs):
return self
@tool
def lookup_pnr(pnr: str) -> str:
'''Return the booking status for a PNR.'''
return {"JX48Q2": "BLR-DEL cancelled, Rao, Gold tier"}.get(pnr, "PNR not found")
@tool
def search_flights(origin: str, dest: str) -> str:
'''Find alternate flights between two airport codes.'''
return "AI-506 09:40, AI-812 14:15"
# Grounded answer: lookup, then search, then reply. Three model turns.
agent = create_agent(
ScriptedChatModel(responses=[
AIMessage(content="", tool_calls=[{"name": "lookup_pnr", "args": {"pnr": "JX48Q2"}, "id": "a", "type": "tool_call"}]),
AIMessage(content="", tool_calls=[{"name": "search_flights", "args": {"origin": "BLR", "dest": "DEL"}, "id": "b", "type": "tool_call"}]),
AIMessage(content="Cancelled. Options: AI-506 09:40 or AI-812 14:15."),
]),
tools=[lookup_pnr, search_flights],
system_prompt="You are TravelMind.",
)
print(agent.invoke({"messages": [{"role": "user", "content": "JX48Q2 cancelled, options?"}]})["messages"][-1].content)
# Bad PNR: the tool returns a clean error, the model recovers instead of crashing.
recover = create_agent(
ScriptedChatModel(responses=[
AIMessage(content="", tool_calls=[{"name": "lookup_pnr", "args": {"pnr": "ZZZZZZ"}, "id": "e", "type": "tool_call"}]),
AIMessage(content="I could not find booking ZZZZZZ. Please recheck the PNR."),
]),
tools=[lookup_pnr],
system_prompt="You are TravelMind.",
)
print(recover.invoke({"messages": [{"role": "user", "content": "check ZZZZZZ"}]})["messages"][-1].content) |
|
Q1. B |
|
Q1 :B |
|
Q1 B |
|
1.B |
|
Q1 -- B Q5 -- C Q12 --- A, C, D |
<style>
</style>
|
|
B |
|
Q1 - B |
|
1 :B |
Uh oh!
There was an error while loading. Please reload this page.
LangChain Agents · Exercise 2
Language: Python Topics: tools with @tool, the schema the model reads, tool selection by docstring, multi-tool loops, tool errors Level: Foundational to Applied
Answers are letters, pairs like
1-C,T/F, or a sequence. Still reading code, not writing it.Q1 · (2 pts) When the model decides whether to call
lookup_pnr, it reads:Q2 · Dead on arrival (2 pts) Copied from a 2023 blog. Which import no longer belongs in LangChain 1.0?
from langchain.agents import create_agentfrom langchain.agents import AgentExecutorfrom langchain.tools import toolfrom langgraph.graph import StateGraphQ3 · Read the tool, match the schema (4 pts)
{"flight": {"type": "string"}}disruption_reasonReturn why a flight was cancelled or delayed, given its flight number.Q4 · Code walkthrough, match line to role (4 pts)
Q5 · Trace the two-tool flow (3 pts)
flowchart TD U[cancelled, JX48Q2, options?] --> M1[model] M1 -->|call lookup_pnr| T1[booking record] T1 --> M2[model] M2 -->|call search_flights| T2[two flights] T2 --> M3[model] M3 --> A[final answer]How many times does the model node run before the final answer?
Q6 · One step is out of order (3 pts) This flow searches before it knows the booking.
flowchart TD U[cancelled, JX48Q2, options?] -->|a| M1[model] M1 -->|b call search_flights| T2[two flights] T2 -->|c| M2[model] M2 -->|d call lookup_pnr| T1[booking record]Which tagged edge is the problem?
aB)bC)cD)dQ7 · Order the trace (3 pts) The model calls
lookup_pnr, then answers. Order the four messages.AIMessagerequestinglookup_pnrHumanMessagewith the questionAIMessagewith the grounded answerToolMessagewith the booking recordQ8 · Predict the output (3 pts)
Assume
lookup_pnrreturns"PNR not found"for unknown PNRs. The printout is:PNR not foundI could not find booking ZZZZZZ. Please recheck the PNR.Q9 · Spot the risky line (3 pts)
Which line most weakens the model's ability to pick this tool correctly?
Q10 · Pick the flow that grounds its answer (2 pts)
Option A
flowchart LR U[is JX48Q2 cancelled?] --> M[model] --> A[answer from memory]Option B
flowchart LR U[is JX48Q2 cancelled?] --> M[model] --> T[lookup_pnr] --> M2[model] --> A[answer from the record]Q11 · Match across frameworks (4 pts)
@toolon a functioncreate_agent(model, tools=[...], system_prompt=)Agent(model=, tools=[...])@toolon a functionstr(agent("..."))result["messages"][-1].contentafterinvokeresponse_format=ModelQ12 · Pick all that apply (3 pts) A good tool description:
Case study · Two tools, one wrong pick (5 pts)
Two tools ship together. A user types "sort out my booking."
flowchart TD U[sort out my booking] --> M{model picks a tool} M --> C[cancel_booking: permanently cancel, start a refund, irreversible] M --> H[handle: handle the booking]Q13a (2 pts) Which tool is the model most likely to misfire on?
cancel_booking, its description is too detailedhandle, its description says nothing about what it doesQ13b (3 pts) The safest fix:
cancel_bookinghandlea precise description of exactly what it doeshandletohandle2Q14 · Pick the docstring that steers the model right (3 pts) For a
search_flights(origin, dest, date)tool:'''search''''''does flight stuff''''''Find alternate flights between two airport codes on a given date.''''''flights table'''All reactions