# `LangChain.Chains.DataExtractionChain`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.4/lib/chains/data_extraction_chain.ex#L1)

Defines an LLMChain for performing data extraction from a body of text.

Provide the schema for desired information to be parsed into. It is treated as
though there are 0 to many instances of the data structure being described so
information is returned as an array.

The result is always a list. If the LLM returns a single map instead of an
array, it is automatically wrapped in a list so callers can rely on a
consistent return type.

Originally based on:
- https://github.com/langchain-ai/langchainjs/blob/main/langchain/src/chains/openai_functions/extraction.ts#L43

## Example

    # JSONSchema definition of data we want to capture or extract.
    schema_parameters = %{
      type: "object",
      properties: %{
        person_name: %{type: "string"},
        person_age: %{type: "number"},
        person_hair_color: %{type: "string"},
        dog_name: %{type: "string"},
        dog_breed: %{type: "string"}
      },
      required: []
    }

    # Model setup
    {:ok, chat} = ChatOpenAI.new(%{temperature: 0})

    # run the chain on the text information
    data_prompt =
      "Alex is 5 feet tall. Claudia is 4 feet taller than Alex and jumps higher than him.
      Claudia is a brunette and Alex is blonde. Alex's dog Frosty is a labrador and likes to play hide and seek."

    {:ok, result} = LangChain.Chains.DataExtractionChain.run(chat, schema_parameters, data_prompt)

    # Example result
    [
      %{
        "dog_breed" => "labrador",
        "dog_name" => "Frosty",
        "person_age" => nil,
        "person_hair_color" => "blonde",
        "person_name" => "Alex"
      },
      %{
        "dog_breed" => nil,
        "dog_name" => nil,
        "person_age" => nil,
        "person_hair_color" => "brunette",
        "person_name" => "Claudia"
      }
    ]

If the LLM returns a single map (e.g. when only one entity is found), it is
wrapped in a list automatically:

    # Single-entity result normalised to a list
    [
      %{
        "person_name" => "Alex",
        "person_age" => nil,
        ...
      }
    ]

## Accessing the LLMChain

`run/4` returns only the extracted data. When more than the data is needed,
for instance to log or report the token usage of the extraction, use
`run_chain/4` to get the executed `LangChain.Chains.LLMChain` and
`extract_result/1` to pull the data out of it:

    {:ok, chain} = LangChain.Chains.DataExtractionChain.run_chain(chat, schema_parameters, data_prompt)

    usage = LangChain.TokenUsage.get(chain.last_message)
    {:ok, result} = LangChain.Chains.DataExtractionChain.extract_result(chain)

## Callbacks

The `LLMChain` used for the extraction is built internally, so handlers
registered on the `llm` itself are not used. Pass `:callbacks` to observe the
run as it happens, which is the only way to see streamed deltas:

    LangChain.Chains.DataExtractionChain.run(chat, schema_parameters, data_prompt,
      callbacks: [%{on_llm_token_usage: fn _chain, usage -> log_usage(usage) end}]
    )

Handlers are registered on the internally run `LLMChain`, so the full set of
`LangChain.Chains.ChainCallbacks` events is available.

The `schema_parameters` in the previous example can also be expressed using a
list of `LangChain.FunctionParam` structs. An equivalent version looks like
this:

    alias LangChain.FunctionParam

    schema_parameters = [
      FunctionParam.new!(%{name: "person_name", type: :string}),
      FunctionParam.new!(%{name: "person_age", type: :number}),
      FunctionParam.new!(%{name: "person_hair_color", type: :string}),
      FunctionParam.new!(%{name: "dog_name", type: :string}),
      FunctionParam.new!(%{name: "dog_breed", type: :string})
    ]
    |> FunctionParam.to_parameters_schema()

# `build_extract_function`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.4/lib/chains/data_extraction_chain.ex#L253)

```elixir
@spec build_extract_function(json_schema :: map()) ::
  LangChain.Function.t() | no_return()
```

Build the function to expose to the LLM that can be called for data
extraction.

# `extract_result`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.4/lib/chains/data_extraction_chain.ex#L198)

```elixir
@spec extract_result(LangChain.Chains.LLMChain.t()) ::
  {:ok, result :: [any()]} | {:error, LangChain.LangChainError.t()}
```

Return the extracted data from an executed `LangChain.Chains.LLMChain` that
was run by `run_chain/4`.

Returns an error when the LLM did not respond with the expected extraction
tool call.

# `normalize_extraction_info`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.4/lib/chains/data_extraction_chain.ex#L134)

```elixir
@spec normalize_extraction_info(term()) ::
  {:ok, [any()]} | {:error, LangChain.LangChainError.t()}
```

Coerces the extraction tool's `info` argument to a list of rows.

Models sometimes return one JSON object instead of a one-element array; `run/4`
uses this so callers always get `{:ok, list}`.

# `run`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.4/lib/chains/data_extraction_chain.ex#L226)

```elixir
@spec run(
  LangChain.ChatModels.ChatOpenAI.t(),
  json_schema :: map(),
  prompt :: [any()],
  opts :: Keyword.t()
) :: {:ok, result :: [any()]} | {:error, LangChain.LangChainError.t()}
```

Run the data extraction chain and return the extracted data.

When the executed chain is needed as well, for instance to report token usage,
use `run_chain/4` with `extract_result/1`.

Accepts the same options as `run_chain/4`.

# `run_chain`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.4/lib/chains/data_extraction_chain.ex#L170)

```elixir
@spec run_chain(
  LangChain.ChatModels.ChatOpenAI.t(),
  json_schema :: map(),
  prompt :: [any()],
  opts :: Keyword.t()
) ::
  {:ok, LangChain.Chains.LLMChain.t()}
  | {:error, LangChain.Chains.LLMChain.t(), LangChain.LangChainError.t()}
```

Run the data extraction chain and return the executed `LangChain.Chains.LLMChain`.

Use this instead of `run/4` when the chain itself is needed and not just the
extracted data. The chain gives access to the returned messages, token usage,
and everything else recorded during execution.

    {:ok, chain} = DataExtractionChain.run_chain(chat, schema_parameters, data_prompt)

    # inspect the token usage of the extraction
    usage = LangChain.TokenUsage.get(chain.last_message)

    # get the extracted data from the chain
    {:ok, result} = DataExtractionChain.extract_result(chain)

Follows the same return pattern as `LangChain.Chains.LLMChain.run/2`.

## Options

- `:verbose` - when `true`, enables verbose logging on the internally run
  `LLMChain`. Defaults to `false`.
- `:callbacks` - a list of callback handler maps to register on the
  internally run `LLMChain`. See `LangChain.Chains.ChainCallbacks` for the
  available events. Defaults to `[]`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
