What is a Tool?
A Tool is a function or service that a language model can call to perform a specific task.
Instead of generating an answer solely from its training data, the model can use a tool to retrieve information, perform calculations, interact with APIs, or execute code.
Simple definition:
A Tool is a function that extends the capabilities of a language model by allowing it to perform real-world tasks.
Why Do We Need Tools?
Large Language Models (LLMs) are excellent at understanding and generating text, but they have limitations:
- They may not know the latest news.
- They cannot perform precise calculations reliably.
- They cannot access private databases.
- They cannot send emails or interact with external applications by themselves.
Tools overcome these limitations by allowing the model to interact with external systems.
For example:
- Search the web for current information
- Perform mathematical calculations
- Query a SQL database
- Read a PDF document
- Call an external API
- Send an email
- Retrieve documents from a knowledge base
LangChain Tools β Complete TutorialΒΆ
Give your LLM superpowersΒΆ
LangChain: 1.3.6 | Python: 3.11.9
Prerequisite: Chains tutorial
What We’ll CoverΒΆ
| # | Topic | Tools Covered |
|---|---|---|
| 1 | Why Tools? | The problem LLMs cannot solve alone |
| 2 | Custom Tools | @tool decorator β any Python function |
| 3 | Math & Data | Calculator, REPL, statistics, unit converter |
| 4 | Web & Search | DuckDuckGo, Wikipedia, web fetch |
| 5 | Datetime & Files | Dates, read/write files |
| 6 | Tools Inside Chains | Combine tools with LCEL |
| 7 | LLM Tool Calling | Let the LLM pick the right tool |
| 8 | Interesting Tools | Passwords, Morse code, readability + more |
| 9 | All Together | Full demo with 17 tools |
No extra API keys needed for most tools β DuckDuckGo, Wikipedia, Python REPL are all free.
SetupΒΆ
# !pip install langchain==1.3.6 langchain-openai==1.2.2 langchain-community==0.4.2 openai==2.54.0
!pip install duckduckgo-search==8.1.1 wikipedia==1.4.0 requests==2.34.2
Collecting duckduckgo-search==8.1.1 Downloading duckduckgo_search-8.1.1-py3-none-any.whl.metadata (16 kB) Collecting wikipedia Downloading wikipedia-1.4.0.tar.gz (27 kB) Installing build dependencies: started Installing build dependencies: finished with status 'done' Getting requirements to build wheel: started Getting requirements to build wheel: finished with status 'done' Preparing metadata (pyproject.toml): started Preparing metadata (pyproject.toml): finished with status 'done' Requirement already satisfied: requests==2.34.2 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (2.34.2) Requirement already satisfied: click>=8.1.8 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from duckduckgo-search==8.1.1) (8.5.0) Collecting primp>=0.15.0 (from duckduckgo-search==8.1.1) Downloading primp-2.0.0-cp310-abi3-win_amd64.whl.metadata (4.0 kB) Collecting lxml>=5.3.0 (from duckduckgo-search==8.1.1) Downloading lxml-6.1.3-cp311-cp311-win_amd64.whl.metadata (3.4 kB) Requirement already satisfied: charset_normalizer<4,>=2 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from requests==2.34.2) (3.5.1) Requirement already satisfied: idna<4,>=2.5 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from requests==2.34.2) (3.19) Requirement already satisfied: urllib3<3,>=1.26 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from requests==2.34.2) (2.7.0) Requirement already satisfied: certifi>=2023.5.7 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from requests==2.34.2) (2026.7.22) Requirement already satisfied: beautifulsoup4 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from wikipedia) (4.15.0) Requirement already satisfied: soupsieve>=1.6.1 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from beautifulsoup4->wikipedia) (2.9.2) Requirement already satisfied: typing-extensions>=4.0.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from beautifulsoup4->wikipedia) (4.16.0) Downloading duckduckgo_search-8.1.1-py3-none-any.whl (18 kB) Downloading lxml-6.1.3-cp311-cp311-win_amd64.whl (4.0 MB) ---------------------------------------- 0.0/4.0 MB ? eta -:--:-- --- ------------------------------------ 0.3/4.0 MB 9.9 MB/s eta 0:00:01 --- ------------------------------------ 0.3/4.0 MB 9.9 MB/s eta 0:00:01 --- ------------------------------------ 0.3/4.0 MB 9.9 MB/s eta 0:00:01 --- ------------------------------------ 0.3/4.0 MB 9.9 MB/s eta 0:00:01 --- ------------------------------------ 0.3/4.0 MB 9.9 MB/s eta 0:00:01 --- ------------------------------------ 0.3/4.0 MB 9.9 MB/s eta 0:00:01 ------- -------------------------------- 0.7/4.0 MB 2.2 MB/s eta 0:00:02 ----------- ---------------------------- 1.2/4.0 MB 3.1 MB/s eta 0:00:01 ---------------- ----------------------- 1.7/4.0 MB 3.9 MB/s eta 0:00:01 ------------------ --------------------- 1.9/4.0 MB 4.2 MB/s eta 0:00:01 ------------------ --------------------- 1.9/4.0 MB 4.2 MB/s eta 0:00:01 ------------------ --------------------- 1.9/4.0 MB 4.2 MB/s eta 0:00:01 ------------------ --------------------- 1.9/4.0 MB 4.2 MB/s eta 0:00:01 ------------------ --------------------- 1.9/4.0 MB 4.2 MB/s eta 0:00:01 ------------------ --------------------- 1.9/4.0 MB 4.2 MB/s eta 0:00:01 -------------------- ------------------- 2.1/4.0 MB 2.8 MB/s eta 0:00:01 -------------------- ------------------- 2.1/4.0 MB 2.8 MB/s eta 0:00:01 -------------------- ------------------- 2.1/4.0 MB 2.8 MB/s eta 0:00:01 -------------------- ------------------- 2.1/4.0 MB 2.8 MB/s eta 0:00:01 -------------------- ------------------- 2.1/4.0 MB 2.8 MB/s eta 0:00:01 --------------------- ------------------ 2.2/4.0 MB 2.2 MB/s eta 0:00:01 ----------------------- ---------------- 2.4/4.0 MB 2.3 MB/s eta 0:00:01 ------------------------ --------------- 2.5/4.0 MB 2.3 MB/s eta 0:00:01 ------------------------ --------------- 2.5/4.0 MB 2.3 MB/s eta 0:00:01 ------------------------ --------------- 2.5/4.0 MB 2.3 MB/s eta 0:00:01 ------------------------ --------------- 2.5/4.0 MB 2.3 MB/s eta 0:00:01 ------------------------ --------------- 2.5/4.0 MB 2.3 MB/s eta 0:00:01 ------------------------- -------------- 2.6/4.0 MB 1.9 MB/s eta 0:00:01 -------------------------- ------------- 2.7/4.0 MB 2.0 MB/s eta 0:00:01 -------------------------- ------------- 2.7/4.0 MB 2.0 MB/s eta 0:00:01 -------------------------- ------------- 2.7/4.0 MB 2.0 MB/s eta 0:00:01 -------------------------- ------------- 2.7/4.0 MB 2.0 MB/s eta 0:00:01 -------------------------- ------------- 2.7/4.0 MB 2.0 MB/s eta 0:00:01 --------------------------- ------------ 2.8/4.0 MB 1.7 MB/s eta 0:00:01 ----------------------------- ---------- 2.9/4.0 MB 1.8 MB/s eta 0:00:01 ------------------------------ --------- 3.1/4.0 MB 1.8 MB/s eta 0:00:01 ------------------------------ --------- 3.1/4.0 MB 1.8 MB/s eta 0:00:01 ------------------------------ --------- 3.1/4.0 MB 1.8 MB/s eta 0:00:01 ------------------------------ --------- 3.1/4.0 MB 1.8 MB/s eta 0:00:01 ------------------------------ --------- 3.1/4.0 MB 1.8 MB/s eta 0:00:01 ------------------------------- -------- 3.2/4.0 MB 1.6 MB/s eta 0:00:01 --------------------------------- ------ 3.4/4.0 MB 1.7 MB/s eta 0:00:01 --------------------------------- ------ 3.4/4.0 MB 1.7 MB/s eta 0:00:01 --------------------------------- ------ 3.4/4.0 MB 1.7 MB/s eta 0:00:01 --------------------------------- ------ 3.4/4.0 MB 1.7 MB/s eta 0:00:01 --------------------------------- ------ 3.4/4.0 MB 1.7 MB/s eta 0:00:01 --------------------------------- ------ 3.4/4.0 MB 1.7 MB/s eta 0:00:01 ---------------------------------- ----- 3.5/4.0 MB 1.6 MB/s eta 0:00:01 ------------------------------------ --- 3.7/4.0 MB 1.6 MB/s eta 0:00:01 --------------------------------------- 4.0/4.0 MB 1.7 MB/s eta 0:00:01 ---------------------------------------- 4.0/4.0 MB 1.7 MB/s eta 0:00:00 Downloading primp-2.0.0-cp310-abi3-win_amd64.whl (5.2 MB) ---------------------------------------- 0.0/5.2 MB ? eta -:--:-- ---------------------------------------- 0.0/5.2 MB ? eta -:--:-- ---------------------------------------- 0.0/5.2 MB ? eta -:--:-- ---------------------------------------- 0.0/5.2 MB ? eta -:--:-- ---------------------------------------- 0.0/5.2 MB ? eta -:--:-- ---------------------------------------- 0.0/5.2 MB ? eta -:--:-- - -------------------------------------- 0.2/5.2 MB 653.6 kB/s eta 0:00:08 -- ------------------------------------- 0.3/5.2 MB 1.0 MB/s eta 0:00:05 -- ------------------------------------- 0.3/5.2 MB 1.0 MB/s eta 0:00:05 -- ------------------------------------- 0.3/5.2 MB 1.0 MB/s eta 0:00:05 -- ------------------------------------- 0.3/5.2 MB 1.0 MB/s eta 0:00:05 -- ------------------------------------- 0.3/5.2 MB 1.0 MB/s eta 0:00:05 --- ------------------------------------ 0.4/5.2 MB 763.9 kB/s eta 0:00:07 ----- ---------------------------------- 0.7/5.2 MB 1.1 MB/s eta 0:00:05 ----- ---------------------------------- 0.7/5.2 MB 1.1 MB/s eta 0:00:05 ----- ---------------------------------- 0.7/5.2 MB 1.1 MB/s eta 0:00:05 ----- ---------------------------------- 0.7/5.2 MB 1.1 MB/s eta 0:00:05 ----- ---------------------------------- 0.7/5.2 MB 1.1 MB/s eta 0:00:05 ----- ---------------------------------- 0.7/5.2 MB 1.1 MB/s eta 0:00:05 ------ --------------------------------- 0.9/5.2 MB 988.4 kB/s eta 0:00:05 -------- ------------------------------- 1.2/5.2 MB 1.2 MB/s eta 0:00:04 ----------- ---------------------------- 1.5/5.2 MB 1.5 MB/s eta 0:00:03 -------------- ------------------------- 1.9/5.2 MB 1.8 MB/s eta 0:00:02 ------------------ --------------------- 2.4/5.2 MB 2.2 MB/s eta 0:00:02 --------------------- ------------------ 2.8/5.2 MB 2.5 MB/s eta 0:00:01 --------------------- ------------------ 2.8/5.2 MB 2.5 MB/s eta 0:00:01 --------------------- ------------------ 2.8/5.2 MB 2.5 MB/s eta 0:00:01 --------------------- ------------------ 2.8/5.2 MB 2.5 MB/s eta 0:00:01 --------------------- ------------------ 2.8/5.2 MB 2.5 MB/s eta 0:00:01 ---------------------- ----------------- 3.0/5.2 MB 2.1 MB/s eta 0:00:02 -------------------------- ------------- 3.4/5.2 MB 2.4 MB/s eta 0:00:01 -------------------------- ------------- 3.5/5.2 MB 2.4 MB/s eta 0:00:01 -------------------------- ------------- 3.5/5.2 MB 2.4 MB/s eta 0:00:01 -------------------------- ------------- 3.5/5.2 MB 2.4 MB/s eta 0:00:01 -------------------------- ------------- 3.5/5.2 MB 2.4 MB/s eta 0:00:01 -------------------------- ------------- 3.5/5.2 MB 2.4 MB/s eta 0:00:01 ---------------------------- ----------- 3.8/5.2 MB 2.2 MB/s eta 0:00:01 ------------------------------ --------- 4.0/5.2 MB 2.3 MB/s eta 0:00:01 ------------------------------ --------- 4.0/5.2 MB 2.3 MB/s eta 0:00:01 ------------------------------ --------- 4.0/5.2 MB 2.3 MB/s eta 0:00:01 ------------------------------ --------- 4.0/5.2 MB 2.3 MB/s eta 0:00:01 ------------------------------ --------- 4.0/5.2 MB 2.3 MB/s eta 0:00:01 ------------------------------ --------- 4.0/5.2 MB 2.0 MB/s eta 0:00:01 -------------------------------- ------- 4.2/5.2 MB 2.1 MB/s eta 0:00:01 ---------------------------------- ----- 4.5/5.2 MB 2.2 MB/s eta 0:00:01 ------------------------------------- -- 4.9/5.2 MB 2.3 MB/s eta 0:00:01 -------------------------------------- - 5.0/5.2 MB 2.3 MB/s eta 0:00:01 -------------------------------------- - 5.0/5.2 MB 2.3 MB/s eta 0:00:01 -------------------------------------- - 5.0/5.2 MB 2.3 MB/s eta 0:00:01 -------------------------------------- - 5.0/5.2 MB 2.3 MB/s eta 0:00:01 -------------------------------------- - 5.0/5.2 MB 2.3 MB/s eta 0:00:01 --------------------------------------- 5.2/5.2 MB 2.2 MB/s eta 0:00:01 ---------------------------------------- 5.2/5.2 MB 2.2 MB/s eta 0:00:00 Building wheels for collected packages: wikipedia Building wheel for wikipedia (pyproject.toml): started Building wheel for wikipedia (pyproject.toml): finished with status 'done' Created wheel for wikipedia: filename=wikipedia-1.4.0-py3-none-any.whl size=11785 sha256=7586d4b97b04d2c4ddba826834725ce7f606772f7beb49d76149685185f2272a Stored in directory: c:\users\ash32\appdata\local\pip\cache\wheels\8f\ab\cb\45ccc40522d3a1c41e1d2ad53b8f33a62f394011ec38cd71c6 Successfully built wikipedia Installing collected packages: primp, lxml, wikipedia, duckduckgo-search Successfully installed duckduckgo-search-8.1.1 lxml-6.1.3 primp-2.0.0 wikipedia-1.4.0
[notice] A new release of pip is available: 24.0 -> 26.2.1 [notice] To update, run: python.exe -m pip install --upgrade pip
pip install ddgs==9.16.0
Collecting ddgs Downloading ddgs-9.16.0-py3-none-any.whl.metadata (16 kB) Requirement already satisfied: click>=8.1.8 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from ddgs) (8.5.0) Requirement already satisfied: primp>=1.3.1 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from ddgs) (2.0.0) Requirement already satisfied: lxml>=4.9.4 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from ddgs) (6.1.3) Downloading ddgs-9.16.0-py3-none-any.whl (47 kB) ---------------------------------------- 0.0/47.6 kB ? eta -:--:-- ---------------------------------- ----- 41.0/47.6 kB 991.0 kB/s eta 0:00:01 ---------------------------------------- 47.6/47.6 kB 811.7 kB/s eta 0:00:00 Installing collected packages: ddgs Successfully installed ddgs-9.16.0 Note: you may need to restart the kernel to use updated packages.
[notice] A new release of pip is available: 24.0 -> 26.2.1 [notice] To update, run: python.exe -m pip install --upgrade pip
pip install langchain_tavily==0.2.18
Collecting langchain_tavily Downloading langchain_tavily-0.2.18-py3-none-any.whl.metadata (20 kB) Requirement already satisfied: aiohttp<4.0.0,>=3.11.14 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langchain_tavily) (3.14.3) Requirement already satisfied: langchain<2.0.0,>=1.0.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langchain_tavily) (1.3.6) Requirement already satisfied: langchain-core<2.0.0,>=1.2.11 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langchain_tavily) (1.6.2) Requirement already satisfied: requests<3.0.0,>=2.32.3 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langchain_tavily) (2.34.2) Requirement already satisfied: aiohappyeyeballs>=2.5.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from aiohttp<4.0.0,>=3.11.14->langchain_tavily) (2.7.1) Requirement already satisfied: aiosignal>=1.4.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from aiohttp<4.0.0,>=3.11.14->langchain_tavily) (1.4.0) Requirement already satisfied: attrs>=17.3.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from aiohttp<4.0.0,>=3.11.14->langchain_tavily) (26.1.0) Requirement already satisfied: frozenlist>=1.1.1 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from aiohttp<4.0.0,>=3.11.14->langchain_tavily) (1.8.0) Requirement already satisfied: multidict<7.0,>=4.5 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from aiohttp<4.0.0,>=3.11.14->langchain_tavily) (6.7.1) Requirement already satisfied: propcache>=0.2.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from aiohttp<4.0.0,>=3.11.14->langchain_tavily) (0.5.2) Requirement already satisfied: typing_extensions>=4.4 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from aiohttp<4.0.0,>=3.11.14->langchain_tavily) (4.16.0) Requirement already satisfied: yarl<2.0,>=1.17.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from aiohttp<4.0.0,>=3.11.14->langchain_tavily) (1.24.5) Requirement already satisfied: langgraph<1.3.0,>=1.2.4 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langchain<2.0.0,>=1.0.0->langchain_tavily) (1.2.11) Requirement already satisfied: pydantic<3.0.0,>=2.7.4 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langchain<2.0.0,>=1.0.0->langchain_tavily) (2.13.5) Requirement already satisfied: httpx<1.0.0,>=0.23.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langchain-core<2.0.0,>=1.2.11->langchain_tavily) (0.28.1) Requirement already satisfied: jsonpatch<2.0.0,>=1.33.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langchain-core<2.0.0,>=1.2.11->langchain_tavily) (1.33) Requirement already satisfied: langchain-protocol>=0.0.17 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langchain-core<2.0.0,>=1.2.11->langchain_tavily) (0.0.19) Requirement already satisfied: langsmith<1.0.0,>=0.3.45 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langchain-core<2.0.0,>=1.2.11->langchain_tavily) (0.12.1) Requirement already satisfied: packaging>=23.2.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langchain-core<2.0.0,>=1.2.11->langchain_tavily) (26.3) Requirement already satisfied: pyyaml<7.0.0,>=5.3.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langchain-core<2.0.0,>=1.2.11->langchain_tavily) (6.0.3) Requirement already satisfied: tenacity!=8.4.0,<10.0.0,>=8.1.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langchain-core<2.0.0,>=1.2.11->langchain_tavily) (9.1.4) Requirement already satisfied: uuid-utils<1.0,>=0.12.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langchain-core<2.0.0,>=1.2.11->langchain_tavily) (0.17.0) Requirement already satisfied: charset_normalizer<4,>=2 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from requests<3.0.0,>=2.32.3->langchain_tavily) (3.5.1) Requirement already satisfied: idna<4,>=2.5 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from requests<3.0.0,>=2.32.3->langchain_tavily) (3.19) Requirement already satisfied: urllib3<3,>=1.26 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from requests<3.0.0,>=2.32.3->langchain_tavily) (2.7.0) Requirement already satisfied: certifi>=2023.5.7 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from requests<3.0.0,>=2.32.3->langchain_tavily) (2026.7.22) Requirement already satisfied: anyio in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from httpx<1.0.0,>=0.23.0->langchain-core<2.0.0,>=1.2.11->langchain_tavily) (4.15.1) Requirement already satisfied: httpcore==1.* in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from httpx<1.0.0,>=0.23.0->langchain-core<2.0.0,>=1.2.11->langchain_tavily) (1.0.9) Requirement already satisfied: h11>=0.16 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from httpcore==1.*->httpx<1.0.0,>=0.23.0->langchain-core<2.0.0,>=1.2.11->langchain_tavily) (0.16.0) Requirement already satisfied: jsonpointer>=1.9 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from jsonpatch<2.0.0,>=1.33.0->langchain-core<2.0.0,>=1.2.11->langchain_tavily) (3.1.1) Requirement already satisfied: langgraph-checkpoint<5.0.0,>=4.1.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langgraph<1.3.0,>=1.2.4->langchain<2.0.0,>=1.0.0->langchain_tavily) (4.2.0) Requirement already satisfied: langgraph-prebuilt<1.2.0,>=1.1.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langgraph<1.3.0,>=1.2.4->langchain<2.0.0,>=1.0.0->langchain_tavily) (1.1.0) Requirement already satisfied: langgraph-sdk<0.5.0,>=0.4.2 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langgraph<1.3.0,>=1.2.4->langchain<2.0.0,>=1.0.0->langchain_tavily) (0.4.4) Requirement already satisfied: xxhash>=3.5.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langgraph<1.3.0,>=1.2.4->langchain<2.0.0,>=1.0.0->langchain_tavily) (4.0.1) Requirement already satisfied: distro>=1.7.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langsmith<1.0.0,>=0.3.45->langchain-core<2.0.0,>=1.2.11->langchain_tavily) (1.9.0) Requirement already satisfied: httpx2<3,>=2 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langsmith<1.0.0,>=0.3.45->langchain-core<2.0.0,>=1.2.11->langchain_tavily) (2.12.0) Requirement already satisfied: orjson>=3.9.14 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langsmith<1.0.0,>=0.3.45->langchain-core<2.0.0,>=1.2.11->langchain_tavily) (3.12.0) Requirement already satisfied: requests-toolbelt>=1.0.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langsmith<1.0.0,>=0.3.45->langchain-core<2.0.0,>=1.2.11->langchain_tavily) (1.0.0) Requirement already satisfied: sniffio>=1.1 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langsmith<1.0.0,>=0.3.45->langchain-core<2.0.0,>=1.2.11->langchain_tavily) (1.3.1) Requirement already satisfied: websockets>=15.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langsmith<1.0.0,>=0.3.45->langchain-core<2.0.0,>=1.2.11->langchain_tavily) (16.1.1) Requirement already satisfied: zstandard>=0.23.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langsmith<1.0.0,>=0.3.45->langchain-core<2.0.0,>=1.2.11->langchain_tavily) (0.25.0) Requirement already satisfied: annotated-types>=0.6.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from pydantic<3.0.0,>=2.7.4->langchain<2.0.0,>=1.0.0->langchain_tavily) (0.8.0) Requirement already satisfied: pydantic-core==2.46.5 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from pydantic<3.0.0,>=2.7.4->langchain<2.0.0,>=1.0.0->langchain_tavily) (2.46.5) Requirement already satisfied: typing-inspection>=0.4.2 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from pydantic<3.0.0,>=2.7.4->langchain<2.0.0,>=1.0.0->langchain_tavily) (0.4.4) Requirement already satisfied: httpcore2==2.12.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from httpx2<3,>=2->langsmith<1.0.0,>=0.3.45->langchain-core<2.0.0,>=1.2.11->langchain_tavily) (2.12.0) Requirement already satisfied: truststore>=0.10 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from httpx2<3,>=2->langsmith<1.0.0,>=0.3.45->langchain-core<2.0.0,>=1.2.11->langchain_tavily) (0.10.4) Requirement already satisfied: ormsgpack>=1.12.0 in c:\users\ash32\desktop\education\play_langchain_langgraph\.venv\lib\site-packages (from langgraph-checkpoint<5.0.0,>=4.1.0->langgraph<1.3.0,>=1.2.4->langchain<2.0.0,>=1.0.0->langchain_tavily) (1.12.2) Downloading langchain_tavily-0.2.18-py3-none-any.whl (30 kB) Installing collected packages: langchain_tavily Successfully installed langchain_tavily-0.2.18 Note: you may need to restart the kernel to use updated packages.
[notice] A new release of pip is available: 24.0 -> 26.2.1 [notice] To update, run: python.exe -m pip install --upgrade pip
import importlib.metadata
# List the distribution package names
packages = ["langchain", "langchain-community", "langchain-openai", "openai",
"langchain_core", "duckduckgo-search", "wikipedia", "requests",
"ddgs", "langchain_tavily"]
for package in packages:
try:
version = importlib.metadata.version(package)
print(f"{package} version: {version}")
except importlib.metadata.PackageNotFoundError:
print(f"{package} is not installed in this environment.")
# langchain version: 1.3.6
# langchain-community version: 0.4.2
# langchain-openai version: 1.2.2
# openai version: 2.54.0
# langchain_core version: 1.6.2
# duckduckgo-search version: 8.1.1
# wikipedia version: 1.4.0
# requests version: 2.34.2
# ddgs version: 9.16.0
# langchain_tavily version: 0.2.18
langchain version: 1.3.6 langchain-community version: 0.4.2 langchain-openai version: 1.2.2 openai version: 2.54.0 langchain_core version: 1.6.2 duckduckgo-search version: 8.1.1 wikipedia version: 1.4.0 requests version: 2.34.2 ddgs version: 9.16.0 langchain_tavily version: 0.2.18
import os
from dotenv import load_dotenv
load_dotenv() # read .env file
# TAVILY_API_KEY = os.getenv("TAVILY_API_KEY")
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
import os
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
llm = ChatOpenAI(api_key = OPENAI_API_KEY,
model="gpt-4o-mini",
temperature=0 # temperature=0 for tool use
)
response = llm.invoke("Confirm connection by replying with the word 'Active'")
print("\nConnection Successful!")
print(f"AI Response: '{response.content.strip()}'")
Connection Successful! AI Response: 'Active'
1οΈ) Why Do We Need Tools?ΒΆ
LLMs Are Smart But LimitedΒΆ
| LLM Can β | LLM Cannot β |
|---|---|
| Reason, explain, summarise | Know today’s news |
| Write, translate, code | Do precise arithmetic |
| Answer questions from training data | Access the internet |
| Understand context | Check current stock prices |
The GapΒΆ
llm.invoke('What is 2847 * 3921?')
# LLM might say: 11,162,487 -- WRONG! Correct: 11,155,287
llm.invoke('What is today\'s date?')
# LLM: 'I don\'t have access to real-time information...'
llm.invoke('What is the temperature in New Delhi ?')
# LLM: 'I don\'t have access to real-time information...'
Tools bridge this gap β they let the LLM call real code and real APIs.
How Tools WorkΒΆ
User: 'What is 2847 * 3921?'
β
LLM sees the question + available tools
β
LLM decides: 'I should use the calculator tool'
β
Tool runs: calculator('2847 * 3921') -> 11,155,287
β
LLM forms response: '2847 x 3921 = 11,155,287'
# Demonstrate the problem β LLMs are unreliable at arithmetic
response = llm.invoke('What is 2847 * 3921? Give just the number, no explanation.')
print('LLM answer: ', response.content)
print('Correct answer:', 2847 * 3921)
print('Match?', str(2847 * 3921) in response.content.replace(',',''))
LLM answer: 11,155,787 Correct answer: 11163087 Match? False
2οΈ Custom Tools β The @tool DecoratorΒΆ
The simplest way to create a tool: any Python function with @tool.
Three things the LLM uses:ΒΆ
- Function name β identifies the tool
- Docstring β LLM reads this to decide WHEN to use it
- Type hints β tells LangChain input/output types
@tool
def my_tool(input: str) -> str:
"""Describe WHAT this does and WHEN to use it.
The LLM reads this like instructions."""
return "result"
# Defining tool and printing its metadata
from langchain_core.tools import tool
# Simplest possible tool
@tool
def greet(name: str) -> str:
"""
Greet a person by name. Use when you need to say hello to someone.
"""
return f"Hello, {name}! Welcome to LangChain Tools! π"
print(greet.invoke({"name": "Priya"}))
print("--- Tool Metadata ---")
print("Name: ", greet.name)
print("Description:", greet.description)
print("Args schema:", greet.args)
Hello, Priya! Welcome to LangChain Tools! π
--- Tool Metadata ---
Name: greet
Description: Greet a person by name. Use when you need to say hello to someone.
Args schema: {'name': {'title': 'Name', 'type': 'string'}}
# Tool with multiple parameters
@tool
def calculate_bmi(weight_kg: float, height_m: float) -> str:
"""
Calculate Body Mass Index (BMI) given weight in kg and height in meters.
Use when someone asks about BMI or healthy weight range.
"""
bmi = weight_kg / (height_m ** 2)
if bmi < 18.5: category = 'Underweight'
elif bmi < 25: category = 'Normal weight'
elif bmi < 30: category = 'Overweight'
else: category = 'Obese'
return f"BMI: {bmi:.1f} β {category}"
print(calculate_bmi.invoke({"weight_kg": 70, "height_m": 1.75}))
print(calculate_bmi.invoke({"weight_kg": 50, "height_m": 1.70}))
BMI: 22.9 β Normal weight BMI: 17.3 β Underweight
# Tool with optional parameters
from typing import Optional
@tool
def format_currency(amount: float, currency: str = 'USD', decimals: int = 2) -> str:
"""
Format a number as currency. Defaults to USD with 2 decimal places.
Supports USD, EUR, GBP, INR, JPY. Use for any money formatting request.
"""
symbols = {'USD': '$', 'EUR': 'β¬', 'GBP': 'Β£', 'INR': 'βΉ', 'JPY': 'Β₯'}
symbol = symbols.get(currency.upper(), currency + ' ')
return f"{symbol}{amount:,.{decimals}f}"
print(format_currency.invoke({"amount": 1234567.89}))
print(format_currency.invoke({"amount": 9999.5, "currency": "INR"}))
print(format_currency.invoke({"amount": 500, "currency": "EUR", "decimals": 0}))
$1,234,567.89 βΉ9,999.50 β¬500
# Best practice demo: vague vs descriptive docstrings
# IMPORTANT: The docstring should be descriptive and helpful for an LLM agent to decide which tool
# to call
@tool
def bad_tool(x: str) -> str:
"""
Does stuff with input.
"""
return x
@tool
def word_counter(text: str) -> str:
"""
Count the number of words in a piece of text.
Use when asked 'how many words', 'word count', or the length of a text in words.
Input should be the full text string.
"""
count = len(text.split())
return f"The text contains {count} words."
print("Bad tool:", bad_tool.description)
print("-----------\n")
print("Good tool:", word_counter.description)
Bad tool: Does stuff with input. ----------- Good tool: Count the number of words in a piece of text. Use when asked 'how many words', 'word count', or the length of a text in words. Input should be the full text string.
3οΈ. Math & Data ToolsΒΆ
LLMs are notoriously unreliable at arithmetic. Always use a tool for calculations.
| Tool | Use case |
|---|---|
| Calculator | Safe math expression evaluation |
| Stats calculator | Mean, median, std dev etc. |
| Python REPL | Run arbitrary Python |
| Unit converter | Length, weight, temperature, speed |
import math
@tool
def calculator(expression: str) -> str:
"""
Evaluate a mathematical expression. Input must be valid Python math.
Supports: +, -, *, /, **, sqrt, sin, cos, log, pi, e.
Examples: '2847 * 3921', 'math.sqrt(144)', 'math.pi * 5**2'
ALWAYS use for any calculation instead of computing mentally.
"""
try:
allowed = {k: getattr(math, k) for k in dir(math) if not k.startswith('_')}
allowed['abs'] = abs
allowed['round'] = round
result = eval(expression, {"__builtins__": {}}, allowed)
return f"{expression} = {result}"
except Exception as e:
return f"Error evaluating '{expression}': {e}"
print(calculator.invoke({"expression": "2847 * 3921"}))
print(calculator.invoke({"expression": "math.sqrt(144)"}))
print(calculator.invoke({"expression": "math.pi * 7**2"}))
print(calculator.invoke({"expression": "math.log(1000, 10)"}))
print(calculator.invoke({"expression": "(15 + 27 + 33 + 42) / 4"}))
2847 * 3921 = 11163087 Error evaluating 'math.sqrt(144)': name 'math' is not defined Error evaluating 'math.pi * 7**2': name 'math' is not defined Error evaluating 'math.log(1000, 10)': name 'math' is not defined (15 + 27 + 33 + 42) / 4 = 29.25
import statistics
@tool
def stats_calculator(numbers: str) -> str:
"""
Calculate statistics for a list of numbers.
Input: comma-separated numbers like '10, 20, 30, 40, 50'
Returns: mean, median, std deviation, min, max, range.
"""
try:
nums = [float(x.strip()) for x in numbers.split(',')]
result = {
'count': len(nums),
'mean': round(statistics.mean(nums), 4),
'median': statistics.median(nums),
'std_dev': round(statistics.stdev(nums), 4) if len(nums) > 1 else 0,
'min': min(nums),
'max': max(nums),
'range': max(nums) - min(nums)
}
return "\n".join(f"{k}: {v}" for k, v in result.items())
except Exception as e:
return f"Error: {e}"
scores = "72, 85, 91, 68, 77, 95, 83, 79, 88, 64"
print("Exam Score Statistics:")
print(stats_calculator.invoke({"numbers": scores}))
Exam Score Statistics: count: 10 mean: 80.2 median: 81.0 std_dev: 10.0973 min: 64.0 max: 95.0 range: 31.0
# Python REPL Tool(Read-Eval-Print Loop) β run actual Python code using python
# Most powerful data tool β great for complex data manipulation
import sys
from io import StringIO
# Clean replacement β no extra packages needed
import sys
from io import StringIO
from langchain_core.tools import tool
@tool
def python_repl(code: str) -> str:
"""
Execute Python code and return the printed output.
Use for data manipulation, calculations, sorting, or any Python logic.
Input should be valid Python code as a string.
"""
old_stdout = sys.stdout
sys.stdout = StringIO()
try:
exec(code, {})
output = sys.stdout.getvalue()
except Exception as e:
output = f"Error: {e}"
finally:
sys.stdout = old_stdout
return output if output else "Code ran successfully (no output)"
# Same test β works identically
result = python_repl.invoke({"code": """
students = [
{"name": "Alice", "score": 85},
{"name": "Bob", "score": 72},
{"name": "Carol", "score": 91},
{"name": "Dave", "score": 68},
{"name": "Eve", "score": 95},
]
ranked = sorted(students, key=lambda x: x['score'], reverse=True)
print("=== CLASS RANKING ===")
for i, s in enumerate(ranked, 1):
grade = "A" if s["score"] >= 90 else "B" if s["score"] >= 80 else "C"
print(f"{i}. {s['name']:10s} {s['score']} Grade: {grade}")
avg = sum(s['score'] for s in students) / len(students)
print(f"\\nClass average: {avg:.1f}")
"""})
print(result)
=== CLASS RANKING === 1. Eve 95 Grade: A 2. Carol 91 Grade: A 3. Alice 85 Grade: B 4. Bob 72 Grade: C 5. Dave 68 Grade: C Class average: 82.2
Application of aboveΒΆ
- One agent can create a python and second agent can RUN the python code
@tool
def unit_converter(value: float, from_unit: str, to_unit: str) -> str:
"""
Convert between common units of measurement.
Supports length (km/miles/meters/feet/cm/inches),
weight (kg/pounds/grams), temperature (celsius/fahrenheit/kelvin),
volume (liters/gallons/ml), speed (kmh/mph).
Example: unit_converter(100, 'km', 'miles')
"""
conversions = {
('km','miles'): lambda x: x * 0.621371,
('miles','km'): lambda x: x * 1.60934,
('meters','feet'): lambda x: x * 3.28084,
('feet','meters'): lambda x: x * 0.3048,
('cm','inches'): lambda x: x * 0.393701,
('inches','cm'): lambda x: x * 2.54,
('kg','pounds'): lambda x: x * 2.20462,
('pounds','kg'): lambda x: x * 0.453592,
('celsius','fahrenheit'):lambda x: x * 9/5 + 32,
('fahrenheit','celsius'):lambda x: (x - 32) * 5/9,
('celsius','kelvin'): lambda x: x + 273.15,
('kelvin','celsius'): lambda x: x - 273.15,
('liters','gallons'): lambda x: x * 0.264172,
('gallons','liters'): lambda x: x * 3.78541,
('kmh','mph'): lambda x: x * 0.621371,
('mph','kmh'): lambda x: x * 1.60934,
}
key = (from_unit.lower(), to_unit.lower())
if key in conversions:
result = conversions[key](value)
return f"{value} {from_unit} = {result:.4f} {to_unit}"
return f"Conversion from {from_unit!r} to {to_unit!r} not supported."
print(unit_converter.invoke({"value": 100, "from_unit": "km", "to_unit": "miles"}))
print(unit_converter.invoke({"value": 37, "from_unit": "celsius", "to_unit": "fahrenheit"}))
print(unit_converter.invoke({"value": 70, "from_unit": "kg", "to_unit": "pounds"}))
print(unit_converter.invoke({"value": 120, "from_unit": "kmh", "to_unit": "mph"}))
100.0 km = 62.1371 miles 37.0 celsius = 98.6000 fahrenheit 70.0 kg = 154.3234 pounds 120.0 kmh = 74.5645 mph
4οΈ. Web & Search ToolsΒΆ
The most important category β these give LLMs access to current information. Your LLM training data has a cutoff date. Search tools fix that.
| Tool | Free? | Best for |
|---|---|---|
| DuckDuckGo Search | β Free | General web search |
| Wikipedia | β Free | Encyclopedic knowledge |
| Web Fetch (requests) | β Free | Read any webpage |
| Tavily Search | API key | High quality search results |
from langchain_community.tools import DuckDuckGoSearchRun, DuckDuckGoSearchResults
# Option A: plain text summary β easiest to use
search = DuckDuckGoSearchRun()
result = search.invoke("latest developments in quantum computing 2025")
print("=== DuckDuckGoSearchRun (plain text) ===")
print(result[:1200])
C:\Users\ash32\AppData\Local\Temp\ipykernel_4100\1986155536.py:1: DeprecationWarning: `langchain-community` is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration guidance toward standalone integration packages. from langchain_community.tools import DuckDuckGoSearchRun, DuckDuckGoSearchResults
=== DuckDuckGoSearchRun (plain text) === gartner.com has been visited by 10K+ users in the past month Meet with Technology Solution Providers and Get the Latest in Emerging Technologies. Don't miss the chance to connect with Tech enthusiasts, discover cutting-edge technologies Featured Topics, Emerging Technologies, CIO Network Programs and more Something remarkable has happened in quantum computing between 2024 and 2026. For years, the technology lived mostly in research labs, generating headlines but little real-world impact. That changed β fast. Aug 1, 2025 Β· Explore how quantum computing breakthroughs in 2025 are transforming industries, solving complex problems, and redefining global innovation. Aug 19, 2025 Β· Quantum computing is evolving into a tangible technology that holds significant business and commercial promise, although the exact timing of when it will impact those areas remains unclear, according to a new report led by researchers at the MIT Initiative on the Digital Economy. Nov 13, 2025 Β· The year isn't over yet, but we've already seen record-breaking quantum computers, skyrocketing levels of investment, and demonstrations of real-world benefits.
# Option B: structured results with title + URL + snippet
search_results = DuckDuckGoSearchResults(num_results=3)
results = search_results.invoke("Python programming news 2025")
print("=== DuckDuckGoSearchResults (structured) ===")
print(results[:1200])
=== DuckDuckGoSearchResults (structured) === snippet: Discover how Python is evolving in 2025 with new tools, frameworks, and trends shaping AI, data science, and API development., title: Top Python Trends in 2025 : Tools, Frameworks, and Innovations - Geeky ..., link: https://www.geeky-gadgets.com/modern-python-frameworks-fastapi-streamlit/, snippet: Python 3.14 was released on 7th October 2025. Here we summarise some of the more interesting changes and some trends in Python development and data-science over the past year. We will highlight the following: the colourful Python command-line interface; project-management tool uv; free-threading; and a brief summary of other developments. The Python 3.14 release notes also describe the changes ..., title: What's new for Python in 2025? - R-bloggers, link: https://www.r-bloggers.com/2025/10/whats-new-for-python-in-2025/, snippet: Python 3.14 is officially out, Python 3.15 begins, and Python 3.9 reaches end of life. Plus, Django 6.0 first beta released, new PEPs, and more Python news., title: Python 3.14 Released and Other Python News for November 2025, link: https://realpython.com/python-news-november-2025/
# Need api key from tavily
from langchain_tavily import TavilySearch
TAVILY_API_KEY = os.getenv("TAVILY_API_KEY")
tavily_search = TavilySearch(tavily_api_key=TAVILY_API_KEY)
extracted_info = tavily_search.run("What is recent development Agentic AI?")
extracted_info
{'query': 'What is recent development Agentic AI?',
'follow_up_questions': None,
'answer': None,
'images': [],
'results': [{'url': 'https://www.incredibuild.com/blog/agentic-ai-changing-software-development',
'title': 'How Agentic AI Is Changing Software Development',
'content': 'Agentic AI refers to AI systems that can act autonomously to achieve goals, without needing step-by-step instructions from humans.\n\nThis type of AI breaks down objectives into subtasks, makes decisions, adapts when things go off course.\n\nTo put it loosely: generative AI is like a really smart pen (you ask, it writes). Agentic AI is like a proactive project manager (you set the goal, it figures out how to get there). [...] A recent survey on βAI agentic programmingβ\\ covers exactly this: systems that decompose goals, use tool integration, monitor execution, and adapt.\n\nCI/CD Pipeline Optimization\n\nContinuous integration and continuous delivery can be noisy and brittle. Agentic AI could: [...] ## Key Takeaways\n\n Agentic AI is autonomous and goal-driven, able to plan and act without constant human prompts.\n Itβs reshaping software development through smarter onboarding, collaboration, coding, and testing.\n Teams can use agentic AI t to automate routine work while keeping humans in charge of oversight and strategy.\n Risks like hallucinations, security gaps, and hidden logic create a demand for strong governance\n\n## What Is Agentic AI?',
'score': 0.7999589,
'raw_content': None,
'id': 'a74d71-00'},
{'url': 'https://www.ibm.com/think/topics/agentic-ai',
'title': 'What is Agentic AI? - IBM',
'content': 'Agentic AI is an artificial intelligence system that can accomplish a specific goal with limited supervision. It consists of AI agentsβmachine learning models that mimic human decision-making to solve problems in real time. In a multiagent system, each agent performs a specific subtask required to reach the goal and their efforts are coordinated through AI orchestration. [...] Agentic AI builds on generative AI (gen AI) techniques by using large language models (LLMs) to function in dynamic environments. While generative models focus on creatingcontent based on learned patterns, agentic AI extends this capability by applying generative outputs toward specific goals. A generative AI model like OpenAIβs ChatGPT might produce text, images or code, but an agentic AI system can use that generated content to complete complex tasks autonomously by calling external tools. [...] The most important advancement of agentic systems is that they allow for autonomy to perform tasks without constant human oversight. Agentic systems can maintain long-term goals, manage multistep problem-solving tasks and track progress over time.',
'score': 0.7975099,
'raw_content': None,
'id': '60b919-01'},
{'url': 'https://aws.amazon.com/what-is/agentic-ai',
'title': 'What is Agentic AI? - Agentic AI Explained - AWS',
'content': 'Agentic AI is an autonomous AI system that can act independently to achieve pre-determined goals. Traditional software follows pre-defined rules, and traditional artificial intelligence also requires prompting and step-by-step guidance. However, agentic AI is proactive and can perform complex tasks without constant human oversight. "Agentic" indicates agency β the ability of these systems to act independently, but in a goal-driven manner. [...] Agentic AI also facilitates multi-agent orchestration, where supervisors use multiple specialist models to construct complex research and development pipelines. For example, agentic AI could draw from recent research published on credible platforms, synthesize the results, plan further tests, and present researchers with the final product they need to investigate. This approach saves a significant amount of time and cost involved in research.\n\n### Code transformation [...] ### Supporting research and development\n\nResearch and development in any field requires a great deal of manual processes, such as testing hypotheses, gathering research information, collecting data, synthesizing insights across data sources, and more. Agentic AI can reduce the need for human intervention with these manual processes. It streamlines research and better coordinates teams that are working on research and development challenges.',
'score': 0.7738498,
'raw_content': None,
'id': '9329d7-02'},
{'url': 'https://cloud.google.com/discover/what-is-agentic-ai',
'title': 'What is agentic AI? Definition and differentiators | Google Cloud',
'content': 'Agentic AI is a subset of generative AI that is centered around the orchestration and execution of agents that use LLMs as a "brain" to perform actions through tools. Agentic AI goes beyond content creation and function calling by executing actions in underlying systems to achieve higher-level goals. [...] # What is agentic AI?\n\nAgentic AI is an advanced form of artificial intelligence focused on autonomous decision-making and action. Unlike traditional AI, which primarily responds to commands or analyzes data, agentic AI can set goals, plan, and execute tasks with minimal human intervention. This emerging technology has the potential to revolutionize various industries by automating complex processes and optimizing workflows.\n\nVideo about agentic AI for developers\n\n## Key concepts of agentic AI [...] Agentic AI systems are designed to operate with a higher degree of autonomy. It works by using AI agents, which are essentially autonomous entities designed to perform specific tasks. At its core, this technology is built on several key components:',
'score': 0.7722049,
'raw_content': None,
'id': '3ec444-03'},
{'url': 'https://aimultiple.com/agentic-ai-trends',
'title': '10+ Agentic AI Trends and Examples',
'content': '## Agentic AI explained\n\nAgentic AI refers to AI systems capable of acting autonomously, adapting in real-time, and solving complex multi-step problems based on context and objectives.\n\nIt combines multiple AI agents, leveraging large language models (LLMs) and reasoning capabilities.\n\nKey features: [...] Agentic AI refers to AI systems that autonomously make decisions and act towards achieving complex goals with minimal supervision. It combines the flexibility of large language models (LLMs) with the precision of traditional programming.\n\nUnlike generative AI, which is reactive to input, agentic AI proactively adapts to situations and makes context-based decisions. Itβs used in applications like robotics, complex analysis, and virtual assistants.\n\n## The impact of AI agents on business growth [...] Advances in AI-enabled pipeline automation: Agentic systems can autonomously handle multi-step workflows such as data ingestion, validation, and incident detection. As automation advances, engineers can manage larger systems with fewer resources, while analysts independently maintain workflows.',
'score': 0.6929958,
'raw_content': None,
'id': '3d3740-04'},
{'url': 'https://mitsloan.mit.edu/ideas-made-to-matter/agentic-ai-explained',
'title': 'Agentic AI, explained',
'content': 'Today, attention has shifted to the next evolution of generative AI: AI agents or agentic AI, a new breed of AI systems that are semi- or fully autonomous and thus able to perceive, reason, and act on their own. Different from the now familiar chatbots that field questions and solve problems, this emerging class of AI integrates with other software systems to complete tasks independently or with minimal human supervision. [...] ## Next steps\n\nRead aboutfour recent studies about agentic AI from the MIT Initiative on the Digital Economy.\n\nRead more about agentic AI in MIT Sloan Management Review:\n\n1. βThe Emerging Agentic Enterprise: How Leaders Must Navigate a New Age of AIβ\n2. βAgentic AI: Nine Essential Questionsβ\n\nRead the research briefingβBusiness Models in the Agentic AI Era,β from the MIT Center for Information Systems Research. [...] Aral draws a slight distinction between AI agents and the broader category of agentic AI, although most people still refer to the two interchangeably. He defines agentic AI as systems that incorporate multiple, different agents that are orchestrating a task together β for example, a marketplace of agents representing both the buy and sell side during a negotiation or transaction.\n\n## How are businesses using agentic AI?',
'score': 0.68748367,
'raw_content': None,
'id': '639d21-05'},
{'url': 'https://www.instaclustr.com/education/agentic-ai/agentic-ai-frameworks-top-10-options-in-2026',
'title': 'Agentic AI Frameworks: Top 10 Options in 2026',
'content': 'Agentic AI frameworks are designed to create AI systems that act as independent agents, capable of perceiving their environment, learning from it, and making decisions to achieve specific objectives. These frameworks require a data infrastructure that can support real-time data ingestion, processing, and storage at scale. Instaclustrβs platform ensures that these requirements are met with enterprise-grade security, high availability, and 24/7 support, allowing businesses to focus on developing [...] The integration of managed open source services with Instaclustr with agentic AI frameworks unlocks new possibilities for innovation and automation. For example, an agentic AI system designed for supply chain optimization can leverage Instaclustr for Apache Kafka for real-time data streaming and Instaclustr for Apache Cassandra for scalable data storage. This enables the AI system to process live data from multiple sources, adapt to changing conditions, and make autonomous decisions to improve [...] Image 2 Source: LangChain\n\n### 2. AutoGen\n\nImage 3\n\nAutoGen is a framework for building conversational AI agents and multi-agent systems with layered abstractions. It supports both rapid prototyping through a web-based interface and programmatic development for scalable, event-driven agent orchestration. The framework separates concerns into Studio (no-code), AgentChat (Python API), Core (event-driven runtime), and Extensions for integrations.\n\nKey features include:',
'score': 0.6301622,
'raw_content': None,
'id': '616f05-06'},
{'url': 'https://agentic.ai',
'title': 'Agentic.ai - Find AI That Actually Does Things',
'content': 'Teams\n\nFrameworks and platforms for coordinating multiple AI agents working together. Build agent teams, manage inter-agent communication, and orchestrate parallel workflows with shared memory and tool access.\n\n8tools\n\nOur Framework\n\n## What Makes a Tool βAgenticβ?\n\nWe evaluate every tool using our 36-point scoring system. βAgenticβ means AI that can decide and act in a loopβnot just generate text.Read the full guide.\n\nTakes a goal and runs a decide\u2009β\u2009act\u2009β\u2009observe loop\n\nTakes Action [...] Coding Agents\n\nAugment Code is an enterprise-focused AI coding agent built around a 200K-token Context Engine. Closed-source SaaS with strong SWE-bench Verified results (70.6% self-reported) and the highest accuracy on the only public benchmark for AI-assisted code review.\n\nOpenHands\n\nAgenticness18/36Β·Adaptive Collaborator\n\nCoding Agents [...] Takes Action\n\nExecutes real actions via APIs, tools, or external systems\n\nAdjusts next steps based on results and changing context\n\nWhat is agentic AI?Scoring framework\n\nFrom the studio behind Agentic.ai\n\n## Agentic tools we build\n\nWe make agentic AI too. We score our own tools on the same public 36-point rubric as everything else here, and we never charge for placement β so you can judge them exactly like any other listing.\n\nOur studio\n\nagentic-news.ai\n\nAgentic News',
'score': 0.4581311,
'raw_content': None,
'id': 'ad4ee9-07'}],
'response_time': 0.78,
'request_id': '107ebe6c-4682-48a6-96c1-540db384f9e8'}
from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper
wiki = WikipediaQueryRun(
api_wrapper=WikipediaAPIWrapper(
top_k_results=1,
doc_content_chars_max=1000
)
)
result = wiki.invoke("Large Language Models history")
print("=== Wikipedia Result ===")
print(result)
=== Wikipedia Result === Page: Large language model Summary: A large language model (LLM) is an AI model (typically a neural network) trained on a vast amount of text for natural language processing tasks, especially language generation. LLMs can typically generate, summarize, translate, and analyze text in many contexts. They are the basis for many modern chatbots, such as ChatGPT, Claude, Gemini, Grok, and DeepSeek. LLMs are typically based on transformer architecture. Generative pre-trained transformers (GPTs) are a type of LLM that is pre-trained to predict the next word. GPTs are then often fine-tuned to follow instructions and to behave as assistants. Biased or inaccurate training data can make an LLM's output less reliable. Benchmark evaluations for LLMs attempt to measure model reasoning, factual accuracy, alignment, and safety.
import requests, re
@tool
def fetch_webpage(url: str) -> str:
"""
Fetch and return the text content of any webpage URL.
Use when you need to read the content of a specific website.
Input should be a full URL starting with https://
"""
try:
headers = {"User-Agent": "Mozilla/5.0"}
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
text = re.sub(r'<[^>]+>', ' ', response.text)
text = re.sub(r'\s+', ' ', text).strip()
return f"Content from {url}:\n{text[:1500]}..."
except Exception as e:
return f"Could not fetch {url}: {e}"
# result = fetch_webpage.invoke({"url": "https://httpbin.org/json"})
result = fetch_webpage.invoke({"url": "https://loxfordacademy.com/blog/uncategorized/hugging-face-the-github-of-ai-models/"})
print(result[:1000])
Content from https://loxfordacademy.com/blog/uncategorized/hugging-face-the-github-of-ai-models/:
/* */ /* */ :root { --lp-container-max-width: 1290px; --lp-cotainer-padding: 1rem; --lp-primary-color: #ffb606; --lp-secondary-color: #442e66; } Hugging Face: The GitHub of AI Models – loxfordacademy.com img:is([sizes=auto i],[sizes^="auto," i]){contain-intrinsic-size:3000px 1500px} /*# sourceURL=wp-img-auto-sizes-contain-inline-css */ img.wp-smiley, img.emoji { display: inline !important; border: none !important; box-shadow: none !important; height: 1em !important; width: 1em !important; margin: 0 0.07em !important; vertical-align: -0.1em !important; background: none !important; padding: 0 !important; } /*# sourceURL=wp-emoji-styles-inline-css */ .wp-block-audio :where(figcaption){color:#555;font-size:13px;text-align:center}.is-dark-theme .wp-block-audio :where(figcaption){color:#ffffffa6}.wp-block-audio{margin:0 0 1em}.wp-block-code{border:1px solid #ccc;border-radius:4px;font-fami
import datetime
@tool
def get_current_datetime() -> str:
"""
Get the current date and time.
Use when asked about todays date, current time, what day it is,
or anything involving now or today.
"""
now = datetime.datetime.now()
return (
f"Date: {now.strftime('%A, %B %d, %Y')}\n"
f"Time: {now.strftime('%I:%M %p')}\n"
f"ISO: {now.isoformat()}"
)
@tool
def days_between_dates(date1: str, date2: str) -> str:
"""Calculate the number of days between two dates.
Input format: YYYY-MM-DD for both dates.
Use for deadline calculations, age calculations, or any date difference."""
try:
d1 = datetime.datetime.strptime(date1, "%Y-%m-%d")
d2 = datetime.datetime.strptime(date2, "%Y-%m-%d")
delta = abs((d2 - d1).days)
weeks, days = divmod(delta, 7)
return f"{delta} days ({weeks} weeks and {days} days) between {date1} and {date2}"
except ValueError as e:
return f"Error: {e}. Use YYYY-MM-DD format."
@tool
def add_days_to_date(date: str, days: int) -> str:
"""Add or subtract days from a date. Input: YYYY-MM-DD format.
Use negative days to go back in time. Good for scheduling and deadlines."""
try:
d = datetime.datetime.strptime(date, "%Y-%m-%d")
result = d + datetime.timedelta(days=days)
return f"{date} + {days} days = {result.strftime('%A, %B %d, %Y')}"
except ValueError as e:
return f"Error: {e}"
print(get_current_datetime.invoke({}))
print()
print(days_between_dates.invoke({"date1": "2025-01-01", "date2": "2025-12-31"}))
print()
print(add_days_to_date.invoke({"date": "2025-06-01", "days": 90}))
Date: Sunday, September 06, 2026 Time: 12:16 PM ISO: 2026-09-06T12:16:49.993547 364 days (52 weeks and 0 days) between 2025-01-01 and 2025-12-31 2025-06-01 + 90 days = Saturday, August 30, 2025
import os
from langchain_core.tools import tool
@tool
def write_file(filename: str, content: str) -> str:
"""Write content to a text file.
Use when the user asks to save, export, or create a file.
"""
try:
with open(filename, 'w', encoding='utf-8') as f:
f.write(content)
size = os.path.getsize(filename)
return f"Written {size} bytes to {filename!r}"
except Exception as e:
return f"Error: {e}"
@tool
def read_file(filename: str) -> str:
"""Read and return the contents of a text file.
Use when asked to open, read, or load a file.
"""
try:
with open(filename, 'r', encoding='utf-8') as f:
return f.read()
except FileNotFoundError:
return f"File {filename!r} not found."
except Exception as e:
return f"Error: {e}"
@tool
def list_files(directory: str = '.') -> str:
"""List all files in a directory. Default is current directory.
Use when asked what files exist, to browse a folder, or find files.
"""
try:
items = sorted(os.listdir(directory))
if not items:
return f"Directory {directory!r} is empty."
lines = []
for f in items:
icon = 'π' if os.path.isdir(os.path.join(directory, f)) else 'π'
lines.append(f" {icon} {f}")
return "\n".join(lines)
except Exception as e:
return f"Error: {e}"
print(write_file.invoke({"filename": "notes.txt", "content": "LangChain tools are awesome!\nLine 2."}))
print(read_file.invoke({"filename": "notes.txt"}))
print()
print("Files:")
print(list_files.invoke({}))
Written 37 bytes to 'notes.txt' LangChain tools are awesome! Line 2. Files: π .env π .ipynb_checkpoints π LangChain_tutorial_1_Chains_UPDATED.ipynb π LangChain_tutorial_2_Tools_UPDATED.ipynb π LangChain_tutorial_3_Agents_Memory.ipynb π notes.txt
6οΈ. Using Tools Inside ChainsΒΆ
Tools do not have to be used by agents. Call them inside chains with RunnableLambda.
Input
β
Chain Step 1: LLM generates data
β
Chain Step 2: Tool processes the data (no LLM needed)
β
Chain Step 3: LLM interprets the result
β
Output
from langchain_core.runnables import RunnableLambda, RunnablePassthrough
# Step 1: LLM generates 8 exam scores
generate_data = (
ChatPromptTemplate.from_template(
"Generate 8 realistic exam scores (50-100) for a {subject} class. "
"Return ONLY comma-separated numbers, nothing else."
)
| llm
| StrOutputParser()
)
# Step 2: Tool processes the data β no LLM needed here
run_stats = RunnableLambda(lambda scores: stats_calculator.invoke({'numbers': scores}))
# Step 3: LLM interprets the stats
interpret = (
ChatPromptTemplate.from_template(
"Here are statistics for a class exam:\n{stats}\n\n"
"Write a 2-sentence teacher comment on the class performance."
)
| llm | StrOutputParser()
)
pipeline = (
{"scores": generate_data, "subject": RunnablePassthrough()}
| RunnablePassthrough.assign(stats=lambda x: run_stats.invoke(x['scores']))
| RunnablePassthrough.assign(comment=lambda x: interpret.invoke({'stats': x['stats']}))
)
result = pipeline.invoke({"subject": "mathematics"})
print("Scores generated:", result["scores"])
print("\nStats:")
print(result["stats"])
print("\nTeacher Comment:")
print(result["comment"])
Scores generated: 76, 85, 92, 67, 88, 94, 73, 81 Stats: count: 8 mean: 82.0 median: 83.0 std_dev: 9.5019 min: 67.0 max: 94.0 range: 27.0 Teacher Comment: The class demonstrated a solid understanding of the material, with a mean score of 82.0 and a median of 83.0, indicating that most students performed well. However, the range of scores suggests there is some variability in performance, highlighting opportunities for targeted support for those who may be struggling.
# Search β summarise β a very common real-world pattern
summarise_prompt = ChatPromptTemplate.from_template(
"Based on this search result, write a clear 3-bullet summary:\n\n"
"{search_result}\n\nTopic: {topic}\nKeep each bullet under 20 words."
)
research_chain = (
RunnablePassthrough.assign(
search_result=lambda x: search.invoke(x['topic'])
)
| summarise_prompt
| llm
| StrOutputParser()
)
print(research_chain.invoke({"topic": "benefits of meditation"}))
- Meditation enhances emotional regulation, focus, and decision-making by promoting awareness of thoughts. - Regular practice reduces stress, anxiety, and blood pressure while increasing self-awareness and mindfulness. - It strengthens willpower and inner strength, aiding in overcoming challenges.
7οΈ. LLM Tool Calling β Let the Model DecideΒΆ
Instead of you choosing which tool to call, the LLM decides based on the question.
llm_with_tools = llm.bind_tools([tool_a, tool_b, tool_c])
The LLM can respond with:
- A text answer (no tool needed)
- A tool call (tool name + arguments)
You execute the tool and feed the result back for the final answer.
# Bind tools to the LLM
tools_basic = [calculator, get_current_datetime, unit_converter, stats_calculator, wiki]
llm_with_tools = llm.bind_tools(tools_basic)
# Ask questions β watch which trigger tool calls vs direct answers
questions = [
"What is 1337 * 42?",
"What is the capital of France?", # no tool needed
"What day is it today?",
"Convert 100 miles to km",
]
for q in questions:
response = llm_with_tools.invoke(q)
if response.tool_calls:
print(f"\nβ {q}")
print(f" π§ Tool: {response.tool_calls[0]['name']}")
print(f" π₯ Args: {response.tool_calls[0]['args']}")
else:
print(f"\nβ {q}")
print(f" π¬ Direct answer: {response.content}")
β What is 1337 * 42?
π§ Tool: calculator
π₯ Args: {'expression': '1337 * 42'}
β What is the capital of France?
π§ Tool: wikipedia
π₯ Args: {'query': 'Capital of France'}
β What day is it today?
π§ Tool: get_current_datetime
π₯ Args: {}
β Convert 100 miles to km
π§ Tool: unit_converter
π₯ Args: {'value': 100, 'from_unit': 'miles', 'to_unit': 'km'}
from langchain_core.messages import HumanMessage, ToolMessage
tool_map = {t.name: t for t in tools_basic}
def ask_with_tools(question: str) -> str:
"""Full round-trip: question -> tool call -> result -> final answer."""
messages = [HumanMessage(content=question)]
response = llm_with_tools.invoke(messages)
messages.append(response)
if response.tool_calls:
for tc in response.tool_calls:
print(f" π§ Calling {tc['name']!r} with {tc['args']}")
result = tool_map[tc['name']].invoke(tc['args'])
messages.append(ToolMessage(
content=str(result),
tool_call_id=tc['id']
))
final = llm_with_tools.invoke(messages)
return final.content
return response.content
test_questions = [
"What is 999 * 888?",
"Convert 37 celsius to fahrenheit",
"What is today's date?",
# "Tell me about Python in one sentence", # no tool
]
for q in test_questions:
print(f"\nβ {q}")
print('β
', ask_with_tools(q))
β What is 999 * 888?
π§ Calling 'calculator' with {'expression': '999 * 888'}
β
The result of \( 999 \times 888 \) is 887,112.
β Convert 37 celsius to fahrenheit
π§ Calling 'unit_converter' with {'value': 37, 'from_unit': 'celsius', 'to_unit': 'fahrenheit'}
β
37 degrees Celsius is equal to 98.6 degrees Fahrenheit.
β What is today's date?
π§ Calling 'get_current_datetime' with {}
β
Today's date is Sunday, September 6, 2026.
# Multiple tool calls β some questions need more than one tool
result = ask_with_tools(
"What is today's date, and also calculate 365 / 12 rounded to 2 decimal places?"
)
print(result)
π§ Calling 'get_current_datetime' with {}
π§ Calling 'calculator' with {'expression': '365 / 12'}
Today's date is Sunday, September 06, 2026.
The result of \( 365 / 12 \) rounded to two decimal places is approximately 30.42.
Following is optional (Only if time permits)ΒΆ
8οΈ. Interesting & Fun ToolsΒΆ
| Tool | What it does |
|---|---|
| Password generator | Creates secure random passwords |
| Morse code | Encode and decode Morse code |
| Readability scorer | Flesch-Kincaid reading ease score |
| Timezone converter | Convert times across timezones |
| Number to words | 1234 to ‘one thousand two hundred…” |
| Word tools | Palindromes, ROT13, vowel counter |
import random, string
@tool
def generate_password(length: int = 16, include_symbols: bool = True) -> str:
"""
Generate a secure random password.
Length defaults to 16. Set include_symbols=False for alphanumeric only.
Use when asked to create a password or generate a secure string.
"""
chars = string.ascii_letters + string.digits
if include_symbols:
chars += "!@#$%^&*"
password = [
random.choice(string.ascii_uppercase),
random.choice(string.ascii_lowercase),
random.choice(string.digits),
]
if include_symbols:
password.append(random.choice("!@#$%^&*"))
password += [random.choice(chars) for _ in range(length - len(password))]
random.shuffle(password)
return ''.join(password)
print("Sample passwords:")
for _ in range(5):
print(" ", generate_password.invoke({"length": 16, "include_symbols": True}))
Sample passwords: O&F6GY91@iYdHbpS b8n%l$J8AH1iYt$s H*Yxt3nj26Q3A8G& DiZk0C94D#xzgM^^ F*h*Qso*SzB0hm1T
@tool
def morse_code(text: str, mode: str = 'encode') -> str:
"""
Encode text to Morse code or decode Morse back to text.
mode: use 'encode' to convert text to morse, 'decode' for morse to text.
Morse uses dots and dashes, words separated by ' / '.
Example encode input: HELLO β Example decode input: .... . .-.. .-.. ---
"""
CODE = {
'A':'.-','B':'-...','C':'-.-.','D':'-..','E':'.','F':'..-.','G':'--.','H':'....','I':'..','J':'.---',
'K':'-.-','L':'.-..','M':'--','N':'-.','O':'---','P':'.--.','Q':'--.-','R':'.-.','S':'...','T':'-',
'U':'..-','V':'...-','W':'.--','X':'-..-','Y':'-.--','Z':'--..',
'0':'-----','1':'.----','2':'..---','3':'...--','4':'....-','5':'.....','6':'-....','7':'--...','8':'---..','9':'----.',
}
DECODE = {v: k for k, v in CODE.items()}
if mode == 'encode':
result = []
for word in text.upper().split():
result.append(' '.join(CODE.get(c, '?') for c in word))
return ' / '.join(result)
else:
words = text.strip().split(' / ')
return ' '.join(''.join(DECODE.get(c, '?') for c in word.split()) for word in words)
encoded = morse_code.invoke({"text": "HELLO WORLD", "mode": "encode"})
print("Encoded:", encoded)
decoded = morse_code.invoke({"text": encoded, "mode": "decode"})
print("Decoded:", decoded)
Encoded: .... . .-.. .-.. --- / .-- --- .-. .-.. -.. Decoded: HELLO WORLD
@tool
def readability_score(text: str) -> str:
"""
Calculate the Flesch-Kincaid readability score of a text (0-100).
Higher score = easier to read.
Score 90-100: Very Easy, 60-70: Standard, 30-50: Difficult, 0-30: Very Difficult.
Use to analyse writing complexity or compare texts.
"""
sentences = max(text.count('.') + text.count('!') + text.count('?'), 1)
words = text.split()
if not words:
return "No text provided."
def count_syllables(word):
word = word.lower().strip('.,!?;:')
vowels = 'aeiouy'
count = sum(1 for i, c in enumerate(word) if c in vowels and (i == 0 or word[i-1] not in vowels))
return max(count, 1)
syllables = sum(count_syllables(w) for w in words)
score = 206.835 - 1.015*(len(words)/sentences) - 84.6*(syllables/len(words))
score = max(0, min(100, score))
if score >= 90: level = 'Very Easy (5th grade)'
elif score >= 70: level = 'Fairly Easy (7th grade)'
elif score >= 60: level = 'Standard (8th-9th grade)'
elif score >= 50: level = 'Fairly Difficult (10th-12th grade)'
elif score >= 30: level = 'Difficult (college level)'
else: level = 'Very Difficult (professional)'
return f"Score: {score:.1f}/100 β {level} | Words: {len(words)} | Sentences: {sentences}"
easy = "The cat sat on the mat. It was a big cat. The cat was very happy."
hard = "The epistemological implications of quantum indeterminacy necessitate fundamental reexamination of classical causality."
print("Easy:", readability_score.invoke({"text": easy}))
print("Hard:", readability_score.invoke({"text": hard}))
Easy: Score: 100.0/100 β Very Easy (5th grade) | Words: 16 | Sentences: 3 Hard: Score: 0.0/100 β Very Difficult (professional) | Words: 12 | Sentences: 1
@tool
def convert_timezone(time_str: str, from_offset: str, to_offset: str) -> str:
"""
Convert a time between UTC offsets.
time_str: HH:MM in 24-hour format.
from_offset and to_offset: UTC offset like '+5:30', '-8', '+0'.
Use for scheduling across countries or converting meeting times.
"""
try:
h, m = map(int, time_str.split(':'))
def parse(tz):
tz = tz.strip().lstrip('UTC').strip()
if not tz or tz == '+0' or tz == '0': return 0
sign = 1 if '+' in tz else -1
tz = tz.replace('+','').replace('-','')
parts = tz.split(':')
return sign * (int(parts[0]) * 60 + (int(parts[1]) if len(parts) > 1 else 0))
total = h * 60 + m - parse(from_offset) + parse(to_offset)
total = total % (24 * 60)
return f"{time_str} (UTC{from_offset}) = {total//60:02d}:{total%60:02d} (UTC{to_offset})"
except Exception as e:
return f"Error: {e}"
meeting = "14:30"
print(f"Meeting at {meeting} UTC:")
print(convert_timezone.invoke({"time_str": meeting, "from_offset": "+0", "to_offset": "+5:30"}), " India")
print(convert_timezone.invoke({"time_str": meeting, "from_offset": "+0", "to_offset": "-8"}), " US Pacific")
print(convert_timezone.invoke({"time_str": meeting, "from_offset": "+0", "to_offset": "+9"}), " Japan")
Meeting at 14:30 UTC: 14:30 (UTC+0) = 20:00 (UTC+5:30) India 14:30 (UTC+0) = 06:30 (UTC-8) US Pacific 14:30 (UTC+0) = 23:30 (UTC+9) Japan
@tool
def number_to_words(number: int) -> str:
"""
Convert a number to its English word representation.
Useful for writing cheques, formal documents, or accessibility.
Works for numbers up to 999,999,999.
"""
if number == 0: return 'zero'
ones = ['','one','two','three','four','five','six','seven','eight','nine',
'ten','eleven','twelve','thirteen','fourteen','fifteen','sixteen',
'seventeen','eighteen','nineteen']
tens = ['','','twenty','thirty','forty','fifty','sixty','seventy','eighty','ninety']
def three(n):
if n == 0: return ''
elif n < 20: return ones[n]
elif n < 100: return tens[n//10] + ('-' + ones[n%10] if n%10 else '')
else: return ones[n//100] + ' hundred' + (' and ' + three(n%100) if n%100 else '')
result = ''
if number >= 1_000_000:
result += three(number // 1_000_000) + ' million '
number %= 1_000_000
if number >= 1_000:
result += three(number // 1_000) + ' thousand '
number %= 1_000
if number > 0:
result += ('and ' if result else '') + three(number)
return result.strip()
for n in [42, 1000, 15750, 1_000_000, 999_999_999]:
print(f"{n:>12,} -> {number_to_words.invoke({'number': n})}")
42 -> forty-two
1,000 -> one thousand
15,750 -> fifteen thousand and seven hundred and fifty
1,000,000 -> one million
999,999,999 -> nine hundred and ninety-nine million nine hundred and ninety-nine thousand and nine hundred and ninety-nine
@tool
def word_tools(word: str, operation: str) -> str:
"""
Perform word operations.
operation choices:
- palindrome: check if word/phrase is a palindrome
- reverse: reverse the string
- vowels: count vowels and consonants
- rot13: apply ROT13 Caesar cipher
"""
w = word.lower().replace(' ', '')
if operation == 'palindrome':
is_p = w == w[::-1]
return f"{word!r} {'IS β
' if is_p else 'is NOT β'} a palindrome"
elif operation == 'reverse':
return f"Reversed: {word[::-1]!r}"
elif operation == 'vowels':
v = sum(1 for c in word.lower() if c in 'aeiou')
c = sum(1 for c in word.lower() if c.isalpha() and c not in 'aeiou')
return f"{word!r}: {v} vowels, {c} consonants"
elif operation == 'rot13':
result = ''.join(
chr((ord(c)-65+13)%26+65) if c.isupper()
else chr((ord(c)-97+13)%26+97) if c.islower()
else c for c in word)
return f"ROT13: {word!r} -> {result!r}"
return f"Unknown operation: {operation}"
print(word_tools.invoke({"word": "racecar", "operation": "palindrome"}))
print(word_tools.invoke({"word": "A man a plan a canal Panama", "operation": "palindrome"}))
print(word_tools.invoke({"word": "LangChain", "operation": "vowels"}))
print(word_tools.invoke({"word": "Hello World", "operation": "rot13"}))
'racecar' IS β a palindrome 'A man a plan a canal Panama' IS β a palindrome 'LangChain': 3 vowels, 6 consonants ROT13: 'Hello World' -> 'Uryyb Jbeyq'
all_tools = [
# Math & Data
calculator, stats_calculator, unit_converter, python_repl,
# Web & Search
search, wiki, fetch_webpage,
# Datetime
get_current_datetime, days_between_dates, add_days_to_date,
# Files
write_file, read_file, list_files,
# Interesting
generate_password, morse_code, readability_score,
convert_timezone, number_to_words, word_tools,
]
print(f"Total tools: {len(all_tools)}")
for t in all_tools:
print(f" π§ {t.name:30s} {t.description[:50]}...")
Total tools: 19
π§ calculator Evaluate a mathematical expression. Input must be ...
π§ stats_calculator Calculate statistics for a list of numbers.
In...
π§ unit_converter Convert between common units of measurement.
S...
π§ python_repl Execute Python code and return the printed output....
π§ duckduckgo_search A wrapper around DuckDuckGo Search. Useful for whe...
π§ wikipedia A wrapper around Wikipedia. Useful for when you ne...
π§ fetch_webpage Fetch and return the text content of any webpage U...
π§ get_current_datetime Get the current date and time.
Use when asked ...
π§ days_between_dates Calculate the number of days between two dates.
...
π§ add_days_to_date Add or subtract days from a date. Input: YYYY-MM-D...
π§ write_file Write content to a text file.
Use when the use...
π§ read_file Read and return the contents of a text file.
U...
π§ list_files List all files in a directory. Default is current ...
π§ generate_password Generate a secure random password.
Length defa...
π§ morse_code Encode text to Morse code or decode Morse back to ...
π§ readability_score Calculate the Flesch-Kincaid readability score of ...
π§ convert_timezone Convert a time between UTC offsets.
time_str: ...
π§ number_to_words Convert a number to its English word representatio...
π§ word_tools Perform word operations.
operation choices:
...
llm_all = llm.bind_tools(all_tools)
tool_map_all = {t.name: t for t in all_tools}
def smart_ask(question: str) -> str:
from langchain_core.messages import HumanMessage, ToolMessage
messages = [HumanMessage(content=question)]
response = llm_all.invoke(messages)
messages.append(response)
if response.tool_calls:
for tc in response.tool_calls:
print(f" π§ {tc['name']}({tc['args']})")
result = tool_map_all[tc['name']].invoke(tc['args'])
messages.append(ToolMessage(content=str(result), tool_call_id=tc['id']))
return llm_all.invoke(messages).content
return response.content
showcase = [
"What is 4096 / 64?",
"Encode LANGCHAIN in Morse code",
"Generate a 12-character password without symbols",
"Convert 500 pounds to kg",
"Is Never odd or even a palindrome?",
"Write 1234567 in words",
"What day of the week is it today?",
"How many days between 2025-01-01 and 2025-12-31?",
]
for q in showcase:
print(f"\nβ {q}")
print('β
', smart_ask(q))
β What is 4096 / 64?
π§ calculator({'expression': '4096 / 64'})
β
The result of \( 4096 \div 64 \) is \( 64.0 \).
β Encode LANGCHAIN in Morse code
π§ morse_code({'text': 'LANGCHAIN', 'mode': 'encode'})
β
The Morse code for "LANGCHAIN" is: **.-.. .- -. --. -.-. .... .- .. -.**
β Generate a 12-character password without symbols
π§ generate_password({'length': 12, 'include_symbols': False})
β
Here is your 12-character password without symbols: **rn2lePUAKmK6**
β Convert 500 pounds to kg
π§ unit_converter({'value': 500, 'from_unit': 'pounds', 'to_unit': 'kg'})
β
500 pounds is approximately 226.80 kilograms.
β Is Never odd or even a palindrome?
π§ word_tools({'word': 'Never odd or even', 'operation': 'palindrome'})
β
Yes, "Never odd or even" is a palindrome!
β Write 1234567 in words
π§ number_to_words({'number': 1234567})
β
The number 1,234,567 in words is: **one million two hundred and thirty-four thousand and five hundred and sixty-seven**.
β What day of the week is it today?
π§ get_current_datetime({})
β
Today is Sunday.
β How many days between 2025-01-01 and 2025-12-31?
π§ days_between_dates({'date1': '2025-01-01', 'date2': '2025-12-31'})
β
There are 364 days between January 1, 2025, and December 31, 2025.
Summary β Tools Cheat SheetΒΆ
# 1. CREATE A TOOL
from langchain_core.tools import tool
@tool
def my_tool(param: str) -> str:
"""Descriptive docstring β the LLM reads this to decide when to call it."""
return "result"
my_tool.invoke({'param': 'value'}) # call directly
# 2. BUILT-IN COMMUNITY TOOLS
from langchain_community.tools import DuckDuckGoSearchRun # web search (free)
from langchain_community.tools import WikipediaQueryRun # Wikipedia (free)
from langchain_community.tools import PythonREPLTool # run Python (free)
# 3. BIND TO LLM β let LLM decide which to call
llm_with_tools = llm.bind_tools([tool_a, tool_b, tool_c])
# 4. HANDLE TOOL CALLS
from langchain_core.messages import HumanMessage, ToolMessage
response = llm_with_tools.invoke([HumanMessage(content='question')])
if response.tool_calls:
for tc in response.tool_calls:
result = tool_map[tc['name']].invoke(tc['args'])
# feed result back as ToolMessage
