From d5af78e20c9d5056bb1451fe13e512a87193406d Mon Sep 17 00:00:00 2001 From: Steve Polito Date: Wed, 27 Aug 2025 06:00:47 -0400 Subject: [PATCH] Artificial Intelligence: Filter sensitive information Introduces new section for Artificial Intelligence, and demonstrates how to filter sensitive information from messages. --- artificial-intelligence/README.md | 6 +++ .../how-to/filter_sensitive_information.md | 44 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 artificial-intelligence/README.md create mode 100644 artificial-intelligence/how-to/filter_sensitive_information.md diff --git a/artificial-intelligence/README.md b/artificial-intelligence/README.md new file mode 100644 index 00000000..66fad1e0 --- /dev/null +++ b/artificial-intelligence/README.md @@ -0,0 +1,6 @@ +# Artificial Intelligence + +## Security + +- Filter sensitive information before sending data to an LLM or chatbot. + [Example](./how-to/filter_sensitive_information.md). diff --git a/artificial-intelligence/how-to/filter_sensitive_information.md b/artificial-intelligence/how-to/filter_sensitive_information.md new file mode 100644 index 00000000..a8640c4d --- /dev/null +++ b/artificial-intelligence/how-to/filter_sensitive_information.md @@ -0,0 +1,44 @@ +# Filter Sensitive Information + +Before sending free text to an LLM or chatbot, filter all messages for +potentially sensitive information first. + +```ruby +require "openai" +require "top_secret" + +openai = OpenAI::Client.new( + api_key: Rails.application.credentials.openai.api_key! +) + +original_messages = [ + "Ralph lives in Boston.", + "You can reach them at ralph@thoughtbot.com or 877-976-2687" +] + +# Filter all messages +result = TopSecret::Text.filter_all(original_messages) +filtered_messages = result.items.map(&:output) + +user_messages = filtered_messages.map { {role: "user", content: it} } + +# Instruct LLM how to handle filtered messages +instructions = <<~TEXT + I'm going to send filtered information to you in the form of free text. + If you need to refer to the filtered information in a response, just reference it by the filter. +TEXT + +messages = [ + {role: "system", content: instructions}, + *user_messages +] + +chat_completion = openai.chat.completions.create(messages:, model: :"gpt-5") +response = chat_completion.choices.last.message.content + +# Restore the response from the mapping +mapping = result.mapping +restored_response = TopSecret::FilteredText.restore(response, mapping:).output + +puts(restored_response) +```