How to attach runtime configuration to a Runnable
This guide assumes familiarity with the following concepts:
Sometimes we want to invoke a Runnable
with predefined configuration that doesnβt need to be assigned by the caller. We can use the Runnable.withConfig()
method to set these arguments ahead of time.
Binding stop sequencesβ
Suppose we have a simple prompt + model chain:
- npm
- yarn
- pnpm
npm i @langchain/openai @langchain/core
yarn add @langchain/openai @langchain/core
pnpm add @langchain/openai @langchain/core
import { StringOutputParser } from "@langchain/core/output_parsers";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { ChatOpenAI } from "@langchain/openai";
const prompt = ChatPromptTemplate.fromMessages([
[
"system",
"Write out the following equation using algebraic symbols then solve it. Use the format\n\nEQUATION:...\nSOLUTION:...\n\n",
],
["human", "{equation_statement}"],
]);
const model = new ChatOpenAI({ model: "gpt-4o", temperature: 0 });
const runnable = prompt.pipe(model).pipe(new StringOutputParser());
const res = await runnable.invoke({
equation_statement: "x raised to the third plus seven equals 12",
});
console.log(res);
EQUATION: x^3 + 7 = 12
SOLUTION:
Subtract 7 from both sides:
x^3 = 5
Take the cube root of both sides:
x = β5
In certain prompting techniques it can be useful to set one or more stop
words that halt generation when they are emitted by the model. When using the model directly we set stop
words via the extra options
argument passed to invoke
. For example, what if we wanted to modify the example to work as an equation formatter utility? We could instruct the generation process to stop at the word SOLUTION
, and the resulting output would be only the formatted equation.
In this case we are using our model as part of a RunnableSequence. Rather than relying on the preceeding step to output config that contains stop words, we can simply bind the necessary config using withConfig
while creating the RunnableSequence
:
// stop generating after the equation is written
const equationFormatter = prompt
.pipe(model.withConfig({ stop: ["SOLUTION"] }))
.pipe(new StringOutputParser());
// generate only the equation, without needing to set the stop word
const formattedEquation = await equationFormatter.invoke({
equation_statement: "x raised to the third plus seven equals 12",
});
console.log(formattedEquation);
EQUATION: x^3 + 7 = 12
This makes the resulting Runnable
pipeline easier to consume. The caller doesnβt need to know the exact prompting format used, nor do they need to specify the stop word upon invocation. They can simply run their query and get back the result they expect.
Attaching OpenAI toolsβ
Another common use-case is tool calling. While you should generally use the .bindTools()
method for tool-calling models, you can also bind provider-specific args directly if you want lower level control:
const tools = [
{
type: "function",
function: {
name: "get_current_weather",
description: "Get the current weather in a given location",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "The city and state, e.g. San Francisco, CA",
},
unit: { type: "string", enum: ["celsius", "fahrenheit"] },
},
required: ["location"],
},
},
},
];
const modelWithTools = new ChatOpenAI({ model: "gpt-4o" }).withConfig({
tools,
});
await modelWithTools.invoke("What's the weather in SF, NYC and LA?");
AIMessage {
"id": "chatcmpl-BXjkosti03tvSmaxAuYtpRvbEkhRx",
"content": "",
"additional_kwargs": {
"tool_calls": [
{
"id": "call_a15PVBt9g3eCHULn7DBRbL9a",
"type": "function",
"function": "[Object]"
},
{
"id": "call_bQrHLyJ6fAaNkEPNBtgYfIFb",
"type": "function",
"function": "[Object]"
},
{
"id": "call_FxRswXKWou53G0LNQQCvPod4",
"type": "function",
"function": "[Object]"
}
]
},
"response_metadata": {
"tokenUsage": {
"promptTokens": 82,
"completionTokens": 71,
"totalTokens": 153
},
"finish_reason": "tool_calls",
"model_name": "gpt-4o-2024-08-06",
"usage": {
"prompt_tokens": 82,
"completion_tokens": 71,
"total_tokens": 153,
"prompt_tokens_details": {
"cached_tokens": 0,
"audio_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
},
"system_fingerprint": "fp_90122d973c"
},
"tool_calls": [
{
"name": "get_current_weather",
"args": {
"location": "San Francisco, CA"
},
"type": "tool_call",
"id": "call_a15PVBt9g3eCHULn7DBRbL9a"
},
{
"name": "get_current_weather",
"args": {
"location": "New York, NY"
},
"type": "tool_call",
"id": "call_bQrHLyJ6fAaNkEPNBtgYfIFb"
},
{
"name": "get_current_weather",
"args": {
"location": "Los Angeles, CA"
},
"type": "tool_call",
"id": "call_FxRswXKWou53G0LNQQCvPod4"
}
],
"invalid_tool_calls": [],
"usage_metadata": {
"output_tokens": 71,
"input_tokens": 82,
"total_tokens": 153,
"input_token_details": {
"audio": 0,
"cache_read": 0
},
"output_token_details": {
"audio": 0,
"reasoning": 0
}
}
}
Next stepsβ
You now know how to bind runtime arguments to a Runnable.
Next, you might be interested in our how-to guides on passing data through a chain.