Packages
langchain
0.8.4
0.9.2
0.9.1
0.9.0
0.8.14
0.8.13
0.8.12
0.8.11
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.4.0-rc.3
0.4.0-rc.2
0.4.0-rc.1
0.4.0-rc.0
0.3.3
0.3.2
0.3.1
0.3.0
0.3.0-rc.2
0.3.0-rc.1
0.3.0-rc.0
0.2.0
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Elixir implementation of a LangChain style framework that lets Elixir projects integrate with and leverage LLMs.
Current section
Files
Jump to
Current section
Files
lib/tools/calculator.ex
defmodule LangChain.Tools.Calculator do
@moduledoc """
Defines a Calculator tool for performing basic math calculations.
This is an example of a pre-built `LangChain.Function` that is designed and
configured for a specific purpose.
This defines a function to expose to an LLM and provides an implementation for
the `execute/2` function for evaluating when an LLM executes the function.
When using the `Calculator` tool, you will either need to:
* make repeated calls to run the chain as the tool is called and the results
are then made available to the LLM before it returns the final result.
* OR run the chain using the `mode: :until_success` option like this:
`LangChain.LLMChain.run(chain, mode: :until_success)`
## Example
The following is an example that uses a prompt where math is needed. What
follows is the verbose log output.
{:ok, updated_chain, %Message{} = message} =
%{llm: ChatOpenAI.new!(%{temperature: 0}), verbose: true}
|> LLMChain.new!()
|> LLMChain.add_message(
Message.new_user!("Answer the following math question: What is 100 + 300 - 200?")
)
|> LLMChain.add_functions(Calculator.new!())
|> LLMChain.run(mode: :until_success)
Verbose log output:
LLM: %LangChain.ChatModels.ChatOpenAI{
endpoint: "https://api.openai.com/v1/chat/completions",
model: "gpt-3.5-turbo",
api_key: nil,
temperature: 0.0,
frequency_penalty: 0.0,
receive_timeout: 60000,
seed: 0,
n: 1,
json_response: false,
stream: false,
max_tokens: nil,
user: nil
}
MESSAGES: [
%LangChain.Message{
content: "Answer the following math question: What is 100 + 300 - 200?",
index: nil,
status: :complete,
role: :user,
name: nil,
tool_calls: [],
tool_results: nil
}
]
TOOLS: [
%LangChain.Function{
name: "calculator",
description: "Perform basic math calculations or expressions",
display_text: nil,
function: #Function<0.75045395/2 in LangChain.Tools.Calculator.execute>,
async: true,
parameters_schema: %{
type: "object",
required: ["expression"],
properties: %{
expression: %{
type: "string",
description: "A simple mathematical expression"
}
}
},
parameters: []
}
]
SINGLE MESSAGE RESPONSE: %LangChain.Message{
content: nil,
index: 0,
status: :complete,
role: :assistant,
name: nil,
tool_calls: [
%LangChain.Message.ToolCall{
status: :complete,
type: :function,
call_id: "call_NlHbo4R5NXTA6lHyjLdGQN9p",
name: "calculator",
arguments: %{"expression" => "100 + 300 - 200"},
index: nil
}
],
tool_results: nil
}
EXECUTING FUNCTION: "calculator"
FUNCTION RESULT: "200"
TOOL RESULTS: %LangChain.Message{
content: nil,
index: nil,
status: :complete,
role: :tool,
name: nil,
tool_calls: [],
tool_results: [
%LangChain.Message.ToolResult{
type: :function,
tool_call_id: "call_NlHbo4R5NXTA6lHyjLdGQN9p",
name: "calculator",
content: "200",
display_text: nil,
is_error: false
}
]
}
SINGLE MESSAGE RESPONSE: %LangChain.Message{
content: "The result of the math question \"100 + 300 - 200\" is 200.",
index: 0,
status: :complete,
role: :assistant,
name: nil,
tool_calls: [],
tool_results: nil
}
"""
require Logger
alias LangChain.Function
@doc """
Define the "calculator" function. Returns a success/failure response.
"""
@spec new() :: {:ok, Function.t()} | {:error, Ecto.Changeset.t()}
def new() do
Function.new(%{
name: "calculator",
description: "Perform basic math calculations or expressions",
parameters_schema: %{
type: "object",
properties: %{
expression: %{type: "string", description: "A simple mathematical expression"}
},
required: ["expression"]
},
function: &execute/2
})
end
@doc """
Define the "calculator" function. Raises an exception if function creation fails.
"""
@spec new!() :: Function.t() | no_return()
def new!() do
case new() do
{:ok, function} ->
function
{:error, changeset} ->
raise LangChain.LangChainError, changeset
end
end
@doc """
Performs the calculation specified in the expression and returns the response
to be used by the the LLM.
"""
@spec execute(args :: %{String.t() => any()}, context :: map()) ::
{:ok, String.t()} | {:error, String.t()}
if Code.ensure_loaded?(Abacus) do
def execute(%{"expression" => expr} = _args, _context) do
try do
case Abacus.eval(expr) do
{:ok, number} ->
{:ok, to_string(number)}
{:error, reason} ->
Logger.warning(
"Calculator tool errored in eval of #{inspect(expr)}. Reason: #{inspect(reason)}"
)
{:error, "ERROR: #{inspect(expr)} is not a valid expression"}
end
rescue
err ->
{:error, "ERROR: An invalid expression raised the exception #{inspect(err)}"}
end
end
else
def execute(%{"expression" => expr} = _args, _context) do
Logger.warning(
"Calculator tool failed to execute expression #{inspect(expr)} because Abacus module not loaded"
)
{:error, "Error: Abacus module not loaded"}
end
end
end