使用R包ellmer接入Deepseek

因为价格和付费方式等原因,LLM 模型的接入对于普通用户来说一直是一大挑战。然而,自从 Deepseek 把价格打下来后,那些曾经望尘莫及的功能终于成为现实。借助 ellmer,R 用户现在不仅可以轻松调用各大前沿大语言模型,还能实现从智能问答、工具调用到结构化数据提取的全方位应用。

本文主要包括两个部分,第一部分(1-4)是基于ellmer文档的介绍,第二部分(5)是调用Deepseek尝试对富集分析的结果进行解释。对文档内容不感兴趣的话,可以直接划到该部分看实际使用的效果。

  1. 简介

ellmer 是一款专为 R 用户打造的工具包,旨在简化调用各大 LLM(大型语言模型)的流程。无论是实现流式输出、调用工具函数还是提取结构化数据,ellmer 都能轻松应对。 只要对API调用略知一二,便可开发自己的LLM调用工具,事实上R中的类似工具也有不少,选用ellmer最主要的原因是它是Hadley Wickham开发的。

ellmer 集成了多种模型调用接口,不同函数对应不同的 LLM 供应商,例如:

  • Anthropic 的 Claude:chat_claude()

  • AWS Bedrock:chat_bedrock()

  • Azure OpenAI:chat_azure()

  • Databricks:chat_databricks()

  • DeepSeek:chat_deepseek()

  • GitHub 模型市场:chat_github()

  • Google Gemini:chat_gemini()

  • Groq:chat_groq()

  • Ollama:chat_ollama()

  • OpenAI:chat_openai()

  • OpenRouter:chat_openrouter()

  • perplexity.ai:chat_perplexity()

  • Snowflake Cortex:chat_snowflake() 和 chat_cortex_analyst()

  • VLLM:chat_vllm()

温馨提示: 在企业环境中可能会有安全或合规要求,此时建议选择大云厂商的模型(如 Azure、Bedrock、Databricks 或 Snowflake)。

因为大部分API都可能要收钱,所以之前也没有深入了解其使用,但是过年期间不是DS把价格打下来了,也让我们可以在R中体验一下LLM,区别于帮忙写代码的功能,这里我更关注的是如何将ellmer的功能接入到对方法的描述和对结果的解释中。

  1. 官方文档

ellmer 提供了多种使用模式,满足不同场景需求:

2.1. 创建 Chat 对象

先加载 ellmer,再创建一个状态化的 chat 对象:

javascript 复制代码
library(ellmer)chat <- chat_openai(  model = "gpt-4o-mini",  system_prompt = "You are a friendly but terse assistant.")

该对象会保存整个对话的历史记录,方便连续交互。

2.2. 交互式聊天

使用 live_console(chat) 或 live_browser() 即可实时在 R 控制台或浏览器中聊天,且会保存会话上下文。

bash 复制代码
live_console(chat)#> ╔════════════════════════════════════════════════════════╗#> ║  Entering chat console. Use """ for multi-line input.  ║#> ║  Press Ctrl+C to quit.                                 ║#> ╚════════════════════════════════════════════════════════╝#> >>> Who were the original creators of R?#> R was originally created by Ross Ihaka and Robert Gentleman at the University of#> Auckland, New Zealand.#>#> >>> When was that?#> R was initially released in 1995. Development began a few years prior to that,#> in the early 1990s.

2.3. 方法调用聊天

通过直接调用 chat 对象的 chat() 方法,可以在脚本中轻松获取响应:

bash 复制代码
chat$chat("What preceding languages most influenced R?")#> R was primarily influenced by the S programming language, particularly S-PLUS.#> Other languages that had an impact include Scheme and various data analysis#> languages.

如果需要向模型提问图片问题,还可结合 content_image_file() 或 content_image_url() 一起使用。

bash 复制代码
chat$chat(  content_image_url("https://www.r-project.org/Rlogo.png"),  "Can you explain this logo?")

2.4. 编程式调用

将整个过程封装在函数中,可关闭流式输出,并返回完整结果,便于进一步处理:

php 复制代码
my_function <- function() {  chat <- chat_openai(    model = "gpt-4o-mini",    system_prompt = "You are a friendly but terse assistant."  )  chat$chat("Is R a functional programming language?")}my_function()#> [1] "Yes, R supports functional programming concepts. It allows functions to#> be first-class objects, supports higher-order functions, and encourages the#> use of functions as core components of code. However, it also supports#> procedural and object-oriented programming styles."

