使用C#构建一个论文总结AI Agent

前言

我觉得将日常生活中一些简单重复的任务交给AI Agent,是学习构建AI Agent应用一个很不错的开始。本次分享我以日常生活中一个总结论文的简单任务出发进行说明,希望对大家了解AI Agent有所帮助。任务可以是多种多样的,真的帮助自己提升了效率,那就是一个很不错的开始了!!

我的这个简单任务是这样的,有一篇文献,如下所示:

image-20250102100353781

我想要对该文献进行总结,然后将md格式笔记保存。

我之前的做法是使用Cherry Studio新建一个论文总结助手,如下所示:

image-20250102100813485

然后上传文献,进行总结,如下所示:

image-20250102101204179

然后新建一个笔记md文件,将这些内容复制进去,这样就完成了一个简单的任务,如下所示:

image-20250102101513430

虽然说已经比最开始的时候,只是将文献翻译一下,就直接开始读,然后尝试自己总结主要内容强太多了。但是还是有需要改进的地方,那就是选择文件,新建笔记文件,复制笔记内容这些简单重复的事,可以尝试一下把这些交给一个AI Agent!!

使用C#构建一个论文总结AI Agent相关实践

前几个月,当我刚开始尝试构建AI Agent应用的时候,经过测试,我发现在Semantic Kernel中,想要使用函数调用的话,只有OpenAI与Kimi的模型能用,而OpenAI模型的使用在国内是不太方便的,而构建一个AI Agent函数调用功能是必不可少的。经过一番探索,找到了一位大佬的方法,可以通过提示词来实现函数调用:

Semantic Kernel/C#:一种通用的Function Calling方法,文末附大模型清单

然后根据这个方法,做了一个简单的AI Agent项目进行介绍:

SimpleAIAgent:使用免费的glm-4-flash即可开始构建简单的AI Agent应用

GitHub地址:https://github.com/Ming-jiayou/SimpleAIAgent

经过几个月的发展,我发现现在在Semantic Kernel中使用国内具有函数调用能力的模型效果也还行了。现在开始构建我们自己的AI Agent应用吧!!

为了尽量保持简单,不增加无关的心智负担,便于感兴趣的朋友自己动手,新建一个C#控制台项目。

实现这个简单的Demo可以有五种不同的方式:

image-20250102103959346

第一种使用基本的Semantic Kernel中的Function calling with chat completion

相关文档:Function calling with chat completion | Microsoft Learn

第二种使用Semantic Kernel Chat Completion Agent

相关文档:Exploring the Semantic Kernel Chat Completion Agent (Experimental) | Microsoft Learn

第三种使用Microsoft.Extensions.AI

相关文档:extensions/src/Libraries/Microsoft.Extensions.AI.OpenAI at main · dotnet/extensions

第四种使用Semantic Kernel Open AI Assistant Agent

相关文档:Exploring the Semantic Kernel Open AI Assistant Agent (Experimental) | Microsoft Learn

第五种使用UniversalLLMFunctionCaller

相关文档:Jenscaasen/UniversalLLMFunctionCaller: A planner that integrates into Semantic Kernel to enable function calling on all Chat based LLMs (Mistral, Bard, Claude, LLama etc)

我先使用第二种方式进行说明。

先安装这三个库:

image-20250102105224219

实现这个AI Agent需要自己先写好一个总结论文的相关插件:

