Published on

【译】使用大型语言模型自动化研究工作流程

摘要

本文深入探讨了通过在研究中使用LLMs来增强人类智力的概念,灵感来源于道格拉斯·恩格尔巴特对技术作为放大人类认知能力工具的愿景。它探讨了LLMs在研究环境中的实际应用,例如假设生成、文献综述自动化和证据评估,强调了结构良好的提示和系统消息的重要性,以确保可靠和可验证的输出。作者展示了利用LLMs简化研究任务的UI模式和工具的示例,包括Elicit的表格UI用于结构化数据展示、语义缩放用于信息概览,以及Luminate用于在潜在空间中探索想法。文章还介绍了“研究原语”的概念以及使用Python的Pydantic库将这些原语捕捉为语义数据结构,确保LLM输出是有意义和可控的。最后,它提到了在迭代研究报告中实验性使用代理工作流程以及在终端环境中集成LLMs以增强可组合性和自动化。

观点

  • 作者认为LLMs应该增强而不是取代人类在研究中的认知参与,通过道格拉斯·恩格尔巴特设想的工具增强能力。
  • 文章认为LLMs可以有效地作为放大工具,帮助研究人员管理、综合和导航大量数据,从而导致更深入的理解和更快的问题解决。
  • 作者强调LLMs在执行细粒度研究任务中的多功能性,这可以显著减少认知负担。
  • 有观点认为LLMs可以被利用来构建语义上有意义的原语,这些原语可以通过使用结构化输出和数据验证框架(如Pydantic)链接成强大的工作流程。
  • 作者建议将评估机制集成到LLM驱动的工作流程中,对于减轻幻觉等问题和确保可靠结果至关重要,尤其是对于非专家用户。
  • 文章对LLMs在研究中的未来潜力表示热情,强调寻找人类与LLMs有效接口的最佳方式的重要性。

使用LLMs自动化研究工作流程

通过原子化使用AI增强研究人员

最近,我有幸在伦敦开放数据科学会议上举办了一场研讨会,我讨论了我认为可能是一个有趣的LLMs在通过自动化某些任务组来增强学术和非学术研究人员的潜在角色。

在这篇文章中,我想深入探讨在那次研讨会上讨论的核心概念,并讨论我认为AI通过与不同领域的研究人员整合而出现的迷人新角色。

增强什么?

我所呈现的研讨会探讨了以下问题:

我们如何利用LLMs来增强或增强研究工作流程,而不降低研究人员的认知参与度?

触及这个增强的话题总是很棘手,可能会引发一些关于AI将在不久的将来取代人类的尴尬对话。因此,为了清晰起见,我想先更具体地定义一下:

增强 = 通过工具增强能力

增强的概念深深植根于道格拉斯·恩格尔巴特的工作中,他在一篇题为增强人类智力:一个概念框架的文章中开创了这一理念的先河,认为技术应该增强人类能力。

他建议工具——无论是机械的还是认知的——应该放大一个人处理复杂问题的能力,而不是取代理解的过程。

通过增强人类智力,我们的意思是提高人类处理复杂问题情境的能力,以满足其特定需求并得出问题的解决方案。

同样,LLMs可以有效地作为放大工具,帮助研究人员管理、综合和导航大量的数据和信息,从而实现更深入的理解和更快的问题解决。

LLM Tangibles

术语“LLM tangibles”指的是LLM在研究环境中可以提供的现实世界应用和能力。这个术语的灵感来自于恩格尔巴特在同一篇论文中的这句话:

我们指的是在一个综合领域的生活方式,在这里直觉的尝试和错误的无形事物与对情况的人的感觉有用地共存,强大的概念、精简的术语和符号、复杂的方法以及高效的电子辅助工具。

但我称之为tangibles,以强调它们使用的原子性和实用性。

我认为LLMs是非常多才多艺的,可以通过执行细粒度的研究任务来减少认知负担,例如生成假设、从论文中提取关键发现,以及以可用格式组织数据。

我的观点是,与其将LLMs视为人类努力的潜在替代品,我们应该从原子层面来看待它们,从 研究原语 的角度出发,LLMs可以按需执行小规模的重复任务或语义类程序,因此,增强研究人员进行有效知识工作和解决问题的能力。

