Secretary
Secretary is a Rust library that transforms natural language into structured data using large language models (LLMs). With its powerful derive macro system, you can extract structured information from unstructured text with minimal boilerplate code.
Table of Contents
- Secretary
- Roadmap
- Contributing
- License
Features
- ๐ Unified Task Trait: Single trait combining data extraction, schema definition, and system prompt generation with
#[derive(Task)] - ๐ Schema-Based Extraction: Define your data structure using Rust structs with field-level instructions
- ๐ Declarative Field Instructions: Use
#[task(instruction = "...")]attributes to guide extraction - โก Async Support: Built-in async/await support for concurrent processing
- ๐ฏ Distributed Generation: Field-level extraction for improved accuracy and error isolation
- ๐ง Reasoning Model Support: Force generation methods for models without JSON mode (o1, deepseek, etc.)
- ๐ Multiple LLM Providers: Supports OpenAI API and Azure OpenAI with extensible provider system
- ๐ก๏ธ Type Safety: Leverage Rust's type system for reliable data extraction
- ๐งน Simplified API: Consolidated traits reduce boilerplate and complexity
Quick Start
Basic Example
use Task;
use OpenAILLM;
use GenerateData;
use ;
// Define your data structure with extraction instructions
How It Works
- Define Your Schema: Create a Rust struct with
#[derive(Task)]and field-level instructions - Annotate Fields: Use
#[task(instruction = "...")]to guide the LLM on how to extract each field - Create Task Instance: Initialize with
YourStruct::new() - Process Text: Send natural language input to an LLM through the Secretary API with additional instructions
- Get Structured Data: Receive structured data parsed into your struct
Field Instructions
The #[task(instruction = "...")] attribute tells the LLM how to extract each field:
Advanced Features
Async Processing
Secretary provides full async support for concurrent processing:
use AsyncGenerateData;
use tokio;
async
Distributed Field-Level Generation
For improved accuracy and better error isolation, Secretary supports distributed generation where each field is extracted separately and then combined. This approach is more resilient to failures in individual fields. If a field fails to deserialize, the system will now raise a FieldDeserializationError, pinpointing the exact issue without affecting the successfully extracted fields.
use ;
// Synchronous distributed generation
let result: PersonInfo = llm.fields_generate_data?;
// Asynchronous distributed generation
let result: PersonInfo = llm.async_fields_generate_data.await?;
Benefits of Distributed Generation:
- Improved accuracy: Each field gets focused attention from the LLM
- Parallel processing: Multiple fields extracted simultaneously
- Better for complex extractions: Handles complex data structures more reliably
Multiple Extractions
Process multiple inputs with the same task configuration:
Force Generation for Models Without a JSON Mode
Secretary supports reasoning models like o1 and deepseek that don't have built-in JSON mode support through force generation methods:
use ;
// Synchronous force generation
let result: PersonInfo = llm.force_generate_data?;
// Asynchronous force generation
let result: PersonInfo = llm.async_force_generate_data.await?;
System Prompt Generation
The derive macro automatically generates comprehensive system prompts:
let task = new;
let prompt = task.get_system_prompt;
println!;
// Output includes:
// - JSON structure specification
// - Field-specific extraction instructions
// - Response format requirements
Examples
The examples/ directory contains practical demonstrations:
Basic Usage
sync.rs- Basic person information extraction using synchronous APIasync.rs- Async product information extraction with comprehensive testing
Distributed Generation
distributed.rs- Field-level distributed extraction using synchronous APIasync_distributed.rs- Field-level distributed extraction using async API
Force Generation (for Reasoning Models)
sync_force.rs- Financial report extraction using force generation for models without JSON modeasync_force.rs- Research paper extraction using async force generation for reasoning models
Run examples with:
# Basic synchronous example
# Async example with comprehensive testing
# Distributed generation examples
# Force generation examples (for o1, deepseek, etc.)
# To test with real API, set environment variables:
# For OpenAI:
# or "o1-preview", "deepseek-reasoner", etc.
# For Azure OpenAI:
LLM Provider Setup
OpenAI
For production use with OpenAI:
In your code:
use OpenAILLM;
let api_base = var
.expect;
let api_key = var
.expect;
let model = var
.expect;
let llm = new?;
Azure OpenAI
For Azure OpenAI deployments:
In your code:
use AzureOpenAILLM;
let endpoint = var
.expect;
let api_key = var
.expect;
let deployment_id = var
.expect;
let api_version = var
.expect;
let llm = new;
API Reference
Core Traits
| Trait | Purpose | Key Methods |
|---|---|---|
Task |
Main trait for data extraction tasks | get_system_prompt(), get_system_prompts_for_distributed_generation() |
GenerateData |
Synchronous LLM interaction | generate_data(), force_generate_data(), fields_generate_data() |
AsyncGenerateData |
Asynchronous LLM interaction | async_generate_data(), async_force_generate_data(), async_fields_generate_data() |
IsLLM |
LLM provider abstraction | send_message(), async_send_message(), get_authorization_credentials() |
LLM Providers
| Provider | Description | Constructor |
|---|---|---|
OpenAILLM |
OpenAI API compatible provider | new(api_base, api_key, model) |
AzureOpenAILLM |
Azure OpenAI service provider | new(endpoint, api_key, deployment_id, api_version) |
Derive Macro (secretary-derive)
The secretary-derive crate provides procedural macros for automatic trait implementation:
#[derive(Task)]- Automatically implements theTasktrait with system prompt generation#[task(instruction = "...")]- Provides field-specific extraction instructions for the LLM
The derive macro generates:
- JSON schema definitions based on your struct fields
- System prompts that include field instructions
- Automatic
Defaulttrait implementation (no manual derive needed) - Default implementations for the
Tasktrait
Note: As of version 0.3.70, the Default trait is automatically implemented by the derive macro. You no longer need to include Default in your derive list. If you're upgrading from a previous version, simply remove Default from your #[derive(...)] declarations.
Error Handling
secretary uses a comprehensive error enum, SecretaryError, to handle various issues that can arise during data extraction. A particularly important variant is FieldDeserializationError.
FieldDeserializationError
This error occurs when the LLM returns data that cannot be deserialized into the target struct's field type (e.g., providing a string for a u32 field). The error provides detailed context:
failed_fields: A list of fields that failed to deserialize.successful_fields: A list of fields that were parsed correctly.original_error: The underlying error fromserde_json.
This makes it much easier to debug issues, especially when using distributed generation.
Troubleshooting
Common Issues
"Failed to execute function" Error
- Check your API key and endpoint configuration
- Verify network connectivity
- Ensure the model name is correct
Serialization Errors
- Ensure all data fields implement
SerializeandDeserialize - Check that field types match the expected JSON structure
- Verify that optional fields are properly handled
- If you receive a
FieldDeserializationError, check the following:- The
instructionfor the failed field. It might not be specific enough. - The data type of the field in your struct. It might not match what the LLM is returning.
- The
Performance Tips
- Use async methods for concurrent processing
- Batch multiple requests when possible
- Consider caching LLM responses for repeated queries
- Use specific field instructions to improve extraction accuracy
Roadmap
- Azure OpenAI support (โ Completed in v0.3.60)
- Support for additional LLM providers (AWS, Anthropic, Cohere, etc.)
- Enhanced error handling and validation
- Performance optimizations and caching
- Integration with more serialization formats
- Advanced prompt engineering features
- Streaming response support
Dependencies
- Core:
serde,serde_json,reqwest,tokio,async-trait - Derive:
proc-macro2,quote,syn - Parsing:
surfing(for force generation with reasoning models)
Contributing
Contributions are welcome!
License
This project is licensed under the MIT License - see the LICENSE file for details.