使用SKILL库

本节内容参考CaseStudy目录下的文件"LLMCaller.Table"的窗口"自动生成Foxtable代码"。

我相信大家经常使用AI自动生成代码,是不是觉得很神奇。

其实自动生成代码并不神奇,有了Foxtable的LLMCaller,我们完全可以自己实现这样的功能,而且实现的代码很简单。

要实现自动生成代码功能,首先得有指导AI生成代码的技能库。

本节就以大家经常使用的Foxtable Coder为例,我已经将这个技能库解压到CaseStudy的Coder子目录中。

技能库结构

要大模型学会Foxtable的开发技能,并生成高质量的代码,最简单直接方式是将整个Foxtable的开发指南发送给大模型的API接口。

但Foxtable的开发指南非常庞大,而大模型的上下文长度是有限制的(目前最大的也就是1M),所以需要将Foxtable的开发指南进行拆分。

Foxtable Coder将Foxtable的开发指南按功能类别拆分成了48个单独的技能,也就是48个技能文件,为便于管理,每个技能都用一个单独的目录存放,目录名就是技能名。

AI收到用户问题后,如何知道调用哪个技能来解决问题呢? 所有除了48个技能文件,还需要一个总(路由)入口文件,对每一个技能进行介绍。

有的技能内容非常多(如事件编程),如果将全部内容都放在一个技能文件中,也很容易撑爆上下文,所以对于大型技能,技能文件只进行主要的介绍,然后将细节进行二次拆分,存放在多个参考文件。

综上所属,Foxtable Coder这个技能库的结构为:

例如:

/事件编程/SKILL.md:事件编程技能的具体说明,

/事件编程/references/01-基础知识.md:事件编程技能的参考文件之一,可能有多个。

设计思路

为了达到极致的效率和准确率,这里采用了“一脑两手”的 Agent 架构:

参考代码

打开示例文件"LLMCaller.Table"后,可以在命令窗口测试执行下面的代码:

