Excel Adapter
Load and execute ffai workflows from Excel (.xlsx) files, with write-back of results.
Setup
1. Install with Excel support
pip install ffai-workflow-adapters[excel]
2. No environment variables required
Excel files are read from the local filesystem. No API keys needed.
Loading Workflows
load_workflow_excel(path, *, ...)
from ffai_workflow_adapters import load_workflow_excel
spec = load_workflow_excel(
"workflows/my_workflow.xlsx",
sheet="Steps", # optional: sheet name or index (default: active sheet)
adapter="marketing", # optional: named adapter from config
name="my_workflow",
defaults={"temperature": 0.5},
clients={"reviewer": {"type": "litellm", "model": "gpt-4o"}},
)
Excel File Format
The first row must be a header with column names. Each subsequent row is a workflow step.
Required Columns
Column |
Description |
|---|---|
|
Unique step identifier |
|
Prompt text (supports |
Optional Columns
Column |
Description |
Default |
|---|---|---|
|
Client name from |
System default |
|
Direct model string override |
Client default |
|
Comma-separated step names for context |
— |
|
Sampling temperature (0-2) |
Client default |
|
Maximum tokens to generate |
Client default |
|
Per-step system prompt |
— |
|
Skip step unless expression is true |
— |
|
Abort workflow if expression is true |
— |
See Airtable adapter docs for the full list of column name aliases.
Example Excel Workflow
name |
prompt |
client |
history |
temperature |
|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
Writing Results
write_workflow_results_excel(result, path=None, *, ...)
from ffai_workflow_adapters import write_workflow_results_excel
result = await ffai.execute_workflow(spec)
# Write using config defaults (output_path, output_sheet from adapters.yaml)
write_workflow_results_excel(result)
# Override path and/or sheet
write_workflow_results_excel(result, path="output/run2.xlsx")
write_workflow_results_excel(result, sheet="Run 2")
# With passthrough columns — pass the spec returned by load_workflow_excel
write_workflow_results_excel(result, spec=spec)
path and sheet are optional — if omitted, they fall back to output_path and output_sheet from the resolved adapter config. Raises ValueError if neither is set.
If the file exists, results are appended to the sheet. If the sheet exists, rows are appended after existing data. Parent directories are created automatically.
Output Columns
Column |
Description |
|---|---|
|
Workflow name |
|
Step name |
|
Execution status |
|
AI response text |
|
Model used |
|
Prompt tokens |
|
Completion tokens |
|
Estimated cost |
|
Execution time (ms) |
|
ISO 8601 timestamp |
Column names are remapped via output_field_map if configured.
Field Mapping
Same system as the Airtable adapter. Configure in config/adapters.yaml:
adapters:
excel:
input_field_map:
Task: name
Instructions: prompt
"AI Model": client
output_field_map:
step: Task
response: Output
named:
quarterly:
input_field_map:
Step: name
Query: prompt
See Airtable adapter - Field Mapping for full details on mapping and inheritance rules.
Passthrough Columns
Carry extra source columns (Comments, Priority, etc.) into the output. Configure in config/adapters.yaml:
adapters:
excel:
passthrough_columns:
- Comments
- Priority
- Category
At load time, values are captured from the source workbook and stored as metadata on the spec. At write time, pass the spec to include them:
spec = load_workflow_excel("workflows/steps.xlsx")
result = await ffai.execute_workflow(spec)
write_workflow_results_excel(result, spec=spec)
Passthrough columns appear in the output after the standard columns, with their original names (or remapped via output_field_map if configured). If a step has no value for a passthrough column, None is written.
Named adapters inherit passthrough_columns from the base config and can override.
Extra Output Columns
Add derived columns to every output row. Configure in config/adapters.yaml:
adapters:
excel:
extra_output_columns:
run_id: "{{run_id}}"
run_date: "{{date}}"
batch_id: "2026-Q2-run-01"
run_time: "{{now:%H:%M:%S}}"
Template Expressions
Template |
Resolves to |
|---|---|
|
Timestamp-based run ID (e.g., |
|
Current UTC date (e.g., |
|
Current UTC ISO timestamp |
|
|
Any other string |
Literal value |
All templates resolve once per write call — every row in the same run gets the same run_id, date, etc. Pass run_id="batch-42" to write_workflow_results_excel() to use a custom ID instead of the auto-generated one.
Extra columns appear in the output after passthrough columns. Named adapters inherit and can override.
Schema Validation
At load time, the adapter validates your workbook before making any API calls:
Required columns —
nameandpromptmust be present (after field mapping). RaisesTabularLoadErrorwith the list of missing columns and suggestions.Type checking —
temperaturemust be numeric,max_tokensmust be numeric. Raises per-row errors.Unrecognized columns — columns that don’t match any canonical field, field map entry, or passthrough column trigger a warning log message. They’re passed through to ffai (which ignores them).
Canonical Field Names
Field |
Type |
Required |
|---|---|---|
|
string |
Yes |
|
string |
Yes |
|
string |
No |
|
string |
No |
|
string |
No |
|
float |
No |
|
int |
No |
|
string |
No |
|
string |
No |
|
string |
No |
|
string |
No |
|
string |
No |
|
bool |
No |
|
string |
No |
|
string |
No |
If your workbook uses different column names, configure input_field_map to map them.
Column Order in Output
Standard columns → passthrough columns → extra output columns.
Observability
Adapter operations emit OpenTelemetry spans when FFAI’s observability is enabled. Spans cover Excel load and write operations, including file paths, record counts, timing, and error details.
Enabling
Same as Airtable adapter — see Airtable adapter - Observability.
Emitted Spans
Span Name |
Operation |
Key Attributes |
|---|---|---|
|
Load workflow from file |
|
|
Write results to file |
|
Config Reference
adapters:
excel:
# Output destination (used when path= is omitted)
output_path: "output/results.xlsx"
output_sheet: "Results"
# Carry source columns to output
passthrough_columns:
- Comments
- Priority
# Add derived columns
extra_output_columns:
run_id: "{{run_id}}"
run_date: "{{date}}"
batch: "demo-run"
# Remap source column names to canonical fields
input_field_map:
Name: name
Prompt: prompt
# Remap output column names
output_field_map:
step: Step
response: Response
# Named adapter overrides
named:
custom:
output_path: "output/results_custom.xlsx"
output_sheet: "Custom Results"
input_field_map:
Task: name
Instructions: prompt
output_field_map:
step: Task
response: Output
Full Example
import asyncio
from ffai import FFAI
from ffai.Clients.AsyncFFLiteLLMClient import AsyncFFLiteLLMClient
from ffai_workflow_adapters import load_workflow_excel, write_workflow_results_excel
async def main():
client = AsyncFFLiteLLMClient(model_string="mistral/mistral-small-latest", api_key="...")
ffai = FFAI(client)
spec = load_workflow_excel("workflows/steps.xlsx", name="excel_workflow")
result = await ffai.execute_workflow(spec)
# Writes to output/results.xlsx (from config) with passthrough + extra columns
write_workflow_results_excel(result, spec=spec)
asyncio.run(main())