让AI给你写代码(八)- 引导AI小助手根据输入的要求以参数化方式调用本地代码

之前的内容,我们已经可以让AI逐步具备根据输入的需求,创建并完善代码,但有一个显而易见问题,例如:
我们可以要求AI给出代码获得 300001的最新价格的代码,但如果要求给出000001的最新价格就需要重新生成一次代码,且生成过程也存在一定的不稳定性,能不能利用现有的代码实际获取结果呢? 那就需要解决两个问题:
1 怎么引导AI调用本地资源
2 怎么完成参数化调用

解决问题1的基本方法,还是之前提到过语意匹配调用本地方法,解决问题2则设法采用正则匹配,例如将600XXX,300XXX直接转化为stock_code等标准化变量,基于上述思路,就可以考虑本地资源应该具备哪些特征:
1 代码需要以函数+入参的方式存在
2 代码需要包含函数说明,中文,包含摘要,入参,出参

具体解决问题的思路如下:
1 对已有代码,输入需求,由AI改造为函数方法(带函数说明,入参,出参)
2 对改造后的代码,注册为本地资源
3 对用户输入的语意,按正则表达式提取基本语义和参数
4 按语意匹配到本地函数,并注入参数
5 如果没有匹配到则提交到网络重新生成代码

为了方便,本地资源注册表暂时设计为json文件: 项目名称/config/method_config.json,包含本地资源路径(module),方法(method),函数方法描述(desc),入参(params)

{"获取本地方法": 
	[
	{"module": "pythonRepository.get_latest_stock_price", 
	 "method": "get_latest_stock_price", 
	 "desc": "获取指定股票代码的最新股价。", 
	 "params": ["stock_code: str"]
	 },
	 ......
	]
}

为避免冗长描述,代码只标识修改部分,其他部分请参考之前的blog文章
AI小助手的修改
主程序 testAIcode.py ,增加匹配本地资源部分

import ...

# 执行本地方法
def exec_local_func(module_name: str, func_name: str, **args):
    module = __import__(module_name, fromlist=[''])
    func = getattr(module, func_name)
    return func(**args)


# 匹配入参
def match_param(params: list, message: str):
    patterns = [{"stock_code": r"30\d{4}|60\d{4}|00\d{4}"},     
                {"report_date": r"\d{4}\d{2}\d{2}"}
                ]
    args = {}
    if len(params) > 0:
        for param in params:
            if param.startswith("stock_code"):
                stock_code = match_pattern(message, patterns[0]["stock_code"])
                args['stock_code']=stock_code
            elif ...
        return args


# AI对话
def conversation_mutual():
    # 初始化小助手
    assistant = Assistant()

    # 初始化基本操作列表
    operation_set = {
        "打开文件": assistant.openFile,
        "保存文件": assistant.saveFile,
        "保存代码": assistant.saveFile,
        "执行代码": assistant.executeCode,
        "另存为本地资源": assistant.saveAsLocal,      # 增加注册为本地工具
        "结束对话": assistant.endTalk
    }
   
    # 初始化工具
    textUtil = NPLUtil()
    while True:
        message = input('master:')
        op_reply = ""
        pytools = assistant.getConfig()["获取本地方法"]   # 获取本地方法注册文件
        ...
        cn_msg = remove_non_chinese(message)  # 获得对话中中文主干部分
        ...

        # 匹配操作
        ops = list(operation_set.keys())  # 获得操作列表
        ...
        if similarity > 0.8:
            # 执行操作
            ...
        else:
            # 匹配本地module,本地方法
            my_module = []
            my_method = []
            my_desc = []
            my_params = []

            if len(pytools) > 0:
                for tool in pytools:
                    my_module.append(tool["module"])
                    my_method.append(tool["method"])
                    my_desc.append(tool["desc"])
                    my_params.append(tool["params"])

                similarity, s_desc = textUtil.text_similarity(my_desc, cn_msg)
                if similarity > 0.8:
                    # 执行操作
                    module_name = my_module[my_desc.index(s_desc)]
                    method_name = my_method[my_desc.index(s_desc)]
                    params = my_params[my_desc.index(s_desc)]
                    print(module_name, method_name, params)
                   
                    args = match_param(params,message)

                    print(args)

                    # op_reply = exec_local_func(module_name, method_name, stock_code=code)
                    op_reply = exec_local_func(module_name, method_name, **args)

                    print('小助手:', end='')
                    print(op_reply, end='')
                else:
                    assistant.conversation_ask() # 提交给AI
            else:
                assistant.conversation_ask()  # 提交给AI

        print('\n')
if __name__ == '__main__':
    conversation_mutual()

主程序说明, 在操作列表里增加一个操作“另存为本地资源”,进行本地注册; 主程序增加一个匹配本地资源的判断,先对输入语句的中文主干进行匹配的本地资源函数方法描述(desc),如果相似性大于0.8 则匹配入参(match_param),并执行本地方法(exec_local_func)