可以通过token_usage()查看token数量。

php 复制代码
library(ellmer)
# 创建一个基于 OpenAI 模型的对话对象,设定初始系统提示chat <- chat_openai(  model = "gpt-4o",  system_prompt = "You are a friendly assistant with expertise in R programming.")
# 发起第一轮对话,询问 R 的创始人response <- chat$chat("Who created R?", echo = FALSE)print(response)
# 查看当前对话中使用的 token 数量print(token_usage())

同时,还可以通过 echo 参数进行更细致的控制。

此外,ellmer 附带了多篇详细的教程:

  • 基本用例: vignette("ellmer")

  • Prompt 设计: vignette("prompt-design")

  • 工具/函数调用: vignette("tool-calling")

  • 结构化数据提取: vignette("structured-data")

  • 流式和异步 API: vignette("streaming-async")

应该不会有人会想在R中花费API额度和LLM聊天吧。。。所以streaming-async,prompt-design的内容大概是可以略过的。

  1. 工具调用

3.1. 概述

现代聊天模型的一大亮点是它们能利用用户定义的外部工具。模型只负责识别何时调用工具、传递合适的参数以及如何利用结果,它并不直接执行外部代码。整个流程确保了执行安全,同时使得模型具备了拓展外部数据和服务的能力。工具调用功能大大扩展了聊天模型的应用范围,使其不仅能够回答静态问题,更能通过调用外部资源动态生成高质量答案。

很多人容易误解为工具调用的过程是这样的:

用户提出请求 → 模型执行代码 → 返回结果给用户。

但实际上,正确的流程如下:

用户发起请求,需要调用工具时,模型会请求调用者执行工具函数。调用者执行函数并返回结果,随后模型利用这些结果生成最终回答。

模型的核心价值在于判断何时调用工具、选择传递哪些参数以及如何利用返回值来生成更准确的回答。

3.2. 示例

在许多情况下,模型本身不具备实时信息(如当前时间),这时工具调用就显得尤为重要。下面通过一个实例说明如何利用 ellmer 的工具功能来补充这一能力。如果直接提问"Neil Armstrong 何时登月?",模型回答了历史时间信息,但在计算"距今多久"时却缺乏当前时间数据,因此要求确认当前日期。

bash 复制代码
chat <- chat_openai(model = "gpt-4o")chat$chat("How long ago exactly was the moment Neil Armstrong touched down on the moon?")#> Neil Armstrong touched down on the moon on July 20, 1969, at 20:17 UTC. To determine how long ago that#> was from the current year of 2023, we can calculate the difference in years, months, and days.#>#> From July 20, 1969, to July 20, 2023, is exactly 54 years. If today's date is after July 20, 2023, you#> would add the additional time since then. If it is before, you would consider slightly less than 54#> years.#>#> As of right now, can you confirm the current date so we can calculate the precise duration?

因此,我们可以引入一个工具来返回当前时间。

php 复制代码
#' 获取指定时区的当前时间#'#' @param tz 获取当前时间的时区,默认为 "UTC"#' @return 返回指定时区的当前时间字符串get_current_time <- function(tz = "UTC") {  format(Sys.time(), tz = tz, usetz = TRUE)}
get_current_time()#> [1] "2024-09-18 17:47:14 UTC"a

接下来,我们需要将上面定义的 get_current_time 函数注册到聊天对象中,告知模型该工具的功能及参数。代码如下:

swift 复制代码
library(ellmer)chat <- chat_openai(model = "gpt-4o")chat$register_tool(tool(  get_current_time,  "Gets the current time in the given time zone.",  tz = type_string(    "The time zone to get the current time in. Defaults to `\"UTC\"`.",    required = FALSE  )))

如果不想手写所有注册代码,可以调用 create_tool_def(get_current_time),它会自动生成相应代码。但生成结果需仔细检查后再使用。

注册完成后,我们再次提出查询:"Neil Armstrong 何时登月?"模型这次会检测到需要获取当前时间,并自动调用 get_current_time 工具。模型获取到最新时间后,将进行日期计算并生成详细回答。

