LLM拥有很强的自助能力,可以自主判断是否使用工具,使用什么工具。一般来说,工具可以是函数,也可以是外部的MCP 服务,根据最新的资料,也可以是Claude code中的skill。函数通常是自定义的,使用token量不大,MCP会消耗大量的token,上下文较多,skill是新的技术,比较灵活,只获取description部分,必要时才进一步加载内容,消耗降低了很多。
这里的工具,类似之前software时代的开发插件、报表控件,可以扩展LLM的能力。Tool的返回结果会作为上下文传递给LLM,供后续使用。对于Tool Use来说,一个比较重要的特性是条件使用,LLM需要智能的判断什么时候使用Tool,什么时候调用自己的知识库,甚至使用RAG来获取更多资料。这个对LLM的要求能区分什么需求是静态的(可内化),什么需求是动态的(需求外)。
对于更复杂的需求,可以通过多个Tool Use 的串联,来形成工作流进行处理。Tool Use可以超越LLM的知识边界,实现复杂逻辑。当然,Tool Use 也可以封装到agent里,再抽象一层,最外层的LLM 只处理agent,具体的工作由各个agent 来调用Tool Use 或者agent的LLM节点来处理。
在Tool Use的早期,需要在提示词中明确:FUNCTION *** 来手动调用,现在随着LLM能力的增强,已经不需要手动明确了。只需在system prompt中对LLM明确告诉模型有哪些工具可用,如果需要调用某个function,应该如何格式化其输出。function 是可以带参数输入的,提示词和 LLM 的输出需要包含参数信息。函数执行的结果会作为新的上下文,送回给模型,让它继续推理或生成最终答案。
Andrew Ng团队开源了一个AI Suite 库,简化的封装了各个不同的LLM,提供了一个抽象层,可以自动处理工具描述,极大简化了开发流程。 当 函数传入 tools 参数后,AI Suite 会在后台自动为其生成一个 JSON Schema。这个 Schema 是传递给 LLM 的真实数据结构。需要注意的是,定义function时,要是一个带有清晰 docstring 的 Python 函数。
如果说有过多需要自定义的琐碎代码,影响节点的灵活性时,可以让LLM自己来创建function,在处理时有如下两个要点:1)指令模型:“编写代码来解决用户的问题”。 2)要求模型将答案以 Python 代码形式返回,并用 <execute_python> 和 </execute_python> 标签包裹。
LLM 自己创建的代码,可以通过python的exec()函数来执行,也可以通过沙箱等手段来执行。代码可以通过正则表达式来进行提取,执行结果作为上下文,传入下一个节点。如果执行失败,失败的log 一样作为上下文进行返回,LLM通过Reflection 来对代码进行调整,重新尝试一轮迭代。
在沙盒环境外运行由模型生成的任意代码是有风险的。安全的代码执行很重要,尤其涉及到对唯一数据源的删除、修改等操作。推荐使用Docker、E2B等沙盒环境,对代码进行有效隔离。
MCP 作为function的一种扩展,现在已经成为行业标准,以CS的结构,不光提供数据的获取,也提供更多的资源操作。使用时需要注意token的消耗,可能比比较大量。
CC的skill 是在此基础上,将server段迁移到了本地,并很大程度减少上下文token的一种优化。