62 lines
2.7 KiB
Python
62 lines
2.7 KiB
Python
# examples/mcp_modes/plan_and_execute.py
|
||
import os, asyncio
|
||
from typing import List
|
||
from langchain_core.messages import HumanMessage, ToolMessage
|
||
from langgraph_qwen.chat_model import ChatQwenOpenAICompat
|
||
from langgraph_qwen.mcp import load_mcp_tools
|
||
|
||
async def plan(task: str) -> List[str]:
|
||
planner = ChatQwenOpenAICompat(temperature=0)
|
||
ai = await planner.ainvoke([HumanMessage(content=f"把任务拆成可执行步骤(每行一步):\n{task}")])
|
||
steps = [s.strip() for s in str(ai.content).splitlines() if s.strip()]
|
||
return steps[:8]
|
||
|
||
async def tools_for_step(step_idx: int):
|
||
# ★ 示例:偶数步用 weather,奇数步用 play/test 工具;也可来自文件
|
||
if step_idx % 2 == 0:
|
||
return await load_mcp_tools(servers={
|
||
"weather": {"url":"http://127.0.0.1:8000/mcp/","transport":"streamable_http"}
|
||
})
|
||
else:
|
||
cfg = os.getenv("MCP_CONFIG_PATH") # 比如 ./mcp_servers.yaml
|
||
return await load_mcp_tools(config_path=cfg)
|
||
|
||
async def execute(steps: List[str], max_tool_steps_per_step: int = 4):
|
||
msgs = []
|
||
for i, step in enumerate(steps, 1):
|
||
tools = await tools_for_step(i)
|
||
tool_map = {t.name: t for t in tools}
|
||
model = ChatQwenOpenAICompat(temperature=0).bind_tools(tools).bind(tool_choice="auto")
|
||
|
||
msgs.append(HumanMessage(content=f"执行第{i}步:{step}"))
|
||
for _ in range(max_tool_steps_per_step):
|
||
ai = await model.ainvoke(msgs)
|
||
msgs.append(ai)
|
||
calls = getattr(ai, "tool_calls", []) or ai.additional_kwargs.get("tool_calls", [])
|
||
if not calls:
|
||
break
|
||
for call in calls:
|
||
name, args, call_id = call.get("name"), call.get("args", {}), call.get("id") or ""
|
||
tool = tool_map.get(name)
|
||
if not tool:
|
||
msgs.append(ToolMessage(tool_call_id=call_id, content=f"Unknown tool: {name}"))
|
||
continue
|
||
try:
|
||
out = await tool.ainvoke(args) if hasattr(tool, "ainvoke") else tool.invoke(args)
|
||
msgs.append(ToolMessage(tool_call_id=call_id, content=str(out)))
|
||
except Exception as e:
|
||
msgs.append(ToolMessage(tool_call_id=call_id, content=f"Error: {e}"))
|
||
|
||
final = await ChatQwenOpenAICompat(temperature=0).ainvoke(
|
||
msgs + [HumanMessage(content="请汇总执行结果,简洁给出结论。")]
|
||
)
|
||
print("=== Final ===")
|
||
print(final.content)
|
||
|
||
async def main():
|
||
steps = await plan("在巴塞罗那找一个带游泳池的民宿,然后搜索附近的餐厅和景点")
|
||
await execute(steps, max_tool_steps_per_step=4)
|
||
|
||
if __name__ == "__main__":
|
||
asyncio.run(main())
|