PromptingTools.jl

repository·main·Indexed 41 days ago

https://github.com/svilupp/promptingtools.jl

A Julia package to streamline interactions with Large Language Models (LLMs). It provides high-level macros and functions for prompting, templating, and managing AI workflows, including support for OpenAI, Anthropic, and local models via Ollama. Key features include task-oriented functions like `aigenerate`, `aiembed`, and `aiclassify`, asynchronous calls via the `aai` macro, and experimental agentic workflows with `airetry!` and lazy execution through `AgentTools`.

Tokens
41.8K
Snippets
167
Records
200
Agent score
48%

What's inside PromptingTools.jl

  1. Core RAG functions in RAGTools

    main

    RAGTools provides a modular pipeline for Retrieval-Augmented Generation. The primary functions are:

    • build_index(documents; ...): Creates a ChunkIndex from a list of documents.
    • airag(index; question): An end-to-end function that performs both retrieval and generation, returning an AIMessage.
    • retrieve(index, question): Retrieves relevant chunks from the index for a given question. Returns a RAGResult.
    • generate!(index, result): Takes a RAGResult (from retrieve) and generates an answer from the retrieved chunks.
    • annotate_support: Highlights which parts of an answer are supported by the index documents. This is applied automatically when using pprint(result).
    • build_qa_evals: Generates question-answer pairs from a corpus for evaluating RAG models.
  2. Core features of PromptingTools.jl

    main

    PromptingTools.jl is designed to unify prompt engineering across different backends. Key capabilities include:

    • Prompt Templating: Use placeholders to manage complex prompts easily.
    • Observability: Automatic serialization and tracing of AI conversations.
    • Fine-tuning Support: Export conversations into ShareGPT-compatible formats.
    • Debugging: Code evaluation and automatic error localization for LLM debugging.
    • Agentic Workflows: The AgentTools module supports lazy ai* calls with states, automatic code feedback, and Monte-Carlo tree search-based auto-fixing.
    • RAG Support: Retrieval-Augmented Generation workflows are supported via the companion package RAGTools.jl.
  3. Prompt File Format and Metadata

    main

    Prompt files can be plain text or include optional TOML frontmatter for metadata. If frontmatter is used, the fields are accessible via the .meta property of the loaded prompt object.

    Example File Structure:

    ---
    title = "Expert System Prompt"
    version = "1.0"
    author = "Team Name"
    description = "A system prompt for expert assistance"
    ---
    You are a {role}. Be {style} and helpful.

    If no frontmatter is provided, the file is treated as plain text and the filename is used as the title.

  4. How to have multi-turn conversations

    main

    There are two primary ways to maintain conversation state:

    1. Using the ai macros

    The ai!"" macro (with an exclamation mark) automatically uses the last response as the context for the next turn.

    2. Using the aigenerate function

    Pass the conversation keyword argument to include previous messages. To capture the history, you must set return_all=true.

    # Using macros
    ai"Hi! I'm John"
    ai!"What's my name?"
    
    # Using aigenerate
    conv = aigenerate("Hi! I'm John"; return_all=true)
    response = aigenerate("What's my name?"; return_all=true, conversation=conv)
  5. Understand the PromptingTools.jl Package Interface

    main

    The package is built around three core pillars that allow it to interface with various LLM providers (OpenAI, Anthropic, Ollama, etc.) using a unified approach:

    1. Prompt Schemas: Subtypes of AbstractPromptSchema that define how prompts are structured, separated, and rendered for specific APIs (e.g., OpenAISchema). Task functions use these schemas for dispatch.
    2. Messages: Representations of a conversation. Use SystemMessage for instructions, UserMessage for inputs, and AIMessage for model responses. A conversation is typically a collection of these messages.
    3. Task-oriented functions: High-level functions starting with ai... (e.g., aigenerate, aiembed, aiclassify) that perform specific tasks. These functions are dispatched based on the provided AbstractPromptSchema.
  6. Use XML-formatted templates for Anthropic models

    main
    When working with models that perform well with XML structures (like Anthropic's Claude), you can use XML-formatted templates. These templates use specific tags like <question>, <task>, <data>, <user_code>, and <special_instructions> to structure the prompt. This helps the model clearly distinguish between instructions, data, and the code being analyzed.
  7. Improve retrieval using HyDE (Hypothetical Document Embeddings)

    main

    HyDE (Hypothetical Document Embeddings) is a query transformation technique used in RAG to improve retrieval accuracy. Instead of searching with the raw user query, you use an LLM to generate a brief, hypothetical passage that would answer the query. This passage is then used for vector search, which often yields better matches than the original query.

    General HyDE (RAGQueryHyDE)

    Generates a 20-30 word hypothetical passage aligned with the search objective. Placeholder: query

    Julia-specific HyDE (RAGJuliaQueryHyDE)

    Optimized for the Julia language ecosystem. It instructs the LLM to act as a world-class Julia assistant to generate a succinct passage from Julia documentation. Placeholder: query

    # RAGQueryHyDE System Prompt
    You are a world-class search expert specializing in query transformations.
    Your task is to write a hypothetical passage that would answer the below question in the most effective way possible.
    It must have 20-30 words and be directly aligned with the intended search objective.
    Try to include as many key details as possible.
    
    # RAGQueryHyDE User Prompt
    Query: {{query}}
    
    Passage:
  8. How PromptingTools.jl routes AI calls via schemas

    main
    PromptingTools.jl uses subtypes of AbstractPromptSchema to determine how data is formatted and where it is sent. When you call an ai* function, the library selects a schema (e.g., OpenAISchema, AnthropicSchema) to ensure the request matches the specific requirements of the model provider. This abstraction allows the same high-level function calls to work across different providers like OpenAI, Anthropic, Google, or local servers like Ollama.
  9. Use the OpenAI Responses API for agentic workflows

    main

    The Responses API is designed for agentic workflows and reasoning models. Unlike the standard Chat Completions API, it supports server-side state management, built-in tools (web search, file search, code interpreter), and better caching efficiency (40-80% improvement). To use this API, you must use OpenAIResponseSchema() instead of OpenAISchema().

    using PromptingTools
    const PT = PromptingTools
    
    # Use OpenAIResponseSchema to target the Responses API
    schema = PT.OpenAIResponseSchema()
    
    msg = aigenerate(schema, "What is the capital of France?"; model="gpt-5-mini")
  10. How Logfire.jl observability works

    main
    The integration works by wrapping registered models in a Logfire tracing schema. When Logfire.instrument_promptingtools!() is called, Logfire modifies the model registry to route all calls through its tracing layer. This allows all ai* functions to capture rich metadata (request parameters, usage metrics, provider metadata, conversation history, and errors) without requiring any changes to your existing PromptingTools workflows.
  11. How PromptingTools.jl works: Key Concepts

    main

    PromptingTools.jl operates using five core abstractions that manage the flow from user input to AI response:

    1. API/Model Providers: The interface to the LLM (e.g., OpenAI API, or local providers like Ollama/Llama.cpp).
    2. Schemas: Objects of type AbstractPromptSchema that determine how messages are formatted and which provider is used (e.g., OpenAISchema).
    3. Prompts: The information (questions, context, or commands) sent to the model.
    4. Messages: The basic unit of communication (e.g., UserMessage, AIMessage).
    5. Prompt Templates: Re-usable prompts (AITemplate) with placeholders (e.g., {{name}}) that allow for dynamic input injection.

    The typical execution flow is: render $\rightarrow$ UserMessage(s) $\rightarrow$ render $\rightarrow$ Provider API $\rightarrow$ AIMessage.

  12. Register models to simplify API calls

    main

    To avoid manually passing the schema every time you call aigenerate or aiembed, you can register a model name in the PT.MODEL_REGISTRY. You can also create aliases in PT.MODEL_ALIASES for easier access.

    Supported functions for these calls: aigenerate and aiembed.

    # Register a model with a specific schema
    PT.register_model!(; name = "my-model", schema = PT.CustomOpenAISchema())
    
    # Create an alias
    PT.MODEL_ALIASES["shortname"] = "my-model"
    
    # Use the registered model or alias directly
    msg = aigenerate("Hello!"; model = "shortname")
    # Or using the macro syntax
    ai"Hello!"shortname