先总结一下AI编程小助手已具备的能力,目前AI小助手已经可以利用本地知识库和在线大模型(我们用的是qwen)生成可测试,可执行代码的能力(具体流程参考从让AI给你写代码(9.1)),并具备一定的知识库扩展能力(让AI给你写代码(9.3):一点改进,支持扩展本地知识库)
支持用户逐步丰富代码及相关描述。
但目前面临的问题有两方面:
1) 提示驱动(prompt)只能利用外部库(例如akshare),还不具备利用本地资源的能力,而外部库只能解决获得金融市场各种数据的能力,但数据再加工,快速读取,形成中间数据集就需要本地代码解决,如果每次都靠语言驱动重新生成本地代码,无论是代码稳定性,代码资产的复用性都不好,效率都很低, 因此我们需要进一步发展promt利用本地/外部资源的能力。
2) 更进一步,代码功能复杂化导致prompt也变得复杂,会带来稳定性,准确性和可执行性一系列问题,最终可能会使得AI编程效率低到还不如传统的硬编码,必须发展出一种方法,克服或者至少缓解这个问题,使得AI助手可以逐步形按较为简单的prompt成生成复杂代码的能力,使得编码用户能够更加聚焦于功能本身开发,而不是复杂繁琐的调试。
解决思路可以参照接口化编程的思想,具体如下:我们已经知道如果把中文提示(prompt)看成是一种中文编码方式,那么在线大模型(LLM)就充当了中文编码解释器的作用,把中文需求转换为标准代码,更进一步,利用提示工程驱动LLM的方法基于代码生成一个标准化接口(interface)和一个调用该接口的标准化需求prompt,保存到本地知识库, 并把该标准化接口对应的代码,保存到代码库; 那么下次利用中文提示开发时,就可以在提示中直接引用该接口完成指定的工作,LLM生成代码后,可以通过import方式直接调用该接口执行,然后可以再次驱动LLM基于新代码生成一个标准化接口(interface)和一个调用该接口的标准化需求prompt,以此类推,就可以逐步集成生成代码,利用接口访问,综合调用本地和外部资源,完成执行一些复杂功能,并且调用方便,具备“一句话”匹配本地知识库调用相关接口的能力。
升级后的小助手总体架构如下:
升级后的小助手分为两类主要功能:
- 蓝色部分——prompt匹配本地接口库,调用匹配到的接口方法,驱动对应代码库中的接口方法代码执行获得结果
- 红色部分——prompt驱动大模型生成新的接口方法的代码和调用提示的过程,具体如下,prompt中描述需要干的工作并完成该工作需要调用接口方法名,输入值和输出值,然后驱动LLM输出代码,并执行,然后再利用LLM驱动分析新的代码,获得接口函数(方法)名,代码功能说明,入参和返回值(出参),然后利用上述要素生成简单接口描述; 再有人工判断是否要存储接口函数及描述,如果需要还可以修改接口描述,然后分别把的代码存储到接口库中,并把接口描述存储到本地接口库中。
下面,我们先通过一个例子来看看工作流程和功能
基础配置:
1)本地库用的向量持久化工具: ES 7.9
2)本地库匹配使用的embedding: 抱脸虫HuggingFaceEmbeddings的paraphrase-multilingual-MiniLM-L12-v2
3)LLM 还是选qwen-max
以上和之前一致
4) 本地接口知识库: es_repository-interface
初始配置了4个接口方法的描述
1- akshare库的stock_zh_a_spot_em接口,获取全市场行情
2- akshare库的stock_zh_a_hist接口,获取历史行情
3- 本地pythonRepository库的getReportDataLocal接口,获得指定日期的全市场报业绩报表数据(本地)
4- 本币pythonRepository库的CalAnnualRatio接口,根据指定日期和增长率,换算成年增长率
备注: 3是把akshare的报表下载库函数包装后,进行下载并指定调用打开方法(报表包含季报),4是把季报数据进行年化处理
- 本地代码库: pythonRepository目录:
其中fetch_stock_financial_reports.py对应的getReportDataLocal接口代码(3)
calculate_annual_growth_rate.py对应的是CalAnnualRatio接口(4)
下面我们逐步利用以上资产,让AI小助手为我们编写更加复杂功能的代码
任务简介
第一步: 获取沪深300指数的成份股列表,并返回这些股票的代码
【用户-提出需求】:
请输入您的问题:获得沪深300成份股列表,生成getHS300List(),无入参,按akshare库的index_stock_cons(symbol="000300")接口获得沪深300成份股生成df_hs300_list,其中列名重新定为[‘股票代码‘、‘股票简称’、‘纳入日期’],打印并返回df_hs300_list['股票代码']
【AI-判断是否和本地库匹配,不匹配】
raw_code:: 与上下文无关。
【AI-提交给LLM生成代码】
根据您的要求,以下是使用akshare库获取沪深300成份股列表,并按照指定方式处理数据的Python代码示例:
```python
import akshare as ak
def getHS300List():
# 使用akshare的index_stock_cons接口获取沪深300成份股数据
df_hs300 = ak.index_stock_cons(symbol="000300")
# 重命名列名
df_hs300.columns = ['股票代码', '股票简称', '纳入日期']
# 打印df_hs300的股票代码列
print(df_hs300['股票代码'])
# 返回股票代码列
return df_hs300['股票代码']
# 调用函数
getHS300List()
这段代码首先导入了`akshare`库,并定义了一个函数`getHS300List`来获取沪深300指数的成份股列表。通过调用`ak.index_stock_cons(symbol="000300")`接口获取数据,然后重命名DataFrame的列名,并打印及返回股票代码列。
【AI-执行代码,并返回结果】
开始执行...
0 600415
1 300418
2 600161
3 688082
4 688009
...
295 000425
296 000157
297 000063
298 000001
299 000002
Name: 股票代码, Length: 300, dtype: object
执行成功: None
result:: {
'exec_res': None, 'code': '\nimport akshare as ak\n\ndef getHS300List():\n # 使用akshare的index_stock_cons接口获取沪深300成份股数据\n df_hs300 = ak.index_stock_cons(symbol="000300")\n \n # 重命名列名\n df_hs300.columns = [\'股票代码\', \'股票简称\', \'纳入日期\']\n \n # 打印df_hs300的股票代码列\n print(df_hs300[\'股票代码\'])\n \n # 返回股票代码列\n return df_hs300[\'股票代码\']\n\n# 调用函数\ngetHS300List()\n', 'exec_succ': True}
【AI-询问是否将接口代码保存的到代码库(接口仓库),用户回复 yes】
是否需要将接口函数保存到接口仓库?(y/n): y
【AI-需求入库】
开始存需求库
prompt::
请根据
import akshare as ak
def getHS300List():
# 使用akshare的index_stock_cons接口获取沪深300成份股数据
df_hs300 = ak.index_stock_cons(symbol="000300")
# 重命名列名
df_hs300.columns = ['股票代码', '股票简称', '纳入日期']
# 打印df_hs300的股票代码列
print(df_hs300['股票代码'])
# 返回股票代码列
return df_hs300['股票代码']
# 调用函数
getHS300List()
所示代码起一个合适英语文件名
file_name:: fetch_HS300_constituents.py
文件保存成功
m_name:: fetch_HS300_constituents
保存接口函数成功
【AI-分析代码形成接口描述建议】
module_name:: pythonRepository.fetch_HS300_constituents
导入接口函数成功
raw_doc:: ```
主要功能: 获取沪深300指数的成份股列表,并返回这些股票的代码。
函数名: getHS300List
入参: 无
返回值: 返回一个包含沪深300指数所有成份股股票代码的Series对象。
code_desc(接口方法提示建议):: 获取沪深300指数的成份股列表,并返回这些股票的代码。可以使用pythonRepository库的getHS300List接口,入参无,返回值是返回一个包含沪深300指数所有成份股股票代码的Series对象。使用python编码,打印返回值,代码格式为```python...```
【AI-询问是否要讲接口描述插入接口知识库 - 用户回复 yes】
是否需要将接口需求插入知识库?(y/n): y
{
'name': 'node-1', 'cluster_name': 'elasticsearch', 'cluster_uuid': 'F6X7HlMMS-eYJlzY8Tg3Mw', 'version': {
'number'