Cool LLM-Based UI Patterns

谈论这个的灵感来自于我最近看到的一些非常有趣的UI模式,这些模式以这种方式利用LLMs,特别是我想提到:

  1. Elicit Table UI

作者提供的图片,来自elicit.com的截图

Elicit是一个引人入胜的工具,旨在帮助研究人员通过允许他们提出研究问题并获得结构化的数据驱动响应来自动化他们的工作流程。

该应用程序将来自多篇研究论文的数据组织成一个经过深思熟虑的表格UI体验,并附有有用的列,如 主要发现摘要方法论 等。在后台,LLMs被用来生成跨多篇论文的数据点,从而允许在一个界面中有效地进行跨论文比较。

2. 语义缩放 受到Amelia Wattenberger精彩演讲Climbing the ladder of abstraction的启发:

语义缩放是利用LLMs以不同复杂度级别查看信息的概念。通过使用LLM的能力来总结一本书,例如,您可以在不同级别上探索它,例如每章只获取一句话的概述,然后再深入阅读这本书。

3. 使用Luminate进行潜在空间的创意探索 我将提到的最后一个例子是Luminate,这是最近发布的这篇论文,伴随着一个非常酷的演示,您可以在不同的 语义维度(如语气、角色发展、风格等)中探索写作故事的创意。

这个工具使用LLMs创建这种潜在空间般的创意映射,打包成一个超级直观的用户界面,提供了一种独特的方式来视觉和概念上探索概念,允许您放大和缩小不同的创意,比较在感兴趣的语义维度上的生成等。

作者提供的图像,取自公共luminate演示

第0级:为更好的研究工作流程提供提示

好的,这些想法共同的特点是它们利用了非常简单的LLM能力,但通过将它们作为原语集成到一个直观且有用的应用程序中,它们产生了一些相当令人印象深刻的结果。

我在这篇文章中最大的主张是LLMs可以有效地用于组合语义上有意义的原语,这些原语可以串联成强大的工作流程。

这种放大的第一个级别(我称之为第0级)可以非常容易地理解,并且指的是改善研究工作流程的LLMs的最基本应用:良好的提示。

更具体地说,系统消息(描述像 ChatGPT 这样的模型所期望的整体行为的消息)可以作为实用函数来执行特定的、细粒度的任务。

当研究人员使用结构良好的提示时,他们可以提取更有意义的数据,更有效地组织信息,并确保 LLM 的输出是可靠和可验证的。

第 0 级提示的关键原则:

  • 系统消息作为实用函数
  • 提示应执行的操作是 - 可靠的 - 易于验证的 - 产生一个有意义的数据转换

我在下面展示了一些使用 Python 代码进行研究的示例:

  • 论证构造
from openai import OpenAI

client = OpenAI()

MODEL='gpt-4o-mini'

def get_response(prompt_question, sys_msg):
    response = client.chat.completions.create(
        model=MODEL,
        messages=[{"role": "system", "content": sys_msg},
                  {"role": "user", "content": prompt_question}]
    )

    return response.choices[0].message.content

SYS_MSG_ARG_CONSTRUCT = """
# Argument Construction Utility
You are a research expert specialized in constructing arguments. Your task is to build a logical and persuasive argument based on the given topic or claim. Follow these steps:
1. Identify the main claim or thesis.
2. List key supporting points.
3. Organize points in a logical flow.
4. Anticipate potential counterarguments.
5. Provide a concluding statement that reinforces the main claim.
Respond with a structured argument without additional commentary.
"""

prompt_question = """
Claim: Artificial intelligence (AI) will increase job opportunities rather than eliminate them.
"""

response = get_response(prompt_question, SYS_MSG_ARG_CONSTRUCT)
print(response)
  • 假设生成
from openai import OpenAI

client = OpenAI()

MODEL='gpt-4o-mini'

def get_response(prompt_question, sys_msg):
    response = client.chat.completions.create(
        model=MODEL,
        messages=[{"role": "system", "content": sys_msg},
                  {"role": "user", "content": prompt_question}]
    )

    return response.choices[0].message.content

