{"slug": "tool-calling-code", "title": "Tool Calling Code", "summary": "A developer published a walkthrough for implementing tool calling in a LangChain agent, using the @tool decorator to expose Python functions such as get_weather and add_numbers, binding them to a Groq-hosted model via bind_tools, and manually executing the model's tool_calls before a second LLM invocation produces the final answer. The example also covers virtual environment setup and a pinned requirements.txt that includes langchain, langchain-groq, langgraph, and chromadb.", "body_md": "\n\n```\npython -m venv .venv\npython3 -m venv .venv\napt install python3.12-venv\npython3.12 -m venv .venv\nsource .venv/bin/activate\npython3 <python file>\npip install -r requirements.txt\n\nIf virtual environment to be removed,\nrm -rf .venv\n```\n\nuser , first reply and then agent.\n\n``` python\nfrom dotenv import load_dotenv\nfrom langchain_core.messages import HumanMessage\nfrom langchain_core.tools import tool\nfrom langchain_groq import ChatGroq\n\nload_dotenv()\n\n@tool  # Decorator\ndef get_weather(city: str) -> str:\n    \"\"\"\n    Get the current weather for a given city.\n    city: name of the city.\n    \"\"\"  # Docstrings\n    # Replace with a real weather API call\n    return f\"The weather in {city} is sunny and 25°C.\"\n\n@tool\ndef add_numbers(a: int, b: int) -> int:\n    \"\"\"Add two numbers together.\"\"\"\n    return a + b\n\ntools = [get_weather, add_numbers]\ntool_map = {t.name: t for t in tools}\nprint(tool_map)\n\nllm = ChatGroq(model=\"openai/gpt-oss-120b\", temperature=0)\nllm_with_tools = llm.bind_tools(tools)\n\ndef run_query(question: str) -> str:\n    messages = [HumanMessage(question)]\n    print(\"Initial Messages \", messages)\n    # input(\"Wait ....\")\n\n    # First call: model decides whether to answer directly or call a tool\n    ai_msg = llm_with_tools.invoke(messages)\n    messages.append(ai_msg)\n    print(\"Messages after first call \", messages)\n    # input(\"Wait ....\")\n\n    if ai_msg.tool_calls:\n        print(\"tool calls \", ai_msg.tool_calls)\n        # input(\"wait ...\")\n        # Execute each requested tool call\n        for call in ai_msg.tool_calls:\n            selected_tool = tool_map[call[\"name\"]]\n            tool_result = selected_tool.invoke(call[\"args\"])\n            messages.append(\n                {\n                    \"role\": \"tool\",\n                    \"content\": str(tool_result),\n                    \"tool_call_id\": call[\"id\"],\n                }\n            )\n            print(\"Messages after tool call \", messages)\n            # input(\"Wait ....\")\n\n        # Second call: let the model turn tool results into a final answer\n        print(\"Total Messages \", messages)\n        input(\"Wait Final....\")\n        final_response = llm_with_tools.invoke(messages)\n        return final_response.content\n    else:\n        # No tool needed — first response is already the final answer\n        return ai_msg.content\n\nif __name__ == \"__main__\":\n    # print(run_query(\"Give me climate in paris and london?\"))\n    # print(run_query(\"What is 15 plus 27?\"))\n    print(run_query(\"convert 100rs to usd\"))\naiohappyeyeballs==2.7.1\naiohttp==3.14.3\naiosignal==1.4.0\nannotated-doc==0.0.5\nannotated-types==0.8.0\nanyio==4.14.2\nasgiref==3.12.1\nasync-timeout==4.0.3\nattrs==26.1.0\nbcrypt==5.0.0\nbuild==1.6.1\ncertifi==2026.7.22\ncharset-normalizer==3.5.1\nchromadb==1.5.9\nclick==8.5.0\ncoloredlogs==15.0.1\ndistro==1.9.0\ndurationpy==0.11\nexceptiongroup==1.3.1\nfastapi==0.141.1\nfilelock==3.32.6\nflatbuffers==25.12.19\nfrozenlist==1.8.0\nfsspec==2026.7.0\ngoogleapis-common-protos==1.75.3\ngreenlet==3.5.5\ngroq==0.37.1\ngrpcio==1.83.1\nh11==0.16.0\nhf-xet==1.6.0\nhttpcore==1.0.9\nhttpcore2==2.12.0\nhttptools==0.8.0\nhttpx==0.28.1\nhttpx-sse==0.4.3\nhttpx2==2.12.0\nhuggingface_hub==1.31.0\nhumanfriendly==10.0\nidna==3.19\nimportlib_resources==7.1.0\njsonpatch==1.33\njsonpointer==3.1.1\njsonschema==4.26.0\njsonschema-specifications==2025.9.1\nkubernetes==36.0.3\nlangchain==1.3.18\nlangchain-chroma==1.1.0\nlangchain-classic==1.0.8\nlangchain-community==0.4.2\nlangchain-core==1.6.1\nlangchain-groq==1.1.3\nlangchain-ollama==1.1.0\nlangchain-protocol==0.0.19\nlangchain-text-splitters==1.1.2\nlanggraph==1.2.11\nlanggraph-checkpoint==4.2.0\nlanggraph-prebuilt==1.1.0\nlanggraph-sdk==0.4.4\nlangsmith==0.12.1\nmarkdown-it-py==4.2.0\nmdurl==0.1.2\nmmh3==5.3.0\nmpmath==1.3.0\nmultidict==6.8.0\nnumpy==2.2.6\noauthlib==3.3.1\nollama==0.6.2\nonnxruntime==1.23.2\nopentelemetry-api==1.44.0\nopentelemetry-exporter-otlp-proto-common==1.44.0\nopentelemetry-exporter-otlp-proto-grpc==1.44.0\nopentelemetry-proto==1.44.0\nopentelemetry-sdk==1.44.0\nopentelemetry-semantic-conventions==0.65b0\norjson==3.12.0\normsgpack==1.12.2\noverrides==7.7.0\npackaging==26.3\npropcache==0.5.2\nprotobuf==7.36.1\npybase64==1.5.0\npydantic==2.13.5\npydantic-settings==2.15.0\npydantic_core==2.46.5\nPygments==2.21.0\npypdf==6.18.1\nPyPika==0.51.1\npyproject_hooks==1.2.0\npython-dateutil==2.9.0.post0\npython-dotenv==1.2.3\nPyYAML==6.0.3\nreferencing==0.37.0\nrequests==2.34.2\nrequests-oauthlib==2.0.0\nrequests-toolbelt==1.0.0\nrich==15.0.0\nrpds-py==0.30.0\nruff==0.16.5\nshellingham==1.5.4\nsix==1.17.0\nsniffio==1.3.1\nSQLAlchemy==2.0.52\nsqlparse==0.6.0\nstarlette==1.6.0\nsympy==1.14.0\ntenacity==9.1.4\ntokenizers==0.23.2\ntomli==2.4.1\ntqdm==4.70.1\ntruststore==0.10.4\ntyper==0.27.2\ntyping-inspection==0.4.4\ntyping_extensions==4.16.0\nurllib3==2.7.0\nuuid_utils==0.17.0\nuvicorn==0.52.4\nuvloop==0.22.1\nwatchfiles==1.2.0\nwebsocket-client==1.9.2\nwebsockets==16.1.1\nxxhash==4.0.1\nyarl==1.24.5\nzstandard==0.25.0\n```\n\nGROQ_API_KEY=\"\"\n\npython -m pipe freeze > requirements.txt\n\n{'get_weather': StructuredTool(name='get_weather', description='Get the current weather for a given city.\\ncity: name of the city.', args_schema=, func=), 'add_numbers': StructuredTool(name='add_numbers', description='Add two numbers together.', args_schema=, func=)}\n\n**Initial Messages**  [HumanMessage(content='Give me climate in Chennai and Mumbai?', additional_kwargs={}, response_metadata={})]\n\nMessages after first call  [HumanMessage(content='Give me climate in Chennai and Mumbai?', additional_kwargs={}, response_metadata={}), AIMessage(content='', additional_kwargs={'reasoning_content': 'The user asks: \"Give me climate in Chennai and Mumbai?\" Likely they want current weather/climate. We have a function get_weather that can get current weather for a city. We can call it for Chennai and Mumbai. Probably need to call twice. Use function calls.', 'tool_calls': [{'id': 'fc_8ee481c4-db27-4a4f-a4e8-839700ea29bb', 'function': {'arguments': '{\"city\":\"Chennai\"}', 'name': 'get_weather'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 85, 'prompt_tokens': 161, 'total_tokens': 246, 'completion_time': 0.176815886, 'completion_tokens_details': {'reasoning_tokens': 57}, 'prompt_time': 0.007317037, 'prompt_tokens_details': None, 'queue_time': 0.34890584, 'total_time': 0.184132923}, 'model_name': 'openai/gpt-oss-120b', 'system_fingerprint': 'fp_068241849b', 'service_tier': 'on_demand', 'finish_reason': 'tool_calls', 'logprobs': None, 'model_provider': 'groq'}, id='lc_run--01a0de65-11eb-75a2-b3b4-2770359461ad-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'Chennai'}, 'id': 'fc_8ee481c4-db27-4a4f-a4e8-839700ea29bb', 'type': 'tool_call'}], invalid_tool_calls=[], usage_metadata={'input_tokens': 161, 'output_tokens': 85, 'total_tokens': 246, 'output_token_details': {'reasoning': 57}})]\n\ntool calls  [{'name': 'get_weather', 'args': {'city': 'Chennai'}, 'id': 'fc_8ee481c4-db27-4a4f-a4e8-839700ea29bb', 'type': 'tool_call'}]\n\n**Messages after tool call**  [HumanMessage(content='Give me climate in Chennai and Mumbai?', additional_kwargs={}, response_metadata={}), AIMessage(content='', additional_kwargs={'reasoning_content': 'The user asks: \"Give me climate in Chennai and Mumbai?\" Likely they want current weather/climate. We have a function get_weather that can get current weather for a city. We can call it for Chennai and Mumbai. Probably need to call twice. Use function calls.', 'tool_calls': [{'id': 'fc_8ee481c4-db27-4a4f-a4e8-839700ea29bb', 'function': {'arguments': '{\"city\":\"Chennai\"}', 'name': 'get_weather'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 85, 'prompt_tokens': 161, 'total_tokens': 246, 'completion_time': 0.176815886, 'completion_tokens_details': {'reasoning_tokens': 57}, 'prompt_time': 0.007317037, 'prompt_tokens_details': None, 'queue_time': 0.34890584, 'total_time': 0.184132923}, 'model_name': 'openai/gpt-oss-120b', 'system_fingerprint': 'fp_068241849b', 'service_tier': 'on_demand', 'finish_reason': 'tool_calls', 'logprobs': None, 'model_provider': 'groq'}, id='lc_run--01a0de65-11eb-75a2-b3b4-2770359461ad-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'Chennai'}, 'id': 'fc_8ee481c4-db27-4a4f-a4e8-839700ea29bb', 'type': 'tool_call'}], invalid_tool_calls=[], usage_metadata={'input_tokens': 161, 'output_tokens': 85, 'total_tokens': 246, 'output_token_details': {'reasoning': 57}}), {'role': 'tool', 'content': 'The weather in Chennai is sunny and 25°C.', 'tool_call_id': 'fc_8ee481c4-db27-4a4f-a4e8-839700ea29bb'}]\n\n**Total Messages**  [HumanMessage(content='Give me climate in Chennai and Mumbai?', additional_kwargs={}, response_metadata={}), **AIMessage**(content='', additional_kwargs={'reasoning_content': 'The user asks: \"Give me climate in Chennai and Mumbai?\" Likely they want current weather/climate. We have a function get_weather that can get current weather for a city. We can call it for Chennai and Mumbai. Probably need to call twice. Use function calls.', 'tool_calls': [{'id': 'fc_8ee481c4-db27-4a4f-a4e8-839700ea29bb', 'function': {'arguments': '{\"city\":\"Chennai\"}', 'name': 'get_weather'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 85, 'prompt_tokens': 161, 'total_tokens': 246, 'completion_time': 0.176815886, 'completion_tokens_details': {'reasoning_tokens': 57}, 'prompt_time': 0.007317037, 'prompt_tokens_details': None, 'queue_time': 0.34890584, 'total_time': 0.184132923}, 'model_name': 'openai/gpt-oss-120b', 'system_fingerprint': 'fp_068241849b', 'service_tier': 'on_demand', 'finish_reason': 'tool_calls', 'logprobs': None, 'model_provider': 'groq'}, id='lc_run--01a0de65-11eb-75a2-b3b4-2770359461ad-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'Chennai'}, 'id': 'fc_8ee481c4-db27-4a4f-a4e8-839700ea29bb', 'type': 'tool_call'}], **invalid_tool_calls**=[], usage_metadata={'input_tokens': 161, 'output_tokens': 85, 'total_tokens': 246, 'output_token_details': {'reasoning': 57}}), {'role': 'tool', 'content': 'The weather in Chennai is sunny and 25°C.', 'tool_call_id': 'fc_8ee481c4-db27-4a4f-a4e8-839700ea29bb'}]\n\nWait Final....", "url": "https://wpnews.pro/news/tool-calling-code", "canonical_source": "https://dev.to/technonotes/tool-calling-code-1kg6", "published_at": "2026-09-26 16:15:13+00:00", "updated_at": "2026-09-26 16:29:07.702169+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "large-language-models", "developer-tools"], "entities": ["LangChain", "Groq", "ChatGroq", "langchain-groq", "langgraph", "chromadb", "Python"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/tool-calling-code", "markdown": "https://wpnews.pro/news/tool-calling-code.md", "text": "https://wpnews.pro/news/tool-calling-code.txt", "jsonld": "https://wpnews.pro/news/tool-calling-code.jsonld"}}