Abstract
The current landscape of agent frameworks predominantly focuses on low-code development (using static diagrams or pipelines) or addressing specific domain tasks, which often leads to difficulties in debugging and rigid workflows. \textbf{L}anguage \textbf{Agent} addresses these challenges by offering an imperative and Pythonic programming style that treats code as an agent. This approach facilitates easier debugging and streamlines the development of agent workflows. Additionally, Lagent allows for straightforward deployment as an HTTP service, supporting the construction of distributed multi-agent applications through centralized programming. This enhances development efficiency while maintaining effectiveness.
In this paper, we detail the principles that drove the implementation of Lagent and how they are reflected in its architecture. We emphasize that every aspect of Lagent is a regular Python program under the full control of its user. We also explain how the careful and pragmatic implementation of the key components of its runtime enables them to work together to achieve compelling performance.
Usability centric design
Consequently, the agents themselves evolved rapidly from a single Plan-Action-Iteration agent or Plan-Then-Act agent\cite{} into incredibly varied numerical programs often composed of many loops and recursive functions
To support this growing complexity, Lagent foregoes the potential benefits of a graph-metaprogramming-based or event-driven-based\cite{} approach to preserve the imperative programming model of Python. PyTorch inspired this design. Lagent extends this to all aspects of agent workflows. Defining LLMs, tools, and memories, deploying an HTTP service, distributing multi-agents, and making the inference process asynchronous are all expressed using the familiar concepts developed for general-purpose programming.
This solution ensures that any new potential agent architecture can be easily implemented with Lagent. For instance, agents (which in agent learning commonly be understood as Instruction + LLM + Memory + Plan/Action based on current state) are typically expressed as Python classes whose constructors create and initialize their parameters, and whose forward methods process an input. Similarly, multi-agents are usually represented as classes that compose single agents, but let us state again that nothing forces the user to structure their code in that way. Listing demonstrates how ReAcT(a common used agent) and TranslateAgentv(translation agent pipeline) can be created by lagent. Note that ReACT is of course part of the library, but we show an example implementation to highlight how simple it is.
python
class ReACT(Agent):
def __init__(self):
llm = LLM()
self.tools = tools
react_instruction = react_instruction.format(
action_info=get_tools_description(self.tools)
self.select_agent = Agent(
llm=llm, template=react_instruction)
self.finish_condition = lambda m:
'FinalAnswer' in m.content
super().__init__()
def forward(
self, message: AgentMessage, **kwargs
) -> AgentMessage:
for _ in range(self.max_turn):
message = self.select_agent(message)
if self.finish_condition(message):
return message
message = self.tools(message)
return message
python
class TranslateAgent(Agent):
def __init__(self):
self.llm = LLM()
self.initial_agent = Agent(
template=initial_trans_template, llm=llm)
self.reflection_agent = Agent(
template=reflection_template, llm=llm)
self.improve_agent = Agent(
tempalte=improve_translation_template, llm=llm)
super().__init__()
def forward(
self, message: AgentMessage, **kwargs
) -> AgentMessage:
initial_message = self.initial_agent(message)
reflection_message = self.reflection_agent(message,
initial_message)
response_message = self.improve_agent(
message,
initial_message,
reflecion_message)
return response_message