Skip to content

Why Archytas over LangChain

David-Andrew Samson edited this page Apr 26, 2023 · 15 revisions

Langchain's ReAct process does not work reliably with GPT-4

langchain defaults to GPT-3 (Davinci), but GPT-3 has limited planning capacity and frequently fails to accomplish mildly complex tasks. GPT-4 is much more capable, and quite necessary to have a chance at doing most of the things that are useful but complex

langchain supports the GPT-3.5/GPT-4 chat-style API interface, but the prompting is not good enough. Frequently both will fail to follow the expected langchain format (which would be parsed into thoughts/actions/input/etc.), causing langchain to crash.

Archytas is purpose built around GPT-4, and properly prompts it to generate output in the desired (json) format. On the rare occasions GPT-4 fails to follow the format, archytas feeds the LLM sensible error messages that allow the agent to recover and continue using the correct format.

GPT-3.5-turbo support

unfortunately it seems GPT-3.5-turbo is a lost cause in any sort of ReAct loop:

  • No amount of prompting can convince it to output a valid json without any extra text outside the json body, though it will generate valid json's that archytas can use.
  • handling the spurious text (e.g. via dirtyjson) is possible, but it frequently gets stuck in infinite loops of repeating the same thing over and over, rather than continuing the ReAct process until the task is solved

Archytas has better tool ergonomics

Tools created in langchain must be a function that take a single string as input, and then return a single string as output. If the tool wants to use a different type or have multiple inputs, it must explicitly handle parsing the input string into the desired shape. And same for any output which must be manually converted to a string format so the LLM can understand it. Additionally, it is up to the tool developer to explain to the LLM any expectations for the input so that it can be parsed accordingly. This is pretty ad-hoc if you're doing anything more complex than string in, string out.

Archytas has a consistent interface for all tools it presents to the LLM: JSON values. Tools can take any number of arguments, that may be any valid python-equivalent of JSON objects

  • dict
  • list
  • int/float
  • bool
  • str
  • None

When the LLM is interacting with tools, Archytas will automatically parse/convert the LLM string into the correct types corresponding to the tool's function signature. Then when the tool returns it's response (if any), archytas will then convert it back into a string the LLM can understand. This means that your tool functions can look much more like regular functions with multiple arguments, typing, etc. and aren't forced to conform to the def mytool(s:str) -> str interface required by langchain

Archytas effortlessly works with stateful tools and sets of related tools

If your python-fu is strong then yes you can certainly create a langchain tool that keeps internal state (e.g. by making a class instance, and then pulling one of the bound methods out to be the tool). However it's a rather cumbersome process.

Additionally, if you want to have a set of related tools that are conceptually bundled together, there's not really a canonical approach for doing this in langchain. To do so, it's ultimately a matter of giving your tools good names, and then explaining very well in all of the tool descriptions how they interact, and work together.

@toolsets

Archytas provides the @toolset decorator which applies to classes. This easily solves both handling tools with state, as well as bundled toolsets that have many related tools. The class interface provides a solid conceptual interface for bundling related tools, as well as for managing stateful tools

  • e.g. Let's say you were making a bunch of math tools, you could have Math.sin, Math.abs, Math.sqrt, Math.pi, etc. all be grouped together under a single math toolset. Archytas automatically generates a prompt for the LLM explaining how to access each of the subtools in the toolset, and manages delegating calls to the correct methods in the class.
  • For stateful tools, archytas maintains an instance of the class toolset when running the ReAct loop, making it trivial to maintain and update the state whenever any of the tool methods are called.

Graceful error handling

archytas tools can raise exceptions, which then get caught and shown to the LLM in a consistent manner. In the Archytas ReAct loop, the LLM can then seamlessly recover from errors encountered while using tools, based on the exceptions. (TODO: lookup how langchain handles exceptions during tool usage)

Archytas generates better prompts

(in langchain, when making a tool, you had to explain in detail how your tool worked so the llm could use it. but it wasn't really obvious how to explain the precise format that inputs/outputs should take.)(archytas has a very clear paradigm that is responses are parsed as json, tool input arguments are extracted from fields in the json. prompt for this is generated automatically assuming the tool is type annotated and has a matching docstring)

Archytas is simpler+easier to peek inside

Clone this wiki locally