我手搓了一个面向应用的 AI 框架和脚本语言 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
riceball
V2EX    程序员

我手搓了一个面向应用的 AI 框架和脚本语言

 
  •   riceball 2025 年 3 月 19 日 2507 次点击
    这是一个创建于 322 天前的主题,其中的信息可能已经有所发展或是发生改变。

    为什么从头手搓 AI 框架,而不是使用现有框架?

    最初我也尝试了多个框架(包括 LangChain 、AutoGen 、LMQL 、Outlines 、MemGPT 等),但它们都无法完全满足我的需求。我想要的是一个极度灵活可配置的 AI 应用框架,用来打造我设想的「真AI PC 」而非当前大多数 AI 产品那种“远程 AI 服务+本地空壳”的模式。

    在当前阶段,我认为面向应用的 AI 框架应聚焦于提示词( Prompt )的工程化这是人类与 AI 交互的唯一桥梁。我的目标是: 将提示词转化为可编程的“函数”,支持自由组合、独立调用,并能持续迭代优化。

    但是 langchain 对提示词的抽象只是总结的一些范式,而这些范式在我看来不太不实用,而且更糟糕的是 langchain 自身实现就将提示词直接内嵌到它的代码中,根本无法对框架中的提示词进行替换和迭代。 而 AutoGen 是以多智能体架构和事件驱动为核心实现复杂协作工作流;至于 LMQL 作为一种用于语言模型交互的查询语言更像是炫技; Outlines 聚焦在结构化文本的生成; MemGPT 只想实现长久记忆, 这些就不多做评价了。

    我想要的 AI 框架核心功能

    我想要的是以提示词为核心驱动的框架:

    1. 提示词即函数:让提示词象普通函数一样的使用,提示词可以与代码无缝双向调用,代码可以调用提示词获得结果,提示词也可以调用代码获得结果。
    2. 加密保护: 支持提示词加密,保障知识产权
    3. 模型中立: 提示词可适配不同模型及参数规模。
    4. 继承机制:支持提示词“类”的继承,如同面向对象编程。
    5. 简洁易用:提示词应该靠近自然语言,简单易读写。
    6. 打包为应用:能将多个提示词打包成完整 AI 应用。
    7. 高度可扩展:支持任意能力的扩展,如:看(图生文),听(STT),说(TTS),画(文生图/视频)等等。
    8. 全栈兼容:跨平台支持(浏览器、服务器端),尽量统一语言减少维护成本(选型 Javascript )。

    开发历程

    在 2024 年多方搜寻无果的情况下,2024 年 5 月我开始从头写可编程提示词(Programmable Prompt Engine)AI 规范,当然最开始不是叫这个名字,最开始叫 AI Agent,后来是表伟提议既然实质是让提示词成为可编程的软件工程,那么不妨就叫 PPE ,我想也对,这个概念更准确,AI Agent 应该是以 PPE 提示词为基础打造,它其实是更上层的概念,遂更名为 PPE 。

    既然要全栈,那就只能选 Javascript, 从前端到后端,从服务器到浏览器通吃,并且 JS 极度灵活和可扩展,而这正是我所需要的。

    **PPE 框架核心亮点功能汇总 (来自 AI 总结)

    1. 提示词即函数 将提示词封装为可调用函数,支持与代码双向交互,实现灵活组合与迭代优化。

    2. **安全与加密 提示词加密保护知识产权,支持工具调用白名单与多级权限控制。

    3. 模型中立与扩展 自动适配多模型(如 QwenAI/Llama ),动态优化硬件资源( GPU/内存)。

    4. 面向对象设计 提示词继承机制(类/子类),角色群聊与私聊管理,复杂流无缝协作。

    5. 智能增强功能 深度思考模式( CoT )无需模型训练,LRU 缓存加速重复调用,动态参数传递。

    6. 全栈与易用 基于 Javascript 全平台运行(浏览器/服务器),JSON/YAML/自然语言输出智能转换。

    7. 结构化对话与多轮 YAML 分隔多轮对话,输入输出分离配置,支持条件指令($if/$for/$match)。

    8. 工具生态与安全调用 内置工具安全调用框架,支持文生图/语音交互等扩展,开发者可自由封装工具包。

    9. Package 智能体生态 提示词、脚本知识库打包为独立应用,便于共享与复用。

    10. 性能优化 自动检测硬件资源,智能分配计算层与上下文窗口,无需手动配置。

    结构化对话消息

    刚开始写的时候,还是很茫然无措的,没有项目可供参考,

    最初就想着用 YAML 配置的方式简单的来结构化对话消息,然后既然提示词是函数那就肯定需要约定函数的输入和输出: 用input来约定提示词的输入参数, outputJson Schema来约定提示词的输出:

    templateFormat: hf prompt: messages: - role: system content: Carefully Think about the intent of following The CONVERSATION user provided. Output the json object with the Intent Category and Reason. - role: user content: |- The CONVERSATION: {{ conversation }} input: conversation: "messages[1].content" output: type: object properties: Intent: type: "string" Reason: type: "string" 

    感觉,这样很不自然方便,于是将结构化对话消息的输入/输出配置与对话内容分离:

    --- input: conversation: {required: true} output: type: object properties: Intent: type: "string" Reason: type: "string" --- system: Carefully Think about the intent of following The CONVERSATION user provided. Output the json object with the Intent Category and Reason. user: |- The CONVERSATION: {{ conversation }} 

    这样就感觉好多了。

    提示词调用与代码集成

    那么如何在提示词中使用(调用)AI 赋值以及其他提示词或代码?于是有了高级替换:

    --- # 导入 js 函数 import: - eval.js --- # JOKE 会被 AI 赋值,存放于: `prompt.JOKE` 中,供下次使用 assistant: "讲个笑话:[[JOKE]] 希望您喜欢!" # 调用外部提示词`calculator` user: "五加二等于 [[@calculator("5+2")]]" # 调用函数代码`eval` user: "五加二等于 [[@$eval("5+2")]]" 
    // eval.js export function eval(value) { return ... } 

    甚至支持了让 AI 只能在我给的列表中选择:

    user: 你喜欢什么水果? assistant: "我超喜欢[[FRUIT:|苹果|香蕉|橙子]]" 

    待续...

    6 条回复    2025-03-22 15:18:36 +08:00
    chenhaobuaixuexi
        1
    chenhaobuaixuexi  
       2025 年 3 月 19 日
    将提示词转化为可编程的“函数”,支持自由组合、独立调用,并能持续迭代优化。
    ----
    哥, 没看懂, 会有啥收益。有案例吗?
    chenhaobuaixuexi
        2
    chenhaobuaixuexi  
       2025 年 3 月 19 日
    仓库链接呢?
    pinktu
        3
    pinktu  
       2025 年 3 月 19 日
    @chenhaobuaixuexi 看起来有点像使用 AI 生成代码然后达到一种低代码效果
    riceball
        4
    riceball  
    OP
       2025 年 3 月 19 日
    @chenhaobuaixuexi 地址在这里: https://github.com/offline-ai/cli 如果你用心读,其实也能在规范中发现。

    不过现在还在 WIP 阶段,还有很多功能没实现,比如还没有实现编译为独立应用。

    说到例子,应该更简单的实现类似组建软件公司的智能体,当然我自己的应用就是作为 AI PC 内核。

    比如,简单的让几个智能体尬聊几个回合:

    char_dobby.ai.yaml:

    ---
    # 表示继承自 char 角色类型脚本(提示词类型继承)
    type: char
    # 这里是根据“char”角色的一些具体设置
    # 角色的名字
    name: "Dobby"
    # 对角色的描述
    description: "Dobby 是哈利波特世界里的一个小精灵"
    ---
    # 用户提问
    user: "你是谁?"
    ---
    # 根据角色设定的回答
    assistant: "我是 Dobby 。Dobby 很开心。"


    char_harry.ai.yaml:

    ---
    # 表示继承自 char 角色类型脚本(提示词类型继承)
    type: char
    name: "Harry Potter"
    description: "一个拥有魔法能力的巫师,一个在霍格沃茨魔法与巫术学校学习的孤儿,一个被选中对抗黑暗巫师伏地魔的英雄."
    ---
    user: 你是谁?
    ---
    assistant: "我是哈利波特。"


    guide.ai.yaml:

    ---
    description: "You are a professional guide. You can guide the user to complete the task."
    name: "guide"
    # 约定使用的角色列表,key 为角色别名,值为角色脚本 ID
    roles:
    dobby: char_dobby
    harry: char_harry
    ---
    # harry 对 dobby 说,dobby 脚本自动(一定)回复
    # - harry: "@dobby, I want to go to the moon."
    # guide 对 translator 说
    - harry: "@dobby, 你好,Dobby, 让我们来聊聊南瓜魔法。"
    - $for: 2 # 来两轮对话
    do:
    - harry: "@dobby, [[AI]]"
    riceball
        5
    riceball  
    OP
       2025 年 3 月 19 日
    @pinktu 不算是低代码,当然看你如何定义低代码的,如果你把提示词当代码来看,似乎也说得过去,提示词看上去是比代码简单些。但其实比代码难写。
    riceball
        6
    riceball  
    OP
       2025 年 3 月 22 日
    这,居然不能编辑帖子,回复也不支持 md 格式!
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2694 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 04:41 PVG 12:41 LAX 20:41 JFK 23:41
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86