bash 复制代码
chat$chat("How long ago exactly was the moment Neil Armstrong touched down on the moon?")#> Neil Armstrong touched down on the moon on July 20, 1969, at 20:17 UTC.#>#> To calculate the time elapsed from that moment until the current time (September 18, 2024, 17:47:19#> UTC), we need to break it down.#>#> 1. From July 20, 1969, 20:17 UTC to July 20, 2024, 20:17 UTC is exactly 55 years.#> 2. From July 20, 2024, 20:17 UTC to September 18, 2024, 17:47:19 UTC, we need to further break down:#>#>    - From July 20, 2024, 20:17 UTC to September 18, 2024, 17:47:19 UTC, which is:#>      - 1 full month (August)#>      - 30 -- 20 = 10 days of July#>      - 18 days of September until 17:47:19 UTC#>#> So, in detail:#>    - 55 years#>    - 1 month#>    - 28 days#>    - From July 20, 2024, 20:17 UTC to July 20, 2024, 17:47:19 UTC: 23 hours, 30 minutes, and 19 seconds#>#> Time Total:#> - 55 years#> - 1 month#> - 28 days#> - 23 hours#> - 30 minutes#> - 19 seconds#>#> This is the exact time that has elapsed since Neil Armstrong's historic touchdown on the moon.

模型输出示例(经过工具调用后):首先回答登月时间为 1969 年 7 月 20 日 20:17 UTC。接着利用当前时间(例如 2024-09-18 17:47:19 UTC)计算出自登月以来的具体年、月、日、小时、分钟和秒数。最终生成一个详细的时间间隔说明。

虽然示例较为简单,但这种工具调用机制可以支持更复杂的应用场景,例如:

  • 调用第三方 API:

    获取实时天气、金融数据等信息。

  • 数据库操作:

    读取或写入数据,动态生成报告。

  • 触发复杂计算或模拟:

    通过工具调用启动其他服务或模型(例如图像生成模型)。

  • Shiny 应用:

    利用工具设置或更新 reactive 值,实现复杂交互逻辑。

注意:虽然返回df一般能工作,但要注意数据量不能太大,否则会消耗大量 token,影响上下文窗口和计费。

  1. 结构化数据

4.1. 概述

当使用 LLM 从文本或图像中提取数据时,我们通常希望输出格式为 JSON或其他预定格式。但由于模型输出可能被包裹在 json 标记中,ellmer 引入了"结构化数据"(structured output)的功能。通过提供一个明确的类型规格(schema),LLM 能够确保返回的数据符合预期结构。这种结构化数据提取方式使得 R 用户可以更加便捷地从复杂文本或图像中提取关键信息,既提升了数据处理效率,也为后续的数据分析和可视化打下了良好的基础。

4.2. 结构化数据提取

采用 $extract_data() 方法而非普通的 $chat(),配合事先定义好的类型规格提取数据。

例如:

bash 复制代码
chat <- chat_openai()chat$extract_data(  "My name is Susan and I'm 13 years old",  type = type_object(    age = type_number(),    name = type_string()  )) 
#> $age#> [1] 13#> #> $name#> [1] "Susan"

上述代码会提取出一个包含年龄和姓名的对象。同样的原理也适用于图像,例如从 R 的 logo 中提取主要形状和颜色信息。

bash 复制代码
chat$extract_data(  content_image_url("https://www.r-project.org/Rlogo.png"),  type = type_object(    primary_shape = type_string(),    primary_colour = type_string()  ))#> $primary_shape#> [1] "oval and letter R"#> #> $primary_colour#> [1] "gray and blue"

4.3. 数据类型的定义

标量(Scalars):

  • type_boolean():逻辑值

  • type_integer():整数

  • type_number():浮点数

  • type_string():字符串

  • type_enum():枚举(类似因子)

数组(Arrays):

使用 type_array() 定义,同一数组内所有元素的类型需一致。例如:

go 复制代码
type_integer_vector <- type_array(items = type_integer())

对象(Objects):使用 type_object() 定义,类似于 R 的命名列表,可包含任意数量的标量、数组和对象。

例如定义一个人:

javascript 复制代码
type_type_person <- type_object(  "A person",  name = type_string("Name"),  age = type_integer("Age, in years."),  hobbies = type_array(    "List of hobbies. Should be exclusive and brief.",    items = type_string()  ))

ellmer 会将模型返回的 JSON 自动转换为最自然的 R 表示形式:标量数组转换为逻辑、整数、数值、字符向量;对象数组转换为数据框;若不需要自动转换,可通过设置 convert = FALSE 获取原始列表。

  1. 4 示例

示例 1:文章信息提取

目标: 提取文章作者、主题、摘要以及评分信息。

实现: 定义一个类型规格 type_summary,调用 $extract_data() 得到结构化结果,并转换为 R 的数据类型(如字符向量、数值、数据框)。

