用WIKI数据自动填写表单
我们如何利用 LLM 的功能来增强现有 Web 应用程序中的用户体验?用户的一个常见痛点是根据外部输入在表单中输入数据。如果我们可以利用 AI 自动用来自 Web 源的数据填充表单字段,会怎么样?在这篇博文中,我们将演示如何使用维基百科、OpenAI 和 react-admin 在电视剧创作表单中实现这一概念。
1、从维基百科获取数据
为了帮助用户填写表单,我们将分两步使用维基百科:
1.1 搜索相应的文章
用户输入他们想要创建的电视剧的标题,应用程序会向维基百科 API 请求相应的文章列表。例如,如果用户输入“Sherlock”:
curl --get 'https://en.wikipedia.org/w/api.php?' \
-d action=opensearch \
-d format=json \
-d limit=10 \
-d list=search \
-d origin=* \
-d search=Sherlock
用户需要选择他们想要用作数据源的系列:
1.2 从选定的文章中提取内容
一旦用户选择了一篇文章,我们就使用准确的页面标题来获取相应的维基百科文章:
curl --get 'https://en.wikipedia.org/w/api.php?' \
-d action=query \
-d explaintext=true \
-d format=json \
-d prop=extracts \
-d redirects=true \
-d origin=* \
-d titles=Sherlock_%28TV_series%29
使用查询参数 explaintext=true
和 prop=extracts
,我们从维基百科页面检索内容的纯文本版本。此摘录已经相对优化,它没有导航、图像……
提示:为避免 CORS 问题并启用跨域请求,维基百科建议添加查询参数 origin=*
。此请求将被视为已注销(即作为匿名用户)处理。
3、抽象维基百科 API
React-admin 应用程序通过其数据提供程序调用 API,因此我们将向数据提供程序添加两个自定义函数以从维基百科检索信息。这里没有什么特别的,只需使用正确的参数调用维基百科 API 并解析响应即可。我们将使用 react-admin 提供的 fetchJson
函数发出请求。
export const wikipediaDataProvider = {
getWikipediaList: async (parameters = { search: '' }) => {
const queryParams = new URLSearchParams({
action: 'opensearch',
limit: '10',
list: 'search',
search: parameters.search,
origin: '*',
format: 'json',
});
const url = `https://en.wikipedia.org/w/api.php?${queryParams.toString()}`;
const requestOptions = {
method: 'GET',
headers: new Headers({ 'Content-Type': 'application/json' }),
};
const { json } = await fetchUtils.fetchJson(url, requestOptions);
const data = json[1].map((title, index) => {
return { title, url: json[3][index] };
});
return { data };
},
getWikipediaContent: async (parameters = { title: '' }) => {
// ...
},
};
这些自定义方法仅返回应用程序所需的信息,例如文章的标题和 URL,而不包括内容。
4、使用 LLM 提取结构化信息
我们将制作一个提示,要求 OpenAI 从 Wikipedia 摘录中提取我们需要的字段。我们将遵循 OpenAI 的提示工程最佳实践,以确保获得最佳结果。以下是我们将使用的提示模板:
SYSTEM: You will be provided with a document delimited by triple quotes.
Your task is to extract structured information from this document.
Provide output in JSON format as follows:
{"title":"...",...}
The fields to extract are:
[FIELD LIST]
The value for each field should be a string or a number
(no object as field value). Use \'null\' as value if the document
does not contain the field. Do not add extra fields.
USER: """[DOCUMENT]"""
ASSISTANT:
翻译:
系统:你将获得一个由三重引号分隔的文档。你的任务是从此文档中提取结构化信息。以 JSON 格式提供输出,如下所示:{"title":"...",...}。要提取的字段为:[字段列表]。每个字段的值应为字符串或数字(不要用对象作为字段值)。如果文档不包含该字段,则使用 'null' 作为值。请勿添加额外字段。
用户:“”[文档]”””
助手:
我们将使用 GPT 3.5 Turbo 来处理提示,因为它是此任务最快且最便宜的 OpenAI 模型。
在 OpenAI Playground 上使用“Sherlock (TV Series)”维基百科文章进行测试时,此提示似乎效果很好:
{
"title": "Sherlock",
"synopsis": "British mystery crime drama television series based on Sir Arthur Conan Doyle's Sherlock Holmes detective stories. Produced by BBC, Hartswood Films. Stars Benedict Cumberbatch as Sherlock Holmes and Martin Freeman as Dr. John Watson.",
"type": null,
"genre": "Crime, Drama, Mystery",
"creator": "Steven Moffat, Mark Gatiss",
"director": null,
"nbSeasons": 4
}
但这种方法很快就会遇到限制。
4.1 达到令牌上限
在许多情况下,OpenAI API 会返回错误,因为提示超出了输入令牌限制。
什么是令牌?
令牌可以被认为是单词的片段。在 API 处理请求之前,输入会被分解为 token。这些标记不会在单词的开始或结束位置准确切割 - 令牌以包括尾随空格甚至子词。以下是一些有助于理解令牌长度的经验法则:
- 1 个令牌 ~= 4 个英文字符
- 1 个令牌 ~= ¾ 个单词
- 100 个令牌 ~= 75 个单词
摘自什么是标记以及如何计算它们?
大型语言模型使用令牌(token)处理文本。令牌限制取决于所使用的模型。在这里,我们使用 gpt-3.5-turbo-0125 模型,其限制为 16,385 个令牌。你可以在 OpenAI 模型列表中找到有关每个模型的更多信息。
例如,对于 Sherlock 电视剧 Wikipedia 文章,提取的文本权重为 41KB。令牌化版本计数约 9,000 个标记,低于限制。
提示:要计算字符串中的令牌数,可以使用 OpenAI Tokenizer 页面。他们还为此提供了一个 API。
但较大的文章通常会超出标记限制,OpenAI API 拒绝处理请求。此外,LLM 通常难以从非常大的上下文中提取信息。这被称为“注意力稀释”。因此,数据提取在大型文章上表现不佳。
4.2 拆分文档
对于 AI 代理来说,一个好的经验法则是,如果它们不能一次性执行复杂的任务,它们应该将其分解为更小、更易于管理的任务。对于数据提取任务,我们需要将文档拆分成更小的部分,并要求 LLM 填写每个部分的字段。
但是,我们遇到了另一个挑战:对 OpenAI API 的不同请求之间没有上下文持久性。为了解决这个问题,我们决定在每个请求中包含我们要检索的相同字段列表,而不发送之前的响应。如果 LLM 在请求中找到字段的值,我们会使用它。否则,我们保留先前的值。这种简单的方法使我们能够快速汇总来自多个请求的结果。
另一种方法是在处理完所有文档片段后再次调用 OpenAI API,以便在有多个可用值时为每个字段选择最佳值。但这会延迟响应时间并增加请求的成本。我们选择让解决方案保持简单和高效。
因此,我们将每个 token 组发送到 OpenAI API 以 JSON 格式检索相关字段值(例如标题、类型、季节数等)。至于其他 API 调用,我们在应用程序数据提供程序中实现这一点:
export const openAIDataProvider = {
getOpenAIValuesFromContent: async (content: string, keys: [string]) => {
const messageWithoutContent = `fields ${keys.join(',')}.text:`;
const groups = tokenizeContent(content, messageWithoutContent);
let result = {};
for (const group of groups) {
const message = `${messageWithoutContent}${group}`;
const data = await fetchOpenAI(message);
const sanitizedData = removeNullUndefined(data);
result = { ...sanitizedData, ...result };
}
return { data: result };
},
// ...
};
4.3 填写表单
我们使用 React-Hook-Form 的 setValue
方法用检索到的值更新表单数据。
由于 AI 代理可能会返回错误数据,因此我们提供了一种丢弃建议值的方法。这意味着在使用 AI 代理之前保存当前表单值,并在用户决定丢弃建议时恢复它们。
5、结束语
这次探索让我们更好地了解了使用 AI 自动填写表单(使用从外部来源如维基百科提取的数据)所带来的挑战和机遇。虽然这种方法很有前景,但我们遇到了一些障碍,例如对 OpenAI API 的请求成本高昂,以及对相同查询的响应变化多端。
我们将在下一个 hack day 中探索 OpenAI 在表单中的更多用途。我们将尝试为同一要求提供多个建议。这个实验将引发有关评估 LLM 的输出质量、改进请求和提供用户友好体验的问题。
原文链接:Using AI To Autofill Forms With Wikipedia
汇智网翻译整理,转载请标明出处