修改assist.py,解决保存注册本地资源的问题

import...

class Assistant:
    def __init__(self):
        ... 
        # 注册json文件
        self.config_file = "/home/cfets/gitea/pyWebTest1/config/method_config.json"
        # 本地资源
        self.local_pythonRepository = "/home/cfets/gitea/pyWebTest1/pythonRepository/"
    ...
    # 读取注册文件
    def getConfig(self):
        config = json.load(open(self.config_file))
        return config  
    ...
    # 保存到本地资源
    def saveAsLocal(self):
        # 从content抽取函数名,函数说明
        python_content = re.findall(r'```python(.*?)```', self.last_AI_message, re.DOTALL)
        func_name = ""
        args = []
        if len(python_content) <= 0:
            python_content =self.last_content
            print(len(python_content))

            func_name, args = extract_function_names(python_content)   # 方法名和参数列表
        if func_name == "":
            res_content = "未找到函数名,保存失败"
        else:
            # 代码保存到本地仓库目录
            with open(self.local_pythonRepository + func_name + ".py", 'w') as f:
                f.write(python_content)

            res_content = "保存成功"

            # 注册到本地配置文件
            desc = extract_description(python_content)  # 函数描述
            desc = desc.strip()
            module_name = "pythonRepository." + func_name   # 模块名

            config = self.getConfig()
            tools = config["获取本地方法"]

            tools.append({"module": module_name, "method": func_name, "desc": desc, "params": args})

            my_dict = {"获取本地方法": tools}

            # 把tools写回config文件
            with open(self.config_file, 'w') as f:
                json.dump(my_dict, f, ensure_ascii=False)

        return res_content

这部分基本比较清楚,需要说明程序利用extract_function_names方法会自动提取函数名和参数

# 匹配函数名称的正则表达式
def extract_function_names(code: str):
    # print('code:',code)

    pattern = r"def\s+(\w+)\s*\("
    if re.search(pattern, code, re.DOTALL):
        print(f'{code} 是一个有效的函数名称')
        function_names = re.findall(pattern, code, re.DOTALL)[0]
        arglist = code.split(function_names)[1].split(")")[0].split("(")[1]
        # print('arglist:', arglist)
        args = [arg.strip() for arg in arglist.split(",")]
        print('args:', args)
    else:
        print(f'{code} 不是一个有效函数名称')
        function_names = ""
        agrs = []

    return function_names, args

下面还是以“获取股票XXXXXX的最新股价” 为例,看看运行过程
AI 生成的原始代码/pyTest_2024-04-12_18:00:03_97.py

import akshare as ak

# 获取市场行情数据
stock_em_df = ak.stock_zh_a_spot_em()

# 按照指定的股票代码过滤行情数据
target_stock_df = stock_em_df[stock_em_df['代码'] == '300001']

# 提取并打印当前市场价格(最新价)
print(f"股票300001现在的市场价格是:{target_stock_df.iloc[0]['最新价']}元")

操作步骤

master: 请打开文件 /pyTest_2024-04-12_18:00:03_97.py
小助手:
import akshare as ak

# 获取市场行情数据
stock_em_df = ak.stock_zh_a_spot_em()

# 按照指定的股票代码过滤行情数据
target_stock_df = stock_em_df[stock_em_df['代码'] == '300001']

# 提取并打印当前市场价格(最新价)
print(f"股票300001现在的市场价格是:{target_stock_df.iloc[0]['最新价']}元")

master: 请结合源代码转换为函数,入参为股票代码,返回最新股价,并给出函数说明,使用中文

小助手:
fromAI:
```python
def get_latest_stock_price(stock_code: str) -> float:
    """
    获取指定股票代码的最新股价。

    参数:
        stock_code (str): 股票代码,例如 "600029"

    返回值:
        float: 最新股价,单位为元
    """
    # 获取所有A股实时行情数据
    stock_zh_a_spot_em_df = ak.stock_zh_a_spot_em()

    # 按股票代码过滤,获取对应行数据
    target_stock_data = stock_zh_a_spot_em_df[stock_zh_a_spot_em_df["代码"] == stock_code]

    # 返回最新价格(中文字段为"最新价")
    return target_stock_data['最新价'].values[0]

# 示例使用
stock_code = "600029"
latest_price = get_latest_stock_price(stock_code)
print(f"{stock_code}股票的最新价格为:{latest_price}元")
'''
根据源代码重新生成了函数 get_latest_stock_price,入参是......  

master:请另存为本地资源     #注意保存为本地资源前,请注释掉函数方法代码,给出的示例使用部分
小助手:保存成功

master:获取股票000977的最新股价
小助手:37.85

现在我们的AI小助手获得使用本地方法的能力,但还是比较笨拙,比如参数需要事先定义,再比如,语意匹配不是很丝滑, 比如“获取浪潮信息(000977)的最新股价”就不行了,还需要进一步打磨改进。

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhyuli

您的鼓励是对我付出努力一种赞赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值