阿里妹导读
本文主要讲述,以“无需训练模型”的方式实现:AI智能分析功能需求、写代码、review代码解决特定业务问题的实践过程
摘要
本文主要讲述,以“无需训练模型”的方式实现:AI智能分析功能需求、写代码、review代码解决特定业务问题的实践过程,解决的是一款极其小众的开发语言的问题,模型并无相关领域知识,因此具备一定的代表性。与讲解大模型原理和方法论的文章不同,本文主要站在工程同学视角记录实践经验,例如:如何做RAG优化、rank排序剪枝、small2big、prompt调优、fewshot、避免幻象等,并不会对算法原理做过多剖析,希望能对同样没有算法背景的同学有所帮助,文中内容仅代表个人观点,若有不严谨之处,欢迎指出讨论。
利用AI实现通过功能需求描述生成脚本代码,并具备自动补全、格式化和CodeReview能力:
业务背景
Aviator是一个高性能、轻量级的 java 语言实现的表达式求值引擎, 主要用于各种表达式的动态求值。现在已经有很多开源可用的 java 表达式求值引擎,为什么还需要 Avaitor 呢? Aviator的设计目标是轻量级和高性能,相比于Groovy、JRuby的笨重, Aviator非常小, 加上依赖包也才 537K,不算依赖包的话只有 70K; 当然, Aviator的语法是受限的, 它不是一门完整的语言, 而只是语言的一小部分集合。 其次, Aviator的实现思路与其他轻量级的求值器很不相同, 其他求值器一般都是通过解释的方式运行, 而Aviator则是直接将表达式编译成 JVM 字节码, 交给 JVM 去执行。简单来说, Aviator的定位是介于 Groovy 这样的重量级脚本语言和 IKExpression 这样的轻量级表达式引擎之间。 github:https://github.com/killme2008/aviatorscript
use java.io.File;
let io = require('io');
let files = count(ARGV) == 0 ? 5 : long(ARGV[0]);
let nums = count(ARGV) < 2? 1000 : long(ARGV[1]);
let temp_dir = "/tmp";
for i in range(0, files) {
let file = "#{temp_dir}#{File.separator}data.#{i}";
let writer = io.writer(io.file(file));
for j in range(0, nums) {
write(writer, "#{rand(100000000)}\r\n");
}
io.close(writer);
p("Generate #{nums} random numbers to file #{file}");
}
let testResult = indicator_execute("TEST", "TEST-INDICATOR", seq.map());
if (is_empty(testResult)) {
log.log("测试指标调用结果为空");
}
let testNameSet = seq.set();
for testData in testResult {
seq.add(testNameSet, testData.get("name"));
}
...
业务问题
一、研发脚本困难
语言小众不熟悉
无成熟IDE环境
难以维护
二、审阅脚本困难
评审脚本困难
实践方案
一、挑战&解题思路
1、模型预训练的知识能力有限
2、模型对Aviator的泛化能力很差
3、解题思路
二、RAG实现Aviator语法知识问答
如前文所述,Aviator虽然具备高性能、轻量级且高度兼容java的特性,但它是一个非常小众的脚本语言,其推广程度和业界熟悉程度都非常低,为此,我们没有办法直接使用LLM来做Aviator语法知识的问答。
1、知识向量化与检索
2、LLM内容增强
你非常擅长回答关于aviator脚本相关的技术问题,需要按以下步骤和回答用户问题。
# 步骤
- 识别用户输入的问题,问题在<input></input>中;
- 理解已有的参考文档,文档在<ref></ref>中;
- 对参考文档中的信息进行整理,将相关信息与用户问题进行关联,形成回答内容,提供详细和准确的回答;
# 要求
- 你需要在回答中注明参考文档的来源和链接,以便用户可以进一步查看相关资料。
# 限制
- 如果问题与aviator脚本技术并不相关,则直接回复"我只能回答aviator技术相关问题。"
- 严格按照参考文档中的内容进行回答,如果没有能回答问题的参考文档,你需要直接回答“没有找到相关文档,我只能回答aviator技术相关问题!”。
- 不能使用js、ruby、python、java等其他语言规范回答问题,不要捏造或创造不正确的答案。
<input>
如何遍历集合
</input>
<ref>
# 10. 数组、集合和 Sequence
## 摘要
这一章,我们将介绍<em>如何</em>在 AviatorScript <em>如何</em>方便地创建和操作数组、<em>集合</em>。同时介绍在此之上的 Sequence 抽象。AviatorScript 中将数组和<em>集合</em>都抽象成一个序列<em>集合</em> Sequence,在此之上可以用同一套高阶函数方便地...
[文档链接](https://www.yuque.com/boyan-avfmj/aviatorscript/zg7bf9)
# 用户指南(5.0之前版本)
## 摘要
本文档不再维护,请参考《<em>如何</em>升级到 5.0 大版本(老用户必读)》,升级到 5.0 大版本,阅读《AviatorScript 编程指南》,谢谢。简介 Aviator是一个高性能、轻量级的 java 语言实现的表达式求值引擎,主要用于各种...
[文档链接](https://www.yuque.com/boyan-avfmj/aviatorscript/ra28g1)
</ref>
3、下一步优化
检索结果Rerank重排序
Small to Big
三、LLM实现通过功能描述生成脚本代码
在AI营销泛滥的时代,网上充斥着各种AI自动写代码、程序员失业的软文,但事实上,离AI根据prd需求直接生成项目代码并能正常运行的时代还较远,一些公司的团队正在做类似的项目,但也并没有达到可商业化落地的阶段。虽然AI还并不具备通过业务需求生成可商业化项目级代码的能力,但AI已经具备一些通过单代码文件实现简单清晰的function需求的能力了,例如:我们可以让AI帮我们写一个对map数据进行sort by value的操作代码。
1、使用Few Shot,根据指标名称和功能描述生成脚本代码
你需要按照以下"步骤"和"要求"来帮助用户按照描述生成新的脚本代码:
# 步骤
- 使用aviator脚本语法进行分析、理解和代码生成,不要使用其他开发语言的语法;
- 分析理解<prefix></prefix>部分描述的案例,其中描述了不同名称和功能的脚本代码是如何实现的;
- 理解<name></name>部分,它代表当前用户需要编写的脚本的名称;
- 理解<desc></desc>部分,它代表当前用户需要编写的脚本需要实现的功能说明;
- 根据上述信息,生成能实现<name>和<desc>所描述名称和功能的脚本代码;
# 要求
- 生成代码要符合aviator语法规范,不要生成与描述无关的内容;
- 生成代码变量和函数以驼峰方式进行命名;
- 生成代码统一以两个空格进行缩进;
- 生成代码时要添加注释,aviator仅支持使用```##```单行注释;
- 生成代码做好必要的判空处理,避免发生不预期的异常;
- 可以使用内置函数,如indicator_execute、hsf_invoke、db_query等,以originalContext结构体作为输入;
- 尽量调用已有脚本而少写重复代码,格式为:indicator_execute($code, $args...),其中$code为被调用脚本编码,$args为参数列表;
- 生成内容按名称、功能、代码分段展示,采用markdown格式输出;
<prefix>
%s
</prefix>
<name>
%s
</name>
<desc>
%s
</desc>
2、使用Rerank对样例数据进行相关度排序和筛选,剪枝上下文
3、下一步优化
四、接入AoneCopilot实现脚本代码自动补全
虽然模型根据功能描述能自动生成脚本代码,但依然存在需要对代码进行调整的场景,继续采用上述的思路,已有的指标脚本是可以用来指导我们进行代码的自动补全的。这里可以学习了解一下Aone Copilot以及GitHub Copilot的实现原理,简单来说就是使用高质量的代码库(300多种开发语言)进行模型训练,结合待补全文件的:1、语言类型;2、相关代码(如同路径、import、打开tab的文件等);3、相似代码片段等进行推理来实现代码补全的。而aone copilot也提供了代码补全的api 服务,但接入服务需要传入代码仓库地址、代码prefix、代码suffix以进行项目级别的prompt的构建。
五、LLM实现通过代码生成功能描述和评审代码
除了自动生成脚本代码外,还需要解决“指标描述无效率高”和“脚本评审效率低”的问题,这个实现就相对来说简单一些,主要是利用prompt优化和LLM本身的能力来进行,例如通过在提示词里给到模型既定的语法规范、评审规则、评审格式、代码本身和修复建议标准,让模型产出具体的评审结果和修改建议。
1、按要求评审脚本并给出修改建议
你拥有高超的代码编写和检查技能,熟悉多种编程语言和设计模式,可以根据代码的具体情况,指出存在的问题。
请你参考<schedule></schedule>中的检查步骤,<tab></tab>中的检查要求,对<code></code>中的代码进行检查。
<tab>
- 空指针:指出可能存在未判定空指针的地方,判定方式为```param == nil```。
- 缺乏一致性:使用了不一致的缩进、命名风格、代码注释等,使得代码难以阅读和维护。
- 变量和函数命名不清晰:变量和函数名未使用驼峰命名,使用没有意义或者太过简单的变量和函数名,无法清晰地表达其用途。
- 长方法或函数:方法或函数超过50行,增加了代码的复杂性,难以理解和测试。
- 注释不足或者错误:缺乏注释或者注释与代码不一致,无法理解代码的用途和实现细节。
- 不合理的代码布局:缺乏良好的排版和布局,使得代码难以理解和浏览。
- 过多的重复代码:存在超过10行的代码段,增加了代码冗余和维护难度,可以将重复代码抽成函数。
- 没有错误处理机制:未考虑异常情况,没有适当的错误处理机制,导致程序容易崩溃或者出现不可预料的错误。
</tab>
<schedule>
- 使用aviator脚本语法进行检查和优化,不要使用其他开发语言的语法,aviator仅支持使用```##```单行注释,统一以两个空格进行缩进,以驼峰方式进行命名,脚本引擎内置了很多函数,如indicator_execute、hsf_invoke、db_query等,脚本以originalContext结构体作为输入;
- 若代码都检查了空指针,则指明具体检查的地方;
- 若方法或函数代码没有超过50行,则无需检查长方法或函数;
- 若重复代码没有超过10行,则无需检查重复代码;
- 深入理解要检查的代码,包括其功能、逻辑和结构等方面的特点;
- 检查代码,指出其存在的问题,说明检查的过程和结果,明确指出问题代码的位置行数,如果没有问题则无需输出;
- 如果可以,针对问题代码给出修改建议,不要针对不同问题重复生成建议代码,而要用一段代码建议解决所有问题,确保不破坏现有功能,不要生成与原代码严重不符的代码建议;
- 回答内容不要复述检查步骤和要求,采用markdown格式输出;
</schedule>
<code>
%s
</code>
1.1 优化prompt以代码样例告诉模型Aviator的语法规范
你拥有高超的代码编写和检查技能,熟悉多种编程语言和设计模式,可以根据代码的具体情况,指出存在的问题。
首先你需要从<example></example>中的样例代码中学习aviator脚本语法规范,例如:
- 使用```let goodName = "name";```的方式定义变量,无需设定变量类型;
- 使用```fn addFunction(a, b) {return a + b;}```的方式定义函数;
- 使用```seq.set()```定义集合,使用```seq.list()```定义数组,使用```seq.map()```定义map;
- 使用```str.isNotBlank(...)```的方式引用字符串工具;
- 使用```json.toJSONString(...)```的方式引用json工具;
- 以originalContext结构体作为输入;
- 内置了很多函数可以调用,如```indicator_execute(...)```、```hsf_invoke(...)```、```db_query(...)```、```with_cache(...)```、```saveData(...)```等,日志输出只支持```log.log(...)```的方式。
然后你需要参考<tab></tab>中的检查要求、<schedule></schedule>中的检查步骤,对<code></code>中的代码进行检查和优化。
<tab>
- 判定空指针:针对使用的变量,必须判定空指针,对函数名无需判定空指针。
- 保持一致性风格:要使用一致的缩进、命名风格、代码注释等,统一用两个空格进行缩进,变量函数要以驼峰方式进行命名;
- 变量和函数命名要清晰:变量和函数名必须使用驼峰命名,同时命名必须有意义,能通过命名理解其用途;
- 方法和函数不能过长:定义的方法和函数不能超过50行,若存在超过50行的方法或函数,应该拆解成更小的方法和函数;
- 注释要充足且有意义:只能使用```##```单行注释,不能用其他如```//```,```/* */```进行注释,不能多行注释,代码不能缺乏注释,注释内容与代码含义必须保持一致;
- 合理的代码布局:代码要有良好的排版和布局,使得代码便于理解和浏览;
- 不能有过多的重复代码:不能存在超过10行的重复代码段,若存在超过10行的重复代码,应该抽成函数进行调用;
- 要有错误处理机制:必须有适当的错误处理机制,增加程序的健壮性;
</tab>
<schedule>
- 深入理解要检查的代码,包括其功能、逻辑和结构等方面的特点;
- 按<tab></tab>中的规则检查代码,清晰说明检查过程和结果,不能使用js、ruby、python、java等其他语言规范;
- 若不存在违反规则约束的问题,不要捏造问题和修改建议;
- 若存在违反规则约束的问题,则首先对问题进行总结分析,要明确指出问题代码的位置和行数,并给出代码修改建议,确保建议代码要符合aviator脚本语法规范,同时与原代码实现的功能和逻辑保持一致,不要对问题以外的代码做修改;
- 如果捏造问题将会受到惩罚,如果修改建议代码不符合aviator语法规范将会受到惩罚,如果修改建议代码与原代码严重不符将会受到惩罚;
- 采用markdown格式输出,建议代码用```包装起来;
</schedule>
<example>
%s
</example>
<code>
%s
</code>
2、根据指标脚本生成功能描述
你拥有高超的脚本代码理解能力,可以根据代码的具体情况,总结出脚本所实现的功能描述。
请你参考<schedule></schedule>中的步骤,对<code></code>中的代码进行总结。
<schedule>
- 使用aviator脚本语法进行分析和理解,不要使用其他开发语言的语法,除aviator基本语法外,脚本引擎内置了很多函数,如indicator_execute、hsf_invoke、db_query等,脚本以originalContext结构体作为输入;
- 深入理解代码,包括其功能、逻辑和结构等方面的特点;
- 用一到两句话总结代码所实现的功能是什么,然后再总结其实现步骤是什么;
- 要简明扼要,不要长篇大论,如果无法理解代码逻辑就无需输出,不要总结出毫不相干的描述;
- 回答内容不要复述处理步骤和要求,采用markdown格式输出;
</schedule>
<code>
%s
</code>
Demo
3、格式化指标代码
你拥有高超的代码编写技能,熟悉多种编程语言和设计模式,可以对代码进行格式化。
首先你需要从<example></example>中的样例代码中学习aviator脚本语法和代码规范,例如:
- 使用```let goodName = "name";```的方式定义变量,无需设定变量类型;
- 使用```fn addFunction(a, b) {return a + b;}```的方式定义函数;
- 使用```seq.set()```定义集合,使用```seq.list()```定义数组,使用```seq.map()```定义map;
- 使用```str.isNotBlank(...)```的方式引用字符串工具;
- 使用```json.toJSONString(...)```的方式引用json工具;
- 以originalContext结构体作为输入;
- 内置了很多函数可以调用,如```indicator_execute(...)```、```hsf_invoke(...)```、```db_query(...)```、```with_cache(...)```、```saveData(...)```等,日志输出只支持```log.log(...)```的方式。
然后你需要参考<tab></tab>中的要求,对<code></code>中的代码给出格式化修改建议。
<tab>
- 每一行的末尾不能有空格;
- 统一用两个空格的方式进行缩进;
- 变量函数要以驼峰方式进行命名;
- 只能使用```##```单行注释,不能用其他如```//```,```/* */```进行注释,不能多行注释,代码不能缺乏注释,注释内容与代码含义必须保持一致;
- 代码要有良好的排版和布局,使得代码便于理解和浏览;
- 不能存在超过10行的重复代码段,若存在超过10行的重复代码,应该抽成函数进行调用;
- 给出代码格式化建议,确保建议代码要符合aviator脚本语法规范,确保不要对代码逻辑做任何修改;
- 如果修改建议代码不符合aviator语法规范将会受到惩罚,如果修改建议代码与原代码严重不符将会受到惩罚;
- 采用markdown格式输出,建议代码用```包装起来;
</schedule>
<example>
%s
</example>
<code>
%s
</code>
下一步实践计划
一、效果评估
二、智能策略
结语
本文实践技术选型
Aviator语法知识库:语雀知识库
文档检索:语雀公共api
LLM:Meta-Llama-3-1-405B-Instruct
Rerank:bge-reranker-v2-m3
脚本代码补全:aone copilot api
提示词及调优:自研
参考链接:
使用 GPU 共享推理一键部署
通过创建ACK集群Pro版,使用云原生AI套件提交模型微调训练任务与部署GPU共享推理服务。支持快速创建Kubernetes集群,白屏配置任务数据共享存储和下载,并通过命令行工具Arena快速提交模型训练任务、部署推理服务。
点击阅读原文查看详情。