Hello-Agents 跑 MCP/A2A 协作:模型 Key 用 TaoToken

发布时间:2026/9/17 19:47:36
Hello-Agents 跑 MCP/A2A 协作:模型 Key 用 TaoToken MCPTool 一挂上去filesystem 的工具就被展开成一串A2AServer 与 A2AClient 又要把 research→write 串成一次任务协商这两步都会把模型调用量放大。而决定它们能不能真发出去请求的是更靠前的那一行HelloAgentsLLM()。TaoTokenhttps://taotoken.net/?utm_sourcetaotoken_aicg_blog_end解决的就是这一行里的两件事Key 从哪来、Base URL 指向哪一次配好MCP 工具展开和 A2A 多智能体协作共用同一条模型通道。原文示例里agent.run(请读取 my_README.md 文件并总结其中的主要内容)看着朴素背后至少两次模型决策先判断调哪个工具、传什么参数拿到文件内容后再生成总结。这种请求密度下Key 散落在每个 A2AServer 里、Base URL 每个文件抄一份出问题是迟早的事。1. MCPTool 展开与 A2A 协商先把模型调用账算清1.1 filesystem 的每个工具背后都是一次模型决策原文那段代码最容易被低估的是agent.add_tool(fs_tool)。filesystem 服务器通过 MCP 暴露一堆能力Hello-Agents 会把它们展开成智能体可调用的独立工具。展开只是开始真正的开销在调用链上agent.run收到一句自然语言模型要先对照工具列表和描述决定调read_file还是先list_directory路径参数怎么填工具返回内容后模型再基于这段内容生成总结。一趟下来就是两次模型请求起步。如果 my_README.md 比较长中间还可能触发多轮工具调用或分段处理。工具数量越多、描述越相近模型在「选哪个」上的推理就越贵。这也是为什么单智能体时代那种「一个 Tool 类配一个 Key」的做法到 MCP 阶段会开始难受。1.2 research→write 把请求数按智能体个数乘开再看 A2A 那段示例researcher、writer、editor各起一个服务客户端依次execute_skill。原文里的 skill 函数是硬编码返回字符串目的是把协议跑通换成真实业务每个 skill 内部多半要调模型研究员做检索归纳撰写员根据素材成文编辑再润色一遍。三个智能体串一次流程模型调用三次起步协商重试还会更多。单体智能体时Key 写在一个地方还能忍。到了多智能体这一步如果每个 A2AServer 都自己实例化一次 LLM、各自填 Key 和地址改一次模型就要翻好几个文件Base URL 漏改一个报错信息还长得差不多定位成本直线上升。1.3 要统一的是 LLM 接入层不是协议本身这里必须分清边界MCP 管的是智能体与工具/资源的标准化通信A2A 管的是智能体之间的对等协商ANP 管的是更大规模网络里的服务发现。这三层协议各有各的规范不该动、也不用动。需要统一的是它们底下那层模型通道。MCPTool展开出的工具由模型来选A2AServer的 skill 里要模型来生成内容它们最终都落到同一个 LLM 实例上。把这个实例的model、api_key、base_url收拢成一处配置MCP 和 A2A 就都不需要各自维护一份接入信息。这就是 TaoToken 在这套架构里的位置统一 API、兼容通道只替换接入层不改协议。2. HelloAgentsLLM 初始化base_url 指向 https://taotoken.net/api2.1 先去落地页把 Key 和模型 ID 拿准原文示例里HelloAgentsLLM()是空括号这在跑演示时没问题一旦接真实服务就必须补参数。补之前先做两件事注册、创建 API Key、确认要用的模型 ID。打开 TaoToken 注册账号在控制台创建一把 API Key先复制到本地安全的地方。然后进模型广场挑一个你要用的模型把它的 ID 原样抄下来。这一步别凭印象写模型名模型广场上是什么就填什么列表会更新以当时看到的为准。提示Key 只创建一次、只填一处。后面写进代码里的 Key 一律用YOUR_API_KEY占位不要把真 Key 提交到 Git。2.2 一份可复制的 HelloAgentsLLM 配置把参数显式传给HelloAgentsLLM是最不容易出错的方式。下面这段只有三个值需要你替换模型 ID 换成模型广场上抄来的那个Key 换成刚创建的Base URL 保持不动。import os from hello_agents import HelloAgentsLLM llm HelloAgentsLLM( modelYOUR_MODEL_ID, # 以模型广场当时列表为准 api_keyYOUR_API_KEY, # 在落地页控制台创建 base_urlhttps://taotoken.net/api, # 末尾不要加 /v1 ) print(llm.chat(用一句话说明你已就绪))有两个细节容易错。第一base_url只能是https://taotoken.net/api末尾不要拼/v1也不要把官网落地页那种带查询参数的地址填进来填进工具和代码里的就是纯接口地址。第二HelloAgentsLLM的具体参数名和方法名会随版本略有差别chat还是invoke以你本地安装的版本为准但base_url这一项的含义是固定的。如果项目里习惯用环境变量统一管理可以自己在.env里定义三个变量名再读进来。变量名叫什么是你项目的事框架只认传进去的值import os from dotenv import load_dotenv from hello_agents import HelloAgentsLLM load_dotenv() llm HelloAgentsLLM( modelos.environ[HELLO_AGENTS_MODEL], api_keyos.environ[HELLO_AGENTS_API_KEY], base_urlos.environ[HELLO_AGENTS_BASE_URL], )对应的.env内容HELLO_AGENTS_MODELYOUR_MODEL_ID HELLO_AGENTS_API_KEYYOUR_API_KEY HELLO_AGENTS_BASE_URLhttps://taotoken.net/api2.3 为什么不让每个服务自己 new 一个 LLM有人图省事在researcher、writer、editor各自的 skill 函数里都写一遍HelloAgentsLLM(...)。跑得通但维护会很难受换模型要改三处Key 轮换要改三处某一处base_url少写一个字符你会看到「只有某一个智能体失败」这种诡异现象。更稳的做法是把配置抽成一个字典或者一个构造函数skill 内部统一从它取。这样 MCP 工具调用和 A2A 协作走的是同一个模型入口排障时只需要确认一个地方。下一节就先从 MCP 这条线验证。3. 文件系统 MCPTool 验证从 MCPClient 裸连到 SimpleAgent3.1 先用 MCPClient 确认 server 起得来这一步不花模型额度纯粹验证 MCP server 能不能被拉起、工具能不能列出来、文件能不能读到。原文的顺序是先连服务器再看工具这里把根目录抽成变量方便你换成自己的目录。import asyncio from hello_agents.protocols import MCPClient async def inspect_filesystem_server(): client MCPClient([ npx, -y, modelcontextprotocol/server-filesystem, ., # 根目录换成你要暴露给智能体的目录 ]) async with client: tools await client.list_tools() print(工具数量:, len(tools)) content await client.call_tool(read_file, {path: my_README.md}) print(content) asyncio.run(inspect_filesystem_server())跑之前确保当前目录下确实有my_README.md也确保本机装了 Node 和 npm——filesystem server 是通过npx拉起来的子进程npx不在 PATH 里就会直接失败。这一步跑通说明 MCP 侧没问题剩下的就是模型侧。3.2 再挂到 SimpleAgent 上让模型真的去选工具工具列表能列出来不等于模型会用。接上第 2 节的llm把 MCPTool 加到 SimpleAgent 上跑一次完整的工具选择与总结from hello_agents import SimpleAgent from hello_agents.tools import MCPTool from llm_config import llm # 第 2 节里那份 HelloAgentsLLM 配置 agent SimpleAgent(name文件助手, llmllm) fs_tool MCPTool( namefilesystem, description访问本地文件系统可读取与列出指定目录下的文件, server_command[npx, -y, modelcontextprotocol/server-filesystem, .], ) agent.add_tool(fs_tool) answer agent.run(请读取 my_README.md 文件并总结其中的主要内容) print(answer)这里能观察到 MCP 的一个关键特性add_tool之后filesystem 的能力被展开成多个独立工具模型看到的是一份工具清单而不是一个笼统的「文件系统」入口。工具描述写得越清楚模型选错的概率越低。description这一栏别敷衍它直接参与模型判断。3.3 这一步容易撞上的几个报错401 或认证失败多半是api_key没传进去或者走环境变量时.env没被加载。先在同一个进程里打印一下llm的配置对象确认 Key 不是空字符串。Key 统一从 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建别混用别处的。404 或找不到接口检查base_url。写成https://taotoken.net/api/v1会多一层路径把带查询参数的落地页地址填进代码同样不对。正确值就是https://taotoken.net/api一个字符都不要多。模型不存在模型 ID 抄错或拼了随意的日期后缀。回到模型广场用当时列表里的 ID 覆盖掉。MCP server 起不来先在普通终端里手动执行一遍npx -y modelcontextprotocol/server-filesystem .看看是 Node 版本问题、网络问题还是根目录路径问题。这一步和模型无关别往 Key 上找原因。4. A2A 三智能体researcher、writer、editor 共用一套通道4.1 A2AServer 只负责协议模型从统一入口取原文的 A2A 示例起三个服务、定义三个 skill思路可以照搬区别在于 skill 内部要真的产出内容时从哪拿 LLM。把配置收到一个地方每个 skill 用同一个入口构造模型实例import threading, time from hello_agents import HelloAgentsLLM from hello_agents.protocols import A2AServer, A2AClient LLM_CONF dict( modelYOUR_MODEL_ID, # 以模型广场当时列表为准 api_keyYOUR_API_KEY, # 从落地页控制台创建 base_urlhttps://taotoken.net/api, # 不带 /v1 ) researcher A2AServer(nameresearcher, description负责检索与素材整理) writer A2AServer(namewriter, description负责根据素材成文) researcher.skill(research) def do_research(topic: str) - str: llm HelloAgentsLLM(**LLM_CONF) # 方法名以你安装的 Hello-Agents 版本为准 outline llm.chat(f围绕「{topic}」列出 5 个可展开的要点只输出列表) return str({topic: topic, findings: outline}) writer.skill(write) def write_article(payload: str) - str: llm HelloAgentsLLM(**LLM_CONF) return llm.chat(f根据以下素材写一段 200 字左右的短文\n{payload})注意这里改变的只有 LLM 的接入参数。A2AServer的任务生命周期、skill 注册方式、客户端调用协议都保持原样——协议层不动是这套做法能成立的前提。4.2 A2AClient 串起 research→write 的验证姿势服务用线程拉起来后客户端按顺序调用两个 skill把研究结果直接喂给写作threading.Thread(targetlambda: researcher.run(port5000), daemonTrue).start() threading.Thread(targetlambda: writer.run(port5001), daemonTrue).start() time.sleep(2) researcher_client A2AClient(http://localhost:5000) writer_client A2AClient(http://localhost:5001) research researcher_client.execute_skill(research, AI 在医疗领域的应用) article writer_client.execute_skill(write, str(research)) print(article)看到最后打印出成段文本就说明两件事同时成立A2A 的任务协商链路通了两个智能体背后的模型通道也都指向了同一个base_url。如果第一个 skill 成功、第二个失败优先怀疑的是调用链传参而不是通道——因为配置本来就共用一份。4.3 端口与并发的两个小坑5000 端口在部分系统上会被别的服务占用服务起不来时先把端口换掉再判断。另外time.sleep(2)只是示意机器慢的时候服务还没监听就发请求会直接连接失败稳妥点可以改成轮询探测端口。还有一点A2A 的价值在于点对点协商不是把所有智能体塞进一个进程。多个 skill 并发调模型时统一通道的好处会更明显——你不会因为并发导致某个服务的 Key 参数被覆盖。5. 跑通之后对账、换模型以及下一步5.1 去控制台确认这次调用有没有记上MCP 读文件和 A2A 生成内容各跑一遍之后回到 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 的控制台看用量记录。重点确认两件事请求有没有正常计入模型 ID 是不是你填的那个。如果用量为空但本地又打印出了结果那说明你的base_url可能还在指向别的地方检查一下配置是否真的生效了。这个动作值得养成习惯。多智能体场景下请求量比单智能体大得多早一点看到用量曲线比月底才发现异常要划算。5.2 换模型时只改一个字段这一节其实是对前面所有配置的回报。想换模型只改LLM_CONF里的model或者.env里那一行MCP 工具列表、A2A 的 skill 定义、客户端调用代码全都不用动。工具描述和模型能力是否匹配需要重新观察但代码层面就是一行的事。反过来说如果哪天你发现换模型要改三四个文件那说明通道还没收拢干净回去把配置入口统一掉。5.3 协议还在早期先把通道跑稳MCP 生态相对成熟A2A 有明确的规范推进ANP 还需要时间。这个阶段最划算的投入不是自己造一套协议实现而是把现有的示例跑通、把模型通道固定下来让后续换模型、加智能体、接新 MCP server 时不用重复折腾接入信息。想先用同一把 Key 试一条消息可以去 模型对话 确认模型和地址没填错如果准备把多智能体协作长期跑在本地开发流程里看一下 Coding Plan 的额度是否够用需要再创建一把独立的 Key给别的项目用时入口在 控制台 API Keys。把这三步走完Hello-Agents 里 MCP 工具展开和 A2A 任务协商的模型通道基本就不会再成为你调试多智能体时的干扰项了。