bash 复制代码
text <- readLines(system.file("examples/third-party-testing.txt", package = "ellmer"))# url <- "https://www.anthropic.com/news/third-party-testing"# html <- rvest::read_html(url)# text <- rvest::html_text2(rvest::html_element(html, "article"))type_summary <- type_object(  "Summary of the article.",  author = type_string("Name of the article author"),  topics = type_array(    'Array of topics, e.g. ["tech", "politics"]. Should be as specific as possible, and can overlap.',    type_string(),  ),  summary = type_string("Summary of the article. One or two paragraphs max"),  coherence = type_integer("Coherence of the article's key points, 0-100 (inclusive)"),  persuasion = type_number("Article's persuasion score, 0.0-1.0 (inclusive)"))chat <- chat_openai()#> Using model = "gpt-4o".data <- chat$extract_data(text, type = type_summary)cat(data$summary)#> The article advocates for effective third-party testing in the AI sector to address potential societal harm caused by frontier AI systems. Anthropic emphasizes the need for a comprehensive testing regime, driven by insights from industry, government, and academia, to complement existing sector-specific regulations. This would involve building a robust framework to evaluate AI systems for safety, particularly those that are large-scale and could pose risks like election interference or security threats. Creating an ecosystem of third-party testers, involving private companies, academia, and government, is suggested as a way to enhance transparency and trust. The text also stresses the importance of proactively crafting thorough regulatory responses to avoid hasty regulations in the wake of AI-caused incidents. Broader issues such as open-source models, regulatory capture, and national security considerations are discussed in relation to third-party testing and its implementation.str(data)#> List of 5#>  $ author    : chr "Anthropic AI"#>  $ topics    : chr [1:4] "AI Policy" "Third-Party Testing" "Regulation" "AI Safety"#>  $ summary   : chr "The article advocates for effective third-party testing in the AI sector to address potential societal harm cau"| __truncated__#>  $ coherence : int 85#>  $ persuasion: num 0.75

示例 2:命名实体识别

目标: 从文本中提取实体名称、类型(人员、地点、组织)和上下文。

实现: 使用 type_object() 定义单个实体,再用 type_array() 收集所有识别结果。

bash 复制代码
text <- "  John works at Google in New York. He met with Sarah, the CEO of  Acme Inc., last week in San Francisco."type_named_entity <- type_object(  name = type_string("The extracted entity name."),  type = type_enum("The entity type", c("person", "location", "organization")),  context = type_string("The context in which the entity appears in the text."))type_named_entities <- type_array(items = type_named_entity)chat <- chat_openai()#> Using model = "gpt-4o".chat$extract_data(text, type = type_named_entities)#>            name         type#> 1          John       person#> 2        Google organization#> 3      New York     location#> 4         Sarah       person#> 5     Acme Inc. organization#> 6 San Francisco     location#>                                                                context#> 1                                    John works at Google in New York.#> 2                                    John works at Google in New York.#> 3                                    John works at Google in New York.#> 4 He met with Sarah, the CEO of Acme Inc., last week in San Francisco.#> 5 He met with Sarah, the CEO of Acme Inc., last week in San Francisco.#> 6 He met with Sarah, the CEO of Acme Inc., last week in San Francisco.

示例 3:情感分析

目标: 提取文本的正面、负面和中性情感得分(得分之和应为 1)。

实现: 定义相应的数值类型字段,通过 $extract_data() 返回一个包含三个分数的列表。

bash 复制代码
text <- "  The product was okay, but the customer service was terrible. I probably  won't buy from them again."type_sentiment <- type_object(  "Extract the sentiment scores of a given text. Sentiment scores should sum to 1.",  positive_score = type_number("Positive sentiment score, ranging from 0.0 to 1.0."),  negative_score = type_number("Negative sentiment score, ranging from 0.0 to 1.0."),  neutral_score = type_number("Neutral sentiment score, ranging from 0.0 to 1.0."))chat <- chat_openai()#> Using model = "gpt-4o".str(chat$extract_data(text, type = type_sentiment))#> List of 3#>  $ positive_score: num 0.1#>  $ negative_score: num 0.7#>  $ neutral_score : num 0.2

示例 4:文本分类

目标: 对文本进行分类,输出类别及对应的概率分数。

实现: 定义一个包含类别(枚举)和分数的对象数组,输出格式为数据框。

