Custom LLM Agents
This guide covers how to build custom LLM agents using LangChain. We'll walk through setting up the environment, tools, prompt template, output parser, LLM, stop sequence, and agent executor.
Overview
An LLM agent consists of four key components:
- Prompt Template: Provides instructions for the LLM on what to do. This allows controlling the agent's behavior.
- LLM: The large language model that powers the agent. Different models have different capabilities.
- Stop Sequence: A special token that tells the LLM when to stop generating text. This is critical to prevent runaway generation.
- Output Parser: Parses the raw LLM text into structured
AgentAction
orAgentFinish
objects. This handles the interface between the LLM and the outside world.
The agent is used in an Agent Executor loop:
- User input is passed to the agent
- The agent returns either an
AgentAction
orAgentFinish
- If it is an
AgentAction
, the executor calls the specified tool and gets anObservation
- The executor repeats the loop, passing the
AgentAction
andObservation
back to the agent until anAgentFinish
is returned
This loop allows the agent to take multiple actions before returning a final response.
Set up Environment
Import the necessary libraries:
from langchain.agents import Tool, AgentExecutor, LLMSingleActionAgent, AgentOutputParser
from langchain.prompts import StringPromptTemplate
from langchain import OpenAI, SerpAPIWrapper, LLMChain
from typing import List, Union
from langchain.schema import AgentAction, AgentFinish, OutputParserException
import re
Set up Tools
Define any tools the agent can use:
# Search tool
search = SerpAPIWrapper()
tools = [
Tool(
name="Search",
func=search.run,
description="Useful for answering questions about current events"
)
]
Prompt Template
Instruct the agent on what to do:
# Template
template = """
You are a helpful assistant with access to these tools:
{tools}
Please follow this format:
Question: {input}
Thought: Think about how to answer the question
Action: Tool to use
Action Input: Input for the tool
Observation: Result from tool
Final Answer: Final response to the original question
{agent_scratchpad}
"""
# Prompt class
class CustomPrompt(StringPromptTemplate):
def format(self, **kwargs):
thoughts = ""
for action, obs in kwargs["intermediate_steps"]:
thoughts += f"{action.log}\nObservation: {obs}\n"
kwargs["agent_scratchpad"] = thoughts
kwargs["tools"] = "\n".join([
f"{t.name}: {t.description}" for t in self.tools
])
return self.template.format(**kwargs)
prompt = CustomPrompt(
template=template,
tools=tools,
input_variables=["input", "intermediate_steps"]
)
The template provides instructions and formats the tools, previous steps, and input.
Output Parser
Parse LLM output into AgentAction
or AgentFinish
:
class CustomOutputParser(AgentOutputParser):
def parse(self, llm_output: str):
if "Final Answer:" in llm_output:
return AgentFinish(
return_values={"output": llm_output.split("Final Answer:")[-1].strip()},
log=llm_output
)
match = re.search(r"Action: (.*)\nInput: (.*)", llm_output, re.DOTALL)
if not match:
raise OutputParserException("Could not parse output")
action = match.group(1).strip()
action_input = match.group(2).strip()
return AgentAction(
tool=action,
tool_input=action_input,
log=llm_output
)
parser = CustomOutputParser()
This parses the raw LLM output into structured objects.
Set up LLM
Choose your LLM:
llm = OpenAI(temperature=0)
Stop Sequence
Tell the LLM when to stop generating:
stop = ["\nObservation:"]
This aligns with the Observation
token in the prompt.
Create Agent
Combine the components:
llm_chain = LLMChain(llm=llm, prompt=prompt)
agent = LLMSingleActionAgent(
llm_chain=llm_chain,
output_parser=parser,
stop=stop,
allowed_tools=[t.name for t in tools]
)
Use the Agent
Run the executor:
executor = AgentExecutor.from_agent_and_tools(
agent=agent,
tools=tools,
verbose=True
)
executor.run("How many people live in Canada?")
Debugging Tips
Some tips for debugging agents:
- Log intermediate LLM outputs to see full responses
- Print parsed
AgentAction
andAgentFinish
objects - Ensure stop sequence aligns with prompt format
- Test output parser on sample LLM outputs
- Simplify prompt and output parsing format if needed
- Adjust LLM temperature if getting inconsistent outputs
Careful prompt design, output parsing, and debugging allows building effective custom agents!