🔌 第9章 基于MCPServer的生活类智能体应用
📄 一句话概括

一句话里四个条件:附近、空闲、快充、还要充四十分钟。 拆这一步是模型的活,工具只负责按参数筛。参数没按文档填,筛出来就是错的。 「够不够充」要算,不能让模型心算——而算得准不准,取决于工具给不给功率。

📝 本章和前面几章的关系

这是第 9 章最后一个案例,它把前面几个的技巧合在一起:坐标、半径、类型、布尔筛选。 也多了一个新问题:结果还要再算一步。 教材这一节的重点在「参数必须按文档填」,这一节补上「算这一步交给谁」。

一、一句话里四个条件

「附近有没有空闲的快充桩,我这车还要充四十分钟」。 四个条件:附近(坐标加半径)、空闲(空闲数大于零)、快充(类型等于快充)、 四十分钟(用来算够不够)。 前三个是筛选条件,第四个是计算条件。 这两类要分开处理:筛选交给工具,计算交给代码。

拆这一步是模型的活。工具如果只收「城市」这一个参数,「附近」这两个字就白说了。 所以工具的参数字段,决定了模型能表达多细的需求。这是设计工具时第一个要想的。

二、参数要按文档填,不能想当然

演示里三种筛法层层收窄:不限四个、三公里内一个。 参数名、单位、取值范围都得按接口文档来。半径传 3 还是 3000,差一千倍。 布尔参数也容易错:有的接口要 free_only=true,有的要 status=idle,有的干脆没有这个参数, 得自己过滤。

所以接一个新 Server 的第一件事,是把它的参数文档读一遍,别照着感觉填。 教材这一节反复强调的就是这一点(界面操作本沙箱不执行)。判据是:同一个问题问两遍,返回的条数一致。

三、「够不够充」这一步交给谁

演示里剩下的那个桩:快充、八个位子空两个、955 米。 四十分钟能补多少电?这一句必须算,不能猜。 算需要两个数:功率、时间。时间用户给了,功率得工具给。

演示里按「每分钟一度」粗算,得四十度。这个数是粗算,因为手头没有真功率。 所以正确的做法是:让工具返回功率,让代码算,别让模型心算。模型心算 40 乘 60 除以 60 也可能错, 而且错了你看不出来。

四、七个案例收尾:三个通用结论

第一,工具数量不重要。 七个案例里六个只有一个工具,照样叫智能体。 第二,参数从哪来决定了智能体的形状。 从定位来、从申请来、从上一句推来,三种形状完全不同。 第三,能算的别让模型算。 距离、合计、够不够,全是代码的活。

这三条在下一章三个效率类案例里还会出现,只是换了个题材。 教材这一章到这里结束。下一章换到「要写数据」的场景,那才是真正需要确认框的地方。

五、动手 Demo:充电桩:三个条件一起筛

一个工具收半径、类型、是否只看空闲,四种筛法各跑一遍。 然后拿剩下的那个算「够不够充四十分钟」,看这一步为什么不能交给模型。 坐标是假定的,距离是真算的(球面距离公式)。

s = Server('charger-mcp')
s.add(Tool('charger.find', '按坐标、半径、类型、是否只看空闲找充电桩',
           schema({'radius': dict(prop('integer', '半径,米'),
                                  maximum=20000),
                   'type': prop('string', '快充或慢充'),
                   'free_only': prop('boolean', '只看有空位的')}, []),
           fn))

for args in [{}, {'radius': 3000},
             {'radius': 3000, 'type': '快充'},
             {'radius': 3000, 'type': '快充', 'free_only': True}]:
    print(len(call(s, 'charger.find', args)['items']), args)

实跑输出:

--------------------------------------------------------------------
充电桩:三个条件一起筛
--------------------------------------------------------------------


  ① 用户的一句话里有三个条件
  --------------------------------------------------------------------
  用户:附近有没有空闲的快充桩,我这车还要充四十分钟