powershell 复制代码
text <- "The new quantum computing breakthrough could revolutionize the tech industry."type_classification <- type_array(  "Array of classification results. The scores should sum to 1.",  type_object(    name = type_enum(      "The category name",      values = c(        "Politics",        "Sports",        "Technology",        "Entertainment",        "Business",        "Other"      )    ),    score = type_number(      "The classification score for the category, ranging from 0.0 to 1.0."    )  ))chat <- chat_openai()#> Using model = "gpt-4o".data <- chat$extract_data(text, type = type_classification)data#>         name score#> 1 Technology  0.85#> 2   Business  0.10#> 3      Other  0.05

示例 5:处理未知键

目标: 提取文本中所有可用的特征信息。

实现: 使用 type_object() 时设置 .additional_properties = TRUE,让模型返回除预定义字段外的其它信息(目前仅 Claude 支持)。

bash 复制代码
type_characteristics <- type_object(  "All characteristics",  .additional_properties = TRUE)prompt <- "  Given a description of a character, your task is to extract all the characteristics of that character.  <description>  The man is tall, with a beard and a scar on his left cheek. He has a deep voice and wears a black leather jacket.  </description>"chat <- chat_claude()str(chat$extract_data(prompt, type = type_characteristics))#>  list()

示例 6:图像数据提取

目标: 从图像(如截图)中提取结构化资产信息。

实现: 定义资产相关的对象结构,然后调用 $extract_data() 对图像进行解析,返回的数据会自动转换为 R 的数据框格式。

powershell 复制代码
type_asset <- type_object(  assert_name = type_string(),  owner = type_string(),  location = type_string(),  asset_value_low = type_integer(),  asset_value_high = type_integer(),  income_type = type_string(),  income_low = type_integer(),  income_high = type_integer(),  tx_gt_1000 = type_boolean())type_assets <- type_array(items = type_asset)chat <- chat_openai()#> Using model = "gpt-4o".image <- content_image_file("congressional-assets.png")data <- chat$extract_data(image, type = type_assets)data#>                            assert_name owner#> 1  11 Zinfandel Lane - Home & Vineyard    JT#> 2 25 Point Lobos - Commercial Property    SP#>                              location asset_value_low asset_value_high#> 1             St. Helena/Napa, CA, US         5000001         25000000#> 2 San Francisco/San Francisco, CA, US         5000001         25000000#>   income_type income_low income_high tx_gt_1000#> 1 Grape Sales     100001     1000000       TRUE#> 2        Rent     100001     1000000       TRUE

4.5. 注意

默认情况下,对象内所有字段均为必选。如果某些字段不一定在文本中出现,可以将 required 参数设置为 FALSE。这样,缺失字段将返回 NULL,而非模型自动生成(hallucinate)的数据。例如这里产生的日期的幻觉(日期并未出现在文本中):

bash 复制代码
type_article <- type_object(  "Information about an article written in markdown",  title = type_string("Article title"),  author = type_string("Name of the author"),  date = type_string("Date written in YYYY-MM-DD format."))prompt <- "  Extract data from the following text:  <text>  # Structured Data  By Hadley Wickham  When using an LLM to extract data from text or images, you can ask the chatbot to nicely format it, in JSON or any other format that you like.  </text>"chat <- chat_openai()#> Using model = "gpt-4o".chat$extract_data(prompt, type = type_article)#> $title#> [1] "Structured Data"#> #> $author#> [1] "Hadley Wickham"#> #> $date#> [1] "2023-10-17"

如果非必须,则会返回NULL

php 复制代码
type_article <- type_object(  "Information about an article written in markdown",  title = type_string("Article title", required = FALSE),  author = type_string("Name of the author", required = FALSE),  date = type_string("Date written in YYYY-MM-DD format.", required = FALSE))chat$extract_data(prompt, type = type_article)#> $title#> [1] "Structured Data"#> #> $author#> [1] "Hadley Wickham"#> #> $date#> NULL

与 R 常用的列式数据框不同,结构化数据要求采用"行导向"方式。定义时使用 type_array(),每个元素为一个对象,代表数据框的一行记录。

go 复制代码
type_my_df <- type_array(  items = type_object(    name = type_string(),    age = type_integer(),    height = type_number(),    weight = type_number()  ))
  1. 具体使用

5.1. 基本功能

首先来到DS-API界面创建API Key

然后这里测试DS的基本功能,查看基本用法

php 复制代码
chat_deepseek(  system_prompt = NULL,  turns = NULL,  base_url = "https://api.deepseek.com",  api_key = deepseek_key(),  model = NULL,  seed = NULL,  api_args = list(),  echo = NULL)

