POML 与 MCP(Model Context Protocol)集成

POML 与 MCP(Model Context Protocol)集成

本文基于官方页面(microsoft.github.io/poml/stable... MCP 的工作原理、安装方式、基于 POML 模板的动态工具集成方案、完整示例、与直接使用 MCP 的对比,以及未来原生支持计划。

导语/背景介绍

  • MCP 是一种开放协议,为 LLM 应用与外部数据源和工具之间提供标准化的上下文访问与工具调用能力。
  • 警告:当前 POML 尚未内置支持 MCP。官方建议通过"工具调用 + 模板"的方式模拟 MCP 行为;未来版本计划提供原生支持。
  • 说明:部分提供方支持远程调用 MCP 服务器(如 OpenAI Response API),这类行为不在本文档范围内,因为开发者无需直接处理 MCP 调用细节。

安装与使用方法(Installation)

bash 复制代码
pip install mcp

工作原理(How MCP Works)

  • 客户端---服务端架构:
    1. 工具发现:MCP 服务器公开可调用的工具/函数
    2. 工具调用:客户端(LLM 应用)按参数调用工具
    3. 响应处理:服务器执行并返回结果给客户端
  • 典型流程:
    • 初始化:建立与 MCP 服务器的连接
    • 列出工具:查询可用工具及其 schema
    • 工具执行:当 LLM 需要调用时向 MCP 服务器发送请求
    • 结果集成:将工具结果整合回对话

动态工具(Dynamic Tools with MCP)

  • 通过 POML 的模板能力,可在运行时动态加载 MCP 服务器提供的工具定义,并在上下文中跟踪交互。
  • 该方案适用于 MCP 的原因(官方表述):
    • MCP 服务器在运行时动态提供工具
    • 不同 MCP 服务器的工具 schema 各不相同
    • 同一个 POML 模板可适配任意 MCP 服务器
    • 需要跨轮次跟踪工具交互

动态工具模板(POML Template for Dynamic Tools)

xml 复制代码
<poml> <system-msg>{{ system }}</system-msg> <human-msg>{{ input }}</human-msg> <!-- Dynamic Tool Loading: Iterates through tools discovered from the MCP server --> <div for="tool in tools"> <!-- Each tool's name, description, and JSON schema are inserted dynamically --> <tool-definition name="{{ tool.name }}" description="{{ tool.description }}"> {{ tool.schema }} </tool-definition> </div> <!-- Interaction History: Maintains conversation history with tool calls and responses --> <div for="i in interactions"> <!-- All dynamic content is provided through the context parameter --> <tool-request for="res in i" id="{{ res.id }}" name="{{ res.name }}" parameters="{{ res.input }}" /> <tool-response for="res in i" id="{{ res.id }}" name="{{ res.name }}"> <!-- Embeds the tool output directly via POML's Object componenet. --> <object data="{{ res.output }}"/> </tool-response> </div> <runtime model="gpt-4.1"/> </poml>

完整示例(Complete Example with MCP Server)

官方示例基于一个"掷骰子"的公共 MCP 演示服务器,演示工具发现、工具调用处理与主对话循环。

1) 工具发现与转换(Tool Discovery and Conversion)

python 复制代码
async def discover_mcp_tools(mcp_session): """Discover available tools from MCP server and convert to POML format""" mcp_tools = (await mcp_session.list_tools()).tools print(f"Available MCP tools: {mcp_tools}") # Convert MCP tools to POML context format. # The format must be compatible with the POML template above. poml_tools = [] for tool in mcp_tools: poml_tools.append({ "name": tool.name, "description": tool.description, "schema": tool.inputSchema }) return poml_tools

2) 处理工具调用(Process Tool Calls)

python 复制代码
async def process_tool_calls(mcp_session, tool_calls): """Execute MCP tool calls and format responses""" responses = [] for tool_call in tool_calls: function = tool_call.function args = json.loads(function.arguments or "{}") # Call MCP server tool result = await mcp_session.call_tool(function.name, args) print(f"Tool {function.name} result: {result}") # Format for POML context. # This format must be compatible with the POML template above. responses.append({ "id": tool_call.id, "name": function.name, "input": args, "output": result.model_dump() }) return responses

3) 主对话循环(Main Conversation Loop)

