前言

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

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

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

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

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

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

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

第一种使用基本的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)

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

先安装这三个库:

实现这个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主要用于与用户交互与选择调用哪个函数。

开始查看效果:

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

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

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

直接使用

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

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

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

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

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

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

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

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

SiliconCloud

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

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

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

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

智谱AI

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

效果:

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

DeepSeek

配置如下所示:

效果:

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

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

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

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

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

零一万物

配置如下:

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

效果:

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

使用C#构建一个论文总结AI Agent的更多相关文章

  1. 强化学习论文(Scalable agent alignment via reward modeling: a research direction)

     原文地址: https://arxiv.org/pdf/1811.07871.pdf ======================================================== ...

  2. [计算机视觉]从零开始构建一个微软how-old.net服务/面部属性识别

    大概两三年前微软发布了一个基于Cognitive Service API的how-old.net网站,用户可以上传一张包含人脸的照片,后台通过调用深度学习算法可以预测照片中的人脸.年龄以及性别,然后将 ...

  3. 构建一个java环境的centos系统镜像并上传到阿里云镜像仓库

    编辑dockerfile 文件 FROM centos MAINTAINER zhaoweifeng ENV LANG en_US.UTF-8 RUN /bin/cp /usr/share/zonei ...

  4. 构建一个基本的前端自动化开发环境 —— 基于 Gulp 的前端集成解决方案(四)

    通过前面几节的准备工作,对于 npm / node / gulp 应该已经有了基本的认识,本节主要介绍如何构建一个基本的前端自动化开发环境. 下面将逐步构建一个可以自动编译 sass 文件.压缩 ja ...

  5. .Net中的AOP系列之构建一个汽车租赁应用

    返回<.Net中的AOP>系列学习总目录 本篇目录 开始一个新项目 没有AOP的生活 变更的代价 使用AOP重构 本系列的源码本人已托管于Coding上:点击查看. 本系列的实验环境:VS ...

  6. .NET Core的文件系统[5]:扩展文件系统构建一个简易版“云盘”

    FileProvider构建了一个抽象文件系统,作为它的两个具体实现,PhysicalFileProvider和EmbeddedFileProvider则分别为我们构建了一个物理文件系统和程序集内嵌文 ...

  7. 基于Vue2.0+Vue-router构建一个简单的单页应用

    爱编程爱分享,原创文章,转载请注明出处,谢谢!http://www.cnblogs.com/fozero/p/6185492.html 一.介绍 vue.js 是 目前 最火的前端框架,vue.js ...

  8. 《Entity Framework 6 Recipes》中文翻译系列 (20) -----第四章 ASP.NET MVC中使用实体框架之在MVC中构建一个CRUD示例

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第四章  ASP.NET MVC中使用实体框架 ASP.NET是一个免费的Web框架 ...

  9. 从零构建一个简单的 Python Web框架

    为什么你想要自己构建一个 web 框架呢?我想,原因有以下几点: 你有一个新奇的想法,觉得将会取代其他的框架 你想要获得一些名气 你遇到的问题很独特,以至于现有的框架不太合适 你对 web 框架是如何 ...

  10. 使用Gradle构建构建一个Java Web工程及持续集成环境Jenkins配置

    安装Eclipse插件——Buildship 什么是Buildship? Buildship能方便我们通过Eclipse IDE创建和导入Gradle工程,同时还能执行Gradle任务. Eclips ...

随机推荐

  1. shiro 框架基本讲解【转载】

    shiro 框架基本讲解[转载] 什么是权限管理: 基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而 ...

  2. 欢迎来到IoT解忧杂货铺

    这是一间特殊的杂货铺 门面不大,却包罗万物 如果你也遇到一些烦恼 欢迎来到,IoT解忧杂货铺 解忧秘方·工业 厂里的几十台设备真让人头疼 协议种类太多太复杂 设备没法全联网 产线故障了也不知道 自己出 ...

  3. 一文了解 Conda(包教包会,不会留言)

    Conda 使用指南 Conda 是一个开源包管理和环境管理系统,能够以跨平台的方式进行软件包的安装.管理和依赖管理,特别适用于 Python 和 R 语言的环境管理.本文整理了常见 Conda 命令 ...

  4. 01_GoLand debug时出现Connected并且程序卡住的问题

    01_GoLand debug时出现Connected并且程序卡住的问题 环境:win10.go version go1.19.4 windows/amd64.GoLand 2020.3.5 x64 ...

  5. Docker启动的centos容器使用systemctl功能

    Failed to get D-Bus connection: Operation not permitted 错误的解决办法 # 启动的时候用如下命令 docker run --privileged ...

  6. 企业网站应配置怎样的SSL证书

    企业网站在选择和配置SSL证书时,需要考虑多个因素以确保网站的数据传输安全.身份验证和用户信任度.以下是对企业网站应配置怎样的SSL证书的详细分析: 一.SSL证书的基本概念 SSL证书是一种数字证书 ...

  7. delphi Image32 SVG图形查看器

    DELPHI 中没有SVG显示组件,需要用到第三方组件,高版本可以使用skia(但必须带上skia.dll). 最新版Image32修改了很多,SVGIconImageList 也因此换成了Image ...

  8. 使用WebRTC技术搭建小型的视频聊天页面

    目录 目录 参考资料 什么是WebRTC? 能做什么? 架构图 个人理解(类比) 核心知识点 核心知识点类比 ICE框架 STUN(协议) NAT(网络地址转换) TURN SDP(会话描述协议) W ...

  9. 超聚变服务器2288H V6使用 iBMC 安装 Ubuntu Server 24.04 LTS及后续系统配置

    一. 超聚变服务器iBMC远程管理 超聚变服务器的iBMC芯片集成了一个专用的管理GE网口,提供全面的故障诊断.自动化运维.硬件安全加固等管理特性.iBMC支持Redfish.SNMP.IPMI 2. ...

  10. .NET Core 线程(Thread)底层原理浅谈

    简介 线程,进程,协程基本概念不再赘述. 原生线程和用户线程 原生线程 在内核态中创建的线程,只服务于内核态 用户线程 由User Application创建的线程,该线程会在内核态与用户态中间来回穿 ...