基本功能通过定义API是非常容易实现的,默认的模型是chat模型

markdown 复制代码
chat <- chat_deepseek(api_key = "sk-*****************",seed=1234)# Using model = "deepseek-chat".chat$chat("Tell me three funny jokes about neuroimaging in chinese")当然可以!以下是三个关于神经影像学的搞笑笑话,用中文表达:
1. **医生与患者**     患者:医生,我的脑部扫描结果出来了吗?     医生:出来了,你的大脑里有个"404错误"------找不到烦恼的区域!     患者:那太好了,我终于可以无忧无虑了!     医生:不,这意味着你的烦恼系统崩溃了,得重装!  
2. **MRI的幽默**     患者:做MRI的时候,我感觉自己像个微波炉里的热狗。     医生:别担心,至少你的大脑不会被烤熟,只会被"扫描熟"!     患者:那我是不是可以改名叫"脑花"?     医生:不,你叫"高清无码脑"!  
3. **脑部图像的秘密**     医生:你看,这是你的脑部图像。     患者:哇,我的大脑看起来像个迷宫!     医生:没错,而且你的"方向感神经元"好像迷路了。     患者:难怪我总是找不到回家的路!     医生:别担心,我们已经帮你标记了出口------就在"记忆区"旁边,如果你能找到的话!  
希望这些笑话能让你会心一笑! 😄

这几个蹩脚的中文笑话实在是太冷吧。。。

经过几次测试,花费的token如下

css 复制代码
token_usage()name input output1OpenAI-api.deepseek.com 3830 1178

非常遗憾,ellmer的结构化提取和工具调用功能(基于结构化提取)目前还不支持DS

5.2. 尝试使用DS解释富集分析的结果

这里针对的是clusterProfiler的输出格式

ruby 复制代码
str(res)Formal class 'gseaResult' [package "DOSE"] with 13 slots  ..@ result     :'data.frame': 7 obs. of  15 variables:  .. ..$ ID                        : chr [1:7] "GO:0048787" "GO:0099059" "GO:0048786" "GO:0099523" ...  .. ..$ Description               : chr [1:7] "presynaptic active zone\nmembrane" "integral component of\npresynaptic active zone\nmembrane" "presynaptic active zone" "presynaptic cytosol" ...  .. ..$ setSize                   : int [1:7] 48 36 75 33 131 109 36  .. ..$ Predictor                 : chr [1:7] "Flanker_Unadj" "Flanker_Unadj" "Flanker_Unadj" "Flanker_Unadj" ...  .. ..$ Unstandardized_Coefficient: num [1:7] 0.000874 0.000887 0.000816 0.000683 0.000399 ...  .. ..$ Standard_Error            : num [1:7] 0.000285 0.000318 0.000285 0.000295 0.000177 ...  .. ..$ t_Value                   : num [1:7] 3.07 2.79 2.87 2.31 2.25 ...  .. ..$ Standardized_Coefficient  : num [1:7] 0.149 0.133 0.141 0.112 0.112 ...  .. ..$ CI_95_Lower               : num [1:7] 0.0533 0.0393 0.0443 0.0168 0.0143 ...  .. ..$ CI_95_Upper               : num [1:7] 0.244 0.227 0.238 0.207 0.21 ...  .. ..$ pvalue                    : num [1:7] 0.0016 0.0034 0.0044 0.0256 0.0316 ...  .. ..$ p.adjust                  : num [1:7] 0.0807 0.0807 0.0807 0.3088 0.3088 ...  .. ..$ qvalue                    : num [1:7] 0.0741 0.0741 0.0741 0.2837 0.2837 ...  .. ..$ null_model                : chr [1:7] "spin_brain" "spin_brain" "spin_brain" "spin_brain" ...  .. ..$ core_enrichment           : chr [1:7] "KCTD12/CPLX3/NTNG1/GRM7/STX1B/CELSR3" "GRM7/GRM8/P2RY1/NRG1/STX1A/HCN1" "TRIO/ROCK2/PI4K2A/IQSEC2/OSBPL2/KCTD12/CPLX3/NTNG1/SCN8A/GRM7/KCNMA1" "PRKCG/MARCKS/SUMO3/GDA" ...  ..@ organism   : chr(0)   ..@ setType    : chr(0)   ..@ geneSets   :List of 55  .. ..$ GO:0007268          : chr [1:109] "ADCY8" "PRKAR1B" "ADCY1" "BAIAP2" ...  .. ..$ GO:0007416          : chr [1:92] "SYDE2" "CDH9" "CADM1" "ADGRL3" ...  ..@ geneList   : Named num [1:55] 2.188 1.889 1.142 1.648 0.497 ...  .. ..- attr(*, "names")= chr [1:55] "GO:0007268" "GO:0007416" "GO:0008021" "GO:0016079" ...  ..@ keytype    : chr "SYMBOL"  ..@ permScores : num [1:55, 1:5000] 0.363 0.134 1.982 -0.345 1.224 ...  .. ..- attr(*, "dimnames")=List of 2  .. .. ..$ : chr [1:55] "GO:0007268" "GO:0007416" "GO:0008021" "GO:0016079" ...  .. .. ..$ : NULL  ..@ params     :List of 10  .. ..$ pvalueCutoff : num 0.05  .. ..$ nPerm        : num 5000  .. ..$ pAdjustMethod: chr "fdr"  .. ..$ minGSSize    : num 20  .. ..$ maxGSSize    : num 200  .. ..$ corMethod    : chr "pearson"  .. ..$ aggreMethod  : chr "ks_pos_neg_sum"  .. ..$ nullType     : chr "spin_brain"  .. ..$ thresType    : chr "sd"  .. ..$ thresVal     : num 1  ..@ gene2Symbol: chr(0)   ..@ readable   : logi TRUE  ..@ termsim    : num[0 , 0 ]   ..@ method     : chr(0)   ..@ dr         : list()

