用c#从头写一个AI agent,实现企业内部自然语言数据统计分析
1、本文目的
不借助任何框架,使用c#写一个agent,实现调用阿里千问大模型完成预定任务。同时完成一个可扩展的agent框架雏形。
2、预期读者
本文假设读者已经了解了一些基本概念,例如AI,functioncall,c#编程等。
3、主要技术
在编写agent的过程中主要用到以下几点:
- 使用c#的WebClient来和千问接口进行通讯。
- 使用functioncall功能实现外部功能调用
4、解决的难题
在实现上述目的的过程中遇到了一些困难,这里记录一下,给自己备注,也为后人提醒。
- tool数量太多。我们都知道,大模型能够调用外部函数,是基于大模型本身的一个功能functioncall,后来这个功能发展成目前非常火热的MCP。不管是那种形式,底层的本质都是一样的,在向大模型输入信息的时候,同时提供给大模型一些工具(tools),以供大模型在需要的时候选择调用(其实这里说大模型调用不适合,应该是大模型指出应该让agent调用哪个function)。对于专注于特定领域的agent来说,也许不需要太多的tools就能完成工作。但是对于一些通用型的agent来说,要辅助人类完成任何可能得任务,需要的function数量非常庞大。想象一下有这样一个agent,可以当做你的助理,不但能在工作中给你提供帮助,还能在生活中为你处理各种事情:查天气,订机票,提醒,订外卖,做旅游规划等等。这样一个功能周全的agent要实现起来需要的tools无法想象。我们每次请求大模型的时候,如果都把这些tools传递给大模型,不但数据量大,速度慢,你的大模型账单也会快速增加,因为大模型是按照tokens收费的。为此设计了一些小技巧,以减少每次提交请求时的tools数量。
- 关键词法:这种方法就是监控用户的请求内容,如果包含指定的关键词,就把相对应的tools一起附带上。比如:当用户提到“天气”、“温度”时,就把查询天气的tools一起提交。
- 分组控制器法:这种方法就是把所有的tool分成一些大类,每个大类包含一定数量的tools,同时为每个大类编写一个tools,这样大模型在选择工具时,先选择大类的tool,然后大类tool的实现中在动态加载这个类别下面的其他tools。比如:我们可以给“预定东西”作为一个大类,这个大类下面包含“订机票”,"订酒店","订外卖"等等。大模型分析到用户的意图是“预定”类的,就先调用这个大类的tool,再有大类tool的实现中,动态加载各个子类的tool,然后根据用户需求调用实际的tool,例如“订机票”。分组控制器法的好处是减少了非必要的tool的提交,弊端是需要二次提交才能定位到具体的小类tool上面。后面会进行优化,尽量减少二次提交的时机。
- 大模型一次只能处理一个任务:在使用大模型function功能进行函数调用时候,发现大模型每次请求只能返回一个函数调用(观点如果有误,请指教)。比如用户请求:“帮我查一下北京明天的天气,然后订一张明天深圳到北京的机票”。在上面的例子中,用户实际给大模型2个任务,第一查天气,第二订机票。这两个任务都可以通过大模型的functioncall功能完成,但是一次请求中,大模型无法返回2个调用,只能返回一个,比如:getWeather(天气查询)。为此我们需要为这样的场景设计一个任务分解的tool,告诉大模型,如果存在多个任务,可以使用方法把任务分解为可以单独执行的最小单元。这样任务分解函数中的实现就可以对每个单独的任务进行重新提交,然后等待所有任务都返回后,整理这些内容在发给用户。
- 逻辑处理:大模型本身具有推理能力,如何把这种推理能力转化为解决实际问题能力成为我们任务中的关键。在上面的任务分级方法来处理复杂任务时,每个任务之间可能存在依赖关系。例如用户请求:“如果明天北京天气好的话,就给我订一张从深圳到北京的机票”。很明显,“订机票”这个任务的执行取决于“查询北京天气”的结果,通过任务分解,并制定任务依赖,使用大模型的推理能力可以解决这类问题。
5、目前完成的功能
- 实现自然语言对内部数据进行统计分析,并给出图形报表。例如:查一下加班最多的3个人是谁。大模型会根据用户的描述生成对应sql查询语句,执行这个查询语句得到结果,再把结果提交个大模型来回答用户的问题。当然这里有个前提,就是需要把内部系统数据表结果发给大模型(使用system的prompt)。
- 个人工作助理:例如可以提醒、通知、会议纪要等。
6、代码说明:打算把相关代码打包下载,但是写完文章,发现无法插入附件。另外代码本身没有难度,代码里面包含了一些我们自己的类库调用,所以无法直接运行,但是这些类库调用不影响阅读、理解,要是把这些类库替换一下(没几个,很好改)也能运行。
既然无法下载,那么接下来我会抽空把一些主要的代码进行单独说明,最后会放到github上下载。
用c#从头写一个AI agent,实现企业内部自然语言数据统计分析的更多相关文章
- 从头写一个Cucumber测试(一) Selenium Test
转载:https://yaowenjie.github.io/%E7%BC%96%E7%A8%8B%E7%9B%B8%E5%85%B3/cucumber-test, 背景(废话不读系列) 前段时间 ...
- 从头写一个Cucumber测试(二) Cucumber Test
转载:https://yaowenjie.github.io/%E7%BC%96%E7%A8%8B%E7%9B%B8%E5%85%B3/cucumber-test-part-2 承接上文 前一篇博 ...
- Java Web 开发利用Struts2+Spring+mybatis写一个用户登录界面以及简单的数据交互
框架的东西太复杂也难以讲通,直接上代码: 一.首先得配置环境 和导入必要的jar包 有一些重要的如下: Filter文件夹下的SafetyFilter.java model文件夹下的 Global ...
- javascript 写一个ajax 自动拦截,并下载数据
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...
- 如何写一个像btgoogle一样的12306泄露数据查询
demo地址:http://www.btgoogle.com/12306/ 圣诞节,12306送给了我们一个大礼物.大约 14w的数据泄露, 看网上都沸沸扬扬的.开始也准备找一个数据库来看看,随后,我 ...
- 从零写一个兼容MySQL/Oracle的Proxy中件间(一)《初识Oracle的通信协议》
0.前言 MySQL由于开源的原因,有各式各样的中件间Proxy ,极大的丰富了做高可用或迁移的方案,习惯了MySQL生态圈的灵活和便利,Oracle官方不开源代码和协议,没有中间件proxy,显得很 ...
- 缓存原理,自己写一个缓存类(c#版)
.net中的MemoryCache是通过内部封装一个静态Dictionary 自己写一个缓存,来看看内部怎么实现的 public class CustomerCache : ICache { priv ...
- Summer——从头开始写一个简易的Spring框架
Summer--从头开始写一个简易的Spring框架 参考Spring框架实现一个简易类似的Java框架.计划陆续实现IOC.AOP.以及数据访问模块和事务控制模块. ...
- 念一句咒语 AI 就帮我写一个应用,我人麻了...
原文链接:https://forum.laf.run/d/232 作为人类,我们时常会有自己独特的想法和脑洞大开的创意.然而,这些想法往往因为成本过高而无法实现,毕竟每个人的能力和精力都是有限的,尤其 ...
- Cordova webapp实战开发:(6)如何写一个iOS下获取APP版本号的插件?
上一篇我们学习了如何写一个Andorid下自动更新的插件,我想还有一部分看本系列blog的开发人员希望学习在iOS下如何做插件的吧,那么今天你就可以来看看这篇文字了. 本次练习你能学到的 学习如何获取 ...
随机推荐
- Windows中GNURadio的安装
对于一个常常使用Python的人来讲(此处指我),conda环境是必不可少的,(Anaconda或Miniconda). 在Windows中且已经安装过conda环境的情况下,安装GNURadio特别 ...
- CentOS7安装nvm和node
一.安装nvm 官方文档:https://github.com/nvm-sh/nvmwindows版文档:https://github.com/coreybutler/nvm-windowswindo ...
- redis启停shell脚本
启停脚本(redis-5.0.5) 一.编辑脚本 vim /u01/redis/redisServer.sh #!/bin/sh # # Simple Redis init.d script conc ...
- Romberg 数值积分算法+P3779 题解
Romberg 算法 吊打 Simpson(?) 的且不玄学(没有什么十五倍)的数值积分算法. 缺点是过程复杂一点,但是只体现在证明上,代码很短. 铺垫算法 梯形求积公式 公式 \[\int _a^b ...
- FLink13--KeyByMaxByApp
一.依赖 https://www.cnblogs.com/robots2/p/16048648.html 二.代码 package net.xdclass.class9; import java.ut ...
- Luogu P11230 CSP-J 2024 接龙 题解 [ 线性 dp ] [ 前缀和 ]
接龙:一个前缀和优化 dp 或者单调队列优化 dp 的题目. 怎么周围的人都秒了 T3 不会 T4 啊,只有我觉得 T4 很套路,T3 比较难写吗. 暴力 dp 为了避免多维的状态定义,我们把每个人的 ...
- nginx 简单实践:Web 缓存【nginx 实践系列之三】
〇.前言 本文为 nginx 简单实践系列文章之二,主要简单实践了两个内容:正向代理.反向代理,仅供参考. 关于 Nginx 基础,以及安装和配置详解,可以参考博主过往文章: https://www. ...
- 历时两天半由浅入深总结了20道Vue高频面试题
作为一个程序员如果你想要找到你心仪的工作,不可避免的就会问到很多八股文,虽然有的和工作没有半毛钱关系,但是你如果想要通过面试还必须得会.所以我最近开始总结一些面试题,一是为了加强自己的理解能够找到一份 ...
- cgroup与systemd: 通过src rpm获取systemd源代码,添加日志并使用rpmbuild重新打包
问题起源 服务跑在富容器中.容器使用init进程作为一号进程,然后用systemd管理所有service. 在做一次升级时,nginx启动脚本有更新,原来是root拉起,现在进行了去root改造,使用 ...
- 【BUUCTF】BabySQli
[BUUCTF]BabySQli 题目来源 收录于:BUUCTF GXYCTF2019 题目描述 纯粹的SQL注入题 随意传入 name=abc&pw=a 返回 wrong user 尝试传入 ...