'''Async
Dim
apiKey As String = "sk-a734b83536da45e9aedc3e42605bfb3a" '请替换为自己的APIKey
Dim
baseDir As String = System.IO.Path.Combine(ProjectPath, "coder") ' 技能库根目录
Dim
caller As New LLMCaller("https://api.deepseek.com/chat/completions", "deepseek-v4-pro", apiKey)
caller.Messages =
New JArray() 

' 1. 读取总控路由文件(根目录的 SKILL.md)
Dim
routerPath As String = System.IO.Path.Combine(baseDir, "SKILL.md")
Dim
routerContent As String = ""
If
System.IO.File.Exists(routerPath) Then
    routerContent = System.IO.File.ReadAllText(routerPath)

Else

    MessageBoxA.Show(
"找不到核心路由文件:SKILL.md")
   
Return ""
End
If 

' 2. 将路由文件内容作为系统提示词(SystemPrompt)
caller.SystemPrompt =
"你是一个资深的 Foxtable 代码开发专家。" & vbCrLf &
   
"下面是你的【总控路由表与语法约定】(必须严格遵守):" & vbCrLf &
    routerContent & vbCrLf & vbCrLf &
   
"=== 行动指南 ===" & vbCrLf &
   
"1. 遇到用户的需求,请先根据上述【路由表】匹配对应的技能名称。" & vbCrLf &
   
"2. 调用 get_skill_content 获取该技能的详细说明。" & vbCrLf &
   
"3. 技能的 SKILL.md 末尾通常有一个【参考文档】表格。如果需要查阅更多细节,请调用 read_reference 读取表格中列出的对应参考文件"  

' 3. 定义两个工具,分别用于读取技能文件和参考文件
With
caller.AddTool("get_skill_content", "获取指定技能的核心 SKILL.md 说明文件。")
    .AddParameter(
"skill_name", "string", "技能名称(即目录名),必须从 SystemPrompt 的路由表中提取。", True)
End
With
With
caller.AddTool("read_reference", "根据技能的 SKILL.md 末尾的《参考文档》表格,读取具体的参考文件内容。")
    .AddParameter(
"skill_name", "string", "技能名称(即目录名)。", True)
    .AddParameter(
"file_name", "string", "参考文件名,例如 '01-基础知识.md'。", True)
End
With
caller.ToolExecutor =

Function
(ttoolName As String, targs As JObject) As String
   
Select Case ttoolName
       
Case "get_skill_content" '读取技能文件
           
Dim skillName As String = targs("skill_name").ToString()
           
Dim filePath As String = System.IO.Path.Combine(baseDir, skillName, "SKILL.md")
           
If FileSys.FileExists(filePath) Then
               
Return FileSys.ReadAllText(filePath)
           
Else
               
Return "{""error"":""未找到该技能的 SKILL.md 文件,请检查技能名是否拼写正确。""}"
           
End If
       
Case "read_reference" '读取参考文件
           
Dim skillName As String = targs("skill_name").ToString()
           
Dim fileName As String = targs("file_name").ToString()
           
Dim filePath As String = System.IO.Path.Combine(baseDir, skillName, "references", fileName)
           
If FileSys.FileExists(filePath) Then
               
Return FileSys.ReadAllText(filePath)
           
Else
               
Return "{""error"":""未找到指定的参考文件。请检查文件名是否与《参考文档》表格中完全一致。""}"
           
End If
       
Case Else
           
Return "未知工具:" & ttoolName
   
End Select
End
Function 

' 4. 测试一个需要查阅参考文档的问题
caller.UserMessage =
"我想在订单表实现:输入产品编号时,自动去产品表里查找对应的品名、型号和单价并填入;输入数量时,自动计算出金额(数量*单价)"
If
caller.GetResult() Then
    MessageBoxA.Show(caller.Result)

Else

    MessageBoxA.Show(caller.Error)

End
If

小提示:为提高代码生成质量,上述代码将大模型改为"deepseek-v4-pro"了。

底层发生了什么?(AI 的心路历程)

当执行这段代码时,大模型并非“一拍脑袋”就写代码,它在后台经历了极其严谨的查阅过程。如果你在代码的最后面加上一行:

Output.Show(caller.GetRequestBody().ToString())

你会看到完整的JSON请求体,其中包含了AI自主发起的两次工具调用交互:

第一轮工具调用:

  1. 查阅路由表:收到用户问题后,AI查阅系统提示词(SystemPrompt)中的路由表,发现解决这个问题需要使用“事件编程”技能。
     

  2. 发起调用:get_skill_content({"skill_name": "事件编程"})。
     

  3. 本地代码返回:“事件编程”的 SKILL.md 全文,里面包含了 e 参数说明、核心事件列表,并在末尾附带了参考文档表格。
     

  4. AI 阅读后继续思考:“这属于自动计算,需要跨表引用。虽然基础说明里有一点代码,但为了确保万无一失,我要看一下底部的 05-计算.md 参考文档。”

第二轮工具调用:

5. 发起调用:read_reference({"skill_name": "事件编程", "file_name": "05-计算.md"})。

6. 本地代码返回:05-计算.md 的详细内容。

7. AI 确认:查阅到了官方最标准的写法,同时深刻记住了系统提示词里的“不要用 Sub 包裹”的红线。

大模型结合所有资料,最终输出类似下面的DataColChanged事件代码:

Dim
dr As DataRow = e.DataRow
'
第一部分:输入产品编号 → 从产品表自动带出品名、型号、单价
If
e.DataCol.Name = "产品编号" Then
   
If e.NewValue Is Nothing Then
       
' 清空产品编号时,同步清空已带出的列
        dr(
"品名") = Nothing
        dr(
"型号") = Nothing
        dr(
"单价") = Nothing
   
Else
       
Dim pr As DataRow = DataTables("产品").Find("[产品编号] = '" & e.NewValue & "'")
       
If pr IsNot Nothing Then
            dr(
"品名") = pr("品名")
            dr(
"型号") = pr("型号")
            dr(
"单价") = pr("单价")
       
End If
   
End If
End
If
'
第二部分:输入数量或单价 → 自动计算金额 = 数量 * 单价
Select
Case e.DataCol.Name
   
Case "数量", "单价"
       
If dr.IsNull("数量") OrElse dr.IsNull("单价") Then
            dr(
"金额") = Nothing
       
Else
            dr(
"金额") = dr("数量") * dr("单价")
       
End If
End
Select

开发智能体软件不是梦

很多人以为智能体软件(比如 AutoGPT、Trae、Devin)是高不可攀的黑科技,但实际上,智能体的核心公式就是:

Agent = 大模型(大脑) + 上下文管理(记忆) + 工具集(手脚) + 循环执行(工作流)

我们刚才写的这套“一脑两手”架构,已经完美具备了前三个要素。如果要把它真正做成一个独立运行的智能体软件,你只需要再加三个“外挂组件”:


本页地址:http://www.foxtable.com/webhelp/topics/7233.htm