SYS_MSG_HYP_GEN = """
You are a research expert specialized in generating relevant, valid, and robust hypotheses. You will:
1. Analyze the given research question or problem.
2. Generate multiple plausible hypotheses.
3. Rank hypotheses by plausibility and testability.
4. Suggest potential experiments or data collection methods to test each hypothesis.
5. Identify potential confounding variables for each hypothesis.
Provide a list of generated hypotheses with brief explanations and testing suggestions.
"""

prompt_question = """
Research question: How does remote work affect employee productivity in software development teams?
"""

response = get_response(prompt_question, SYS_MSG_HYP_GEN)
print(response)

这两个示例简单地通过一些简单的 Python 函数利用 OpenAI API,调用 gpt-4o-mini 模型,使用经过深思熟虑的系统消息来执行常见的研究程序。

第 1 级:使用 Pydantic 和结构化输出的研究原语

第 1 级通过将 结构化输出 与 Python 的 Pydantic 库(数据验证框架)结合起来,将这些研究原语捕捉为 语义数据结构(对这个名称不是 100% 确定,但这是我能想到的最好名称)。

这些原语是研究工作流程的原子组件,例如:假设生成、证据收集和评估等。

作者提供的图片。

这里的核心见解是,这些结构可以具有人工编写的验证程序,然后用于组合更复杂的工作流程,这些工作流程在后端利用 LLM。

通过为这些研究组件定义数据结构,研究人员可以控制他们的工作流程,确保 LLM 生成可验证、可靠和可重用的陈述、数据等。

结构化 LLM 基于研究工作流程的示例

在实践中,LLMs 可以通过生成结构化输出来自动化文献综述的大部分工作,帮助研究人员识别相关论文、分析发现并制定假设。

import arxiv
from datetime import datetime

SYS_MSG_KEYWORD_SEARCH = """
You are a search engine that translates search topics into a list of relevant keywords for effective search.
take in a research topic and you output.
"""

SYS_MSG_SEARCH_QUERIES = """
You are a search engine that takes in a research topic and you output a list of relevant
that perfectly encapsulate that topic.
"""

SYS_MSG_RELEVANCY_JUDGE = """
You are a research expert and an evalation engine for research results given a research topic of interest.
Given a research topic you output a binary score yes|no to determine if a paper summary is strictly relevant to the topic
or not.
"""
from openai import OpenAI
from pydantic import BaseModel, Field
from typing import List, Literal

client = OpenAI()

class Keywords(BaseModel):
    keywords: List[str] = Field(..., description="List of relevant keywords to search for")

class SearchQueries(BaseModel):
    queries: List[str] = Field(..., description="List of queries to search for")

def generate_keywords_for_search(research_topic):
    """

    """
    response = client.beta.chat.completions.parse(
        model=MODEL,
        messages=[{"role": "system", "content": SYS_MSG_KEYWORD_SEARCH},
                  {"role": "user", "content": research_topic}],
        response_format=Keywords
    )

    return response.choices[0].message.parsed

def generate_search_queries(research_topic, num_queries=5):

    response = client.beta.chat.completions.parse(
        model=MODEL,
        messages=[{"role": "system", "content": SYS_MSG_SEARCH_QUERIES},
                  {"role": "user", "content": f'Generate {num_queries} search queries for this research topic: {research_topic}'}],
        response_format=SearchQueries
    )

    return response.choices[0].message.parsed

class RelevantPaper(BaseModel):
    relevancy_score: Literal['yes', 'no'] = Field(description="A binary score yes|no if a paper is relevant given a research topic.")
    justification: str = Field(description="A short one sentence justification for the relevancy score.")

def filter_paper_relevancy(research_topic, paper_summary):
    paper_relevancy_score = client.beta.chat.completions.parse(
            model='gpt-4o-mini',
            messages=[
                {
                    'role': 'system', 'content': SYS_MSG_RELEVANCY_JUDGE,
                    'role': 'user', 'content': f'Given this research topic: {research_topic}, score the relevancy of this paper:\n\n {paper_summary}'
                }
            ],
            response_format=RelevantPaper
        )

    return paper_relevancy_score.choices[0].message.parsed

def filter_out_search_results(research_topic: str, search_results: dict):
    filtered_results = []
    for paper in search_results:
        relevancy = filter_paper_relevancy(research_topic, paper.summary)
        if relevancy.relevancy_score=='yes':
            filtered_results.append((paper, relevancy.justification))
        elif relevancy.relevancy_score=='no':
            continue
        else:
            raise ValueError("Invalid relevancy score")

    return filtered_results

