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")
endMultiple 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: 3Generating 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")
endSuccess: true
Images: 1Using 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")
end714Handling 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)
endLLMRequestResponse subtypes:
ImageCallError
ImageFailure
ImageSuccess
LLMCallError
LLMFailure
LLMSuccess
ResponseCallError
ResponseFailure
ResponseSuccessresult = 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)"
endAssistant: Hello! How can I help you today?
Finish reason: stopFor 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
endHello! What can I help you with today?
Status: completed
Model: gpt-5.2-2025-12-11What's Next?
| Want to... | Read... |
|---|---|
| Build multi-turn conversations | Chat Completions Guide |
| Use the newer Responses API | Responses API Guide |
| Generate images from prompts | Image Generation Guide |
| Call functions from the model | Tool Calling Guide |
| Stream tokens in real-time | Streaming Guide |
| Get structured JSON output | Structured Output Guide |
| Use Azure or Gemini | Multi-Backend Guide |