应该是最“极简”的 LLM 工具调用了:你写的函数、类对象就是工具,不用学任何新东西 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
pmpmp
V2EX    程序员

应该是最“极简”的 LLM 工具调用了:你写的函数、类对象就是工具,不用学任何新东西

  •  
  •   pmpmp 2 天前 843 次点击

    兄弟们,我又来了。前两天发了个帖子《 MCP 到底是个什么鬼?》,没想到对大家有点小帮助,非常开心。

    用 LLM 的时候,工具调用确实是一个很烦的事情(它不难,就是很繁琐),要么你在某个框架里面,把你的工具封装成 MCP 服务,要么你在某个框架里面用它的机制包装(比如加一个装饰器 @tool ),五花八门。

    有没有简单一点的办法呢?有的,比如最近的 lang 家的 deepagents 里面的方式就已经接近优雅了,它可以让你直接使用自己写的函数,函数(工具)本身你想怎么写怎么写,但是,他又搞了个 middleware 的 tool ,看着又很反直觉了,又得学怎么搞,本来挺清爽的,又搞复杂了。

    好麻烦,不就是给 LLM 传工具么?为什么来来回回搞得这么复杂呢?有必要么?

    于是,我前两天更新了一下我的库 :chak ( https://github.com/zhixiangxue/chak-ai ),就干一件事情:让你自己写的函数、对象,都能传给 LLM ,让它当工具用,而你不需要写任何额外的东西,连 @tool 这样的装饰器都不需要,就像这样:

    # 这个函数你该怎么写就怎么写,不需要很麻烦的封装成什么 MCP Server ,不需要加装饰器,不需要任何植入 def get_weather(city: str) -> str: """查询城市天气""" return requests.get(f'xxxx.com?city={city}').text cOnv= chak.Conversation("openai/gpt-4o", tools=[get_weather]) # 直接把函数传进来就行了 respOnse= conv.send("北京天气怎么样?") 

    或者这样:

    from pydantic import BaseModel, Field class UserInput(BaseModel): name: str = Field(description="User's full name") email: str = Field(description="User's email address") age: int = Field(description="User's age") class UserOutput(BaseModel): id: int name: str status: str = "active" # 你的工具的输入输出只要是可以序列化的就行,不必是简单类型,也不需要装饰任何东西 def create_user(user: UserInput) -> UserOutput: """Create a new user""" return UserOutput(id=123, name=user.name, status="active") cOnv= chak.Conversation( "openai/gpt-4o", tools=[create_user] # 直接传进来 ) respOnse= await conv.asend("Create a user: John Doe, [email protected], 30 years old") 

    如果你喜欢把工具封装到一个类里面(这很常见对吧),你传给 LLM 一个对象也是可以的,Chak 会帮你保持对象的状态,调用完成后,你的对象甚至是带有状态更新的,相当于你可以喂给 LLM 一个你的工作流,而这个工作流就是一个普通的对象,像这样:

    # 定义一个购物车 class ShoppingCart: def __init__(self): self.items = [] self.discount = 0 def add_item(self, name: str, price: float, quantity: int = 1): """Add item to cart""" self.items.append({"name": name, "price": price, "quantity": quantity}) def apply_discount(self, percent: float): """Apply discount percentage""" self.discount = percent def get_total(self) -> float: """Calculate total price""" subtotal = sum(item["price"] * item["quantity"] for item in self.items) return subtotal * (1 - self.discount / 100) cart = ShoppingCart() cOnv= chak.Conversation( "openai/gpt-4o", tools=[cart] # 直接把这个对象作为工具 ) # 让 LLM 帮你在这个购物车里面做一些操作 respOnse= await conv.asend( "Add 2 iPhones at $999 each, then apply 10% discount and tell me the total" ) # LLM 折腾完了之后,你的购物车里面的数据就更新了,你都不需要解析什么 LLM 的输入(因为很多时候 LLM 输出的 Json 未必准确,有各种乌七八糟的问题),chak 自动帮你把这事情干完了 print(cart.items) # [{'name': 'iPhone', 'price': 999, 'quantity': 2}] print(cart.discount) # 10 print(cart.get_total()) # 1798.2 

    所以,“工具调用非得用 MCP 、学 MCP 吗?” 其实大可不必(当然 Chak 也是支持 MCP 的,用起来也非常简单)

    让 LLM 可以调用工具,就应该这么简单才丝滑,对吧...

    最后说两句

    工具调用本应该是助力 LLM 变得更强的,现在很多时候成了开发者的负担。如果你也烦透了这事,真心可以试试 chak:它把这些破事都打包了,你只管写业务代码,非常轻量级,依赖非常少。

    项目地址: https://github.com/zhixiangxue/chak-ai

    各位帮忙使用一下,好用的话帮我点个啊,随时提 bug 、issue ,感谢~

    1 条回复    2025-11-28 10:42:50 +08:00
    GoldenMan
        1
    GoldenMan  
       1 天前   1
    很妙的想法,已 Star
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     814 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 17ms UTC 20:54 PVG 04:54 LAX 12:54 FK 15:54
    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