本文目录
交互式意图行为代码 —— IBC-Inter (Intent Behavior Code – Interactive)
本文由群友:哈伯 投稿
交互式意图行为代码,IBC-Inter,一种实验性的编程语言,用于与LLM进行交互。完全使用python进行实现。
IBC-Inter 是一种”自然语言混合编程“代码,其核心思想是把LLM当作函数/表达式来看待,把一次LLM调用拆解成意图、行为两部分,再配合以确定性的代码结构,构成一套独特的可复现,可稳定运行,可自愈的完整 LLM 工作流程。
项目地址:
*这是一个实验性项目,且是一个长期项目,目前处在刚起步的阶段,现在介绍的只是一个实验性的 MVP Demo,未来会持续开发维护。
引子
在现有编程语言中,如果期望实现在代码中接入与 LLM 的交互,往往会涉及到繁琐的函数调用定义或者接口封装。为了提示词的可复用性,开发者有时不得不设计很多辅助函数来参与提示词文本的构建。同时,为了提示词和记忆的管理,现在的 Agent 相关代码总是倾向于使用 Markdwon 来存储相关的提示词文本。而这造成了某种实质上的滥用——给一个 md 文件起一个新名字,rules、skills 之类的概念层出不穷地冒出来,新名词翻来覆去地被发明,声称自己解决了某些关键问题,结果最后回归到一个又一个 Markdwon 文件。
以 Skills 技术栈为例,通过文件夹结构的组织, Skills.md 文件层层嵌套,用条件注入/多步注入/渐进式披露等手段避免上下文污染,甚至出现了把 Skills.md 本身写得像是编程代码一般的局面,这实质上完全违背了 Markdown 的设计初衷 —— 供人阅读。虽然 Anthropic 以及现在的很多自媒体试图把 Skills 这一技术栈描述为某种未来,仿佛只要有了 Skills 的累积,模型就可以自主进化,仿佛所谓的渐进式披露就是一种提示词管理的终极方案,仿佛只要书写这些 Markdown 就是在书写未来。
诚然,已经有很多博主/视频作者详细科普过,为什么现在的 LLM 模型似乎“偏爱于Markdown”来作为提示词的承载体,从模型训练开始,讲到LLM的原理,再说到 Markdown的直观性以及其标记的简洁明确等等等等,个中缘由,倒也轮不到我在此又絮叨或者反驳一番。
然而不容忽视的是 —— “我的 Agent 为什么无法找到正确的Skills?调用了之后又为什么不听指令?”相关的问题在社区中可一点都不少见。
事实上,类似的问题在MCP这一技术路线上,乃至更早的原始 Function Calling 的时代其实就已经出现:加了太多MCP上下文,反而导致语言模型不知所措,长时间思考,烧了大量的不必要token,却最终获得一次“格式错误/调用失败”。个中沮丧和挫败感,相信相关的开发者都深有体会。
一个更近的例子则是 Openclaw ,为了打个招呼就要烧掉无数上下文 Token 用来承载大量工具上下文。除此之外,类似的一些本被许诺为某种节省 Token 并提高模型能力的技术路线自身反而在简单任务中用掉了最多的无意义 Token,然后又导致了其自身的”上下文污染“,不得不说这也是某种让人哭笑不得的黑色幽默。
为了处理这种”上下文污染“,现有的训练路线似乎更多倾向于通过加强对模型的“工具调用能力/agent能力”的强化训练来提高长上下文的指令遵循能力,通过模型自身的性能进步以及训练算力训练数据的堆叠和优化等来解决问题,而本地部署的小尺寸模型在很多人眼中逐渐变成”不可靠“的代名词,只因为其无法参与到 Agent 的游戏中。这不利于 LLM 的平等技术普惠:对旗舰模型的依赖,对算力发展的依赖,对顶尖训练技术的一来,只会愈发加重模型垄断、算力垄断、数据垄断,乃至 GPU 垄断。即便对于大公司来说,参与垄断竞争也意味着员工会持续收获痛苦与高压 —— 哪怕是那些最优秀最顶尖的研发人员 —— 直到某一方把水抽干,熬到某个公司得到胜利,赢家通吃。可怕的是,我们确实似乎在逐渐走向这样的未来。
IBC-Inter 的技术理念
针对上述所有这些问题,我尝试提出一个想法 —— 直接从编程语言这个层级作为切入点,尝试构建一个高效、可控、可复用,且不依赖于具体大模型的”自然语言编程“体系。设计上要简单易用,工作流程上要直观可控,要提供充分可靠的调试工具和监控工具,要让小尺寸语言模型也能在精确的工作流中展示自己的能力极限,让普通人也能无痛构建属于自己的最简 Agent或固定工作流。
这些想法促成了交互式意图行为代码 (IBC-Inter) 的诞生,将 Intent(意图)、Behavior(行为)与 Code(代码)无缝连接,把提示词系统和 LLM 调用提升为编程语言中的一等公民,把 LLM 的行为视作表达式/函数调用:
- Code (代码):确定性的骨架。负责数据结构定义、状态维护、文件交互、流程控制,保证程序的长期稳定性。
- Behavior (行为):交互的桥梁。由 LLM 在运行时动态推理执行,并无缝接入代码逻辑。
- Intent (意图):非确定性的上下文。作为环境的“背景信息栈”动态注入至提示词,告知 AI 当前逻辑运行的主要目的。
- Interactive (交互):解释运行。LLM 的调用开销使得解释器设计不再主要专注于运行效率,而是去专注于更宏观的高级交互功能。
上述内容也意味着 IBC-Inter 建议了一个 LLM 的边界:常规自然语言处理。我们不应强迫 LLM 进行其不擅长的精确计算,不应该试图让 LLM 用人类习惯的任务清单 (也即是 TODO List) 去进行长期流程控制和动态规划,更不应该试图让 LLM 从冗长晦涩的上下文包袱中提取出需要被使用的 tools 或 skills —— 更何况很多 skills 本身也是冗长的上下文包袱。
这些工作应交由确定性的代码脚本完成,通过显式地分解 LLM 的每一步工作职责,每一次 LLM 调用都只执行唯一一个任务,从而让它们能以最高效率发挥自己最大的作用。通过把沉重的上下文负担从 LLM 身上剥离,我们能让很多被忽视的小尺寸开源模型也能够真正地参与到持续且稳定的严肃工作中。
第一印象:Hello World
在 IBC-Inter 中,与 LLM 的交互需要从配置开始。核心 LLM 交互能力由API交互提供,你需要先完成显式的初始化。
让我用一个简单的 hello world 代码来展示这一切。
# 用 api_config.json 配置所使用的 api 信息
dict config = json.parse(file.read("./api_config.json"))
dict default_model = (dict)config["default_model"]
ai.set_config(
(str)default_model["base_url"],
(str)default_model["api_key"],
(str)default_model["model"]
)
str greeting = "你好,请打个招呼"
str result = @~ 请根据要求进行回复: $greeting ~
print("llm 回复的打招呼内容:")
print(result)
在上面这段IBC-Inter代码中,除去 json 读取以及 api 配置等内容,最关键的是这一句:str result = @~ 请根据要求进行回复: $greeting ~
它展示了 ibci 中的一个关键概念:行为描述语句。
行为描述语句由 @~ ... ~ 这样的结构进行书写。在过程中可以通过 $变量名 来对代码中的变量进行调用。而其它部分的内容则会被作为普通的提示词送入 LLM。
因此,此处 print(result) 最终会输出类似于 ”你好!很高兴见到你,有什么我可以帮你的吗?“ 之类的结果。
LLM 函数
对于那些更复杂的提示词构建,我们需要引入 LLM 函数的概念:
llm 翻译(str 文本, str 目标语言) -> str:
__sys__
你是一个翻译专家。
__user__
请将 "$文本" 翻译为 $目标语言。
llmend
llm 函数利用 __sys__和__user__ 来标记系统提示词、用户提示词的内容,利用 llmend 关键字标记结束 LLM 函数的定义。
llm 函数书写不需要缩进,这是为了阅读以及提示词管理的非歧义/便利性,确保所有非顶格书写的空格都可以正常被作为提示词的一部分被送入ai调用过程。
llm 函数的调用方式与普通函数的调用方式基本上一致:
str chinese_text = "编程让世界更美好"
str english_text = 翻译(chinese_text, "English")
print("原文: " + chinese_text)
print("翻译: " + english_text)
上述代码最后会输出 "Programming makes the world a better place."
总体来说,llm 函数的存在允许你定义更复杂、更多样化的 llm 调用方式,也允许你进行更复杂的提示词内容构建。
意图注释
llm 函数自身的定义不变,利用意图注释注入额外约束
@ 所有英文回复信息都采用大写字母
english_text = 翻译(chinese_text, "English")
上述代码最后会输出 "PROGRAMMING MAKES THE WORLD A BETTER PLACE."
prompt 系列协议
IBC-Inter 并不仅仅支持使用 str 类型的变量来和 llm 进行交互。其中内置了三个关键的协议,理论上来说,我们允许任何设计良好的自定义类无缝且自然地与 llm 进行信息交互:
- 输入机制:
__to_prompt__
当变量作为参数被送入 LLM 调用过程时,IBC-Inter 通过 __to_prompt__ 协议将变量转换为提示词的一部分。
str name = "Alice"
str greeting = @~ 用 $name 打个招呼 ~
name 对应类型的 __to_prompt__ 会被调用,结果作为提示词的一部分。对于str来说,基本上就是直接把原文送入。
- 输出约束:
__outputhint_prompt__
每个类型可以定义 __outputhint_prompt__ 方法,用于描述期望的 LLM 输出格式。该约束会被注入到系统提示词中。
int result = (int) @~ 1+1等于几?只答数字 ~
int 的 __outputhint_prompt__() 会提供类似于: "请只返回一个整数,如: 42" 这样的内容,并由解释器注入到 llm 的提示词中作为约束
- 输出解析:
__from_prompt__
LLM 返回后,IBC-Inter 通过 __from_prompt__ 方法将原始文本解析为目标类型。
func __from_prompt__(str llm_result):
int result = llm_result.to_int()
return result
__from_prompt__ 与 __outputhint_prompt__ 是紧密相关的,后者的约束决定llm是否能够提供所需的数据,前者的逻辑则决定相关结果能否被稳健地处理并转化为内存中的变量数据。
*注:从含义上来说,__from_prompt__ 这个命名其实不合适,但目前为了总体协议命名的结构统一,暂时这样用。
行为描述与控制流
str input_text = "今天天气真不错!"
print("输入文本: " + input_text)
if @~$input_text 是否包含积极情绪?~:
print("检测到积极情绪!")
else:
print("未检测到积极情绪")
IBC-Inter 通过对 bool 类进行 __prompt__ 系列协议的建模,让行为描述语句能够和流控语句进行紧密结合。其设计思想其实非常简单:
通过 bool 的 __prompt__ 系列协议,结合IBC-Inter的解释器设计,在 if/elif/for 等语句中,强制要求模型”只能返回0或1“,就可以让模型的回复能够指导后续 if/elif/for 等语句的继续运行。
自愈机制
IBCI 引入了 llmexcept 关键字专门处理 AI 调用产生的非确定性错误(如解析失败、逻辑模糊):
int result = (int) @~ 1 + 1 等于几?只答数字 ~
llmexcept:
print("AI 响应无法解析为整数,正在重试...")
retry "请务必只返回一个纯数字,不要带标点"
当一个特定变量的 __from_prompt__ 方法未能成功把 llm 的输出转化为相关变量的内存数据时,就会由 IBC-Inter 的解释器逻辑触发后续紧跟着的 llmexcept 的代码内容。 retry 中的内容会作为额外系统提示词被注入到 LLM 调用中,其优先级高于用户提示词。
这种设计允许 llm 调用能够通过 llmexcept 机制进行可控重试,并利用额外的提示词注入尝试进行逻辑自愈,从而对抗 llm 输出的一些不确定性。
结语
书写到这里,文章内容已经足够冗长,IBC-Inter 这门语言中那些用来和 llm 进行交互的最核心的机制也都基本上介绍完毕。其实还有很多”小巧思“以及未来的”大饼“没能够写完:
比如被设计用来进行稳定自我演进的机制——”动态宿主“,允许一段 IBC-Inter 代码直接启动一个全新的 ibci 代码的编译和运行过程,允许一个 ibci 代码文件在运行过程中被 llm 动态地创建出来,然后实时地主动创建一个全新的隔离解释器实例,停止当前代码的运行,打下断点保存所有环境上下文,并彻底跳入新的 ibci 代码脚本进行运行。
再比如用来进行功能扩展的非侵入式插件系统,IBC-Inter的内核会嗅探目标目录可能存在的 plugins 文件夹,允许任何用户直接使用python为ibc-inter带来更多自定义能力,允许直接用python简单地书写一个 IBC-Inter 的”自定义内置类“,同时不需要显式地继承任何直接来源于 IBC-Inter 的核心模块。
等等等等。
人总会是想要把自认为有趣的东西 —— 特别是自己做的东西 —— 都一股脑地倒出来。但作为博客来说,到这里应该适可而止了。对于那些对这个项目开始有些兴趣的人们,很欢迎和我进行进一步的交流,甚至参与到构建过程中来。
至此,真的非常感谢你耐心看完了全程,听我絮叨完了这样一个稚嫩的实验项目。(鞠躬)
*最后的注意事项: IBC-Inter 是一个个人项目,而且本质上来说是一个 Vibe Coding 项目。虽然作者通过人在回路以及强架构约束的方式尽全力控制代码质量,但截至目前的开发已经开始让我有些猪脑过载,到了一种不得不先发出一个 MVP Demo 然后给自己放个假的阶段,于是才有了现在这篇博客。目前,代码中必然存在大量问题,甚至还有很多已知 bug 没有进行修复。在此,提前致歉,还请见谅。
