ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于 hello_agents 多智能体协作的智能菜谱助手实战:搜索、筛选与内容提取三 Agent 流水线

基于 hello_agents 多智能体协作的智能菜谱助手实战:搜索、筛选与内容提取三 Agent 流水线 基于 hello_agents 多智能体协作的智能菜谱助手实战搜索、筛选与内容提取三 Agent 流水线【免费下载链接】hello-agents 《从零开始构建智能体》——从零开始的智能体原理与实践教程项目地址: https://gitcode.com/datawhalechina/hello-agents本篇技术指南以 Datawhale《从零开始构建智能体》共创项目 AstrumPush-Smart-Recipe-Agent 为对象讲解如何基于 hello_agents 框架用「菜谱搜索专家 饮食专家 内容提取专家」三个SimpleAgent搭建一条真实可用的菜谱自动搜索流水线。读者读完可掌握MCPTool接入网页搜索工具、Agent 间结构化协作、[TOOL_CALL:...]文本协议解析以及 Markdown 结果落盘的全流程实现。一、项目定位拒绝编造菜谱的多智能体协作系统「智能菜谱助手」是一个基于多 Agent 协作的菜谱搜索系统。用户只需输入饮食需求如我想吃小龙虾、适合降火的家常菜系统会自动完成三步动作搜索菜谱调用网络搜索工具获取相关菜谱列表智能筛选根据用户偏好推荐最合适的菜谱内容提取抓取完整菜谱内容并保存为 Markdown 文件。所有生成的菜谱自动保存在recipes/目录下方便随时查看和使用。该项目最核心的设计理念是拒绝编造所有菜谱信息都必须来自真实网页以香哈网 xiangha.com 为数据源搜索 Agent 与内容提取 Agent 的 system prompt 中都明确写有「不要自己编造菜谱信息」必须调用工具获取。这与 hello_agents 框架「一切皆工具」的设计哲学一脉相承——记忆、RAG、MCP 协议等模块被统一抽象为工具让智能体回归「调用工具」这一最直观的核心逻辑参见 docs/chapter7/Chapter7-Building-Your-Agent-Framework.md 的框架设计说明。二、技术栈概览组件说明hello_agents多智能体编排框架hello-agents[all]0.2.2MCPToolModel Context Protocol 工具接口连接外部 MCP 服务器mzxrai/mcp-webresearch网页搜索与研究 MCP 工具基于 npx 启动python-dotenv环境变量管理json/datetime数据解析与时间戳文件名生成依赖声明见 requirements.txt核心依赖仅两项——hello-agents[all]0.2.2与python-dotenv1.0.0体现了 hello_agents 框架「极简依赖」的轻量设计理念。三、环境准备与三步部署1. 克隆项目并安装依赖git clone 项目仓库地址 cd Smart-Recipe-Agent # 安装 Python 依赖 pip install -r requirements.txt # 安装 Node.js 环境用于 npx 启动 MCP 工具 # 访问 https://nodejs.org 下载安装2. 替换 hello-agents 底层代码关键步骤由于本项目需要MCPTool以server_command[npx, -y, mzxrai/mcp-webresearchlatest]的方式启动外部 MCP 服务器需要将本项目下的 protocol_tools.py 替换掉 hello-agents 安装包中的同名文件。以 Windows Anaconda 为例替换目标地址为根据本机环境自行调整D:\Anaconda3\envs\agents\Lib\site-packages\hello_agents\tools\builtin为什么要替换这个文件从源码看protocol_tools.py 是对 hello_agents 内置协议工具的增强版它在原有MCPTool基础上做了三处关键加固文件内标注了todo: 修改by xcWindows 事件循环策略L18-L24在 Windows 平台将 asyncio 的事件循环策略切换为WindowsSelectorEventLoopPolicy避免ProactorEventLoop的GetQueuedCompletionStatus阻塞问题超时与残留任务清理L412、L470-L491使用asyncio.wait_for设置调用超时在线程中运行完毕后取消所有 pending 任务、关闭线程池防止 MCP transport 未关闭导致管道/文件描述符泄漏GC 强制回收L499-L501每次操作结束后调用gc.collect()强制回收未关闭的句柄。此外该文件还内置了MCP_SERVER_ENV_MAPL29-L36自动检测常见 MCP 服务器server-github、server-slack、server-google-drive、server-postgres 等所需的环境变量并实现了三级环境变量优先级直接传入的env参数 env_keys指定的环境变量 根据server_command自动检测L147-L201。3. 配置环境变量创建.env文件# LLM API 配置根据实际使用的模型提供商填写 OPENAI_API_KEYyour_api_key_here # 或其他模型配置...主程序在开头通过load_dotenv()加载该文件见 diet_recommendation_final.py。4. 运行程序python diet_recommendation_final.py主程序会首先创建recipes/目录os.makedirs(recipes, exist_okTrue)然后进入交互式输入。四、Agent 架构三专家流水线项目采用三个职责单一、串行协作的SimpleAgent整体架构如下┌─────────────────────────────────────┐ │ 用户输入: 我想吃小龙虾 │ └─────────────┬───────────────────────┘ ▼ ┌─────────────────────────────────────┐ │ caipu_search_agent │ │ • 角色菜谱搜索专家 │ │ • 任务调用 web_research 工具搜索 │ │ • 输出菜谱列表菜名链接特点 │ └─────────────┬───────────────────────┘ ▼ ┌─────────────────────────────────────┐ │ caipu_select_agent │ │ • 角色饮食专家 │ │ • 任务根据用户需求筛选最佳菜谱 │ │ • 输出JSON 格式推荐结果 │ └─────────────┬───────────────────────┘ ▼ ┌─────────────────────────────────────┐ │ output_agent │ │ • 角色网页内容提取专家 │ │ • 任务抓取完整菜谱内容 │ │ • 输出Markdown 格式完整菜谱 │ └─────────────┬───────────────────────┘ ▼ ┌─────────────────────────────────────┐ │ 自动保存至 recipes/ 目录 │ └─────────────────────────────────────┘1. 共享工具MCP 网页搜索工具三个 Agent 中的搜索专家与内容提取专家共享同一个MCPTool实例diet_recommendation_final.pyweb_search_tool MCPTool(nameweb_research, server_command[npx, -y, mzxrai/mcp-webresearchlatest])MCPTool的name参数用于标识服务器server_command指定了 MCP 服务器的启动命令——这里通过npx直接拉起mzxrai/mcp-webresearch包无需手动启动独立服务进程。结合 protocol_tools.py 中MCPTool.__init__的实现L69-L145可以看到该工具初始化时会自动完成三步动作准备环境变量_prepare_env→ 自动发现服务器工具_discover_tools→ 根据工具列表自动生成描述_generate_description。工具发现失败不会阻塞初始化L288-L290捕获异常后置空工具列表保证了容错性。2. 搜索专家 caipu_search_agentcaipu_search_agent SimpleAgent( namecaipu_search_agent, llmHelloAgentsLLM(), system_prompt你是菜谱搜索专家。你的任务是根据用户的需求和用户偏好搜索合适的菜谱。... ) caipu_search_agent.add_tool(web_search_tool)它的 system prompt 规定了严格的工具调用格式使用visit_page工具时,必须严格按照以下格式: [TOOL_CALL:visit_page:urlhttps://www.xiangha.com/so/?qcaipus菜谱] [TOOL_CALL:visit_page:urlhttps://www.xiangha.com/so/?qcaipus食材]配套的输入构造函数将用户需求直接透传给 Agentdef build_caipu_search_prompts(user_input): return f调用visit_page工具, 用户需求: {user_input}这种[TOOL_CALL:工具名:参数]的文本协议正是 hello_agents 框架工具调用的标准格式。在框架教学代码 code/chapter7/my_simple_agent.py 中可以看到其解析实现L130-L143通过正则\[TOOL_CALL:([^:]):([^\]])\]提取工具名与参数字符串再由_parse_tool_parameters将keyvalue形式的参数解析为字典L168-L194。这正是本项目 system prompt 中「参数用逗号分隔、格式必须完全正确包括方括号和冒号」的原因。3. 饮食专家 caipu_select_agentcaipu_select_agent SimpleAgent( namecaipu_select_agent, llmHelloAgentsLLM(), system_prompt你是饮食专家。你的任务是根据用户需求和推荐的菜谱列表为用户选择一个最合适的菜谱并给出推荐理由。... )它不绑定任何工具纯靠 LLM 推理完成筛选其 system prompt 强制要求必须从给定的菜谱列表中选择不能凭空产生新的菜名和菜谱链接严格按 JSON 格式输出包含name菜名、url菜谱链接、reason推荐理由三个字段没有合适结果时返回空 JSON{}。推荐理由要求包含 Markdown 格式的要点如- **清蒸烹饪** - 少油少盐便于用户阅读。输入构造函数把用户需求与搜索 Agent 的结果拼接在一起def build_caipu_select_prompts(user_input, caipu_list): return f用户需求: {user_input}推荐的菜谱列表: {caipu_list}4. 内容提取专家 output_agentoutput_agent SimpleAgent( namedemand_analyzer, llmHelloAgentsLLM(), system_prompt你是网页内容提取专家。你的任务是根据用户选择的菜名和菜谱链接返回最终完整的的菜谱。... ) output_agent.add_tool(web_search_tool)它同样必须调用visit_page工具抓取菜谱详情页如https://www.xiangha.com/caipu/102880489.html禁止编造内容。输入构造函数接收筛选阶段产出的 JSONdef build_output_prompts(caipu_json): return f菜名: {caipu_json[name]}, 菜谱链接: {caipu_json[url]}5. 主流程编排主流程diet_recommendation_final.py按「搜索 → 筛选 → 解析 → 生成 → 保存」的顺序串行驱动三个 Agentuser_input input(请输入菜谱需求(例如我想吃小龙虾) ) print(\n\n正在搜索菜谱...) search_caipu_result caipu_search_agent.run(build_caipu_search_prompts(user_inputuser_input)) print(search_caipu_result) print(\n\n正在筛选菜谱...) caipu_select_result caipu_select_agent.run(build_caipu_select_prompts(user_inputuser_input, caipu_listsearch_caipu_result)) print(caipu_select_result) print(\n\n正在解析结果...) caipu_select_json parse_response(caipu_select_result) print(caipu_select_json) if caipu_select_json: print(\n\n正在生成菜谱...) output_result output_agent.run(build_output_prompts(caipu_select_json)) print(\n\n正在保存菜谱...) print(f菜名: {caipu_select_json[name]}\n推荐理由: {caipu_select_json[reason]}) write_content_to_file(output_result) else: print(\n\n未找到合适的菜谱)这里有一个重要的容错细节parse_response返回None时解析失败或返回空 JSON主流程通过if caipu_select_json:进行空值检查打印「未找到合适的菜谱」而非崩溃——这正是 README 注意事项中「解析失败或无匹配结果时程序会友好提示不会崩溃」的实现依据。五、工具调用格式与响应解析规范工具调用格式搜索 Agent 和输出 Agent 使用统一的工具调用格式[TOOL_CALL:visit_page:urlhttps://www.xiangha.com/so/?qcaipus关键词]参数说明参数说明visit_page工具名称MCP 服务器暴露的网页访问工具url目标网页地址支持香哈网搜索页或具体菜谱页关于工具名与调用细节可以参考仓库中的连通性验证脚本 basic_func_test.py。它先用list_tools动作枚举 MCP 服务器提供的全部工具再以call_tool动作直接调用visit_page访问香哈网搜索页web_search_tool MCPTool(nameweb research, server_command[npx, -y, mzxrai/mcp-webresearchlatest]) result web_search_tool.run({action: list_tools}) print(result) result web_search_tool.run({ action: call_tool, tool_name: visit_page, arguments: { url: https://www.xiangha.com/so/?qcaipus五花肉 } }) print(result)对照 protocol_tools.py 中MCPTool.run的实现L351-L504可以梳理出工具调用的底层链路run方法支持list_tools、call_tool、list_resources、read_resource、list_prompts、get_prompt六类动作若未指定action但提供了tool_name会自动推断为call_toolL373-L376。执行时通过hello_agents.protocols.mcp.client.MCPClient建立连接并针对已有运行中事件循环的场景做了线程隔离处理在新线程中创建独立事件循环执行调用见L457-L495。响应解析规则parse_response()函数diet_recommendation_final.py按三种情况逐级提取 JSON响应包含json代码块标记 → 从代码块内提取响应包含代码块标记 → 从代码块内提取响应直接包含{和}→ 取首个{到末个}之间的内容。提取后经json.loads解析为字典。解析失败时打印⚠️ 解析响应失败警告并返回None由主流程的空值检查兜底。六、运行效果与交互示例请输入菜谱需求(例如我想吃小龙虾) 适合夏天吃的清淡家常菜 正在搜索菜谱... [TOOL_CALL:visit_page:urlhttps://www.xiangha.com/so/?qcaipus清淡家常菜] 正在筛选菜谱... { name: 清蒸鲈鱼, url: https://www.xiangha.com/caipu/xxxxx.html, reason: **推荐理由**\n- **清蒸烹饪** - 少油少盐...\n... } 正在生成菜谱... 正在保存菜谱... ✅ 菜谱已创建: recipes/recipes_20260428_153022.md生成的菜谱文件名带时间戳。其实现位于write_content_to_filediet_recommendation_final.pydef write_content_to_file(content): timestamp datetime.now().strftime(%Y%m%d_%H%M%S) # 例: 20260428_143022 filename frecipes/recipes_{timestamp}.md with open(filename, w, encodingutf-8) as wf: wf.write(content) print(f✅ 菜谱已创建: {filename})写入时显式指定encodingutf-8避免中文菜谱内容出现乱码。七、使用建议如何输入更有效推荐的用户输入方式✅ 适合减肥期间吃的低卡菜谱 ✅ 快手早餐10分钟能做完的 ✅ 川菜微辣有鸡肉的 ✅ 适合老人吃的软烂易消化菜品避免的输入方式❌ 随便做个菜 # 需求过于模糊 ❌ 生成一个不存在的菜 # 系统拒绝编造信息 ❌ 直接要求写一个红烧肉做法 # 应通过搜索获取真实菜谱输入质量直接影响搜索 Agent 构造的搜索关键词与筛选 Agent 的推荐效果明确的约束条件时间、口味、食材、人群能显著提升推荐质量。八、注意事项网络依赖程序需要联网调用 MCP 搜索工具请确保网络通畅网站适配当前针对香哈网xiangha.com优化更换数据源需调整 prompt 中的 URL 模板API 配额注意 LLM 和搜索工具的调用频率限制文件权限确保程序有recipes/目录的写入权限主程序启动时已通过os.makedirs(..., exist_okTrue)自动创建错误处理解析失败或无匹配结果时程序会友好提示不会崩溃。另外若在 Windows 上运行遇到 MCP 工具卡死或句柄占用问题正是 protocol_tools.py 中事件循环策略替换与超时清理逻辑所要解决的场景务必使用增强版替换官方内置文件。九、扩展开发指南1. 添加新数据源修改 Agent 的system_prompt中的 URL 模板即可例如为下厨房添加支持# 示例添加下厨房网站支持 [TOOL_CALL:visit_page:urlhttps://www.xiachufang.com/search/?keyword关键词]MCP 的visit_page工具本身是通用的网页访问能力数据源扩展的核心在于 prompt 中的 URL 模板与解析预期。2. 自定义筛选逻辑调整caipu_select_agent的 prompt添加个性化推荐规则- 优先推荐烹饪时间 30分钟的菜谱 - 排除含用户过敏食材的菜品 - 根据季节推荐当季食材菜谱3. 增加输出格式修改write_content_to_file()支持更多格式# 支持导出 PDF/HTML 等 def write_content_to_file(content, formatmd): ...十、项目结构速览smart-recipe-agent/ ├── main.py # 主程序入口 ├── .env # 环境变量配置需手动创建 ├── recipes/ # 生成的菜谱文件目录自动创建 │ └── recipes_20260428_153022.md ├── requirements.txt # Python 依赖 ├── protocol_tools.py # 需要替换到 hello-agents 的增强版协议工具模块 ├── basic_func_test.py # 用于验证是否可以使用 web_search 模块 └── README.md # 项目说明文档在 hello-agents 仓库中对应源码位于 Co-creation-projects/AstrumPush-Smart-Recipe-Agent 目录其中主程序为 diet_recommendation_final.py增强版协议工具为 protocol_tools.py连通性验证脚本为 basic_func_test.py。总结智能菜谱助手是 hello_agents「轻量、教学友好、一切皆工具」设计理念的一个典型落地案例三个职责单一的SimpleAgent通过文本工具协议与 JSON 中间产物完成协作MCP 协议打通了真实网页数据源从而在「拒绝编造」的前提下实现了菜谱的搜索、筛选与内容提取全自动化。理解这条流水线也就掌握了用 hello_agents 搭建任意「搜索 → 决策 → 产出」类多智能体应用的通用范式。【免费下载链接】hello-agents 《从零开始构建智能体》——从零开始的智能体原理与实践教程项目地址: https://gitcode.com/datawhalechina/hello-agents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进