最初的插件:

 [KernelFunction("ExtractPDFContent")][Description("读取指定路径的PDF文档内容")][return: Description("PDF文档内容")]public string ExtractPDFContent(string filePath){StringBuilder text = new StringBuilder();// 读取PDF内容using (PdfDocument document = PdfDocument.Open(filePath)){foreach (var page in document.GetPages()){text.Append(page.Text);}}return text.ToString();}[KernelFunction][Description("根据文件路径与笔记内容创建一个md格式的文件")]public void SaveMDNotes([Description("保存笔记的路径")] string filePath, [Description("笔记的md格式内容")] string mdContent){try{// 检查文件是否存在,如果不存在则创建if (!File.Exists(filePath)){// 创建文件并写入内容File.WriteAllText(filePath, mdContent);}else{// 如果文件已存在,覆盖写入内容File.WriteAllText(filePath, mdContent);}}catch (Exception ex){// 处理异常Console.WriteLine($"An error occurred: {ex.Message}");}}

原本是想AI自己多次调用这些函数,比如先调用第一个获取pdf文献内容,然后生成一个md格式笔记,然后再调用第二个函数。但是在实际实践中,只有OpenAI的模型这样子效果还可以,其他的模型多次函数调用的效果并不好,因此最终选择内置一个Kernel的方法。

最终的插件:

    internal sealed class PaperAssistantPlugin{public PaperAssistantPlugin() {IKernelBuilder builder = Kernel.CreateBuilder();
#pragma warning disable SKEXP0010 // 类型仅用于评估,在将来的更新中可能会被更改或删除。取消此诊断以继续。builder.AddOpenAIChatCompletion(modelId: "deepseek-ai/DeepSeek-V2.5",apiKey: "sk-xxx",endpoint: new Uri("https://api.siliconflow.cn"));         
#pragma warning restore SKEXP0010 // 类型仅用于评估,在将来的更新中可能会被更改或删除。取消此诊断以继续。InterKernel = builder.Build();}internal Kernel InterKernel { get; set; }[KernelFunction("ExtractPDFContent")][Description("读取指定路径的PDF文档内容")][return: Description("PDF文档内容")]public string ExtractPDFContent(string filePath){StringBuilder text = new StringBuilder();// 读取PDF内容using (PdfDocument document = PdfDocument.Open(filePath)){foreach (var page in document.GetPages()){text.Append(page.Text);}}return text.ToString();}[KernelFunction][Description("根据文件路径与笔记内容创建一个md格式的文件")]public void SaveMDNotes([Description("保存笔记的路径")] string filePath, [Description("笔记的md格式内容")] string mdContent){try{// 检查文件是否存在,如果不存在则创建if (!File.Exists(filePath)){// 创建文件并写入内容File.WriteAllText(filePath, mdContent);}else{// 如果文件已存在,覆盖写入内容File.WriteAllText(filePath, mdContent);}}catch (Exception ex){// 处理异常Console.WriteLine($"An error occurred: {ex.Message}");}}[KernelFunction][Description("总结论文内容生成一个md格式的笔记,并将笔记保存到指定路径")]      public async void GeneratePaperSummary(string filePath1,string filePath2){StringBuilder text = new StringBuilder();// 读取PDF内容using (PdfDocument document = PdfDocument.Open(filePath1)){foreach (var page in document.GetPages()){text.Append(page.Text);}}// 生成md格式的笔记string skPrompt = """论文内容:{{$input}}请总结论文的摘要、前言、文献综述、主要论点、研究方法、结果和结论。论文标题为《[论文标题]》,作者为[作者姓名],发表于[发表年份]。请确保总结包含以下内容:论文摘要论文前言论文文献综诉主要研究问题和背景使用的研究方法和技术主要结果和发现论文的结论和未来研究方向""";var result = await InterKernel.InvokePromptAsync(skPrompt, new() { ["input"] = text.ToString() });try{// 检查文件是否存在,如果不存在则创建if (!File.Exists(filePath2)){// 创建文件并写入内容File.WriteAllText(filePath2, result.ToString());Console.WriteLine($"生成笔记成功,笔记路径:{filePath2}");}else{// 如果文件已存在,覆盖写入内容File.WriteAllText(filePath2, result.ToString());}}catch (Exception ex){// 处理异常Console.WriteLine($"An error occurred: {ex.Message}");}}}
}

内置的一个Kernel用于生成md格式的论文笔记。

主函数如下所示:

    internal class Program{public static async Task Main(){Console.WriteLine("Initialize plugins...");PaperAssistantPlugin paperAssistantPugin = new PaperAssistantPlugin();Console.WriteLine("Creating kernel...");IKernelBuilder builder = Kernel.CreateBuilder();//builder.AddOpenAIChatCompletion(//    "gpt-4o-mini-2024-07-18",//    "xxx"//  );#pragma warning disable SKEXP0010 // 类型仅用于评估,在将来的更新中可能会被更改或删除。取消此诊断以继续。builder.AddOpenAIChatCompletion(modelId: "Qwen/Qwen2.5-32B-Instruct",apiKey: "xxx",endpoint: new Uri("https://api.siliconflow.cn"));// builder.AddOpenAIChatCompletion(//  modelId: "glm-4-flash",//  apiKey: "xxx",//  endpoint: new Uri("https://open.bigmodel.cn/api/paas/v4")//);// builder.AddOpenAIChatCompletion(//  modelId: "yi-large-fc",//  apiKey: "xxx",//  endpoint: new Uri("https://api.lingyiwanwu.com/v1")//);
#pragma warning restore SKEXP0010 // 类型仅用于评估,在将来的更新中可能会被更改或删除。取消此诊断以继续。builder.Plugins.AddFromObject(paperAssistantPugin);Kernel kernel = builder.Build();Console.WriteLine("Defining agent...");
#pragma warning disable SKEXP0110 // 类型仅用于评估,在将来的更新中可能会被更改或删除。取消此诊断以继续。ChatCompletionAgent agent =new(){Name = "PaperAssistantAgent",Instructions ="""你是一个用于读取pdf文献内容,并总结内容,生成一个md笔记的智能代理。用户提供论文路径与创建笔记的路径注意文件路径的格式应如下所示:"D:\文献\表格识别相关\文献\xx.pdf""D:\文献\表格识别相关\笔记\xx.md"请总结论文的摘要、前言、文献综述、主要论点、研究方法、结果和结论。论文标题为《[论文标题]》,作者为[作者姓名],发表于[发表年份]。请确保总结包含以下内容:论文摘要论文前言论文文献综诉主要研究问题和背景使用的研究方法和技术主要结果和发现论文的结论和未来研究方向""",Kernel = kernel,Arguments =new KernelArguments(new OpenAIPromptExecutionSettings() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(),MaxTokens = 16000})                     };
#pragma warning restore SKEXP0110 // 类型仅用于评估,在将来的更新中可能会被更改或删除。取消此诊断以继续。Console.WriteLine("Ready!");ChatHistory history = [];bool isComplete = false;do{Console.WriteLine();Console.Write("> ");string input = Console.ReadLine();if (string.IsNullOrWhiteSpace(input)){continue;}if (input.Trim().Equals("EXIT", StringComparison.OrdinalIgnoreCase)){isComplete = true;break;}if (input.Trim().Equals("Clear", StringComparison.OrdinalIgnoreCase)){history.Clear();Console.WriteLine("已清除聊天记录");continue;}history.Add(new ChatMessageContent(AuthorRole.User, input));Console.WriteLine();#pragma warning disable SKEXP0110 // 类型仅用于评估,在将来的更新中可能会被更改或删除。取消此诊断以继续。await foreach (ChatMessageContent response in agent.InvokeAsync(history)){// Display response.Console.WriteLine($"{response.Content}");}
#pragma warning restore SKEXP0110 // 类型仅用于评估,在将来的更新中可能会被更改或删除。取消此诊断以继续。} while (!isComplete);}}
}

在主函数中定义的这个Kernel主要用于与用户交互与选择调用哪个函数。

开始查看效果:

image-20250102110835592

会发现在自动调用插件中的这个函数了。

image-20250102110931834

由于我使用的是异步方式,AI会先给出回答,实际上笔记还没有真的生成,当出现生成笔记成功,笔记路径:xxx的时候,笔记才真的生成成功,如下所示:

image-20250102111211988

image-20250102111135929

image-20250102111303999

就成功实现我们自己的简单的AI Agent应用了。

直接使用

可能很多人并不熟悉C#也不太懂得编程,但是对自己构建AI Agent应用还是很感兴趣的。接下来我将手把手地介绍该如何使用,希望完全的小白也能学会使用。

项目GitHub地址:https://github.com/Ming-jiayou/PaperAssistant

C#程序员git clone项目之后,将.env.example改为.env然后填入自己想要使用的模型与密钥以及Endpoint即可。

这里重点介绍一下非程序朋友的使用。

我已经发布了一个版本放到GitHub上了,如果上GitHub有问题,也可以联系我。但还是推荐从GitHub上下载,比较安全一点,随便打开别人给的文件不太好。

image-20250102163753555

image-20250102163814932

下载好了之后,解压如下所示:

image-20250102163832037

将.env.example改为.env然后填入自己想要使用的模型与密钥以及Endpoint即可。

image-20250102163925711

以下是手把手的尝试几个不同的平台。

SiliconCloud

现在注册有送2000万token的活动,最nice的一点是送的token没有时间期限。想试试的朋友可以点击链接:https://cloud.siliconflow.cn/i/Ia3zOSCU,注册使用。

image-20250102144700195

直接点击exe文件,即可使用:

image-20250102144800507

出现完成之后,并没有真的完成:

image-20250102144927790

需要继续等待,等到出现“生成笔记成功,笔记路径:xxx”的时候才真正生成完成:

image-20250102145051958

image-20250102145743037

智谱AI

glm-4-flash是免费使用的,配置如下所示:

image-20250102145436991

效果:

image-20250102145801666

image-20250102145841211

可以发现总结的内容比Qwen/Qwen2.5-72B-Instruct-128K要少很多。

DeepSeek

配置如下所示:

image-20250102150451237

效果:

image-20250102150712209

第一次没成功,就再来一次。

image-20250102150939008

总结的很好,可惜是英文的,再试一次:

image-20250102151237085

总结的也很不错,但是不好的一点是似乎陷入了死循环:

image-20250102151336922

过一会又把生成的覆盖掉了,变成英文的了,如下所示:

image-20250102151457836

一下就花掉了10万token,我这个应用看来不适合使用DeepSeek。

image-20250102151703421

零一万物

配置如下:

image-20250102152515824

需要改成yi-large-fc才行。

效果:

image-20250102152922071

image-20250102153014272

如果有朋友硅基流动赠送的额度都用完了,但是也想体验一下,可以联系我获取体验的api key,用的量多了随时关闭,不太可靠。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/891508.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vs 2022 中xml 粘贴为Class 中,序列化出来的xml 的使用

上图是visual studio 2022 中使用的粘贴功能的菜单位置 在生成的xml 中,有些是类似如下类型的 [System.Serializable] [System.Xml.Serialization.XmlType] public class Item {private bool isVisibleField;private bool isVisibleFieldSpecified;[System.Xml.Se…

代际超越:方太冰箱勾勒“蛙跳模型”轮廓

文:互联网江湖 作者:志刚 每一代人,都有其独特的新需求、新创造和新使命。 曾经的手机领域,苹果以其革命性创新颠覆了诺基亚的塞班系统,惊艳了整个行业。而如今,华为凭借其三折叠和自主研发的鸿蒙系统&am…

spring-boot启动源码分析(二)之SpringApplicationRunListener

在上一篇《spring-boot启动源码分析(一)之SpringApplication实例构造》后,继续看了一个月的Spring boot启动源码,初步把流程看完了,接下来会不断输出总结,以巩固这段时间的学习。同时也希望能帮到同样感兴趣…

Linux-Redis哨兵搭建

环境资源准备 主机名IP端口号角色vm1192.168.64.156379/26379mastervm2192.168.64.166379/26379slavevm3192.168.64.176379/26379slave 6379为redis服务暴露端口号、26379为sentinel暴露端口号。 安装Redis # 包文件下载 wget https://github.com/redis/redis/archive/7.2.2…

MySQL 03 章——基本的SELECT语句

一、SQL概述 (1)SQL背景知识 SQL(Structured Query Language,结构化查询语言)是使用关系模型的数据库应用语言,与数据直接打交道不同的数据库管理系统生产厂商都支持SQL语句,但都有特有内容 …

[羊城杯 2024]1z_misc

得到FL4G.zip和天机不可泄露.txt文件,其中压缩包需要解压密码: 二十八星宿: 东方苍龙七宿:角、亢、氐、房、心、尾、箕 南方朱雀七宿:鬼、井、柳、星、张、翼、轸 西方白虎七宿:奎、娄、胃、昴、毕、觜、…

QT----------多媒体

实现思路 多媒体模块功能概述: QT 的多媒体模块提供了丰富的功能,包括音频播放、录制、视频播放和摄像头操作等。 播放音频: 使用 QMediaPlayer 播放完整的音频文件。使用 QSoundEffect 播放简短的音效文件。 录制音频: 使用 QMe…

云计算学习架构篇之HTTP协议、Nginx常用模块与Nginx服务实战

一.HTTP协议讲解 1.1rsync服务重构 bash 部署服务端: 1.安装服务 [rootbackup ~]# yum -y install rsync 2.配置服务 [rootbackup ~]# vim /etc/rsyncd.conf uid rsync gid rsync port 873 fake super yes use chroot no max connections 200 timeout 600 ignore erro…

《Vue3实战教程》42:Vue3TypeScript 与组合式 API

如果您有疑问&#xff0c;请观看视频教程《Vue3实战教程》 TypeScript 与组合式 API​ 这一章假设你已经阅读了搭配 TypeScript 使用 Vue 的概览。 为组件的 props 标注类型​ 使用 <script setup>​ 当使用 <script setup> 时&#xff0c;defineProps() 宏函数支…

Diffusion Transformer(DiT)——将扩散过程中的U-Net换成ViT:近频繁用于视频生成与机器人动作预测(含清华PAD详解)

前言 本文最开始属于此文《视频生成Sora的全面解析&#xff1a;从AI绘画、ViT到ViViT、TECO、DiT、VDT、NaViT等》 但考虑到DiT除了广泛应用于视频生成领域中&#xff0c;在机器人动作预测也被运用的越来越多&#xff0c;加之DiT确实是一个比较大的创新&#xff0c;影响力大&…

2024年12月 Scratch 图形化(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch图形化等级考试(1~4级)全部真题・点这里 一、单选题(共25题,共50分) 第 1 题 小猫初始位置和方向如下图所示,下面哪个选项能让小猫吃到老鼠?( ) A. B. C.

LLaMA详解

LLaMA 进化史 大规模语言模型(Large Language Model, LLM)的快速发展正在以前所未有的速度推动人工智能(AI)技术的进步。 作为这一领域的先行者, Meta在其LLaMA(Large Language Model Meta AI)系列模型上取得了一系列重大突破。 近日, Meta官方正式宣布推出LLaMA-3, 作为继LL…

SpringMVC(六)拦截器

目录 1.什么是拦截器 2.拦截器和过滤器有哪些区别 3.拦截器方法 4.单个拦截器的执行流程 5.使用拦截器实现用户登录权限验证&#xff08;实例&#xff09; 1.先在html目录下写一个login.html文件 2.在controller包下写一个LoginController文件 3.加拦截器 1.创建一个conf…

推理加速:投机采样经典方法

一 SpecInfer 基于模型 SpecInfer&#xff08;[2305.09781] SpecInfer: Accelerating Generative Large Language Model Serving with Tree-based Speculative Inference and Verification&#xff09; SpecInfer 投机采样利用多个小型模型&#xff08;SSM&#xff09;快速生…

最好用的图文识别OCR -- PaddleOCR(1) 快速集成

最近在项目中遇到了 OCR 的需求&#xff0c;希望能够实现高效而准确的文字识别。由于预算限制&#xff0c;我并未选择商业付费方案&#xff0c;而是优先尝试了开源工具。一开始&#xff0c;我测试了 GOT-OCR2.0&#xff0c;但由于我的 Mac 配置较低&#xff0c;不支持 GPU 运算…

FFmpeg:详细安装教程与环境配置指南

FFmpeg 部署完整教程 在本篇博客中&#xff0c;我们将详细介绍如何下载并安装 FFmpeg&#xff0c;并将其添加到系统的环境变量中&#xff0c;以便在终端或命令行工具中直接调用。无论你是新手还是有一定基础的用户&#xff0c;这篇教程都能帮助你轻松完成 FFmpeg 的部署。 一、…

Spring SpEL表达式由浅入深

标题 前言概述功能使用字面值对象属性和方法变量引用#this 和 #root变量获取类的类型调用对象(类)的方法调用类构造器类型转换运算符赋值运算符条件(关系)表达式三元表达式Elvis 操作符逻辑运算instanceof 和 正则表达式的匹配操作符 安全导航操作员数组集合(Array 、List、Map…

“AI人工智能软件开发公司:创新技术,引领未来

大家好&#xff01;今天我们来聊聊一个充满未来感的话题——AI人工智能软件开发公司。这个公司&#xff0c;用大白话说&#xff0c;就是专门研究和开发人工智能软件的地方&#xff0c;它们用最新的技术帮我们解决问题&#xff0c;让生活和工作变得更智能、更便捷。听起来是不是…

常见中间件漏洞复现

1.tomcat 1.1 CVE-2017-12615(put上传) 当在Tomcat的conf&#xff08;配置目录下&#xff09;/web.xml配置文件中添加readonly设置为false时&#xff0c;将导致该漏洞产 ⽣&#xff0c;&#xff08;需要允许put请求&#xff09; , 攻击者可以利⽤PUT方法通过精心构造的数据包…

memcached的基本使用

memcached是一种基于键值对的内存数据库&#xff0c;一般应用于缓存数据&#xff0c;提高数据访问速度&#xff0c;减轻后端数据库压力。 安装 这里以Ubuntu为例&#xff0c;其他系统安装方法请看官方文档。 sudo apt-get update sudo apt-get install memcached启动 memca…