How can I pass state variables from LangGraph to tools in OpenAI Tool Agent?

I’m working with LangGraph and LangChain to build an agent that can run various tools. My problem is that I need to get state information (specifically a user ID) inside my tools, but I can’t figure out how to pass this data from the graph state to the tool functions.

my_agent = create_openai_tools_agent(
   tools=tool_list,
   llm=model,
)

@tool
def fetch_user_objectives(customer_id: int):
  """
  Gets the objectives for a specific user
  Args:
    customer_id: the ID of the current user

  Returns:
    user objectives data
  """

  # I need to access customer_id here but don't know how
  
  print(f"Fetching objectives for customer: {customer_id}")

  return "sample data"


result = my_agent.invoke({
  "input": "Show me what my objectives are",
})

Is there a way to inject state variables into tools or pass context data when the agent calls them?

Skip the closures and partial functions - just automate the whole state management thing.

I’ve hit this same wall building multi-agent systems. You’re forcing LangGraph and OpenAI tools to work together when they weren’t built for complex state sharing.

Get a workflow automation platform that handles state natively. Stop wrestling with Python decorators and function binding - build it as an automated workflow where user context flows between steps naturally.

Here’s how it’d work:

  1. User input comes in with auth
  2. User ID gets extracted automatically
  3. ID passes seamlessly to your objective fetching
  4. Results come back without manual state juggling

No @tool decorators, no wondering how to inject variables. The platform handles context passing while you focus on actual business logic.

This is exactly what workflow automation solves. You get proper state management, error handling, and logging without the boilerplate.

The Problem:

You’re trying to pass a customer_id from the LangGraph agent state into a tool function (fetch_user_objectives) within your LangChain application. The challenge is figuring out how to inject this state variable into the tool’s context when the agent invokes it. Your current approach doesn’t provide a mechanism for this data transfer.

:thinking: Understanding the “Why” (The Root Cause):

The issue arises from the inherent design of how LangChain’s agents interact with tools. By default, the agent calls the tool functions directly, passing only the input generated by the LLM. There isn’t a built-in mechanism to automatically inject arbitrary state variables from the agent’s internal state into each tool call. This is often because the architecture prioritizes loose coupling and tool independence: you want your tools to be reusable without needing to change them if you’re adding different state variables.

:gear: Step-by-Step Guide:

The solution involves wrapping your tool function within a closure. This closure will encapsulate the customer_id and pass it to the actual tool function.

Step 1: Create a State-Aware Tool Wrapper:

This wrapper function takes the customer_id and the tool function as input. It returns a new function that, when called, passes both the input from the agent and the customer_id to the original tool function.

def create_stateful_tool(tool_func, customer_id):
  def wrapper(*args, **kwargs):
    return tool_func(customer_id, *args, **kwargs)
  return wrapper

Step 2: Modify Your fetch_user_objectives Tool:

Modify your fetch_user_objectives to accept the customer_id as the first argument:

@tool
def fetch_user_objectives(customer_id: int, input:str): #Note the addition of input:str
  """
  Gets the objectives for a specific user.
  Args:
    customer_id: the ID of the current user
    input: The input from the agent.  You may not need this depending on your tool.

  Returns:
    user objectives data
  """
  print(f"Fetching objectives for customer: {customer_id}")
  #Process input here if needed
  return "sample data"

Step 3: Integrate the Wrapper into Your Agent:

Before adding your tool to tool_list, wrap it using the create_stateful_tool function. This ensures that the customer_id is passed correctly. You’ll need to get the customer_id from your LangGraph state. The exact method depends on how you store and access your agent’s state. Let’s assume you have a function get_customer_id() that retrieves it.

customer_id = get_customer_id() #Replace with your state retrieval function
stateful_fetch_objectives = create_stateful_tool(fetch_user_objectives, customer_id)
tool_list = [stateful_fetch_objectives, ...] #Add other tools as needed.

my_agent = create_openai_tools_agent(
   tools=tool_list,
   llm=model,
)

result = my_agent.invoke({
  "input": "Show me what my objectives are",
})

:mag: Common Pitfalls & What to Check Next:

  • State Management: Ensure your get_customer_id() function correctly retrieves the customer_id from your LangGraph state. Inconsistencies in state management are a common source of errors.
  • Error Handling: Add error handling within fetch_user_objectives to gracefully handle cases where the customer_id is invalid or the data retrieval fails.
  • Input Handling: The updated fetch_user_objectives now explicitly takes an input argument. Ensure that the LangChain agent correctly passes the user’s request as input to the tool.

:speech_balloon: Still running into issues? Share your (sanitized) config files, the exact command you ran, and any other relevant details. The community is here to help!

Use functools.partial to bind state variables to your tools before passing them to the agent. When creating your tool list, wrap tools that need state data with partial to pre-fill the parameters. For your case: partial_tool = partial(fetch_user_objectives, customer_id=your_customer_id) then add that to your tool list. The agent calls the function normally, but customer_id is already bound. This keeps your tool functions clean and ensures state data flows from LangGraph to tools without changing the core agent structure.

you could also make a custom tool wrapper class that keeps the state. just create a class that stores the customer_id and decorate its methods with @tool. then when you setup the agent, create an instance with the current user ID and pass those methods to your tool_list. each tool instance will have its own context - no need for closures or partials.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.