TFLPrompt设计思路¶
问题背景¶
基于DSL相关能力,最早的实现是将DSL能力封装成一个DSLTool实现,用户可以将目前已经存在的工具添加到DSLTool中进行纳管进而使其具备脚本调用的能力。
但经过一段时间的实践(2025/4-2025/5),这样做可以实现相关能力,但在使用的便捷性上不足,而且配置上内容产生干涉。比如以下情况:
- 需要手动在LLM中配置DSLPrompt方可启用。
- 同时需要手动维护一个可用的DSLTool保证传入到已经启用DSL的LLM上下文中,否则会抛出异常,因为LLM希望使用DSL能力,但目前上下文中没有可用的DSL工具。
- 基于如上两点,我们不得不封装一个支持DSLTool的Drive(MarkIII-目前已经被标记Deprecated),因为需要尽可能自动化地在不同LLM之间传递DSLTool。
基于以上问题,其核心矛盾是一旦利用工具封装来实现DSL能力,对于大模型的配置->工具调用解析->工具分配->工具执行,这就产生了耦合,因为这个DSLTool是复杂工具,它还可以关联其它工具,这带来了很大的维护成本与配置成本,而且配置之间容易产生干涉(从语法上判断不出问题,而在执行时会生成上下文的混乱)。
设计优化¶
基于如今面临的背景问题,经过五一假期的思考,有如下结论:
- DSL本质上是对工具调用的组织与编排,而这种对编排的解析实现,是通过Interpreter来实现的,而之前的设计是将Interpreter集成到DSLTool这个Tool封装中去了。这样的好处是对整体代码结构影响很小,但缺点如上,对于所有与Tool耦合的地方,均有配置干涉风险。
- 既然是对Tool的编排,那对这个编排的解释执行最合适的地方是Drive或者Chain。其实从理论上来讲,最合适的应该是Drive,因为Drive本质上就是对Tools的管理,但如果放到Drive中,会面临一个问题,如果Procedure中,对工具的调用分散在多个Drive中应该怎么办?
- 最终,我们尝试将DSL的实现,放置到Chain中,因为Chain在拿到LLMResult后,本来就涉及到对工具调用的执行与回收,如此一来,这个过程与DSL过程本质上是一致的,非常像,放置在这个位置也算是合理。
故而有了当前的设计。
方案概述¶
- 我们将DSL语句作为与ToolCalls/FunctionCall平级的回应去对待。最终在LLMResult-Generation的封装里添加了一个独立字段 tfl_procedure。这个字段用于记录DSL编排脚本
- 在Chain中,获取到LLMResult后,与处理ToolCalls/FunctionCall类似,添加一个对于TFLProcedure的处理。
- 最终回收其结果,形成一个LLMTFLMessage作为下一条消息,但受限于目前各个厂商对于API格式要求不一,可能返回的时候消息类型会有一些变化,比如以User信息返回或者以其它角色消息返回。