1. 多智能体协作里,Prompt 为什么总在“打架”
如果你正在用 Python 编排多个 Agent,大概率遇到过这种场面:架构师 Agent 讲着讲着开始聊市场转化,产品经理 Agent 突然给你贴了一段数据库索引优化建议,安全专家 Agent 用起了卖萌语气。任务分发靠 if-else 硬编码,角色定义散落在十几个 py 文件里,改一句“请保持严谨”要重新部署整个服务。
这就是 MCP Prompts 想解决的问题。MCP(Model Context Protocol)把提示词从代码逻辑里抽出来,变成 Server 端可查询、可参数化、可版本化的“资源”。Client 不再自己拼字符串,而是通过标准接口向 Server 要一份带参数的提示词模板。对多智能体系统来说,这相当于给每个 Agent 发了一张“角色身份证”,中控 Agent 按任务类型去 Server 取对应人格,再注入上下文,分发下去。
它适合谁?适合已经在写 Python Agent 编排、被提示词管理折磨过的开发者;也适合刚接触 MCP、想知道 Prompts 原语到底怎么落地的人。下面我用一个“多角色专家咨询系统”的完整链路,把 MCP Prompts 的模板定义、角色切换、上下文注入、任务分发和验证步骤拆开讲,代码可以直接复制跑。
2. TaoToken 前置:给多智能体准备统一模型入口
多智能体系统最怕模型来源不统一。架构师 Agent 调一个模型,产品经理 Agent 调另一个,返回格式、上下文窗口、工具调用能力全不一样,编排层要写一堆适配代码。我的做法是先用 TaoToken 把模型入口统一掉,让所有 Agent 走同一个 Base URL 和 Key,编排层只关心角色和任务,不关心背后是哪个模型。
TaoToken 在这里的角色是“模型网关”:它提供 OpenAI 兼容的 API 接口,Python 侧用 openai 库就能直接调,不需要为每个模型写不同 SDK。对 MCP 场景来说,MCP Server 负责下发提示词模板,TaoToken 负责把模板送进模型,两边职责清晰。
你需要准备三样东西:API Key、Base URL、Model ID。Key 在控制台创建,Base URL 固定为https://taotoken.net/api,Model ID 按你实际要用的模型填。这三件套在后面的 settings 片段和 Python 代码里都会出现,先记牢。
创建 Key 的入口在控制台的 API Keys 页面,模型对话可以在模型对话页先试跑一轮,确认 Key 和模型都通。如果你后面要长期跑编码类 Agent,可以看 Coding Plan;只是验证角色切换,用按量调用就够。
注意:Base URL 填
https://taotoken.net/api,不要带多余路径。OpenAI 兼容库会自动拼/chat/completions,手动加路径会 404。
3. 可复制配置:MCP Prompts 模板与 Python 编排片段
这一节是核心,给你两份可直接复制的配置:一份是 MCP Server 侧的 Prompts 定义(Python),一份是 Client 侧的模型接入 settings(JSON/TOML)。路径和字段名保持和实际一致,你改掉 Key 就能跑。
先看 MCP Server 侧。它暴露一个expert_consultantPrompt,接受role和task_context两个参数,根据 role 返回不同的 system message。这就是“角色切换”的落地点——角色不是写死在 Agent 里,而是 Server 按参数动态生成。
# mcp_server.py import asyncio from mcp.server import Server from mcp.server.stdio import stdio_server import mcp.types as types server = Server("expert-persona-provider") PERSONA_CONFIGS = { "architect": { "title": "资深系统架构师", "focus": "关注高并发、低延迟、高可用,用分层视角描述方案。", "tone": "专业、严谨,多用技术术语,先给结论再给理由。", }, "pm": { "title": "高级产品经理", "focus": "关注用户痛点、转化率、MVP 原则,优先业务价值。", "tone": "有同理心、目标导向、表达简洁。", }, "security": { "title": "安全专家", "focus": "关注注入风险、权限边界、数据泄露面。", "tone": "谨慎、直接,先列风险再给缓解措施。", }, } @server.list_prompts() async def handle_list_prompts() -> list[types.Prompt]: return [ types.Prompt( name="expert_consultant", description="按指定专家角色生成带上下文的提示词", arguments=[ types.PromptArgument( name="role", description="角色名:architect / pm / security", required=True, ), types.PromptArgument( name="task_context", description="任务背景描述", required=True, ), ], ) ] @server.get_prompt() async def handle_get_prompt(name: str, arguments: dict | None) -> types.GetPromptResult: if name != "expert_consultant": raise ValueError(f"Unknown prompt: {name}") role = (arguments or {}).get("role", "architect").lower() context = (arguments or {}).get("task_context", "") cfg = PERSONA_CONFIGS.get(role, PERSONA_CONFIGS["architect"]) system_message = ( f"你现在扮演【{cfg['title']}】。工作重点:{cfg['focus']} " f"说话语气:{cfg['tone']} 只输出该角色视角下的建议。" ) user_message = f"任务背景:{context}\n\n请以该角色给出专业建议。" return types.GetPromptResult( description=f"{role} 角色提示词", messages=[ types.PromptMessage( role="assistant", content=types.TextContent(type="text", text=system_message), ), types.PromptMessage( role="user", content=types.TextContent(type="text", text=user_message), ), ], ) async def main(): async with stdio_server() as (read, write): await server.run(read, write, server.create_initialization_options()) if __name__ == "__main__": asyncio.run(main())再看 Client 侧的模型接入配置。如果你用 Cline 或类似支持 MCP 的客户端,settings 里要同时填 MCP Server 启动命令和模型三件套。下面这份 JSON 片段可以直接放进客户端配置:
{ "mcpServers": { "expert-persona": { "command": "python", "args": ["/path/to/mcp_server.py"] } }, "model": { "baseUrl": "https://taotoken.net/api", "apiKey": "sk-你的Key", "modelId": "你的ModelID" } }如果你用 Codex 的auth.json风格配置,等价写法是:
{ "base_url": "https://taotoken.net/api", "api_key": "sk-你的Key", "model": "你的ModelID" }三件套缺一不可:Base URL 决定请求打到哪,Key 决定能不能过鉴权,Model ID 决定用哪个模型。MCP Server 只负责给提示词,模型调用由 Client 侧完成,两边通过标准协议对接。
4. 验证请求:角色切换与任务命中率怎么测
配置写完,别急着上多智能体编排,先单点验证角色切换是否生效。我试过最省事的办法是写一个 Python 脚本,直接调 MCP Server 的get_prompt,把返回的 system message 打印出来,肉眼确认角色有没有切对。
# verify_prompt.py import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client async def main(): params = StdioServerParameters( command="python", args=["/path/to/mcp_server.py"], ) async with stdio_client(params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() for role in ["architect", "pm", "security"]: result = await session.get_prompt( "expert_consultant", {"role": role, "task_context": "设计一个高并发订单系统"}, ) print(f"=== {role} ===") for msg in result.messages: print(msg.content.text[:120]) print() asyncio.run(main())跑完你会看到三段不同的 system message:architect 强调分层和高可用,pm 强调用户痛点和 MVP,security 强调注入和权限。如果三段输出一样,说明 role 参数没传进去,检查arguments字段名是否和 Server 侧PromptArgument的 name 一致。
角色切换验证通过后,再测任务命中率。做法是准备 10 条任务描述,每条标注“应该由哪个角色回答”,然后让中控 Agent 按关键词或简单分类逻辑选角色,调 MCP Server 取提示词,再走 TaoToken 调模型,最后人工核对角色是否选对。命中率低于 80% 时,优先检查任务描述里的关键词是否覆盖了角色定义里的 focus 字段。
# dispatch_agent.py import asyncio from openai import OpenAI from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client client = OpenAI( base_url="https://taotoken.net/api", api_key="sk-你的Key", ) ROLE_KEYWORDS = { "architect": ["架构", "并发", "扩展", "性能"], "pm": ["用户", "转化", "需求", "MVP"], "security": ["安全", "注入", "权限", "泄露"], } def pick_role(task: str) -> str: for role, kws in ROLE_KEYWORDS.items(): if any(k in task for k in kws): return role return "architect" async def run_task(task: str): role = pick_role(task) params = StdioServerParameters(command="python", args=["/path/to/mcp_server.py"]) async with stdio_client(params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() prompt = await session.get_prompt( "expert_consultant", {"role": role, "task_context": task}, ) messages = [ {"role": "system", "content": prompt.messages[0].content.text}, {"role": "user", "content": prompt.messages[1].content.text}, ] resp = client.chat.completions.create( model="你的ModelID", messages=messages, ) print(f"[{role}] {resp.choices[0].message.content[:200]}") asyncio.run(run_task("订单系统如何扛住双十一流量"))这段代码把 MCP Prompts 和 TaoToken 串起来了:MCP 给角色提示词,TaoToken 给模型能力。跑通后你会看到 architect 角色输出分层架构建议,而不是产品经理的用户故事。任务命中率统计就靠pick_role的返回值和人工标注对比,简单但有效。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
配置和验证过程中,报错集中在几个地方。下面按真实报错逐条给排查路径。
401 Unauthorized:Key 没填对或没带上。检查api_key字段是否以sk-开头,有没有多余空格。如果你把 Key 放在环境变量里,确认os.environ.get("TAOTOKEN_API_KEY")真的读到了值。还有一种情况是 Base URL 写成了https://taotoken.net/api/带尾斜杠,某些库会拼出双斜杠导致鉴权失败,去掉尾斜杠即可。
local proxy failed:这个报错通常出现在客户端尝试走本地代理但代理没起来。检查你的客户端配置里有没有残留的 proxy 字段,MCP Server 启动命令是否被代理拦截。把 proxy 相关配置清掉,让请求直连https://taotoken.net/api。如果你在容器里跑,确认容器网络能出站。
reading choices 报错:典型表现是KeyError: 'choices'或list index out of range。原因一般是模型返回了错误结构,比如 401 时返回的是{"error": ...}而不是标准 completion。先打印完整 response 看结构,再确认 Model ID 是否拼写正确。Model ID 写错时,部分网关会返回非标准错误体,导致解析choices失败。
OAuth 相关报错:如果你用 Claude Code 或类似工具,可能会遇到 OAuth token 过期或 scope 不足。这类工具通常有自己的鉴权流程,和 API Key 是两套。确认你是在用 API Key 模式而不是 OAuth 模式,或者在工具设置里重新走一遍授权。MCP Server 本身不涉及 OAuth,报错一般来自 Client 侧的模型接入层。
排查顺序建议:先确认 Key 和 Base URL 能单独调通(用 curl 或 Python 直调),再确认 MCP Server 能单独返回提示词,最后把两边串起来。哪一步断掉就修哪一步,不要一上来就怀疑多智能体编排逻辑。
6. 从单角色到多智能体:把 Prompts 用成“人格调度层”
单角色验证通过后,多智能体编排就是把这个模式复制 N 份。中控 Agent 不再自己拼提示词,而是维护一张“任务类型 → 角色”的映射表,按任务去 MCP Server 取对应人格,再通过 TaoToken 分发到模型。角色定义集中在 Server 侧,改语气、改 focus 只动一个文件,不用碰编排代码。
上下文注入的优先级也要定清楚:system message 来自 MCP Prompts,优先级最高;任务背景来自中控 Agent,放在 user message;历史对话按需截断,避免把角色定义冲淡。如果发现 Agent 跑着跑着“人格漂移”,优先检查是不是历史对话太长把 system message 挤掉了,而不是急着改提示词。
长期跑编码类 Agent 的话,Coding Plan 比按量调用更稳,额度固定、不怕突发流量把账单打爆。验证模型能力用模型对话页就够,接入文档在 doc 页有完整字段说明。把 MCP Prompts 当成“人格调度层”,TaoToken 当成“模型调度层”,两层解耦,多智能体系统才不会被提示词和模型适配拖垮。