Migrating from LLMMathChain
LLMMathChain
enabled the evaluation of mathematical expressions generated by a LLM. Instructions for generating the expressions were formatted into the prompt, and the expressions were parsed out of the string response before evaluation using thenumexpr library.
This is more naturally achieved viatool calling. We can equip a chat model with a simple calculator tool leveragingnumexpr
and construct a simple chain around it usingLangGraph. Some advantages of this approach include:
- Leverage tool-calling capabilities of chat models that have been fine-tuned for this purpose;
- Reduce parsing errors from extracting expression from a string LLM response;
- Delegation of instructions tomessage roles (e.g., chat models can understand what a
ToolMessage
represents without the need for additional prompting); - Support for streaming, both of individual tokens and chain steps.
%pip install--upgrade--quiet numexpr
import os
from getpassimport getpass
if"OPENAI_API_KEY"notin os.environ:
os.environ["OPENAI_API_KEY"]= getpass()
Legacy
Details
from langchain.chainsimport LLMMathChain
from langchain_core.promptsimport ChatPromptTemplate
from langchain_openaiimport ChatOpenAI
llm= ChatOpenAI(model="gpt-4o-mini")
chain= LLMMathChain.from_llm(llm)
chain.invoke("What is 551368 divided by 82?")
{'question': 'What is 551368 divided by 82?', 'answer': 'Answer: 6724.0'}
LangGraph
Details
import math
from typingimport Annotated, Sequence
import numexpr
from langchain_core.messagesimport BaseMessage
from langchain_core.runnablesimport RunnableConfig
from langchain_core.toolsimport tool
from langchain_openaiimport ChatOpenAI
from langgraph.graphimport END, StateGraph
from langgraph.graph.messageimport add_messages
from langgraph.prebuilt.tool_nodeimport ToolNode
from typing_extensionsimport TypedDict
@tool
defcalculator(expression:str)->str:
"""Calculate expression using Python's numexpr library.
Expression should be a single line mathematical expression
that solves the problem.
Examples:
"37593 * 67" for "37593 times 67"
"37593**(1/5)" for "37593^(1/5)"
"""
local_dict={"pi": math.pi,"e": math.e}
returnstr(
numexpr.evaluate(
expression.strip(),
global_dict={},# restrict access to globals
local_dict=local_dict,# add common mathematical functions
)
)
llm= ChatOpenAI(model="gpt-4o-mini", temperature=0)
tools=[calculator]
llm_with_tools= llm.bind_tools(tools, tool_choice="any")
classChainState(TypedDict):
"""LangGraph state."""
messages: Annotated[Sequence[BaseMessage], add_messages]
asyncdefacall_chain(state: ChainState, config: RunnableConfig):
last_message= state["messages"][-1]
response=await llm_with_tools.ainvoke(state["messages"], config)
return{"messages":[response]}
asyncdefacall_model(state: ChainState, config: RunnableConfig):
response=await llm.ainvoke(state["messages"], config)
return{"messages":[response]}
graph_builder= StateGraph(ChainState)
graph_builder.add_node("call_tool", acall_chain)
graph_builder.add_node("execute_tool", ToolNode(tools))
graph_builder.add_node("call_model", acall_model)
graph_builder.set_entry_point("call_tool")
graph_builder.add_edge("call_tool","execute_tool")
graph_builder.add_edge("execute_tool","call_model")
graph_builder.add_edge("call_model", END)
chain= graph_builder.compile()
# Visualize chain:
from IPython.displayimport Image
Image(chain.get_graph().draw_mermaid_png())
# Stream chain steps:
example_query="What is 551368 divided by 82"
events= chain.astream(
{"messages":[("user", example_query)]},
stream_mode="values",
)
asyncfor eventin events:
event["messages"][-1].pretty_print()
================================[1m Human Message [0m=================================
What is 551368 divided by 82
==================================[1m Ai Message [0m==================================
Tool Calls:
calculator (call_1ic3gjuII0Aq9vxlSYiwvjSb)
Call ID: call_1ic3gjuII0Aq9vxlSYiwvjSb
Args:
expression: 551368 / 82
=================================[1m Tool Message [0m=================================
Name: calculator
6724.0
==================================[1m Ai Message [0m==================================
551368 divided by 82 equals 6724.
Next steps
See guides for building and working with toolshere.
Check out theLangGraph documentation for detail on building with LangGraph.