里面我们只关注显著的通路和基因,把它们放到prompt中,在context_prompt说做了什么,在system_prompt中设定角色,通过API进行请求就可获得返回的结果。

php 复制代码
library(ellmer)interpret <- function(res,                       api_key,                       context_prompt = "These terms are found to be spatially correlated with effect size maps ...",                       system_prompt = "You are an expert in ...",                       turns = NULL,                       base_url = "https://api.deepseek.com",                       model = NULL,                       seed = NULL,                       api_args = list(),                       echo = NULL) {  # Extract information from the gseaResult object.  # We assume that enriched terms are in the "Description" and "core_enrichment" columns.  # Join multiple entries into single strings.  descriptions <- paste(res@result$Description, collapse = "\n")  core_enrichments <- paste(res@result$core_enrichment, collapse = "\n")    # Build a prompt text that includes the user context.  prompt_text <- paste(    "I have performed a gene set enrichment analysis. Here are the enriched terms:",    "\nDescriptions:",    descriptions,    "\nCore Enrichment:",    core_enrichments,    "\nAdditional Context:",    context_prompt,    "\nBased on this, please provide insights for the results?"  )    # Initialize the chat using DeepSeek.  chat <- chat_deepseek(    api_key = api_key,    system_prompt = system_prompt,    turns = turns,    base_url = base_url,    model = model,    seed = seed,    api_args = api_args,    echo = echo  )  # Send the prompt and collect the response.  response <- chat$chat(prompt_text)  return(response)}

调用该函数

markdown 复制代码
interpret(res, api_key = "sk-*************************",          context_prompt = "These terms are found to be spatially correlated with effect size maps of case-control comparisions in Desikan cortical thickness between major depressive disorder patients and health controls",          system_prompt = "You are an expert in bioinformatics and biology. You are going to help me to interpret the results of my gene set enrichment analysis and provide a paragraph of discussion of the findings. The statment or point of view should be coherent and relevant to the context, and also should be supported by proper references.")

返回的讨论/解释:

The gene set enrichment analysis (GSEA) results highlight a strong association between synaptic structure and function, particularly in the context of major depressive disorder (MDD). The enriched terms, such as "presynaptic active zone," "trans-synaptic signaling," and "chemical synaptic transmission," suggest that synaptic dysregulation may play a critical role in the pathophysiology of MDD. These findings align with the growing body of evidence implicating synaptic plasticity and neurotransmission in mood disorders (Duman et al., 2016). The core enrichment genes, including GRM7 (metabotropic glutamate receptor 7), STX1B (syntaxin 1B), and BDNF (brain-derived neurotrophic factor), are particularly noteworthy. GRM7 is involved in modulating glutamatergic signaling, which has been implicated in depressive phenotypes, while BDNF is a key regulator of synaptic plasticity and neurogenesis, both of which are disrupted in MDD (Castrén & Monteggia, 2021). Additionally, the presence of genes like NTNG1 (netrin G1) and DLGAP1 (discs large-associated protein 1) underscores the importance of synaptic adhesion and scaffolding proteins in maintaining synaptic integrity, which may be compromised in MDD.

The spatial correlation of these terms with cortical thickness differences between MDD patients and healthy controls further supports the notion that synaptic dysfunction may underlie structural brain changes observed in MDD. For instance, reduced cortical thickness in regions such as the prefrontal cortex and hippocampus has been consistently reported in MDD (Schmaal et al., 2017). The involvement of genes like ROCK2 and PI4K2A, which regulate cytoskeletal dynamics and membrane trafficking, suggests that synaptic remodeling and neuronal connectivity may be impaired in MDD. This is consistent with the hypothesis that MDD is associated with a loss of synaptic connections and reduced neuroplasticity (Kang et al., 2012).

In summary, these findings highlight the centrality of synaptic dysfunction in MDD, particularly in regions with altered cortical thickness. The identified genes and pathways provide potential targets for therapeutic interventions aimed at restoring synaptic function and plasticity in MDD patients. Future studies should explore the causal relationships between these genetic factors, synaptic alterations, and depressive symptomatology to further elucidate the mechanisms underlying MDD.

References:

Castrén, E., & Monteggia, L. M. (2021). Brain-derived neurotrophic factor signaling in depression and antidepressant action. Biological Psychiatry, 90(2), 128-136.

Duman, R. S., Aghajanian, G. K., Sanacora, G., & Krystal, J. H. (2016). Synaptic plasticity and depression: new insights from stress and rapid-acting antidepressants. Nature Medicine, 22(3), 238-249.

Kang, H. J., Voleti, B., Hajszan, T., Rajkowska, G., Stockmeier, C. A., Licznerski, P., ... & Duman, R. S. (2012). Decreased expression of synapse-related genes and loss of synapses in major depressive disorder. Nature Medicine, 18(9), 1413-1417.

Schmaal, L., Veltman, D. J., van Erp, T. G., Sämann, P. G., Frodl, T., Jahanshad, N., ... & Hibar, D. P. (2017). Subcortical brain alterations in major depressive disorder: findings from the ENIGMA Major Depressive Disorder working group. Molecular Psychiatry, 21(6), 806-812.

第一眼看上去Dumand 和Schmaal的文献是真实的,其他内容准确性未知。

这个讨论花费不到1分钱

css 复制代码
token_usage()                     name input output1 OpenAI-api.deepseek.com   441    779

目前,对于需要直接解释的结果,通过网页版的 LLM 来处理可能会更高效。就这些基本功能而言,暂时看不出使用 ellmer 交互的明显优势。

但随着结构化数据提取功能的不断完善,ellmer 在高级应用场景中的潜力将会大幅提升。

例如,这里的treeplot虽然做了一些基于语义的聚类,但是关键词的提取不尽如人意。可以通过 LLM 对富集的通路进行智能分类,从而为后续的结果展示和分析提供更便捷、高效的支持。

往期推荐:

将ChatGPT整合到Word中

相关推荐
Uu_05kkq11 分钟前
【C语言5】函数:库函数、自定义函数、形参和实参、return语句、数组做函数参数、嵌套调用和链式访问、声明和定义
c语言·开发语言
小沈熬夜秃头中୧⍤⃝13 分钟前
fnOS生态下的WordPress个人网站从本地到公网访问的搭建与配置
java·开发语言
小白教程15 分钟前
python3.13安装教程(附安装包),【2025】python3.13安装图文教程
python·python3.13安装教程·python3.13安装步骤·python3.13安装流程·python3.13安装·python3.13安装指南·python3.13图文教程
dundunmm41 分钟前
【数据挖掘]Ndarray数组的创建
python·机器学习·数据挖掘·numpy
Only*1 小时前
conda虚拟环境中如何查看包的位置
python·conda·pip
Aska_Lv1 小时前
线上问题-我就加了个索引怎么就导致线上事故了
后端
liangblog1 小时前
在Spring Boot项目中导出复杂对象到Excel文件
spring boot·后端·excel
电科_银尘2 小时前
【Python/Pytorch】-- 创建3090Ti显卡所需环境
开发语言·pytorch·python
小白学大数据2 小时前
Ruby爬虫如何控制并发数量:爬取京东电子产品
大数据·开发语言·网络·爬虫·python·ruby
Real_man2 小时前
SQLAlchemy 详细指南
python