### Setup WorkArena Environment
Source: https://github.com/servicenow/workarena/wiki/WorkArena-‐-Human-Evaluation-Study
Installs Mamba, creates and activates a Python 3.12 environment, and installs necessary packages including browsergym-core and workarena-core. Ensure you replace 'PASSWORD_HERE' with the actual password provided.
```bash
export SNOW_INSTANCE_URL="https://dev253956.service-now.com/" && \
export SNOW_INSTANCE_UNAME="admin" && \
export SNOW_INSTANCE_PWD='PASSWORD_HERE' && \
mkdir workarena-human-eval && cd workarena-human-eval && \
if [[ $(uname -m) == 'arm64' ]]; then \
curl -Ls https://micro.mamba.pm/api/micromamba/osx-arm64/latest | tar -xvj bin/micromamba; \
else \
curl -Ls https://micro.mamba.pm/api/micromamba/osx-64/latest | tar -xvj bin/micromamba; \
fi && \
export MAMBA_ROOT_PREFIX=$(pwd)/micromamba && \
eval "$(./bin/micromamba shell hook -s posix)" && \
micromamba env create -n "human-eval" python=3.12 --channel conda-forge -y && \
micromamba activate human-eval && \
pip install --upgrade browsergym-core==0.3.4 && \
pip install --upgrade https://alexdrouin.com/workarena.zip && \
playwright install && \
export PATH=$PATH:micromamba/envs/human-eval/bin/ && \
echo "Installation complete."
```
--------------------------------
### Verify WorkArena Installation
Source: https://github.com/servicenow/workarena/wiki/WorkArena-‐-Human-Evaluation-Study
Runs the WorkArena evaluation tool to confirm that the environment setup was successful. Kill the process with CTRL-C if it starts.
```bash
workarena-human-eval --email YOUR_EMAIL --log test.log --curriculum random
```
--------------------------------
### Install OpenAI Package
Source: https://github.com/servicenow/workarena/blob/main/generate_knowledge_base.ipynb
Installs the necessary OpenAI Python package. Run this command before importing the library.
```python
!pip install openai
```
--------------------------------
### Install BrowserGym WorkArena Package
Source: https://github.com/servicenow/workarena/blob/main/README.md
Install the WorkArena package within the BrowserGym environment using pip. This is a prerequisite for using WorkArena.
```bash
pip install browsergym-workarena
```
--------------------------------
### Start WorkArena Human Evaluation
Source: https://github.com/servicenow/workarena/wiki/WorkArena-‐-Human-Evaluation-Study
Initiates the human evaluation task using the specified email, log file, and curriculum file. Ensure 'YOUR_CURRICULUM_FILE' points to the correct file provided by the session lead.
```bash
workarena-human-eval --email YOUR_EMAIL --log ~/LASTNAME.log --curriculum YOUR_CURRICULUM_FILE
```
--------------------------------
### Install Playwright for Browser Automation
Source: https://github.com/servicenow/workarena/blob/main/README.md
Install Playwright, a tool for browser automation, which is required for WorkArena's interactive components. This command ensures all necessary browser binaries are downloaded.
```bash
playwright install
```
--------------------------------
### Get Most Frequent Items in a List
Source: https://github.com/servicenow/workarena/blob/main/generate_knowledge_base.ipynb
Calculates and returns the most frequent item(s) from a given list. It uses the `Counter` class for efficient frequency counting.
```python
def get_most_frequent_items(my_list):
# Count the frequency of each item in the list
frequency = Counter(my_list)
# Find the maximum frequency
max_frequency = max(frequency.values())
# Get all items with the maximum frequency
most_frequent = [
item for item, count in frequency.items() if count == max_frequency
]
return most_frequent
```
--------------------------------
### Initialize OpenAI Client and Chat Function
Source: https://github.com/servicenow/workarena/blob/main/generate_knowledge_base.ipynb
Initializes the OpenAI client with an API key from environment variables and defines a helper function to interact with the chat completions API.
```python
import json
import openai
import os
client = openai.OpenAI(api_key=os.environ["OPENAI_API_KEY"])
def chat(messages, model="gpt-4-1106-preview"):
return (
client.chat.completions.create(model=model, messages=messages)
.choices[0]
.message
)
```
--------------------------------
### Run WorkArena-L1 Demo with BrowserGym
Source: https://github.com/servicenow/workarena/blob/main/README.md
Executes WorkArena-L1 tasks using BrowserGym. This script shuffles atomic tasks and uses cheat functions to automatically solve each one. For agent evaluation, replace cheat calls with env.step().
```python
import random
from browsergym.core.env import BrowserEnv
from browsergym.workarena import ATOMIC_TASKS
from time import sleep
random.shuffle(ATOMIC_TASKS)
for task in ATOMIC_TASKS:
print("Task:", task)
# Instantiate a new environment
env = BrowserEnv(task_entrypoint=task,
headless=False)
env.reset()
# Cheat functions use Playwright to automatically solve the task
env.chat.add_message(role="assistant", msg="On it. Please wait...")
cheat_messages = []
env.task.cheat(env.page, cheat_messages)
# Send cheat messages to chat
for cheat_msg in cheat_messages:
env.chat.add_message(role=cheat_msg["role"], msg=cheat_msg["message"])
# Post solution to chat
env.chat.add_message(role="assistant", msg="I'm done!")
# Validate the solution
reward, stop, message, info = env.task.validate(env.page, cheat_messages)
if reward == 1:
env.chat.add_message(role="user", msg="Yes, that works. Thanks!")
else:
env.chat.add_message(role="user", msg=f"No, that doesn't work. {info.get('message', '')}")
sleep(3)
env.close()
```
--------------------------------
### Run WorkArena-L2 Demo with BrowserGym
Source: https://github.com/servicenow/workarena/blob/main/README.md
Executes WorkArena-L2 tasks using BrowserGym. This script samples L2 tasks and uses cheat functions to solve each subtask. To sample L3 tasks, modify the filter on line 6. For agent evaluation, replace cheat calls with env.step().
```python
import random
from browsergym.core.env import BrowserEnv
from browsergym.workarena import get_all_tasks_agents
AGENT_L2_SAMPLED_SET = get_all_tasks_agents(filter="l2")
AGENT_L2_SAMPLED_TASKS, AGENT_L2_SEEDS = [sampled_set[0] for sampled_set in AGENT_L2_SAMPLED_SET], [
sampled_set[1] for sampled_set in AGENT_L2_SAMPLED_SET
]
from time import sleep
for (task, seed) in zip(AGENT_L2_SAMPLED_TASKS, AGENT_L2_SEEDS):
print("Task:", task)
# Instantiate a new environment
env = BrowserEnv(task_entrypoint=task,
headless=False)
env.reset()
# Cheat functions use Playwright to automatically solve the task
env.chat.add_message(role="assistant", msg="On it. Please wait...")
for i in range(len(env.task)):
sleep(1)
env.task.cheat(page=env.page, chat_messages=env.chat.messages, subtask_idx=i)
sleep(1)
reward, done, message, info = env.task.validate(page=env.page, chat_messages=env.chat.messages)
if reward == 1:
env.chat.add_message(role="user", msg="Yes, that works. Thanks!")
else:
env.chat.add_message(role="user", msg=f"No, that doesn't work. {info.get('message', '')}")
sleep(3)
env.close()
```
--------------------------------
### Cite WorkArena++ Project
Source: https://github.com/servicenow/workarena/blob/main/README.md
Use this BibTeX entry to cite the WorkArena++ paper, which focuses on compositional planning and reasoning. Include all provided fields for accurate citation.
```bibtex
@misc{boisvert2024workarenacompositionalplanningreasoningbased,
title={WorkArena++: Towards Compositional Planning and Reasoning-based Common Knowledge Work Tasks},
author={Léo Boisvert and Megh Thakkar and Maxime Gasse and Massimo Caccia and Thibault Le Sellier De Chezelles and Quentin Cappart and Nicolas Chapados and Alexandre Lacoste and Alexandre Drouin},
year={2024},
eprint={2407.05291},
archivePrefix={arXiv},
primaryClass={cs.AI},
url={https://arxiv.org/abs/2407.05291}
}
```
--------------------------------
### Print Alternative Answers
Source: https://github.com/servicenow/workarena/blob/main/generate_knowledge_base.ipynb
Prints the generated alternative answers for each item in the knowledge base. Assumes the 'kb' variable has been updated with 'alternative_answers'.
```python
for kb_i in kb:
print(kb_i["alternative_answers"])
```
--------------------------------
### Print Generated Questions
Source: https://github.com/servicenow/workarena/blob/main/generate_knowledge_base.ipynb
Iterates through the processed knowledge base entries and prints the generated questions for each article.
```python
for i in range(len(kb)):
print(f"Article {i}:", kb[i]["questions"])
```
--------------------------------
### Load and Clear Knowledge Base Questions
Source: https://github.com/servicenow/workarena/blob/main/generate_knowledge_base.ipynb
Loads a JSON knowledge base and clears all existing questions and alternative answers from each article. This is useful for regenerating questions.
```python
import concurrent.futures
import re
from collections import Counter
from tqdm.notebook import tqdm
# Reload the generated KB
kb = json.load(open("knowledge_base.json", "r"))
print("Loaded", len(kb), "articles")
# Clear all questions
for kb_i in kb:
if "questions" in kb_i:
kb_i["questions"] = []
kb_i["alternative_answers"] = []
```
--------------------------------
### Cite WorkArena Project
Source: https://github.com/servicenow/workarena/blob/main/README.md
Use this BibTeX entry to cite the original WorkArena paper. Ensure all fields are included for proper academic referencing.
```bibtex
@misc{workarena2024,
title={WorkArena: How Capable Are Web Agents at Solving Common Knowledge Work Tasks?},
author={Alexandre Drouin and Maxime Gasse and Massimo Caccia and Issam H. Laradji and Manuel Del Verme and Tom Marty and Léo Boisvert and Megh Thakkar and Quentin Cappart and David Vazquez and Nicolas Chapados and Alexandre Lacoste},
year={2024},
eprint={2403.07718},
archivePrefix={arXiv},
primaryClass={cs.LG}
}
```
--------------------------------
### Save Knowledge Base to JSON
Source: https://github.com/servicenow/workarena/blob/main/generate_knowledge_base.ipynb
Saves the entire knowledge base, including the newly generated alternative answers, to a JSON file named 'knowledge_base.json'.
```python
json.dump(kb, open("knowledge_base.json", "w"))
```
--------------------------------
### Parallel Question Generation
Source: https://github.com/servicenow/workarena/blob/main/generate_knowledge_base.ipynb
Uses a ThreadPoolExecutor to concurrently generate questions for multiple knowledge base entries. It submits tasks to generate questions for each article and collects the results.
```python
# Assuming kb is a list of dictionaries
with concurrent.futures.ThreadPoolExecutor() as executor:
# Prepare the futures
futures = [
executor.submit(
lambda x: {
**x,
"questions": generate_question(x["article"], x["item"], x["value"]),
},
kb_i,
)
for kb_i in kb
]
# Use tqdm to create a progress bar
kb = [
x.result()
for x in tqdm(concurrent.futures.as_completed(futures), total=len(futures))
]
```
--------------------------------
### Generate Knowledge Base Article
Source: https://github.com/servicenow/workarena/blob/main/generate_knowledge_base.ipynb
Generates a knowledge-base article based on a specific fact, embedding it within fabricated related information. Ensures the fact is included verbatim and the output is in HTML format. Includes retry logic for API calls.
```python
def generate_article(item, value, all_facts, n_retries=5):
prompt = f"""
You are in charge of writing knowledge-base articles to document important company and workplace information.
Your articles will be used as reference by the employees of the company.
Here is a list of facts in the knowledge base:
{all_facts}
You need to write an article about this specific fact:
The {item} is {value}.
* Generate a knowledge-base article that contains the as-is. Do not modify or add to its text.
* Hide the fact inside a bunch of other related information, but do not source the related information from . Make stuff up.
* Make sure that nothing you write contradicts
* You must use HTML format. Generate only the tag.
* Don't include information about the knowledge base itself or headers like \"welcome to our knowledge base\".
"""
messages = [
{
"role": "system",
"content": "You are a ServiceNow system administrator in charge of writing knowledge base articles to help employees in your organization.",
},
{"role": "user", "content": prompt},
]
print("... attempting to produce article")
for retry in range(n_retries):
try:
print(f"... try {retry}")
messages.append({"role": "assistant", "content": chat(messages).content})
article = (
messages[-1]["content"]
.replace("
", "")
.replace("", "")
.replace("```HTML", "")
.replace("```", "")
.replace("", "")
.replace("", "")
.strip()
)
# Validate that the fact is included without modification
assert (
f"the {item} is {value}".lower() in article.lower()
), f'Error: Could not find the string "The {item} is {value}" in this article.'
print("... valid article found.")
break
except AssertionError as e:
messages.append(
{"role": "user", "content": str(e) + "\nDon't apologize and try again."}
)
if messages[-1]["role"] == "user":
raise RuntimeError(
f"Failed to produce a valid article after {n_retries} retries."
)
return article
```
--------------------------------
### Validate and Refine Questions
Source: https://github.com/servicenow/workarena/blob/main/generate_knowledge_base.ipynb
Iterates through questions, checks if they are answerable from an article, and collects feedback for ambiguous questions. It then formats feedback for a language model to improve clarity.
```python
# Validate questions
bad_questions = []
bad_answers = []
for q in questions:
print("... testing:", q, end=" ")
success, answers = is_question_answerable(article, q, value)
if not success:
bad_questions.append(q)
bad_answers.append(answers)
print("FAIL")
print("... preemptively stopping to give feedback")
break
else:
good_questions.add(q)
print("PASS")
# Give feedback and retry
if len(bad_questions) > 0:
feedback = ""
for q, a in zip(bad_questions, bad_answers):
feedback += "\n"
feedback += " \n"
feedback += " " + q + "\n"
feedback += " \n"
feedback += " \n"
feedback += "\n".join(" " + x for x in a) + "\n"
feedback += " \n"
feedback += "\n"
print(feedback)
# print(f"... {len(bad_questions)} questions are ambiguous, fixing them.")
bad_questions = "\n".join(bad_questions)
messages.append(
{
"role": "user",
"content": f"""
The following questions are too ambiguous. I gave them to many company employees,
along with the article and they were not able to answer with exactly \"{value}\".
Please improve their clarity, especially the formatting instructions.
{feedback}
Try again. Do not apologize.""",
}
)
print(f"... gathered {len(good_questions)} good questions")
except AssertionError as e:
print(f"... Error:", e)
messages.append({"role": "user", "content": f"Error: {e}"})
print("... we have enough good questions. stopping.")
return list(good_questions)[:10]
```
--------------------------------
### Update Knowledge Base with Alternative Answers
Source: https://github.com/servicenow/workarena/blob/main/generate_knowledge_base.ipynb
Iterates through a knowledge base (kb) and adds a new field 'alternative_answers' to each entry by calling the `alternative_answers` function. Requires the 'kb' variable to be defined and populated.
```python
for kb_i in tqdm(kb, total=len(kb)):
kb_i["alternative_answers"] = alternative_answers(
kb_i["article"], kb_i["item"], kb_i["value"], kb_i["questions"]
)
```
--------------------------------
### Clean and Save Knowledge Base to JSON
Source: https://github.com/servicenow/workarena/blob/main/generate_knowledge_base.ipynb
Cleans the generated articles by removing specific HTML tags and markdown formatting, then saves the processed facts to a JSON file named 'knowledge_base.json'. This step is crucial for preparing the data for further use or display.
```python
for f in facts:
f["article"] = (
f["article"]
.replace("```HTML", "")
.replace("```", "")
.replace("", "")
.replace("", "")
.strip()
)
json.dump(facts, open("knowledge_base.json", "w"))
```
--------------------------------
### Define Facts for Article Generation
Source: https://github.com/servicenow/workarena/blob/main/generate_knowledge_base.ipynb
A list of dictionaries, where each dictionary contains an 'item' and its corresponding 'value', used as input for generating knowledge base articles.
```python
facts = [
{"item": "password to conference room A-561", "value": "roo918k"},
{"item": "address of office #456", "value": "42, Pizza street, New York, USA"},
{"item": "number of employees in department X", "value": "75"},
{"item": "CEO's name", "value": "Alex Johnson"},
{"item": "year of company establishment", "value": "1998"},
{"item": "Wi-Fi network name in office #456", "value": "Office456_WiFi"},
{"item": "Wi-Fi password for office #456", "value": "456SecureNet!"},
{"item": "average annual revenue", "value": "$50 million"},
{"item": "number of branches worldwide", "value": "18"},
{"item": "name of the head of HR department", "value": "Samantha Green"},
{"item": "brand of coffee machine in kitchen #3", "value": "Delonghi Magnifica"},
{"item": "company's stock ticker symbol", "value": "COMPX"},
{"item": "company's main product", "value": "Advanced Analytics Software"},
{"item": "color of the carpet in conference room A-561", "value": "Navy Blue"},
{"item": "annual budget for marketing department", "value": "$2 million"},
{"item": "capacity of conference room B-762", "value": "30 people"},
{"item": "number of floors in the main office building", "value": "10"},
{"item": "type of plants in the lobby of office #456", "value": "Ficus Lyrata"},
{
"item": "catering service provider for office events",
"value": "Gourmet Caterers",
},
{"item": "software used for payroll management", "value": "QuickBooks Payroll"},
{"item": "number of parking spaces in office #456 parking lot", "value": "150"},
{"item": "company's first product", "value": "Data Analysis Toolkit"},
{"item": "brand of computers used in IT department", "value": "Lenovo ThinkPad"},
{"item": "annual CSR budget", "value": "$500,000"},
]
```
--------------------------------
### Generate Question Variants using LLM
Source: https://github.com/servicenow/workarena/blob/main/scripts/generate_knowledge_base.ipynb
Generates multiple rephrased questions for a given fact and article using a language model. It includes strict validation checks to ensure questions are unambiguous, do not reveal the answer, and follow specific formatting instructions.
```python
def generate_question(article, item, value, n_questions=10, n_retries=5):
prompt = f"""
Here is an article taken from a company knowledge base.
{article}
This article contains the following fact:
The {item} is {value}.
Here is a question about this fact to which the answer is \"{value}\":
What is the {item}?
Produce {n_questions} rephrasings of this question.
* Make sure that your questions are precise and unambiguous.
* It must be clear that the questions are asking about \"{item}\" and
their answer must still be exactly \"{value}\".
* Make sure that you provide clear and specific instructions on the expected
format for the answer (e.g., Day, Month, Year).
* You cannot, in any circumstances, reveal information from the answer in the question or instructions.
* Make sure they are questions that end with a question mark.
* Make sure that your questions do not mention the article (e.g., \"in the article\").
* Answer with one per line and do not number them.
Suppose the question is \"On which day was the company founded?\" and the answer is \"January 26, 2024",
then a good rephrasing would be \"When was the company founded? Answer with Month Day, Year\".
Suppose the question is \"What kind of fridge do we have in the cafeteria?\" and the answer is \"LG X456",
then a good rephrasing would be \"Which type of fridge is in the cafeteria? Answer with Brand followed by Model name\".
Suppose the question is \"Where is the company headquarter located?\" and the answer is \"123, Banana Street, Montreal, Canada",
then a good rephrasing would be \"What's the address of the company headquarter? Answer with Number, Street, City, Country\".
Suppose the question is \"What were the total sales of the company in 2023?\" and the answer is \"150B$\",
then a good rephrasing would be \"What do the company sales for 2023 sum up to? Answer with NumberB$, where B is billions\".
"""
good_questions = set([])
messages = [{"role": "user", "content": prompt}]
while len(good_questions) < n_questions:
try:
# Generate questions
questions = chat(messages).content
# Parse output
# ... check the article is not mentioned
assert (
"article" not in questions.lower()
), "You are not allowed to mention the article in your rephrasing of the questions."
# ... check the number of actual questions included
assert (
questions.count("?") == n_questions
), f"I couldn't find {n_questions} question marks in the output. Make sure all questions end with ?"
# ... heuristic to detect numbered questions
assert not all(
f"{x}." in questions for x in range(4)
), "The questions appear to be numbered, but they should not."
questions = [q.strip() for q in questions.split("\n") if q != ""]
# ... check one question per line
assert (
len(questions) == n_questions
), f"Your answer is not {n_questions} lines long. Make sure it contains {n_questions} questions and one per line."
# ... check each question has instructions
assert all(
len(q.split("?")) > 1 and len("".join(q.split("?")[1:]).strip()) > 5
for q in questions
), f'Make sure you provide clear formatting instructions for each question (e.g., "Question? Answer with").'
# ... check that answer is not mentioned
for q in questions:
error = "Do not include the answer in the questions/instructions!"
# ... exact value is not in the question
assert value.lower() not in q.lower(), error
```
--------------------------------
### Validate Questions and Provide Feedback
Source: https://github.com/servicenow/workarena/blob/main/scripts/generate_knowledge_base.ipynb
Iterates through questions, validates their answerability against an article and expected value, and collects feedback for ambiguous questions. Stops processing if a question is unanswerable.
```python
# Validate questions
bad_questions = []
bad_answers = []
for q in questions:
print("... testing:", q, end=" ")
success, answers = is_question_answerable(article, q, value)
if not success:
bad_questions.append(q)
bad_answers.append(answers)
print("FAIL")
print("... preemptively stopping to give feedback")
break
else:
good_questions.add(q)
print("PASS")
# Give feedback and retry
if len(bad_questions) > 0:
feedback = ""
for q, a in zip(bad_questions, bad_answers):
feedback += "\n"
feedback += " \n"
feedback += " " + q + "\n"
feedback += " \n"
feedback += " \n"
feedback += "\n".join(" " + x for x in a) + "\n"
feedback += "\n"
print(feedback)
# print(f"... {len(bad_questions)} questions are ambiguous, fixing them.")
bad_questions = "\n".join(bad_questions)
messages.append(
{
"role": "user",
"content": f"""
The following questions are too ambiguous. I gave them to many company employees,
along with the article and they were not able to answer with exactly \"{value}\".
Please improve their clarity, especially the formatting instructions.
{feedback}
Try again. Do not apologize.""",
}
)
print(f"... gathered {len(good_questions)} good questions")
except AssertionError as e:
print(f"... Error:", e)
messages.append({"role": "user", "content": f"Error: {e}"})
print("... we have enough good questions. stopping.")
return list(good_questions)[:10]
```
--------------------------------
### Generate Articles for Facts
Source: https://github.com/servicenow/workarena/blob/main/generate_knowledge_base.ipynb
Iterates through a list of facts, generates an article for each fact using the `generate_article` function, and prints the item, value, and generated article. Ensure the `generate_article` function is defined and accessible.
```python
print("Number of facts:", len(facts))
for i, f in enumerate(facts):
f["article"] = generate_article(f["item"], f["value"], all_facts=facts)
print("... Article", i + 1, f["item"], f["value"])
print(f["article"])
print("\n" * 2)
```
--------------------------------
### Generate Alternative Answers Function
Source: https://github.com/servicenow/workarena/blob/main/generate_knowledge_base.ipynb
Defines a function to generate alternative phrasings for an answer using a chat model. It includes validation to ensure the output meets specific criteria, such as not being numbered and having the correct number of unique answers.
```python
def alternative_answers(article, item, value, questions, n_answers=10):
questions = "\n".join(questions)
prompt = f"""
Here is a set of questions:
{questions}
The exact answer to all of these questions is:
{value}
Give me {n_answers} other ways to spell out the answer.
Don't add context words around it or anything, just reformulate it.
Initial value: 5.5/10
Reformulated: 5.5 out of 10
Reformulated: 55%
Reformulated: fifty-five percent
Initial value: Tesla Model X
Reformulated: Model X by Tesla
Reformulated: Tesla's Model X
Initial value: 150$
Reformulated: one hundred fifty dollars
Reformulated: 150.00$
Reformulated: $150
Answer with one per line. Don't number them.
"
messages = [{"role": "user", "content": prompt}]
while True:
try:
answers = chat(messages).content
# Validation
# ... heuristic to detect numbered questions
assert not all(
f"{x}." in answers for x in range(4)
), "The answers appear to be numbered, but they should not."
answers = [a.strip() for a in answers.split("\n") if a != ""]
# ... check one question per line
assert (
len(answers) == n_answers
), f"Your response is not {answers} lines long. Make sure it contains {answers} answers and one per line."
assert (
len(set(answers)) == n_answers
), f"You provided duplicate values. There were only {len(set(answers))} unique values."
break
except AssertionError as e:
print(f"... Error:", e)
messages.append({"role": "user", "content": f"Error: {e}"})
return answers
```
--------------------------------
### Generate Rephrased Questions for a Fact
Source: https://github.com/servicenow/workarena/blob/main/generate_knowledge_base.ipynb
Generates multiple rephrased questions for a given fact within an article. It uses a language model and includes strict validation checks to ensure questions are unambiguous, do not reveal the answer, and follow specific formatting instructions.
```python
def generate_question(article, item, value, n_questions=10, n_retries=5):
prompt = f"""
Here is an article taken from a company knowledge base.
{article}
This article contains the following fact:
The {item} is {value}.
Here is a question about this fact to which the answer is \"{value}\":
What is the {item}?
Produce {n_questions} rephrasings of this question.
* Make sure that your questions are precise and unambiguous.
* It must be clear that the questions are asking about \"{item}\" and
their answer must still be exactly \"{value}\".
* Make sure that you provide clear and specific instructions on the expected
format for the answer (e.g., Day, Month, Year).
* You cannot, in any circumstances, reveal information from the answer in the question or instructions.
* Make sure they are questions that end with a question mark.
* Make sure that your questions do not mention the article (e.g., \"in the article\").
* Answer with one per line and do not number them.
Suppose the question is \"On which day was the company founded?\" and the answer is \"January 26, 2024\",
then a good rephrasing would be \"When was the company founded? Answer with Month Day, Year\".
Suppose the question is \"What kind of fridge do we have in the cafeteria?\" and the answer is \"LG X456\",
then a good rephrasing would be \"Which type of fridge is in the cafeteria? Answer with Brand followed by Model name\".
Suppose the question is \"Where is the company headquarter located?\" and the answer is \"123, Banana Street, Montreal, Canada\",
then a good rephrasing would be \"What's the address of the company headquarter? Answer with Number, Street, City, Country\".
Suppose the question is \"What were the total sales of the company in 2023?\" and the answer is \"150B$\",
then a good rephrasing would be \"What do the company sales for 2023 sum up to? Answer with NumberB$, where B is billions\".
"""
good_questions = set([])
messages = [{"role": "user", "content": prompt}]
while len(good_questions) < n_questions:
try:
# Generate questions
questions = chat(messages).content
# Parse output
# ... check the article is not mentioned
assert (
"article" not in questions.lower()
), "You are not allowed to mention the article in your rephrasing of the questions."
# ... check the number of actual questions included
assert (
questions.count("?") == n_questions
), f"I couldn't find {n_questions} question marks in the output. Make sure all questions end with ?"
# ... heuristic to detect numbered questions
assert not all(
f"{x}." in questions for x in range(4)
), "The questions appear to be numbered, but they should not."
questions = [q.strip() for q in questions.split("\n") if q != ""]
# ... check one question per line
assert (
len(questions) == n_questions
), f"Your answer is not {n_questions} lines long. Make sure it contains {n_questions} questions and one per line."
# ... check each question has instructions
assert all(
len(q.split("?")) > 1 and len("".join(q.split("?")[1:]).strip()) > 5
for q in questions
), f'Make sure you provide clear formatting instructions for each question (e.g., "Question? Answer with").'
# ... check that answer is not mentioned
for q in questions:
error = "Do not include the answer in the questions/instructions!"
# ... exact value is not in the question
assert value.lower() not in q.lower(), error
```
--------------------------------
### Check Question Answerability
Source: https://github.com/servicenow/workarena/blob/main/generate_knowledge_base.ipynb
Determines if a given question can be answered with a specific value based on the provided article content. It cleans answers for case-insensitive comparison and checks against multiple attempts.
```python
def is_question_answerable(article, question, value):
def _clean_for_comparison(x):
return x.lower().replace(",", "").replace("$", "").replace(".", "")
"""
Check that we are able to recover the value from the
article by asking the question
"""
prompt = f"""
Here is a knowledge base article:
{article}
Answer this question based on the content of the article only.
Be factual. If I ask you about sensitive information like passwords,
I only expect you to retrieve the information from the article.
{question}
What is your answer?
"""
messages = [{"role": "user", "content": prompt}]
incorrect_answers = set()
for _ in range(10):
# XXX: We use GPT-3.5 here as a weaker model and to avoid GPT-4 catering to himself
answer = chat(messages, model="gpt-3.5-turbo").content
if _clean_for_comparison(value) not in _clean_for_comparison(answer):
incorrect_answers.add(answer.lower())
return len(incorrect_answers) == 0, incorrect_answers
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.