%{ title: “Cookbook: Chat Response”, description: “Send a single chat request with Jido AI and extract the returned text, model, and usage fields.”, category: :docs, order: 110, doc_type: :cookbook, audience: :beginner, tags: [:docs, :guides, :cookbook, :chat, :ai, :livebook], draft: false, legacy_paths: [“/docs/chat-response”, “/docs/cookbook/chat-response”], prerequisites: [“/docs/getting-started/first-llm-agent”], learning_outcomes: [
"Send a single chat request with Jido.AI.Actions.LLM.Chat",
"Extract the returned text, model, and usage fields"
], livebook: %{
runnable: true,
required_env_vars: ["OPENAI_API_KEY"],
requires_network: true,
setup_instructions: "Set OPENAI_API_KEY or LB_OPENAI_API_KEY before running the request cell."
} }
Setup
This recipe keeps the flow deliberately small: configure a provider key, send one chat request, and read the structured result. If you want a full multi-turn agent afterward, continue to Build an AI Chat Agent.
Mix.install([
{{mix_dep:jido}},
{{mix_dep:jido_ai}},
{{mix_dep:req_llm}}
])
Logger.configure(level: :warning)
# Livebook imports can execute generated docs as doctests.
# Disable compiler docs until the current Jido Hex release drops the invalid signal_types/0 example.
Code.put_compiler_option(:docs, false)
Configure the provider key the same way as Your first LLM agent. In Livebook, store it as a secret named OPENAI_API_KEY, which becomes LB_OPENAI_API_KEY inside the notebook.
openai_key = System.get_env("LB_OPENAI_API_KEY") || System.get_env("OPENAI_API_KEY")
configured? =
if is_binary(openai_key) do
ReqLLM.put_key(:openai_api_key, openai_key)
true
else
IO.puts("Set OPENAI_API_KEY as a Livebook Secret or environment variable to run the request cell.")
false
end
Request
Jido.AI.Actions.LLM.Chat is the compact request-response API. Run it through Jido.Exec.run/2 with a prompt and an optional system prompt:
chat_result =
if configured? do
Jido.Exec.run(
Jido.AI.Actions.LLM.Chat,
%{
model: :fast,
prompt: "Write a two-sentence welcome for a new Jido user.",
system_prompt: "You are a concise, friendly assistant.",
temperature: 0.2,
max_tokens: 120
}
)
else
{:skip, :no_openai_key}
end
IO.inspect(chat_result, label: "Chat result")
The successful shape is {:ok, %{text: ..., model: ..., usage: ...}}. model: :fast resolves through jido_ai model aliases, so the same recipe works if you change the provider backing that alias later.
Response
Pattern match the response map to get the assistant text and any usage data you want to log or display:
chat_text =
case chat_result do
{:ok, %{text: text, model: model, usage: usage}} ->
IO.puts("Model: #{model}")
IO.inspect(usage, label: "Token usage")
text
{:error, reason} ->
"Chat request failed: #{inspect(reason)}"
{:skip, :no_openai_key} ->
"Skipped request. Set OPENAI_API_KEY or LB_OPENAI_API_KEY to run it."
end
IO.puts(chat_text)
Next steps
- Continue to Your first LLM agent for the smallest agent wrapper around chat requests.
- Continue to Build an AI Chat Agent when you need multi-turn state on the same process.