Preramble: I have been building a few different agents for learning purposes, specifically I'm using langchain (typescript). I made some key observations on the complexity levels when chaining vs agents.
The terms "prompt chaining" and "agents" have become increasingly common in the AI space, with agents gaining particular mainstream attention. In frameworks like LangChain, these approaches represent fundamentally different architectural patterns: prompt chaining follows a DAG-like structure with linear, sequential flow, while agents operate as dynamic state machines capable of making decisions and adapting their execution paths.
Prompts are the inputs given to AI models, guiding them to generate specific outputs. They can be simple questions or complex instructions, depending on the task at hand.
Prompt chaining is a technique where multiple prompts are linked together in a sequence to achieve a specific goal or task. Each prompt in the chain builds upon the output of the previous one, creating a linear flow of information. This method is particularly useful for tasks that require a step-by-step process, where each step depends on the results of the previous one.
Agents are autonomous entities that can make decisions, take actions, and interact with their environment based on predefined rules or learned behaviors. They can operate independently, adapting to new information and changing circumstances.
LangChain is a framework designed to simplify the development of applications using large language models (LLMs). It provides tools for building complex workflows, integrating various components, and managing interactions with LLMs. In LangChain, prompt chaining and agents are two key concepts that you'll need to be familiar with if you want to build applications that leverage the power of LLMs effectively.
LangChain Core is the foundational library that provides essential components for building AI applications. It includes tools for managing prompts, agents, and memory (which I've talked a little bit before in a preview article), allowing you to create complex workflows. The core library is designed to be modular and extensible, enabling engineers to customize and extend their AI based applications according to specific needs.
Prompt chaining is a method where multiple prompts are linked together in a sequence to achieve a specific goal. Each prompt in the chain builds upon the output of the previous one, creating a linear flow of information. This approach is particularly useful for tasks that require a step-by-step process, where each step depends on the results of the previous one. Like a pipeline or a DAG, the output of one step is the input for the next, allowing for a clear and structured progression towards the final result.
An example of prompt chaining could be a multi-step question-answering system, where the first prompt gathers initial information, the second refines that information, and the third generates a final answer based on the refined data. This method is straightforward and easy to implement, making it suitable for tasks with well-defined steps. We'll start off by setting up our LLM (Large Language Model) using the OpenAI API, which is a common choice for namely due to the ease of use and pricing.
import { ChatOpenAI } from "@langchain/openai";
const llm = new ChatOpenAI({
model: "gpt-3.5-turbo-1106",
temperature: 0.2,
});
Next, we can define our prompt.
import { ChatPromptTemplate } from "@langchain/core/prompts";
const analysisPrompt = ChatPromptTemplate.fromTemplate(
"Analyze this business problem and identify the key challenges: {problem}. " +
"Provide a structured analysis with main issues, stakeholders, and constraints."
);
const solutionPrompt = ChatPromptTemplate.fromTemplate(
"Based on this analysis: {analysis}, generate 3 potential solutions. " +
"For each solution, provide implementation approach and expected outcomes."
);
const evaluationPrompt = ChatPromptTemplate.fromTemplate(
"Given these solutions: {solutions} and the original problem: {originalProblem}, " +
"evaluate each solution considering feasibility, cost, and impact. " +
"Rank them from best to worst with detailed justification."
);
We can then chain these prompts together to create a sequence of interactions. The first prompt gathers initial information, and the second refines that information based on the user's input.
import { RunnableSequence } from "@langchain/core/runnables";
import { StringOutputParser } from "@langchain/core/output_parsers";
const businessProblem = "Our e-commerce startup is losing customers due to slow website loading times and poor mobile experience. Revenue has dropped 25% in the last quarter.";
const promptChain = RunnableSequence.from([
{
analysis: analysisPrompt.pipe(llm).pipe(new StringOutputParser()),
originalProblem: (input) => input.problem
},
{
solutions: solutionPrompt.pipe(llm).pipe(new StringOutputParser()),
originalProblem: (input) => input.originalProblem
},
evaluationPrompt.pipe(llm).pipe(new StringOutputParser())
]);
const result = await promptChain.invoke({ problem: businessProblem });
console.log("Final Evaluation:", result);
And that's it! The result will contain the final answer based on the initial question and the information gathered through the prompts. This example demonstrates how prompt chaining can be used to create a structured workflow that builds upon previous outputs, allowing for a more refined and accurate response. My opinion; this is a great way to get started with LangChain and LLMs, as it provides a clear and straightforward approach to building complex workflows - however, it can become cumbersome as the number of steps increases, leading to a more complex and less maintainable codebase.
Agents are "autonomous" entities that can make decisions, take actions (tool invocations), and interact with their environment based on predefined rules or learned behaviors. They can operate independently, adapting to new information and changing circumstances. In the context of LangChain, agents are designed to handle more complex tasks that require dynamic decision-making and interaction with various components.
In this example, we will create a simple agent that can answer questions about the weather and perform basic calculations. The agent will use tools to fetch weather data and perform calculations, demonstrating how agents can interact with their environment and make decisions based on user input.
import { Tool } from "@langchain/core/tools";
const weatherTool = new Tool({
name: "get_weather",
description: "Get current weather for a location",
func: async (location: string) => {
return `The weather in ${location} is sunny with 22°C`; // This would be an API call to a weather service
}
});
const calculatorTool = new Tool({
name: "calculator",
description: "Perform basic mathematical calculations",
func: async (expression: string) => {
try {
return `Result: ${eval(expression)}`; // This is a simple eval, in production use a safer parser
} catch (error) {
return "Invalid mathematical expression";
}
}
});
Now that we have our tools defined, we can create an agent that uses these tools to answer questions. The agent will decide which tool to use based on the user's input, demonstrating its ability to make decisions and take actions autonomously.
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { ChatOpenAI } from "@langchain/openai";
const llm = new ChatOpenAI({
model: "gpt-3.5-turbo-1106",
temperature: 0.1,
});
const agent = createReactAgent({
llm,
tools: [weatherTool, calculatorTool],
systemMessage: "You are a helpful assistant that can check weather and perform calculations. Use the available tools when needed."
});
const examples = [
"What's the weather like in Paris?",
"Calculate 15 * 23 + 7",
"Can you tell me the weather in Tokyo and then calculate 100 / 4?"
];
for (const question of examples) {
const result = await agent.invoke({
messages: [{ role: "human", content: question }]
});
console.log(`Question: ${question}`);
console.log(`Answer: ${result.messages[result.messages.length - 1].content}\n`);
}
The agent will process each question and decide on what tool to use based on the content of the question. For example, if the question is about the weather, it will invoke the get_weather tool; if it's a mathematical expression, it will use the calculator tool.
| Feature | Prompt Chaining | Agents |
|---|---|---|
| Structure | Linear sequence of prompts | Autonomous entities with decision-making capabilities |
| Complexity | Simple, easy to implement | More complex, requires understanding of agent behavior |
| Use Cases | Step-by-step tasks, well-defined workflows | Dynamic tasks, real-time decision-making, and tool invocation |
| Interaction | Sequential, each step depends on the previous step | Independent, can interact with multiple tools and components |
| Flexibility | Limited to predefined steps in the chain | Highly flexible, can adapt to new information and changing circumstances |
| Maintenance | Can become cumbersome with many steps | More maintainable for complex tasks due to modularity and autonomy |
In summary, prompt chaining and agents are two distinct approaches to building AI applications using frameworks like LangChain. Prompt chaining is suitable for tasks that require a linear flow of information, while agents are designed for more complex, dynamic tasks that require decision-making and interaction with various components. Understanding the differences between these two approaches is crucial for selecting the right method for your specific use case. As you explore LangChain and its capabilities, consider the nature of your tasks and the level of complexity required to determine whether prompt chaining or agents is the best fit for your application.
Unrelated to agents vs chaining - if you are planning on using langchain with typescript, I highly advise using the python alternative due to the typescript types inference being quite heavy and the code bloat that comes with langchains typescript implementation.