Skip to content

Commit 9315e8c

Browse files
jeremymanningclaude
andcommitted
Replace SemanticScholarTool with WikipediaTool in notebook
Semantic Scholar API was rate-limiting (429 errors) during demos. Wikipedia API is free, reliable, and needs no authentication — much better for a classroom notebook. Updated all references: Part 2 custom tool, Part 3 comparison, exercise suggestions, and summary table. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 58172c2 commit 9315e8c

1 file changed

Lines changed: 7 additions & 165 deletions

File tree

slides/week9/agents_demo.ipynb

Lines changed: 7 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -127,116 +127,26 @@
127127
{
128128
"cell_type": "markdown",
129129
"metadata": {},
130-
"source": [
131-
"---\n",
132-
"\n",
133-
"## Part 2: Custom tools\n",
134-
"\n",
135-
"The real power of agents comes from giving them **custom tools**. A tool is just a Python function with a description that tells the LLM when and how to use it.\n",
136-
"\n",
137-
"Let's build a tool that looks up papers on the [Semantic Scholar](https://www.semanticscholar.org/) API — a real academic search engine."
138-
]
130+
"source": "---\n\n## Part 2: Custom tools\n\nThe real power of agents comes from giving them **custom tools**. A tool is just a Python function with a description that tells the LLM when and how to use it.\n\nLet's build a tool that looks up articles on [Wikipedia](https://en.wikipedia.org/) — using their free, public API."
139131
},
140132
{
141133
"cell_type": "code",
142134
"execution_count": null,
143135
"metadata": {},
144136
"outputs": [],
145-
"source": [
146-
"from smolagents import Tool\n",
147-
"import requests\n",
148-
"\n",
149-
"\n",
150-
"class SemanticScholarTool(Tool):\n",
151-
" \"\"\"Search for academic papers using the Semantic Scholar API.\"\"\"\n",
152-
" name = \"paper_search\"\n",
153-
" description = (\n",
154-
" \"Search for academic research papers by topic. Returns titles, authors, \"\n",
155-
" \"year, citation count, and a URL for each paper. Use this when you need \"\n",
156-
" \"to find scientific literature or verify academic claims.\"\n",
157-
" )\n",
158-
" inputs = {\n",
159-
" \"query\": {\n",
160-
" \"type\": \"string\",\n",
161-
" \"description\": \"The search query (e.g., 'chain of thought prompting')\"\n",
162-
" },\n",
163-
" \"max_results\": {\n",
164-
" \"type\": \"integer\",\n",
165-
" \"description\": \"Maximum number of papers to return (default: 5)\",\n",
166-
" \"nullable\": True\n",
167-
" }\n",
168-
" }\n",
169-
" output_type = \"string\"\n",
170-
"\n",
171-
" def forward(self, query: str, max_results: int = 5) -> str:\n",
172-
" url = \"https://api.semanticscholar.org/graph/v1/paper/search\"\n",
173-
" params = {\n",
174-
" \"query\": query,\n",
175-
" \"limit\": min(max_results or 5, 10),\n",
176-
" \"fields\": \"title,authors,year,citationCount,url\"\n",
177-
" }\n",
178-
" try:\n",
179-
" resp = requests.get(url, params=params, timeout=10)\n",
180-
" resp.raise_for_status()\n",
181-
" data = resp.json()\n",
182-
" except Exception as e:\n",
183-
" return f\"Error searching papers: {e}\"\n",
184-
"\n",
185-
" papers = data.get(\"data\", [])\n",
186-
" if not papers:\n",
187-
" return \"No papers found for this query.\"\n",
188-
"\n",
189-
" results = []\n",
190-
" for p in papers:\n",
191-
" authors = \", \".join(a[\"name\"] for a in (p.get(\"authors\") or [])[:3])\n",
192-
" if len(p.get(\"authors\", [])) > 3:\n",
193-
" authors += \" et al.\"\n",
194-
" results.append(\n",
195-
" f\"- **{p['title']}** ({p.get('year', '?')})\\n\"\n",
196-
" f\" Authors: {authors}\\n\"\n",
197-
" f\" Citations: {p.get('citationCount', '?')} | \"\n",
198-
" f\"URL: {p.get('url', 'N/A')}\"\n",
199-
" )\n",
200-
" return \"\\n\\n\".join(results)\n",
201-
"\n",
202-
"\n",
203-
"# Test the tool directly (before giving it to an agent)\n",
204-
"paper_tool = SemanticScholarTool()\n",
205-
"print(paper_tool.forward(\"ReAct reasoning acting language models\", max_results=3))"
206-
]
137+
"source": "from smolagents import Tool\nimport requests\n\n\nclass WikipediaTool(Tool):\n \"\"\"Look up a topic on Wikipedia and return a summary.\"\"\"\n name = \"wiki_lookup\"\n description = (\n \"Look up a topic on Wikipedia and return a concise summary. Use this \"\n \"when you need factual background information about a person, place, \"\n \"concept, or event. Returns the article title, a summary, and a URL.\"\n )\n inputs = {\n \"query\": {\n \"type\": \"string\",\n \"description\": \"The topic to search for (e.g., 'chain of thought prompting')\"\n }\n }\n output_type = \"string\"\n\n def forward(self, query: str) -> str:\n # Step 1: Search for matching articles\n search_url = \"https://en.wikipedia.org/w/api.php\"\n search_params = {\n \"action\": \"query\",\n \"list\": \"search\",\n \"srsearch\": query,\n \"srlimit\": 3,\n \"format\": \"json\"\n }\n try:\n resp = requests.get(search_url, params=search_params, timeout=10)\n resp.raise_for_status()\n results = resp.json()[\"query\"][\"search\"]\n except Exception as e:\n return f\"Error searching Wikipedia: {e}\"\n\n if not results:\n return f\"No Wikipedia articles found for '{query}'.\"\n\n # Step 2: Get the summary of the top result\n title = results[0][\"title\"]\n summary_url = f\"https://en.wikipedia.org/api/rest_v1/page/summary/{requests.utils.quote(title)}\"\n try:\n resp = requests.get(summary_url, timeout=10)\n resp.raise_for_status()\n data = resp.json()\n except Exception as e:\n return f\"Error fetching summary for '{title}': {e}\"\n\n extract = data.get(\"extract\", \"No summary available.\")\n page_url = data.get(\"content_urls\", {}).get(\"desktop\", {}).get(\"page\", \"N/A\")\n\n return (\n f\"**{data.get('title', title)}**\\n\\n\"\n f\"{extract}\\n\\n\"\n f\"Read more: {page_url}\"\n )\n\n\n# Test the tool directly (before giving it to an agent)\nwiki_tool = WikipediaTool()\nprint(wiki_tool.forward(\"ReAct framework language models\"))"
207138
},
208139
{
209140
"cell_type": "code",
210141
"execution_count": null,
211142
"metadata": {},
212143
"outputs": [],
213-
"source": [
214-
"# Now give the agent BOTH tools: web search AND paper search\n",
215-
"research_agent = CodeAgent(\n",
216-
" tools=[search_tool, paper_tool],\n",
217-
" model=model,\n",
218-
" max_steps=6,\n",
219-
" verbosity_level=2\n",
220-
")\n",
221-
"\n",
222-
"result = research_agent.run(\n",
223-
" \"Find the most cited paper on chain-of-thought prompting. \"\n",
224-
" \"Who are the authors and how many citations does it have?\"\n",
225-
")\n",
226-
"print(f\"\\nFinal answer: {result}\")"
227-
]
144+
"source": "# Now give the agent BOTH tools: web search AND Wikipedia lookup\nresearch_agent = CodeAgent(\n tools=[search_tool, wiki_tool],\n model=model,\n max_steps=6,\n verbosity_level=2\n)\n\nresult = research_agent.run(\n \"What is chain-of-thought prompting? Look it up on Wikipedia, \"\n \"then search the web for who invented it.\"\n)\nprint(f\"\\nFinal answer: {result}\")"
228145
},
229146
{
230147
"cell_type": "markdown",
231148
"metadata": {},
232-
"source": [
233-
"### 💡 Discussion\n",
234-
"\n",
235-
"- The agent had two tools available. How did it decide which one to use?\n",
236-
"- Look at the tool `description` field. How does this influence the agent's behavior?\n",
237-
"- What would happen if two tools had very similar descriptions?\n",
238-
"- Try changing the description to something vague. Does the agent still pick the right tool?"
239-
]
149+
"source": "### 💡 Discussion\n\n- The agent had two tools available. How did it decide which one to use?\n- Look at the tool `description` field. How does this influence the agent's behavior?\n- What would happen if two tools had very similar descriptions?\n- Try changing the description to something vague — like `\"Does stuff\"`. Does the agent still pick the right tool?"
240150
},
241151
{
242152
"cell_type": "markdown",
@@ -263,36 +173,7 @@
263173
"execution_count": null,
264174
"metadata": {},
265175
"outputs": [],
266-
"source": [
267-
"from smolagents import ToolCallingAgent\n",
268-
"\n",
269-
"# Same model, same tools — different agent type\n",
270-
"tool_calling_agent = ToolCallingAgent(\n",
271-
" tools=[search_tool, paper_tool],\n",
272-
" model=model,\n",
273-
" max_steps=6,\n",
274-
" verbosity_level=2\n",
275-
")\n",
276-
"\n",
277-
"# Ask both agents the same question\n",
278-
"question = \"What is MCP (Model Context Protocol) and who created it?\"\n",
279-
"\n",
280-
"print(\"=\" * 60)\n",
281-
"print(\"CODE AGENT\")\n",
282-
"print(\"=\" * 60)\n",
283-
"code_result = agent.run(question)\n",
284-
"\n",
285-
"print(\"\\n\" + \"=\" * 60)\n",
286-
"print(\"TOOL-CALLING AGENT\")\n",
287-
"print(\"=\" * 60)\n",
288-
"tc_result = tool_calling_agent.run(question)\n",
289-
"\n",
290-
"print(\"\\n\" + \"=\" * 60)\n",
291-
"print(\"COMPARISON\")\n",
292-
"print(\"=\" * 60)\n",
293-
"print(f\"Code agent answer: {code_result}\")\n",
294-
"print(f\"Tool-calling agent answer: {tc_result}\")"
295-
]
176+
"source": "from smolagents import ToolCallingAgent\n\n# Same model, same tools — different agent type\ntool_calling_agent = ToolCallingAgent(\n tools=[search_tool, wiki_tool],\n model=model,\n max_steps=6,\n verbosity_level=2\n)\n\n# Ask both agents the same question\nquestion = \"What is MCP (Model Context Protocol) and who created it?\"\n\nprint(\"=\" * 60)\nprint(\"CODE AGENT\")\nprint(\"=\" * 60)\ncode_result = agent.run(question)\n\nprint(\"\\n\" + \"=\" * 60)\nprint(\"TOOL-CALLING AGENT\")\nprint(\"=\" * 60)\ntc_result = tool_calling_agent.run(question)\n\nprint(\"\\n\" + \"=\" * 60)\nprint(\"COMPARISON\")\nprint(\"=\" * 60)\nprint(f\"Code agent answer: {code_result}\")\nprint(f\"Tool-calling agent answer: {tc_result}\")"
296177
},
297178
{
298179
"cell_type": "markdown",
@@ -608,20 +489,7 @@
608489
{
609490
"cell_type": "markdown",
610491
"metadata": {},
611-
"source": [
612-
"---\n",
613-
"\n",
614-
"## Part 6: Build your own agent (exercise)\n",
615-
"\n",
616-
"Now it's your turn! Create a custom tool and use it in an agent. Here are some ideas:\n",
617-
"\n",
618-
"1. **Wikipedia lookup tool** — Use the Wikipedia API to fetch article summaries\n",
619-
"2. **Unit converter** — Convert between metric and imperial units\n",
620-
"3. **Sentiment analyzer** — Analyze the sentiment of text passages\n",
621-
"4. **Course schedule tool** — Look up when classes meet\n",
622-
"\n",
623-
"Use the `SemanticScholarTool` above as a template."
624-
]
492+
"source": "---\n\n## Part 6: Build your own agent (exercise)\n\nNow it's your turn! Create a custom tool and use it in an agent. Here are some ideas:\n\n1. **Weather tool** — Use the [Open-Meteo API](https://open-meteo.com/) (free, no key) to get current weather for a city\n2. **Unit converter** — Convert between metric and imperial units\n3. **Sentiment analyzer** — Analyze the sentiment of text passages\n4. **Course schedule tool** — Look up when classes meet\n\nUse the `WikipediaTool` above as a template."
625493
},
626494
{
627495
"cell_type": "code",
@@ -654,33 +522,7 @@
654522
{
655523
"cell_type": "markdown",
656524
"metadata": {},
657-
"source": [
658-
"---\n",
659-
"\n",
660-
"## Summary\n",
661-
"\n",
662-
"| Concept | What we built | Key takeaway |\n",
663-
"|---------|--------------|-------------|\n",
664-
"| **ReAct loop** | Agent with web search | LLMs can reason step-by-step, calling tools as needed |\n",
665-
"| **Custom tools** | Semantic Scholar search | Tools are just functions with good descriptions |\n",
666-
"| **Code vs. tool-calling** | Compared both paradigms | Code agents are flexible but riskier; tool-calling is safer |\n",
667-
"| **RAG agent** | Knowledge base search | Agents can ground answers in authoritative sources |\n",
668-
"| **Safety** | Injection demo, step limits | Autonomy must be matched to stakes (lecture principle) |\n",
669-
"\n",
670-
"## Connections to the lecture\n",
671-
"\n",
672-
"- **Slide 5 (ReAct)**: You saw the Thought → Action → Observation loop in action\n",
673-
"- **Slide 7 (MCP)**: Our tools follow the same pattern as MCP — structured descriptions that any model can use\n",
674-
"- **Slide 8 (SWE-bench)**: Real coding agents use the same loop, just with more powerful tools\n",
675-
"- **Slides 14–16 (Safety)**: We demonstrated prompt injection, step limits, and the trust boundary\n",
676-
"\n",
677-
"## Further exploration\n",
678-
"\n",
679-
"- [**smolagents documentation**](https://huggingface.co/docs/smolagents/index) — Full guide to building agents\n",
680-
"- [**HuggingFace Agents Course**](https://huggingface.co/learn/agents-course) — Free course on building AI agents\n",
681-
"- [**LangChain**](https://www.langchain.com/) — The most popular agent framework (more complex, more features)\n",
682-
"- [**Yao et al. (2023)**](https://arxiv.org/abs/2210.03629) — The original ReAct paper"
683-
]
525+
"source": "---\n\n## Summary\n\n| Concept | What we built | Key takeaway |\n|---------|--------------|-------------|\n| **ReAct loop** | Agent with web search | LLMs can reason step-by-step, calling tools as needed |\n| **Custom tools** | Wikipedia lookup | Tools are just functions with good descriptions |\n| **Code vs. tool-calling** | Compared both paradigms | Code agents are flexible but riskier; tool-calling is safer |\n| **RAG agent** | Knowledge base search | Agents can ground answers in authoritative sources |\n| **Safety** | Injection demo, step limits | Autonomy must be matched to stakes (lecture principle) |\n\n## Connections to the lecture\n\n- **Slide 5 (ReAct)**: You saw the Thought → Action → Observation loop in action\n- **Slide 7 (MCP)**: Our tools follow the same pattern as MCP — structured descriptions that any model can use\n- **Slide 8 (SWE-bench)**: Real coding agents use the same loop, just with more powerful tools\n- **Slides 14–16 (Safety)**: We demonstrated prompt injection, step limits, and the trust boundary\n\n## Further exploration\n\n- [**smolagents documentation**](https://huggingface.co/docs/smolagents/index) — Full guide to building agents\n- [**HuggingFace Agents Course**](https://huggingface.co/learn/agents-course) — Free course on building AI agents\n- [**LangChain**](https://www.langchain.com/) — The most popular agent framework (more complex, more features)\n- [**Yao et al. (2023)**](https://arxiv.org/abs/2210.03629) — The original ReAct paper"
684526
}
685527
],
686528
"metadata": {

0 commit comments

Comments
 (0)