|
127 | 127 | { |
128 | 128 | "cell_type": "markdown", |
129 | 129 | "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." |
139 | 131 | }, |
140 | 132 | { |
141 | 133 | "cell_type": "code", |
142 | 134 | "execution_count": null, |
143 | 135 | "metadata": {}, |
144 | 136 | "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\"))" |
207 | 138 | }, |
208 | 139 | { |
209 | 140 | "cell_type": "code", |
210 | 141 | "execution_count": null, |
211 | 142 | "metadata": {}, |
212 | 143 | "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}\")" |
228 | 145 | }, |
229 | 146 | { |
230 | 147 | "cell_type": "markdown", |
231 | 148 | "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?" |
240 | 150 | }, |
241 | 151 | { |
242 | 152 | "cell_type": "markdown", |
|
263 | 173 | "execution_count": null, |
264 | 174 | "metadata": {}, |
265 | 175 | "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}\")" |
296 | 177 | }, |
297 | 178 | { |
298 | 179 | "cell_type": "markdown", |
|
608 | 489 | { |
609 | 490 | "cell_type": "markdown", |
610 | 491 | "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." |
625 | 493 | }, |
626 | 494 | { |
627 | 495 | "cell_type": "code", |
|
654 | 522 | { |
655 | 523 | "cell_type": "markdown", |
656 | 524 | "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" |
684 | 526 | } |
685 | 527 | ], |
686 | 528 | "metadata": { |
|
0 commit comments