avatarLaxfed Paulacy

Summary

The website content discusses the advancements in structured data extraction using LangChain's parallel function calling, which simplifies the process of extracting multiple pieces of information simultaneously from unstructured data.

Abstract

The article introduces LangChain's parallel function calling feature as a significant improvement in the field of structured data extraction. It explains that traditional methods of extracting data from unstructured sources, such as entity extraction, were limited to one piece of information at a time, necessitating workarounds like creating an 'Information' class to bundle multiple data points. With parallel function calling, developers can directly pass multiple data types, like 'Person' and 'Location', without complex input structures, reducing the likelihood of errors and simplifying both the input and output processes. The article also provides a code example demonstrating how to set up an extraction chain using LangChain, which integrates with recent OpenAI models capable of handling tools, to efficiently extract structured data.

Opinions

  • The author suggests that the old method of function calling in data extraction was inefficient and required unnecessary hacks, implying a less than ideal developer experience.
  • The new parallel function calling is seen as a major enhancement, offering a better developer experience by requiring less logic for both input creation and output parsing.
  • The author emphasizes that the improvements in function calling not only make the process less complicated but also reduce the chances of the language model producing incorrect outputs.
  • There is an excitement about the potential of function calling beyond creating agents, particularly in structuring outputs from language models for generic use cases like extraction.
  • The author encourages readers to try out parallel function calling, highlighting its ease of use compared to previous methods.

LANGCHAIN — Parallel Function Calling Extraction for Structured Data Extraction

Technology offers us a unique opportunity, though rarely welcome, to practice patience. — Allan Lokos.

Extraction is the process of extracting structured data from unstructured data. A concrete example of this is entity extraction. As Sematext explains:

Entity extraction is, in the context of search, the process of figuring out which fields a query should target, as opposed to always hitting all fields. The reason we may want to involve entity extraction in search is to improve precision.

With old function calling, you could only get one function call back at a time. This made it so that if you wanted to extract multiple pieces of information at a time you had to do some hacks. For example, let’s assume you wanted to extract the following pieces of information:

class Person(BaseModel):
    name: str
    age: int

If I just passed that directly as a function to the old OpenAI models, it would only ever return one piece of information! This is obviously not acceptable if I want to extract multiple pieces of information.

In order to extract multiple pieces of information, I would have to do a hack like:

class Information(BaseModel):
    people: List[Person]

This would construct a new object that had as a field a list of Person objects. This way, when the OpenAI model constructed the function invocation, it would construct one argument that was a list of people.

So how does parallel function calling improve this?

It removes a LOT of the complexity and hacks we had to do. You no longer have to create that ugly, extraneous Information class - you can just pass in Person and Location directly as functions, and the model will output those as separate function calls. This is an improvement because it means:

  • Less logic needed to create the LLM input (better developer experience)
  • Less complicated function definitions to pass to the LLM (saves on tokens, less likely to confuse the LLM)
  • Less complicated output the LLM needs to produce (smaller chance the LLM messes up and outputs incorrect json)
  • Less logic needed to parse the LLM output (better developer experience)

We’ve put all this together into a simple extraction chain. The full logic for the chain looks something like:

# Create a prompt telling the LLM to extract information
prompt = ChatPromptTemplate.from_messages({
        ("system", _EXTRACTION_TEMPLATE),
        ("user", "{input}")
    })

# Convert Pydantic objects to the appropriate schema
tools = [convert_pydantic_to_openai_tool(p) for p in pydantic_schemas]
# Give the model access to these tools
model = llm.bind(tools=tools)
# Create an end to end chain
chain = prompt | model | PydanticToolsParser(tools=pydantic_schemas)

Using this chain we can now do things like:

# Make sure to use a recent model that supports tools
model = ChatOpenAI(model="gpt-3.5-turbo-1106")
chain = create_extraction_chain_pydantic(Person, model)
chain.invoke({"input": "jane is 2 and bob is 3"})

And get:

[Person(name='jane', age=2), Person(name='bob', age=3)]

While most people are excited about function calling for creating agents, there is a very real (and very useful) use case around using it to structure outputs from LLMs more generically. One of these use cases is extraction, but with old function calling you had to do some hacks to get that to work. With parallel function calling it is significantly easier. Try it out!

Langchain
Calling
Function
ChatGPT
Parallel
Recommended from ReadMedium