Getting Started

Prerequisites

  • Julia 1.12+ (as specified in Project.toml)
  • An OpenAI API key (or Azure/Gemini credentials for those backends)

Installation

using Pkg
Pkg.add(url="https://github.com/algunion/UniLM.jl")

Configuration

UniLM.jl reads API credentials from environment variables. Set them before making any requests:

OpenAI (default)

ENV["OPENAI_API_KEY"] = "sk-..."

Or via your shell:

export OPENAI_API_KEY="sk-..."

Azure OpenAI

export AZURE_OPENAI_BASE_URL="https://your-resource.openai.azure.com"
export AZURE_OPENAI_API_KEY="your-key"
export AZURE_OPENAI_API_VERSION="2024-02-01"
export AZURE_OPENAI_DEPLOY_NAME_GPT_5_2="your-gpt52-deployment"

Google Gemini

export GEMINI_API_KEY="your-gemini-key"

Your First Request

Using the Responses API

The simplest way to get started — one function call:

result = respond("Explain Julia's type system in 3 bullet points")
if result isa ResponseSuccess
    println(output_text(result))
else
    println("Request failed — ", output_text(result))
end
- **Dynamic, nominative, and parametric types:** Julia checks types at runtime (dynamic), uses *named* types rather than structural equivalence (nominative), and supports parametric types like `Vector{Int}` and `Dict{K,V}` for generic, reusable code.

- **Multiple dispatch built on a rich type hierarchy:** Functions have many methods specialized on argument types, and Julia selects the most specific applicable method at call time. Types form a lattice with `Any` at the top and `Union{}` (bottom) at the bottom, enabling expressive abstractions.

- **Performance via type inference and specialization:** Although you don’t have to annotate types, Julia’s compiler infers types and generates specialized machine code for concrete types. Writing “type-stable” code (return types predictable from input types) is key to achieving near-C performance.

Using Chat Completions

For stateful, multi-turn conversations:

chat = Chat(model="gpt-4o-mini")
push!(chat, Message(Val(:system), "You are a concise Julia programming tutor."))
push!(chat, Message(Val(:user), "What is multiple dispatch? Answer in 2-3 sentences."))
result = chatrequest!(chat)
if result isa LLMSuccess
    println(result.message.content)
    println("\nFinish reason: ", result.message.finish_reason)
    println("Conversation length: ", length(chat))
else
    println("Request failed — see result for details")
end
Multiple dispatch is a programming paradigm where the method to be executed is determined by the runtime types of all the arguments, rather than just the first one. This allows for more flexible and powerful function overloading, enabling the same function name to handle different types seamlessly based on the combination of input types. In Julia, multiple dispatch is a core feature that enhances code readability and maintainability.

Finish reason: stop
Conversation length: 3

Generating Images

result = generate_image(
    "A watercolor painting of a friendly robot reading a Julia programming book",
    size="1024x1024", quality="medium"
)
if result isa ImageSuccess
    println("Success: true")
    println("Images: ", length(image_data(result)))
else
    println("Success: false")
    println("Images: 0")
end
Success: true
Images: 1

Using Keyword Arguments

For one-shot requests without managing Chat objects:

result = chatrequest!(
    systemprompt="You are a calculator. Respond only with the number.",
    userprompt="What is 42 * 17?",
    model="gpt-4o-mini",
    temperature=0.0
)
if result isa LLMSuccess
    println(result.message.content)
else
    println("Request failed — see result for details")
end
714

Handling Results

All API calls return subtypes of LLMRequestResponse. Use Julia's pattern matching:

using UniLM
using InteractiveUtils

# Construct a chat to show the result type hierarchy
chat = Chat()
push!(chat, Message(Val(:system), "You are helpful."))
push!(chat, Message(Val(:user), "Hello!"))

# Show the type hierarchy:
println("LLMRequestResponse subtypes:")
for T in subtypes(UniLM.LLMRequestResponse)
    println("  ", T)
end
LLMRequestResponse subtypes:
  ImageCallError
  ImageFailure
  ImageSuccess
  LLMCallError
  LLMFailure
  LLMSuccess
  ResponseCallError
  ResponseFailure
  ResponseSuccess
result = chatrequest!(chat)

if result isa LLMSuccess
    println("Assistant: ", result.message.content)
    println("Finish reason: ", result.message.finish_reason)
elseif result isa LLMFailure
    @warn "API returned HTTP $(result.status): $(result.response)"
elseif result isa LLMCallError
    @error "Call failed: $(result.error)"
end
Assistant: Hello! How can I help you today?
Finish reason: stop

For the Responses API:

result = respond("Hello!")

if result isa ResponseSuccess
    println(output_text(result))
    println("Status: ", result.response.status)
    println("Model: ", result.response.model)
elseif result isa ResponseFailure
    @warn "HTTP $(result.status)"
elseif result isa ResponseCallError
    @error result.error
end
Hello! What can I help you with today?
Status: completed
Model: gpt-5.2-2025-12-11

What's Next?

Want to...Read...
Build multi-turn conversationsChat Completions Guide
Use the newer Responses APIResponses API Guide
Generate images from promptsImage Generation Guide
Call functions from the modelTool Calling Guide
Stream tokens in real-timeStreaming Guide
Get structured JSON outputStructured Output Guide
Use Azure or GeminiMulti-Backend Guide