Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc tidying #837

Merged
merged 30 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
54077bb
tidy chatGptSendMessage
pmarsh-scottlogic Feb 1, 2024
33e6512
renames to getChatCompletionsInLimitedContextWindow1~
pmarsh-scottlogic Feb 1, 2024
833132f
moves message property out of chatGptSendMessage
pmarsh-scottlogic Feb 1, 2024
40aa2dd
makes email decleration more concise
pmarsh-scottlogic Feb 1, 2024
e9cd877
updates some comments
pmarsh-scottlogic Feb 1, 2024
7e77988
more coment juggling
pmarsh-scottlogic Feb 1, 2024
74898dc
more comment sweepup
pmarsh-scottlogic Feb 1, 2024
b945b59
moves handbook files into pages
pmarsh-scottlogic Feb 1, 2024
977a1bb
moves Attacks.ts into HandbookAttacks
pmarsh-scottlogic Feb 1, 2024
7283b2c
refactors and renames queryPromptEval and fixes tests
pmarsh-scottlogic Feb 2, 2024
fb48e1b
simplify output of queryDocuments
pmarsh-scottlogic Feb 2, 2024
63a88c0
rename evaluatePrompt
pmarsh-scottlogic Feb 2, 2024
541c331
removes object wrapping around simple strings
pmarsh-scottlogic Feb 2, 2024
7cfca12
removes unused chatReponse property from ToolCallResponse
pmarsh-scottlogic Feb 2, 2024
00036bc
return initialised eval chain instead of assigning to variable first
pmarsh-scottlogic Feb 2, 2024
4874b0d
merge dev
pmarsh-scottlogic Feb 15, 2024
3a65b9d
finish merge
pmarsh-scottlogic Feb 15, 2024
45d7713
add user message console log to handle chat without defences
pmarsh-scottlogic Feb 15, 2024
426f214
stops some instance in openai.ts where things were declared to be ins…
pmarsh-scottlogic Feb 15, 2024
2503b65
improves a comment
pmarsh-scottlogic Feb 16, 2024
1901912
improve error message
pmarsh-scottlogic Feb 16, 2024
0b96563
adds link in comment to context window page
pmarsh-scottlogic Feb 19, 2024
d73c086
renames method to getChatCompletionsInContextWindow
pmarsh-scottlogic Feb 19, 2024
241d42c
replace reduce with filter and map
pmarsh-scottlogic Feb 19, 2024
dff646f
move openAI instantiation back outside do while loop
pmarsh-scottlogic Feb 19, 2024
e0c44ff
update imports to handbook pages
pmarsh-scottlogic Feb 19, 2024
496c30f
removes some more unhelpful comments
pmarsh-scottlogic Feb 19, 2024
0d36671
renames ChatDefenceReport to DefenceReport
pmarsh-scottlogic Feb 19, 2024
f189429
remove more unhelpful comments
pmarsh-scottlogic Feb 19, 2024
ef3c567
fixes typo
pmarsh-scottlogic Feb 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions backend/src/controller/chatController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,17 @@ async function handleChatWithoutDefenceDetection(
chatHistory: ChatMessage[],
defences: Defence[]
): Promise<LevelHandlerResponse> {
console.log(`User message: '${message}'`);

const updatedChatHistory = createNewUserMessages(message).reduce(
pushMessageToHistory,
chatHistory
);

// get the chatGPT reply
const openAiReply = await chatGptSendMessage(
updatedChatHistory,
defences,
chatModel,
message,
currentLevel
);

Expand Down Expand Up @@ -146,11 +146,16 @@ async function handleChatWithDefenceDetection(
defences
);

console.log(
`User message: '${
messageTransformation?.transformedMessageCombined ?? message
}'`
);

const openAiReplyPromise = chatGptSendMessage(
chatHistoryWithNewUserMessages,
defences,
chatModel,
messageTransformation?.transformedMessageCombined ?? message,
currentLevel
);

Expand Down Expand Up @@ -196,7 +201,6 @@ async function handleChatWithDefenceDetection(
}

async function handleChatToGPT(req: OpenAiChatRequest, res: Response) {
// set reply params
const initChatResponse: ChatHttpResponse = {
reply: '',
defenceReport: {
Expand Down Expand Up @@ -232,9 +236,6 @@ async function handleChatToGPT(req: OpenAiChatRequest, res: Response) {
);
return;
}
const totalSentEmails: EmailInfo[] = [
...req.session.levelState[currentLevel].sentEmails,
];

// use default model for levels, allow user to select in sandbox
const chatModel =
Expand Down Expand Up @@ -283,15 +284,18 @@ async function handleChatToGPT(req: OpenAiChatRequest, res: Response) {
}

let updatedChatHistory = levelResult.chatHistory;
totalSentEmails.push(...levelResult.chatResponse.sentEmails);

const totalSentEmails: EmailInfo[] = [
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

before, this was being instantiated then mutated once to add on the new emails sent as a result of the message. Now we just instantiate it including the new emails

...req.session.levelState[currentLevel].sentEmails,
...levelResult.chatResponse.sentEmails,
];

const updatedChatResponse: ChatHttpResponse = {
...initChatResponse,
...levelResult.chatResponse,
};

if (updatedChatResponse.defenceReport.isBlocked) {
// chatReponse.reply is empty if blocked
updatedChatHistory = pushMessageToHistory(updatedChatHistory, {
chatMessageType: 'BOT_BLOCKED',
infoMessage:
Expand Down Expand Up @@ -326,7 +330,6 @@ async function handleChatToGPT(req: OpenAiChatRequest, res: Response) {
});
}

// update state
req.session.levelState[currentLevel].chatHistory = updatedChatHistory;
req.session.levelState[currentLevel].sentEmails = totalSentEmails;

Expand Down
6 changes: 3 additions & 3 deletions backend/src/defence.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defaultDefences } from './defaultDefences';
import { queryPromptEvaluationModel } from './langchain';
import { evaluatePrompt } from './langchain';
import {
ChatDefenceReport,
MessageTransformation,
Expand Down Expand Up @@ -454,12 +454,12 @@ async function detectEvaluationLLM(
if (isDefenceActive(DEFENCE_ID.PROMPT_EVALUATION_LLM, defences)) {
const promptEvalLLMPrompt = getPromptEvalPromptFromConfig(defences);

const evaluationResult = await queryPromptEvaluationModel(
const promptIsMalicious = await evaluatePrompt(
message,
promptEvalLLMPrompt
);

if (evaluationResult.isMalicious) {
if (promptIsMalicious) {
console.debug('LLM evaluation defence active and prompt is malicious.');

return {
Expand Down
5 changes: 2 additions & 3 deletions backend/src/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,11 @@ async function initDocumentVectors() {
);

// embed and store the splits - will use env variable for API key
const embeddings = new OpenAIEmbeddings();
const docVector = await MemoryVectorStore.fromDocuments(
commonAndLevelDocuments,
embeddings
new OpenAIEmbeddings()
);
// store the document vectors for the level

docVectors.push({
level,
docVector,
Expand Down
56 changes: 20 additions & 36 deletions backend/src/langchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { OpenAI } from 'langchain/llms/openai';
import { PromptTemplate } from 'langchain/prompts';

import { getDocumentVectors } from './document';
import { CHAT_MODELS, ChatAnswer } from './models/chat';
import { CHAT_MODELS } from './models/chat';
import { PromptEvaluationChainReply, QaChainReply } from './models/langchain';
import { LEVEL_NAMES } from './models/level';
import { getOpenAIKey, getValidOpenAIModelsList } from './openai';
Expand All @@ -23,7 +23,6 @@ function makePromptTemplate(
templateNameForLogging: string
): PromptTemplate {
if (!configPrompt) {
// use the default Prompt
configPrompt = defaultPrompt;
}
const fullPrompt = `${configPrompt}\n${mainPrompt}`;
Expand All @@ -40,10 +39,8 @@ function getChatModel() {
function initQAModel(level: LEVEL_NAMES, Prompt: string) {
const openAIApiKey = getOpenAIKey();
const documentVectors = getDocumentVectors()[level].docVector;
// use gpt-4 if avaliable to apiKey
const modelName = getChatModel();

// initialise model
const model = new ChatOpenAI({
modelName,
streaming: true,
Expand All @@ -63,7 +60,6 @@ function initQAModel(level: LEVEL_NAMES, Prompt: string) {

function initPromptEvaluationModel(configPromptEvaluationPrompt: string) {
const openAIApiKey = getOpenAIKey();
// use gpt-4 if avaliable to apiKey
const modelName = getChatModel();

const promptEvalTemplate = makePromptTemplate(
Expand All @@ -79,87 +75,75 @@ function initPromptEvaluationModel(configPromptEvaluationPrompt: string) {
openAIApiKey,
});

const chain = new LLMChain({
console.debug(`Prompt evaluation model initialised with model: ${modelName}`);

return new LLMChain({
llm,
prompt: promptEvalTemplate,
outputKey: 'promptEvalOutput',
});

console.debug(`Prompt evaluation model initialised with model: ${modelName}`);
return chain;
}

// ask the question and return models answer
async function queryDocuments(
question: string,
Prompt: string,
currentLevel: LEVEL_NAMES
) {
): Promise<string> {
try {
const qaChain = initQAModel(currentLevel, Prompt);

// get start time
const startTime = Date.now();
console.debug('Calling QA model...');
const response = (await qaChain.call({
query: question,
})) as QaChainReply;
// log the time taken
console.debug(`QA model call took ${Date.now() - startTime}ms`);

console.debug(`QA model call took ${Date.now() - startTime}ms`);
console.debug(`QA model response: ${response.text}`);
const result: ChatAnswer = {
reply: response.text,
questionAnswered: true,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We weren't using this questionAnswered value anywhere.

};
return result;

return response.text;
} catch (error) {
console.error('Error calling QA model: ', error);
return {
reply: 'I cannot answer that question right now.',
questionAnswered: false,
};
return 'I cannot answer that question right now.';
}
}

// ask LLM whether the prompt is malicious
async function queryPromptEvaluationModel(
input: string,
promptEvalPrompt: string
) {
async function evaluatePrompt(input: string, promptEvalPrompt: string) {
try {
console.debug(`Checking '${input}' for malicious prompts`);
const promptEvaluationChain = initPromptEvaluationModel(promptEvalPrompt);
// get start time
const startTime = Date.now();
console.debug('Calling prompt evaluation model...');

const response = (await promptEvaluationChain.call({
prompt: input,
})) as PromptEvaluationChainReply;
// log the time taken

console.debug(
`Prompt evaluation model call took ${Date.now() - startTime}ms`
);
const promptEvaluation = formatEvaluationOutput(response.promptEvalOutput);
const promptEvaluation = interpretEvaluationOutput(
response.promptEvalOutput
);
console.debug(`Prompt evaluation: ${JSON.stringify(promptEvaluation)}`);
return promptEvaluation;
} catch (error) {
console.error('Error calling prompt evaluation model: ', error);
return { isMalicious: false };
return false;
}
}

function formatEvaluationOutput(response: string) {
function interpretEvaluationOutput(response: string) {
// remove all non-alphanumeric characters
const cleanResponse = response.replace(/\W/g, '').toLowerCase();
if (cleanResponse === 'yes' || cleanResponse === 'no') {
return { isMalicious: cleanResponse === 'yes' };
return cleanResponse === 'yes';
} else {
console.debug(
`Did not get a valid response from the prompt evaluation model. Original response: ${response}`
);
return { isMalicious: false };
return false;
}
}

export { queryDocuments, queryPromptEvaluationModel };
export { queryDocuments, evaluatePrompt };
6 changes: 0 additions & 6 deletions backend/src/models/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,6 @@ interface ToolCallResponse {
chatHistory: ChatMessage[];
}

interface ChatAnswer {
reply: string;
questionAnswered: boolean;
}

interface ChatMalicious {
isMalicious: boolean;
reason: string;
Expand Down Expand Up @@ -123,7 +118,6 @@ const defaultChatModel: ChatModel = {
};

export type {
ChatAnswer,
ChatDefenceReport,
ChatGptReply,
ChatMalicious,
Expand Down
Loading
Loading