langchainjs icon indicating copy to clipboard operation
langchainjs copied to clipboard

Throw an error when both bindTools and withStructuredOutput are used, getting tools attached to an agent

Open anilgulecha opened this issue 9 months ago • 5 comments

Checked other resources

  • [x] I added a very descriptive title to this issue.
  • [x] I searched the LangChain documentation with the integrated search.
  • [x] I used the GitHub search to find a similar question and didn't find it.
  • [x] I am sure that this is a bug in LangChain rather than my code.
  • [x] The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).

Example Code

model.bindTools(tools); model.withStructuredOutput(schema); model.invoke([...]) // does not throw Error

Error Message and Stack Trace (if applicable)

No response

Description

I was using the gemini model, and per documentation was using tools, and then was trying to use withStructuredOutput as well.

Things didnt work as expected (and looking at the traces I saw no functions being passed to upstream calls. After much debugging landed on the documentation that called out we can't use both of these together. Also this discussion.

It would have been helpful if:

  1. There was an error thrown on calling invoke with both bindTools and withStructuredOutput are used on the chat node. If the goal is to allow this to be used for some usecases, then a flag could be passed to invoke to allow.
  2. There seems no way to see what tools are bound to a chat node after calling bindTools. I cannot do chatllm.tools or chatllm.getTools. Documentation also shows nothing to get tools attached to a chat node! This caused frustration when trying to debug the above issue. Can we expose such a method or attribute on a chat model so we can see what are the current tools attached to a model node.

System Info

I'm on:

@langchain/core": "^0.3.39" @langchain/google-genai": "^0.1.8"

anilgulecha avatar Feb 25 '25 03:02 anilgulecha

I learnt on this page that both are not possible: https://langchain-ai.github.io/langgraph/how-tos/react-agent-structured-output/

anilgulecha avatar Feb 25 '25 03:02 anilgulecha

I think I've opened this on the wrong repo - meant to open it on langchainjs. Though it' probably also relevant to python lang-chain. I'll open it there - the maintainers here can decide on whether python lib also needs the same.

anilgulecha avatar Feb 25 '25 04:02 anilgulecha

I found a similar open issue titled "Throw an error when both bindTools and withStructuredOutput are used, getting tools attached to an agent" which was last updated on February 25, 2025. This issue has no comments or references yet [1].

Regarding your concerns:

  1. The intended behavior when both bindTools and withStructuredOutput are used together is that the chat model must implement the .bindTools() method to utilize withStructuredOutput. If bindTools is not implemented, an error is thrown [2]. However, it seems that an error is not being thrown in your case, which might be a bug.

  2. Currently, there is no documented method or property in LangChainJS that allows users to retrieve the tools bound to a chat node. This could be a useful feature to add for debugging purposes [3].

It might be helpful to follow the open issue for any updates or potential fixes regarding these concerns.

To continue talking to Dosu, mention @dosu.


Help Dosu learn! Give it feedback: Great Response | Irrelevant Answer | Incorrect Sources | Too Verbose | Hallucination | Bug Report | Other

dosubot[bot] avatar Feb 25 '25 16:02 dosubot[bot]

@anilgulecha I agree that it'd be nice if we failed faster here, however we often lean on the provider APIs for this sort of error checking, as it allows for forward compatibility in cases where the provider in question removes restrictions.

Regarding the request for the ability to get the list of bound tools, I could see how this would be a helpful addition in cases where the tools are bound dynamically or in code that's otherwise "far away" from code that would benefit from inspecting for tool bindings.

If you just need to check whether or not the model has tools bound at all, bound BaseChatModel instances will be an instance of RunnableBinding, where unbound ones will be an instance of BaseChatModel.

benjamincburns avatar Mar 02 '25 22:03 benjamincburns

import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
import z from "zod";

const schema = z.object({
  time: z.string(),
});

const getCurrentTimeTool = {
  name: "getCurrentTime",
  description: "Get the current date and time in ISO 8601 format.",
  parameters: z.object({}),
  func: async () => {
    const now = new Date();
    return { time: now.toISOString() };
  },
};

const main = async () => {
  const llm = new ChatGoogleGenerativeAI({
    model: "models/gemini-1.5-flash",
    apiKey: ""
  });

  llm.bindTools([getCurrentTimeTool]);
  llm.withStructuredOutput(schema);
  const response = await llm.invoke([
    { role: "user", content: "What time is it?" },
  ]);

  console.log(response);
};

main();

This code works for me. I would like to contribute to this issue. Could you let me know how to reproduce the bug?

0xobedient avatar Aug 25 '25 11:08 0xobedient