python 复制代码
async def run_mcp_conversation(mcp_session, context): """Run the conversation loop with MCP tools""" # Discover and add tools to context context["tools"] = await discover_mcp_tools(mcp_session) client = OpenAI() # Conversation loop while True: # Generate OpenAI parameters from POML params = poml.poml("dynamic_tools.poml", context=context, format="openai_chat") response = client.chat.completions.create(**params) message = response.choices[0].message if message.tool_calls: # Process and add tool responses to context responses = await process_tool_calls(mcp_session, message.tool_calls) context["interactions"].append(responses) else: # Final response - conversation complete print(f"Assistant: {message.content}") return message.content

4) 完整集成(Complete Integration)

python 复制代码
import json import asyncio from openai import OpenAI import poml from mcp import ClientSession from mcp.client.sse import sse_client async def main(): # Initialize context for POML context = { "system": "You are a helpful DM assistant. Use the dice-rolling tool when needed.", "input": "Roll 2d4+1", "tools": [], "interactions": [] } # Connect to MCP server (using public demo server) server_url = "https://dmcp-server.deno.dev/sse" async with sse_client(server_url) as (read, write): async with ClientSession(read, write) as mcp_session: await mcp_session.initialize() result = await run_mcp_conversation(mcp_session, context) print(f"Conversation completed: {result}") if __name__ == "__main__": asyncio.run(main())

与直接使用 MCP 的对比(Comparison with Direct MCP Usage)

  • 主要差异(官方表述):
    • 消息管理:直接方式需要手动区分 "role": "assistant""role": "tool";POML 通过请求/响应成对管理,自动处理
    • 内容渲染:直接方式需手动字符串转换与格式化;POML 使用 <object> 组件统一处理各类内容
    • 工具格式:直接方式需手动按 OpenAI 等提供方要求格式化;POML 使用声明式模板完成转换

不使用 POML(Direct Approach)

python 复制代码
# Manually manage message roles and format
messages.append({"role": "assistant", "content": msg.content or "", "tool_calls": msg.tool_calls})
messages.append({"role": "tool", "tool_call_id": tc.id, "name": fn.name, "content": text_result})
# Manually format tool results from MCP
if result.structuredContent is not None:
    text_result = json.dumps(result.structuredContent)
else:
    text_result = "\n".join([c.text for c in result.content if isinstance(c, types.TextContent)])
# Convert MCP tools to OpenAI format
oa_tools.append({
    "type": "function",
    "function": {"name": t.name, "description": t.description, "parameters": t.inputSchema}
})

使用 POML(Structured Approach)

python 复制代码
# Simply track tool request/response pairs
context["interactions"].append([
    {"id": tc.id, "name": fn.name, "input": args, "output": result.model_dump()}
])

未来原生支持(Future Native Support)

  • POML 计划提供 MCP 的原生支持,届时会为 MCP 操作提供简化语法。
  • 在此之前,可采用本文基于模板的方式作为过渡性解决方案。

使用场景

  • 官方页面未提供具体使用场景示例。

总结/展望

  • 文中基于官方页面介绍了 MCP 的工作原理、安装方法、POML 模板的动态工具集成方案、完整示例,以及与直接使用 MCP 的对比与未来计划。
  • 获取完整细节与最新进展,请参考官方文档:
相关推荐
Esaka_Forever7 小时前
Skills安全要点总结
安全·llm
TechEdu20260616 小时前
[人工智能]Claude、GPT、Gemini、Copilot与Llama:概念、架构、应用与评估
人工智能·ai·llm
长谷深风11116 小时前
为什么你的 Tool 总被模型选错?
java·大数据·ai·llm·ai agent·工具设计·agent设计
boooooooom17 小时前
尝尝咸淡:从朴素 RAG 到 Graph RAG——一个烹饪问答系统的三层检索升级之路
前端·后端·llm
武子康20 小时前
33B 音画模型塞进 Apple Silicon,h3.c 重写了哪些 Runtime 职责
人工智能·llm·agent
知几蜗牛20 小时前
一张图看懂AI、机器学习、深度学习和生成式AI之间的关系
llm
XLYcmy20 小时前
小红书 算法一面 十一
google·meta·llm·负载均衡·token·moe·glam
谢白羽21 小时前
Mooncake在LLM的kv cache offload
人工智能·llm·论文·agent·mooncake
牧艺2 天前
DeepSeek Harness 上手:一切皆插件的 Agent 运行时,核心流程怎么走
llm·agent·deepseek
魔术师Grace2 天前
模型“开源”了,就能直接拿来做 Agent 吗?
llm·aigc·agent