arxiv_client = arxiv.Client()

def search_arxiv_papers(keywords, year=2024, MAX_NUM_PAPERS=30):
    query = ' '.join(keywords)

    # Define the start and end dates for the specified year
    start_date = datetime(year, 1, 1)
    end_date = datetime(year, 12, 31)

    # Append the date range filter to the query
    date_filter = f'submittedDate:[{start_date.strftime("%Y%m%d%H%M%S")} TO {end_date.strftime("%Y%m%d%H%M%S")}]'
    full_query = f'{query} AND {date_filter}'

    # Perform the search
    search = arxiv.Search(query=full_query, max_results=MAX_NUM_PAPERS)

    # Fetch the results
    results = list(arxiv_client.results(search))

    return results
research_topic = "LLMs for enhancing human's ability to research and learn"
keywords = generate_keywords_for_search(research_topic)
structured_results = search_arxiv_papers(keywords.keywords)
filtered_papers = filter_out_search_results(research_topic, structured_results)

full_search_result = []
for query in search_queries:
    keywords = generate_keywords_for_search(query)
    structured_results = search_arxiv_papers(keywords.keywords)
    full_search_result.extend(filter_out_search_results(research_topic, structured_results))
full_search_result

例如,在上面的代码中,我使用像 arxiv API 这样的工具与 LLMs 集成,以提取和过滤相关论文,通过利用 LLMs 来帮助我评估不同论文的相关性,从而使文献综述过程更快、更全面。

LLMs 还可以帮助进行证据评估和检查

from pydantic import BaseModel, Field, field_validator
from typing import List, Literal

class Evidence(BaseModel):
    positions: List[Literal['yes', 'no', 'neutral']] = Field(description="A List with 1-3 ternary scores presenting the positions of the paper regarding the query/hypothesis in question as yes|no|neutral.")
    position_descriptions: List[str] = Field(description="List with 1-3 statements presenting the position for, against or neutral regarding the query/hypothesis n question.")
    evidence: List[str] = Field(description="List of DIRECT QUOTES serve as evidence to support each position.")

    @field_validator('positions', 'position_descriptions', 'evidence')
    def validate_list_size(cls, values):
        if len(set(map(len, values))) != 1:
            print("Uncertainty in results, retrying...")
        return values

SYS_MSG_EVIDENCE = """
You are a helpful research assistant. Given a research question or hypothesis you
will inspect the contents of papers or articles for evidence for or against 
the respective hypothesis in question. Your output will be 2 fields:
- positions: List of ternary scores (yes|no|neutral) presenting the positions of the paper regarding the query/hypothesis in question.
- positions_descriptions: List of a short one sentence statements summarizing the position from the text regarding the user's query or hypothesis, like: "Yes this paper validates this idea by pointing out...." etc..
- evidence: a list with DIRECT QUOTES from the paper containing information that supports and validates each position. It should be one quote to validate each position.

All 3 fields should be lists with the same size.
"""
MODEL = "gpt-4o-2024-08-06"
from openai import OpenAI

client = OpenAI()

def inspect_evidence(prompt_question):
    response = client.beta.chat.completions.parse(
        model=MODEL,
        messages=[{"role": "system", "content": SYS_MSG_EVIDENCE},
                  {"role": "user", "content": prompt_question}],
        response_format=Evidence,
    )

    return response.choices[0].message.parsed
# It's actually the entire first page but bare with me.
abstract = pdf_pages[0]
# source: https://www.semanticscholar.org/paper/Improvements-to-visual-working-memory-performance-Adam-Vogel/e18bbb815cf36aa75ef335787ecd9084d418765e
hypothesis = "Working memory training in humans might lead to long-term far transfer improvements in some cognitive abilities."

prompt = f"""
Does this abstract: 
{abstract}\n\n
presents evidence for the following statement:
{hypothesis}
"""

output = inspect_evidence(prompt)

output
for p,pd,e in zip(output.positions, output.position_descriptions, output.evidence):
    print(f"Position: {p}\nPosition Description: {pd}\nEvidence: {e}\n\n")
    print("****")
