一些使用 gptel-tools 的经验

最近一直在针对自己的使用场景配置 gptel,写了一些 gptel-tools,分享一下自己的使用经验。

先说一下不适合使用 tools 的场景。一般来说,如果 LLM 不需要用户返回结果,就不要用 tools,比如我之前一直在用的:

我现在就觉得不太好用,也不知道是不是我 prompt 的原因,涉及到调用 tools 的时候,LLM 智商都不太高 :rofl:,很容易瞎 / 不调用 tools,所以能不用 tools 就不用 tools。

这种情况完全可以自己用 gptel-request 糊一层胶水处理返回的消息。

一些需要用户返回信息的例子就是 fetch 类的 tools,其中我觉得比较好用的是这个 read-documentation。不知道是不是 elisp 训练量没有特别大,LLM 很容易瞎编函数。如果在 prompt 里面加入 “You should actively read the documentation in Emacs to check your code." 之类的字眼配合这个 tool,LLM 就会自动读 Emacs 的文档看这次的主要函有没有调用对。

另一类我觉得可以发掘潜力的是 debug 类,大概就是执行程序 + 返回 debug log 让 LLM 去 debug,不过我没太去深究这部分。

然后关于写 tools 方面,最好把 tools 写成场景化的大函数,然后自己在 elisp 里面拆分逻辑。这样做主要是,LLM 似乎不太会链式调用 tools,比如说有 get_project_rootlist_directory 这两个 tools,我告诉 LLM 可以用 get_project_root 来获取项目根目录,然后再递归地用 list_directory 来获取整个项目的结构,但它就不会调 :melting_face:

这时候最好写一个 get_project_tree 的大 tool,再在 elisp 里面自己拆分逻辑。不要一下子拆成 get_project_root list_directory 两个 tools。

关于模型方面,我觉得比较好的是 Gemini 2.5 Pro,Gemini 2.0 Flash 会频繁瞎调 tools。


一些题外话:

  • 为了用 LLM,我改变了一些习惯。比如说我以前喜欢把文件都分得很细,现在基本把大功能都放在同一个文件,在里面再抽象,这样比较方便直接把 buffer 当 context 发出去。现在我 Emacs 配置都在一个 init.el 里面 :rofl:
  • 还在用 aider,但如果 gptel 功能都糊得差不多可能就弃了,感觉 aider 跟 Emacs 联动不太紧密。比如说我得告诉 aider 在哪个档案改哪个函数,感觉不如我 find-file 然后 gptel 顺手,但感觉 repomap 这个可以抄抄(Emacs 不也有内置 treesit)。
3 个赞

你可以看看这个api based小巧的项目 (无function calls/ tools或者说是自生成的tools)

一个简单的 python repl,分析任务后拆解成各个小任务,小任务变成python方法去执行,然后分析执行结果,再自己修正。不断循环直至完成任务或者超过上下文窗口。

目前缺点是它做啥都得先自己写个函数,单个任务时常有点慢,或许让它把之前执行成果后的函数过程cache下来会越来越好。由于它的运行时是python runtime而且它的系统指令又强调了这一点,一些终端执行的比较方便的/常见的命令,它倾向于输出指令让用户自己在终端执行,除非你坚持让它写个python方法去执行。

优点是效果跟模型能力强相关,没什么外部依赖/约束,它没有的知识可以通过互联网检索或者直接告诉它相关api信息,它自己就能玩得动。python 的生态丰富,而且训练预料又多,许多模型对python都非常友好。


PS: 我简单试过把它改成 emacs lisp runtime,任务规划很好,但是 emacs lisp 生态跟 python 差远了,而且 emacs lisp 语料也少,大模型一次写成 lisp 效果不太行。

1 个赞

用aider.el或者aidermacs的话, find-file打开buffer后,很多命令都是会自动把文件加进context的,或者手动加C-c a f.

原来如此,我一般用 aider 都是纯粹在那个聊天窗口用,所以我一般都是在手动 add file(如果 git 里面没记录),然后跟它说 “In xxx, create a function named yyy, …” ,我比较嫌弃这个啰嗦过程 :melting_face:

不过我现在觉得完全用 gptel 放弃 aider 有点在重复造轮子,完全可以写一些自用胶水让它们联动更紧密。

如果你想In xxx, create a function named yyy 的话, 启动aider session, 打开xxx文件, 在你想加函数的地方写一行注释, 比如

// create a function named yyy, do zzz

然后光标在这行注释上C-c a i 触发aider-implement-todo, aider就会根据你在注释里面的需求在那个位置生成你要的函数.

如果你想修改某个已经有的函数, 把光标放在那个函数里, C-c a r 触发aider-function-or-region-refactor, 输入修改要求, aider就会修改那个函数.

1 个赞