| 条件 | 来自哪几个字 | 变成什么参数 |
|---|---|---|
| 附近 | 「附近」 | 坐标加半径 |
| 空闲 | 「有没有空闲」 | 空闲数大于零 |
| 快充 | 「快充」 | type 等于 快充 |
| 四十分钟 | 「还要充四十分钟」 | 时长,用来算够不够 |

  三句话拆成四个参数。【拆这一步是模型的活,工具只负责按参数筛。】
  如果工具只收「城市」这一个参数,那「附近」这两个字就白说了。

  ② 一个工具,四种筛法
  --------------------------------------------------------------------
四种筛法各跑一遍,看结果怎么收窄:

| 筛法 | 剩几个 | 分别是 |
|---|---|---|
| 不限 | 4 个 | 西湖文化广场站、城站充电场、滨江宝龙站、宜昌东站 |
| 半径 3 公里 | 1 个 | 西湖文化广场站 |
| 再加只看快充 | 1 个 | 西湖文化广场站 |
| 再加有空位 | 1 个 | 西湖文化广场站 |

  【每加一个条件,候选就少一批】——这就是「一句话里条件多」时的正确做法:逐条筛,别一次猜完。
  这次只有 4 条数据,所以只有第一次筛掉了 3 个,后面三次都没再少。
  真机上几百条数据,才看得出层层收窄。

  ③ 剩下那个,够不够充四十分钟
  --------------------------------------------------------------------
  西湖文化广场站:快充,8 个位子空着 2 个,955 米
  四十分钟能补 40 度电(按每分钟 1 度粗算)
  这个数只是个粗算。真接口会给功率,用功率乘时间才准。这里没测出真功率,所以标的是「粗算」。
  但结构是对的:【「够不够」要算,不能靠模型猜。】 让工具返回功率,让代码算,别让模型心算。

  ④ 七个案例到这里收尾
  --------------------------------------------------------------------

| 案例 | 工具数 | 要不要串联 | 难点在哪 |
|---|---:|---|---|
| 旅行规划 | 3 | 要 | 参数来自上一步 |
| 约会助手 | 3(跨 3 个 Server) | 要 | 合并后工具表变长 |
| 天气预报 | 1 | 不要 | 查不到时怎么答 |
| 附近餐厅 | 1 | 不要 | 排序依据没说清 |
| 航班查询 | 1 | 不要 | 多一道要 Key 的流程 |
| 龙虎榜 | 1 | 不要 | 数值排序与免责 |
| 充电桩 | 1 | 不要 | 一句话里四个条件 |

  七个案例,六个都只有一个工具。「智能」不在工具多,在怎么用工具。
  下一章换题材:三个个人效率类,共同点是都要写数据。

①第一张表四行,前三行是筛选、第四行是计算。这两类要分开处理。 ②第二段四种筛法:四个、一个、一个、一个。这次数据只有四条,所以只有第一次筛掉了三个。 ③第三段剩下那个桩离你 955 米,八个位子空两个。这些数都是算出来的,不是估的。 ④第四段那句「每分钟一度是粗算」是必须标的——没测出真功率,就不能写成结论。 ⑤最后那三条通用结论是整章的收尾,下一章换题材还会用到。

30 秒实验

  1. 把半径改成 1500,看还剩几个。算一下你常去的地方到最近充电桩有多远。
  2. 给工具加一个「功率」字段,把粗算换成真算。
  3. 想想「还得等多久」这个问题,该由工具答还是由模型算。

常见误区

  1. 「参数名差不多就行。」半径传 3 还是 3000 差一千倍。接新 Server 先读文档。
  2. 「四个条件让模型自己合起来想。」四个条件要拆成四个参数,逐条筛,别一次猜完。
  3. 「让模型算一下够不够充。」它会算错,而且错了看不出来。让工具给功率,代码算。
自测三问(点开对答案) 1. 一句话里四个条件,哪些是筛选、哪些是计算? —— 附近、空闲、快充是筛选;四十分钟够不够是计算。筛选交工具,计算交代码。 2. 为什么接新 Server 要先读参数文档? —— 参数名、单位、取值范围都不一样。半径传 3 还是 3000 差一千倍,错一次筛出来全错。 3. 「够不够充」为什么不能让模型算? —— 它会算错,而且错了看不出来。让工具返回功率,代码算。

生活类七个案例到此结束。下一章三个效率类,共同点是都要写数据——确认框从这一章开始变成必需品。

相关笔记