def inspect_evidence_for_hypothesis(hypothesis: str, source_content: str):
    """Inspects the evidence for, against or neutral regarding a research hypothesis."""

    prompt = f"""
    Does this abstract: 
    {source_content}\n\n
    presents evidence for the following statement:
    {hypothesis}
    """

    output = inspect_evidence(prompt)

    return output

def display_output_evidence(output):
    for p,pd,e in zip(output.positions, output.position_descriptions, output.evidence):
        print(f"Position: {p}\nPosition Description: {pd}\nEvidence: {e}\n\n")
        print("****")
# source for this abstract: https://pubmed.ncbi.nlm.nih.gov/35107614/
hypothesis_fluid_intelligence = "Working memory training might lead to long lasting improvements in fluid intelligence."
abstract_with_argument_for_improvement_in_fluid_intelligence = """
Abstract
Process-based working memory (WM) training in typically developing children usually leads to short- and long-term improvements on untrained WM tasks. However, results are mixed regarding far transfer to academic and cognitive abilities. Moreover, there is a lack of studies jointly evaluating the different types of transfer, using an adequate design and considering motivational factors. In addition, evidence is needed about how pre-training performance is related to individual differences in training-induced transfer. Therefore, this study aimed to implement and evaluate the efficacy of a computerized process-based WM training in typically developing school-age children. Near and far transfer effects were evaluated both immediately after training and after 6 months, as well as individual differences in training-induced transfer. The sample was composed of 89 typically developing children aged 9-10 years (M = 9.52, SD = 0.30), who were randomized to a WM training group or an active control group. They were evaluated at pre-training, post-training, and follow-up phases with measures of visuospatial and verbal WM, reading comprehension, math computation, and fluid intelligence. Results showed that the training group significantly improved performance in verbal WM and fluid intelligence compared to the active control group, immediately after training and after 6 months. Trained children with lower initial performance in verbal WM or fluid intelligence showed greater transfer gains. No group differences were found in motivational factors. Findings of this study suggest that process-based WM training may promote transfer to cognitive abilities and lead to compensation effects of individual differences in typically developing school-age children.
"""

output = inspect_evidence_for_hypothesis(hypothesis_fluid_intelligence, abstract_with_argument_for_improvement_in_fluid_intelligence)
display_output_evidence(output)

在这段代码中,实际上是受到 Jason Liu 的这场精彩 演讲 的启发,他是 pydantic 的创作者,我创建了这些“语义数据结构”来阅读论文并检查它们是否提供合理的证据,以支持假设,并附有可引用的证据来验证和确认他们的评估。

第 2 级代理工作流程和迭代研究报告

在这一部分,我想提到一个有趣但实验性的工作流程,利用代理进行迭代研究报告。

使用像 GPT Researcher 这样的工具,研究人员可以迭代地生成、完善和验证草稿研究报告,使他们在处理更多未知主题时能够了解“全貌”。

这些报告基于多个来源,每一步都可以与原始来源进行检查和交叉检查,使其成为生成高质量研究文档的强大工具。

作者提供的图像,本地生成,使用 GPT Researcher

可组合性:终端中的 LLM

在我离开之前,我想提到一个非常酷的工具,来自我在 LLM+工具领域最喜欢关注的人之一:Simon Willison

他制作了一个工具叫:LLM(我知道,真幸运,对吧?)——它本质上允许你直接从终端与 LLM 互动,在命令行环境中运行查询和管理任务。

这种控制级别允许你将常规命令和 llm 提示组合在一起,为用户提供了一种可组合性,使他们能够在 bash 中创建一些令人惊叹的自动化单行命令。

最终思考

我喜欢将这个讨论框架视为人类与 LLM 接口的最佳方式的探索。未来我希望更多地研究在个体使用层面集成评估机制,以减轻幻觉的负面影响并检测不连贯性,确保实时使用层面的可靠结果。

未来的一些关键问题:

  • 如何将评估无缝集成到非专家的 LLM 驱动工作流中,也就是说,当我们无法实施工程基础设施来应对幻觉时,例如。
  • 哪些原则将指导人类与 LLM 之间最有效的实时协作?

就这些!感谢阅读!

参考文献