优秀的编程知识分享平台

网站首页 > 技术文章 正文

一步一步学习如何优化程序,用更简洁的代码开发更好的 AI 聊天助手

nanyue 2024-12-24 14:49:30 技术文章 3 ℃

我写程序通常会力求简洁,而不追求完美,因为在资源和实力都有限的情况下,有自知之明是很重要的。骑着自行车一直瞪着房车里的这样那样,这个我想要,那个我也想要,也是不行。

但是一旦你写出一个简单的程序,你就会发现这里要加一点,那里要改一下,可能就越改越复杂,偏离了初衷。所以要点就在于,怎样改进程序代码,使之更好的同时变得更简单?

今天我们就以之前发的聊天助手为实际的案例,分享一下优化代码的过程。

一、 去掉重复的代码。

最近我写的很多程序都用到了 Markdown,每次我都要把相同的代码复制来复制去,这很麻烦,且容易出错。如果你有什么好的改进,只会在一个程序里起作用,其他程序你还得一个个再去改一遍,这很容易出错。

于是我将这些相同的代码放进了一个库文件,然后在 aardio 中新增了一个库 web.form.simpleMarkdown 。

二、把大问题分解成独立的小问题。

web.form.simpleMarkdown 这个库很简单,它只负责一件事:Markdown 格式的解析与呈现。其他与此无关的代码不要放进去。这就使我们面对的复杂问题被拆解成了独立的、简单的小问题,小问题再怎么难搞也比一大堆问题挤在一起更容易解决,写出来的代码质量通常也会更好。

然后我又增加了一个新的库 web.form.chat 。

web.form.chat 主要是处理与维护 AI 聊天时产生的消息队列( 上下文 ),并且将这些消息队列显示在页面上。

web.form.chat 提供了简洁的接口,主要是三个函数:

  1. system 函数用于写入系统提示词。
  2. user 函数用于写入用户提示词。
  3. assistant 函数写入 AI 的回复。

web.form.chat 还负责在页面上显示用户、AI 的图标,在等待 AI 回复时显示加载进度:

三、调整方向与思路。

在我做完这些以后,发现程序突然变得很卡。

这就奇怪了,我没改啥呀,经过反复检查,我发现是 AI 回复打字到页面上,然后我同步到了一个滚动到页面底部的操作,这让程序变得非常卡。

于是我更换了思路,写了一个定时器,每隔 0.5 秒移动一次滚动条。这样一改,不但滚动条变流畅了,打字速度也快了好几倍,程序也不卡了。

过度密集的滚动本是无意义的,还会因为代码堆积与资源浪费导致的卡顿,实际产生的滚动次数会更少。

这只是一个很简单的例子,在实际的编程过程中,你需要经常这样去调整思路与方向。

大道殊途同归,写代码和做人是一回事。一条道走到黑,不知道变通的人,根本不可能写出好的程序。

有些小白和编程外行,总喜欢把程序员脑补成执着而不知变通的木脑袋,其实不知真正的木脑袋是他自己。编程只有习惯于灵活变通才能走下去,不然三天就会摔得鼻青脸肿,走不下去的。

四、重构主程序。

这时候我们的主程序就简单了。

我们去掉了重复的代码,主程序的代码大幅减少。

我们把大问题分解成小问题,并且逐一提前解决。那么主程序需要解决的问题就少了。

下面是主程序的完整代码。代码同样适用 DeepSeek (或者其他大模型)。DeepSeek 也是非常优秀的,我昨天说的那个问题,今天问 DeepSeek 多次,写出来的代码都是对的。

import win.ui;
/*DSG{{*/
var winform = win.form(text="调用大模型 API 实现 AI 聊天助手";right=973;bottom=607)
winform.add(
btnSend={cls="button";text="问 AI";left=801;top=569;right=918;bottom=604;db=1;dr=1;z=2};
editPrompt={cls="edit";left=8;top=452;right=965;bottom=567;db=1;dl=1;dr=1;edge=1;multiline=1;z=3};
promptTool={cls="syslink";text="提示词生成器";left=161;top=574;right=373;bottom=603;db=1;dl=1;z=5};
splitter={cls="splitter";left=8;top=446;right=965;bottom=451;db=1;dl=1;dr=1;frame=1;horz=1;z=4};
wndBrowser={cls="custom";text="自定义控件";left=8;top=5;right=965;bottom=442;db=1;dl=1;dr=1;dt=1;z=1}
)
/*}}*/

import web.form.chat;
var wb = web.form.chat(winform.wndBrowser);
    
//输入系统提示词
wb.system(
    "你是 aardio 编程助手,擅长  aardio 编程。你会解答  aardio 编程问题,并且帮助生成或修改  aardio 代码。"
);

//响应按键事件
winform.btnSend.oncommand = function(id,event){
    
    //输入 AI 提示词
    wb.prompt( winform.editPrompt.text )

    //创建多线程
    thread.invoke( 
        function(winform,wb){ 
            
            import web.rest.jsonClient;
            var client = web.rest.jsonClient();

            //请输入大模型 API 接口的令牌( Key )
            client.setAuthToken("sk-gkX9OxBrGNGU6mWY69Ca14E347844cBbA32064E746E691Cf")
            var bot = client.api("https://api.*******.ai/v1")
        
            //调用接口
            var ok,err = bot.chat.completions({  
                 model = "claude-sonnet-3.5",
                messages = wb.chatMessage, 
                temperature = 0.4,//温度
                stream = true,//启用 SSE 事件流( text/event-stream )
                max_tokens = 500,//限制 AI 生成的  token 数
            },function(eventStream){ //如果不是流式推送则不需要用回调函数接收
                
                //输出 AI 应答( 打字效果输出 )
                wb.assistant(eventStream.data.choices);
            } )  
            
            if(err){
                wb.errorMessage(err)
            }   
        },winform,wb
    )
}

//拆分界面
winform.splitter.split(winform.wndBrowser,winform.editPrompt);

//默认设置输入框焦点
winform.editPrompt.setFocus();

winform.promptTool.link = "https://www.aardio.com/zh-cn/doc/?q=/zh-cn/ai/prompt/"

winform.show();
win.loopMessage();


运行效果:

我还挺佩服他居然会用 aardio 里的 win.ui.grid 。

Tags:

最近发表
标签列表