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,实现企业内部自然语言数据统计分析的更多相关文章

  1. 从头写一个Cucumber测试(一) Selenium Test

    转载:https://yaowenjie.github.io/%E7%BC%96%E7%A8%8B%E7%9B%B8%E5%85%B3/cucumber-test, 背景(废话不读系列)   前段时间 ...

  2. 从头写一个Cucumber测试(二) Cucumber Test

    转载:https://yaowenjie.github.io/%E7%BC%96%E7%A8%8B%E7%9B%B8%E5%85%B3/cucumber-test-part-2 承接上文   前一篇博 ...

  3. Java Web 开发利用Struts2+Spring+mybatis写一个用户登录界面以及简单的数据交互

    框架的东西太复杂也难以讲通,直接上代码: 一.首先得配置环境 和导入必要的jar包 有一些重要的如下: Filter文件夹下的SafetyFilter.java   model文件夹下的 Global ...

  4. javascript 写一个ajax 自动拦截,并下载数据

    <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...

  5. 如何写一个像btgoogle一样的12306泄露数据查询

    demo地址:http://www.btgoogle.com/12306/ 圣诞节,12306送给了我们一个大礼物.大约 14w的数据泄露, 看网上都沸沸扬扬的.开始也准备找一个数据库来看看,随后,我 ...

  6. 从零写一个兼容MySQL/Oracle的Proxy中件间(一)《初识Oracle的通信协议》

    0.前言 MySQL由于开源的原因,有各式各样的中件间Proxy ,极大的丰富了做高可用或迁移的方案,习惯了MySQL生态圈的灵活和便利,Oracle官方不开源代码和协议,没有中间件proxy,显得很 ...

  7. 缓存原理,自己写一个缓存类(c#版)

    .net中的MemoryCache是通过内部封装一个静态Dictionary 自己写一个缓存,来看看内部怎么实现的 public class CustomerCache : ICache { priv ...

  8. Summer——从头开始写一个简易的Spring框架

    Summer--从头开始写一个简易的Spring框架                ​ 参考Spring框架实现一个简易类似的Java框架.计划陆续实现IOC.AOP.以及数据访问模块和事务控制模块. ...

  9. 念一句咒语 AI 就帮我写一个应用,我人麻了...

    原文链接:https://forum.laf.run/d/232 作为人类,我们时常会有自己独特的想法和脑洞大开的创意.然而,这些想法往往因为成本过高而无法实现,毕竟每个人的能力和精力都是有限的,尤其 ...

  10. Cordova webapp实战开发:(6)如何写一个iOS下获取APP版本号的插件?

    上一篇我们学习了如何写一个Andorid下自动更新的插件,我想还有一部分看本系列blog的开发人员希望学习在iOS下如何做插件的吧,那么今天你就可以来看看这篇文字了. 本次练习你能学到的 学习如何获取 ...

随机推荐

  1. oracle之sqlplus删除键不能用

    方法一 1.终端命令,临时有效,重连失效 stty erase ^H 2.配置环境变量,永久有效 vi -oracle/.bash_profile stty erase ^H source -orac ...

  2. 考拉 T_Q_X 的博客搬运(搬运)

    博客搬迁现场直播 各位观众们大家好,欢迎来到新闻透视 今天为您直播某菜鸡oier tqx 的博客搬迁现场. Q:请问tqx,您为什么要将博客从CSDN搬迁到博客园呢? tqx:懂得都懂,不懂的我也不多 ...

  3. QT5笔记: 28. SplashWindow 没听懂,无内容

    没有说明这个SplashWindow咋用 大概小人愚笨 this->setWindowFlag(Qt::SplashScreen);莫非是这个?

  4. Flink - [06] 状态管理

    题记部分 一.Flink中的状态 由一个任务维护,并且用来计算某个结果的所有数据,都属于这个任务的状态. 可以认为状态就是一个本地变量,可以被任务的业务逻辑访问. Flink会进行状态管理,包括状态一 ...

  5. Processing多窗口程序范例(三)

    再来一例~另一种叠加方式呈现...看图: 程序 主程序: package syf.demo.multiwindow3; import processing.core.PApplet; import p ...

  6. springboot接入方式对接股票数据源API接口

    为了创建一个Java项目来对接StockTV的API接口,我们可以使用HttpURLConnection或第三方库如OkHttp来发送HTTP请求,并使用Java-WebSocket库来处理WebSo ...

  7. 面试题55 - II. 平衡二叉树

    地址:https://leetcode-cn.com/problems/ping-heng-er-cha-shu-lcof/ <?php /** 输入一棵二叉树的根节点,判断该树是不是平衡二叉树 ...

  8. 面试题53 - I. 在排序数组中查找数字 I

    地址:https://leetcode-cn.com/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/ <?php /** 面试题53 ...

  9. 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理

    在 AI 编程领域国内外有一堆能叫的上号的应用: Cursor Windsurf Trae 阿里的「通义灵码」 百度的「文心快码」 字节跳动的「MarsCode」 科大讯飞的「iFlyCode」 Gi ...

  10. 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异

    从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异 引言 在开发 Web 应用时,处理 HTTP 错误响应是常见的任务,尤其是在客户端代码中捕获并向用户展示错误信息.然而,当使用 HTTP ...