> For the complete documentation index, see [llms.txt](https://docs.tonic.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tonic.ai/textual/textual-integrations/fireworks-ai-integration.md).

# Fireworks AI integration

You can integrate Tonic Textual with [Fireworks AI](https://fireworks.ai/) to build LLM applications and fine-tuned models on open models without exposing personally identifiable information (PII) or other sensitive data.

Textual detects sensitive values in text, then replaces them with tokens or realistic synthetic values. Fireworks serves and fine-tunes open models behind an OpenAI-compatible API.

This topic explains how Fireworks AI and Textual work together, then walks you through an example where you:

1. Redact prompts before you send them to a Fireworks model.
2. Restore the original values in the response.
3. Control how Textual handles each entity type.
4. Use synthesized values to de-identify conversations.
5. Fine-tune a model on the de-identified conversations.

It also explains how to:

* Use the Textual LangChain integration.
* Configure Fireworks as the LLM provider for a self-hosted Textual instance.

## About Fireworks AI

Fireworks AI is an inference and training platform for open models such as Kimi, DeepSeek, GLM, Qwen, MiniMax, and gpt-oss.

You can either:

* Call models on shared serverless capacity and pay per token.
* Run the models on dedicated deployments.

You can also fine-tune models on your own data and serve the tuned model on the same platform.

Because the Fireworks API is compatible with the OpenAI API, you point the official OpenAI client libraries at the Fireworks base URL, `https://api.fireworks.ai/inference/v1`.

Frameworks that support OpenAI-compatible providers, such as LangChain, work the same way.

For more information, go to:

* [Fireworks AI documentation](https://docs.fireworks.ai/)
* [Fireworks fine-tuning](https://docs.fireworks.ai/fine-tuning/fine-tuning-models)

## How Textual works with Fireworks

Textual can work with Fireworks in the following ways:

<table data-header-hidden><thead><tr><th width="275.67578125" valign="top"></th><th valign="top"></th></tr></thead><tbody><tr><td valign="top"><strong>Prompt redaction</strong></td><td valign="top"><p>Before a prompt leaves your environment, Textual replaces names, contact details, account numbers, and other sensitive values with tokens.</p><p></p><p>It then restores the original values in the model's response.</p></td></tr><tr><td valign="top"><strong>Training data de-identification</strong></td><td valign="top"><p>Textual replaces sensitive values in conversations, tickets, and documents with realistic synthetic values.</p><p></p><p>You can then fine-tune a model on the data without the model learning real PII.</p></td></tr><tr><td valign="top"><strong>LLM-powered features</strong></td><td valign="top">For features that require an LLM, self-hosted Textual instances can, through the Textual OpenAI-compatible provider, use a Fireworks model.</td></tr></tbody></table>

The integration involves the following tasks:

<table><thead><tr><th valign="top">Task</th><th valign="top">Fireworks AI</th><th valign="top">Tonic Textual</th></tr></thead><tbody><tr><td valign="top">Detection</td><td valign="top">Not involved</td><td valign="top">Detects sensitive values, then labels each one with an entity type, such as <code>NAME_GIVEN</code> or <code>EMAIL_ADDRESS</code>.</td></tr><tr><td valign="top">Redaction</td><td valign="top"><p>Generates a response from the redacted prompt.</p><p></p><p>Keeps the tokens in its output.</p></td><td valign="top"><p>Replaces each value with a token, such as <code>[NAME_GIVEN_dySb5]</code>.</p><p></p><p>Uses <code>unredact</code> to restore the original values.</p></td></tr><tr><td valign="top">Synthesis</td><td valign="top">Not involved.</td><td valign="top">Replaces each value with a realistic synthetic value of the same type.</td></tr><tr><td valign="top">Fine-tuning</td><td valign="top"><p>Trains a LoRA adapter on the de-identified dataset.</p><p>Serves the tuned model.</p></td><td valign="top">De-identifies the exported source records as training data.</td></tr></tbody></table>

## Example: Build a privacy-safe support assistant

In this example:

1. You use a Fireworks model to draft replies to customer support messages.
2. Textual redacts each message before it reaches the model.
3. Textual then restores the customer's details in the reply.
4. You de-identify past support conversations.
5. You fine-tune a model on those conversations.

### Supported models for the example

The example can work with the following serverless models. Each of these models keeps Textual tokens intact when the system prompt asks it to.

For the full list of models, go to the [Fireworks model library](https://fireworks.ai/models).

<table><thead><tr><th width="142.70703125" valign="top">Model type</th><th width="343.0546875" valign="top">Model identifier</th><th valign="top">Notes</th></tr></thead><tbody><tr><td valign="top">Chat</td><td valign="top">accounts/fireworks/models/gpt-oss-120b</td><td valign="top">Used in the example.</td></tr><tr><td valign="top">Chat</td><td valign="top"><p>accounts/fireworks/models/kimi-k3</p><p>accounts/fireworks/models/glm-5p3</p><p>accounts/fireworks/models/deepseek-v4p1-flash</p><p>accounts/fireworks/models/minimax-m3</p></td><td valign="top">Use any of these in place of the gpt-oss-120b model.</td></tr><tr><td valign="top">Base model for fine-tuning</td><td valign="top">accounts/fireworks/models/qwen3-8b</td><td valign="top"><p>Used as the base model for fine-tuning in this example.</p><p></p><p>For other base models, go to <a href="https://docs.fireworks.ai/fine-tuning/fine-tuning-models">Fine-tuning models</a>.</p></td></tr></tbody></table>

### Prerequisites

To complete this tutorial, you must have the following:

* A Tonic Textual account.
* A [Textual API key](/textual/tonic-textual-api/textual-api-keys.md). The API key must have permission to redact text strings.
* A Fireworks AI API key. To create one, in the Fireworks console, go to [API Keys](https://app.fireworks.ai/settings/users/api-keys).
* Python 3.9 or later.

### Set up the environment

1. Install the dependencies.

{% code overflow="wrap" %}

```
pip install --quiet --upgrade tonic-textual openai
```

{% endcode %}

2. Set the Textual environment variables.

{% code overflow="wrap" %}

```
export TONIC_TEXTUAL_API_KEY="<textual-api-key>"
export FIREWORKS_API_KEY="<fireworks-api-key>"
```

{% endcode %}

3. Create a Textual client and a Fireworks client, then choose your model.

{% code overflow="wrap" %}

```
import json
import os
 
from openai import OpenAI
from tonic_textual.redact_api import TextualNer
 
textual = TextualNer()
fireworks = OpenAI(
    base_url="https://api.fireworks.ai/inference/v1",
    api_key=os.environ["FIREWORKS_API_KEY"],
)
 
CHAT_MODEL = "accounts/fireworks/models/gpt-oss-120b"
```

{% endcode %}

`TextualNer()` connects to Textual Cloud.&#x20;

On a self-hosted instance, you must pass the instance URL. For example, `TextualNer("https://textual.your-company.com")`.

### Redact prompts and restore responses

Next:

1. Use Textual to redact each customer message.
2. Send the redacted message to Fireworks.
3. To restore the original values, call `unredact` on the response.

The Fireworks model sees only tokens. The customer's name, email address, and telephone number never leave your environment.

The system prompt tells the model to copy tokens exactly. Without this instruction, a model might rewrite a token or drop its brackets, and Textual could not restore the value.

{% code overflow="wrap" %}

```
TOKEN_PROMPT = (
    "Some values in the user's text are replaced with placeholder tokens in square "
    "brackets, such as [NAME_GIVEN_dySb5]. Treat each token as the value that it "
    "stands for. When you refer to one of these values, copy its token exactly, "
    "including the brackets."
)
def private_completion(instruction, text, **redact_options):
    redacted = textual.redact(text, **redact_options).redacted_text
    response = fireworks.chat.completions.create(
        model=CHAT_MODEL,
        messages=[
            {"role": "system", "content": TOKEN_PROMPT},
            {"role": "user", "content": f"{instruction}\n\n{redacted}"},
        ],
    )
    output = response.choices[0].message.content
    return redacted, output, textual.unredact(output)
message = (
    "Hi, this is Maria Lopez. I was charged twice for order 55812 on October 3. "
    "Please email me at maria.lopez@example.com or call 415-555-0134."
)
redacted, output, reply = private_completion(
    "Write a short reply to this customer. Address them by name, and confirm "
    "how you'll contact them.",
    message,
)
print("Sent to Fireworks:\n", redacted)
print("\nReturned by Fireworks:\n", output)
print("\nReply to the customer:\n", reply)
```

{% endcode %}

Fireworks receives a message that looks similar to the following:

{% code overflow="wrap" %}

```
Hi, this is [NAME_GIVEN_dySb5] [NAME_FAMILY_7w4Db3]. I was charged twice for order 55812 on [DATE_TIME_DnuC1]. Please email me at [EMAIL_ADDRESS_q8Zx1] or call [PHONE_NUMBER_3kLm9].
```

{% endcode %}

### Choose how Textual handles each entity type

By default, Textual replaces every value that it detects with a token.

To pass some entity types through unchanged, or to replace them with synthetic values, use the `generator_config` parameter.&#x20;

The following example keeps dates in the prompt, so that the model can reason about them, but still redacts names and contact details.

{% code overflow="wrap" %}

```
redacted, output, reply = private_completion(
    "How many days ago was the duplicate charge if today is October 27? "
    "Answer in one sentence, and address the customer by name.",
    message,
    generator_config={"DATE_TIME": "Off"},
)
print("Sent to Fireworks:\n", redacted)
print("\nReply to the customer:\n", reply)
```

{% endcode %}

The handling options are:

* `Redaction`
* `Synthesis`
* `GroupingSynthesis`
* `ReplacementSynthesis`
* `Off`

For the list of entity types, see [Built-in entity types](/textual/entity-types/built-in-entity-types.md).

To learn more about the options, see [Configure entity type handling for redaction](/textual/tonic-textual-api/textual-python-sdk/datasets-redaction/api-redaction-entity-type-handling.md).

### De-identify training data and fine-tune a model

Past support conversations are good training data for a support model, but they're full of sensitive customer data.

To fine-tune on them safely, replace the sensitive values with synthetic values. Synthesis keeps the text natural, so that the tuned model learns how to handle names and contact details without learning real ones.

1. De-identify each conversation, then write it to a JSONL file.\
   \
   Each line must contain a `messages` array in the chat format.\
   \
   The code sends all the messages of a conversation to Textual in one `redact_bulk` call.\
   \
   Note that in production, you read the conversations from your support system or data warehouse.\
   \
   To de-identify entire files or datasets, use [Textual datasets](/textual/tonic-textual-api/textual-python-sdk/datasets.md) instead.

{% code overflow="wrap" %}

```
conversations = [
    {
        "messages": [
            {"role": "user", "content": "Hi, I'm Daniel Kim. My package for order 77120 never arrived at 12 Oak Street, Austin."},
            {"role": "assistant", "content": "Sorry about that, Daniel. I've opened a trace with the carrier and will update you at the email on your account."},
        ]
    },
    {
        "messages": [
            {"role": "user", "content": "This is Priya Patel. Please change the phone number on my account to 212-555-0199."},
            {"role": "assistant", "content": "Done, Priya. Your account now uses 212-555-0199 for text updates."},
        ]
    },
]
 
with open("train.jsonl", "w") as f:
    for conversation in conversations:
        synthesized = textual.redact_bulk(
            [m["content"] for m in conversation["messages"]],
            generator_default="Synthesis",
        )
        messages = [
            {"role": m["role"], "content": text}
            for m, text in zip(conversation["messages"], synthesized.bulk_redacted_text)
        ]
        f.write(json.dumps({"messages": messages}) + "\n")
```

{% endcode %}

2. Upload the dataset, then start a supervised fine-tuning job with [firectl](https://docs.fireworks.ai/tools-sdks/firectl/firectl), the Fireworks CLI.

{% code overflow="wrap" %}

```
firectl dataset create textual-support-conversations train.jsonl
firectl sftj create \
  --base-model accounts/fireworks/models/qwen3-8b \
  --dataset textual-support-conversations \
  --output-model textual-support-model
```

{% endcode %}

3. When the job finishes, deploy the tuned model. In the example code, use its model identifier as `CHAT_MODEL`.

To learn about supported base models, training methods, and deployment options, go to [Fine-tuning models](https://docs.fireworks.ai/fine-tuning/fine-tuning-models).

## Use Fireworks with the Textual LangChain integration

If you build with LangChain, use:

* The [Textual LangChain integration](/textual/textual-integrations/textual-langchain-integration.md) to redact text inside a chain.
* The [langchain-fireworks](https://python.langchain.com/docs/integrations/providers/fireworks/) package for the chat model.

The following chain:

1. Redacts a support ticket.
2. Summarizes it with a Fireworks model.
3. Restores the original values in the summary.

{% code overflow="wrap" %}

```
pip install --quiet --upgrade langchain-textual langchain-fireworks

from langchain_core.prompts import ChatPromptTemplate
from langchain_fireworks import ChatFireworks
from langchain_textual import TonicTextualRedactText
from tonic_textual.redact_api import TextualNer
TOKEN_PROMPT = (
    "Some values in the user's text are replaced with placeholder tokens in square "
    "brackets, such as [NAME_GIVEN_dySb5]. Treat each token as the value that it "
    "stands for. When you refer to one of these values, copy its token exactly, "
    "including the brackets."
)
prompt = ChatPromptTemplate.from_messages(
    [
        ("system", TOKEN_PROMPT),
        ("human", "Summarize this support ticket in one sentence:\n\n{ticket}"),
    ]
)
llm = ChatFireworks(model="accounts/fireworks/models/gpt-oss-120b")
chain = {"ticket": TonicTextualRedactText()} | prompt | llm
ticket = "Maria Lopez (maria.lopez@example.com) was charged twice for order 55812."
summary = chain.invoke(ticket).content
print(TextualNer().unredact(summary))
```

{% endcode %}

## Use Fireworks as the LLM provider for self-hosted Textual instances

Some Textual features, such as [model-based custom entity types](/textual/entity-types/entity-type-custom-model.md), require a connection to an LLM.

On a self-hosted Textual instance, you can use a Fireworks model through Textual's OpenAI-compatible provider.

In your Textual instance, [set the following environment variables](/textual/textual-install-administer/configuring-textual/textual-env-var-configure.md), then restart the Textual Worker service.

{% code overflow="wrap" %}

```
LLM_DEFAULT_PROVIDER=OpenAi
LLM_DEFAULT_MODEL_NAME=accounts/fireworks/models/kimi-k3
LLM_PROVIDER_OPEN_AI_URL=https://api.fireworks.ai/inference/v1
LLM_PROVIDER_OPEN_AI_API_KEY=<fireworks-api-key>
```

{% endcode %}

To verify the connection, check the Textual Worker logs for a message that the client initialized.

To learn more, go to [Configuring connections to LLM providers](/textual/textual-install-administer/configuring-textual/enable-and-configure-textual-features/configuring-connections-to-llm-providers.md) and [Configuring the default LLM provider and model](/textual/textual-install-administer/configuring-textual/enable-and-configure-textual-features/configuring-the-default-llm-provider-and-model.md).

## Other model and redaction options

Here are some other options to try:

* To use other Fireworks chat models, change the value of `CHAT_MODEL`. For more information, go to the [Fireworks model library](https://fireworks.ai/models).
* Use `redact_json` and `redact_html` to redact JSON and HTML content, such as tool results in an agent. For more information, go to [Redact individual strings](/textual/tonic-textual-api/textual-python-sdk/datasets-redaction/textual-api-redact-strings.md).
* Add Textual custom entity types to detect values that are specific to your business, such as internal account identifiers. For more information, go to [Adding regex-based types](/textual/entity-types/entity-types-custom.md) or [Adding model-based types](/textual/entity-types/entity-type-custom-model.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.tonic.ai/textual/textual-integrations/fireworks-ai-integration.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
