ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

GiftGenius 多智能体礼物推荐系统全栈开发教程:用 TaoToken 统一 Key 打通 HelloAgents 与 SimpleAgent

GiftGenius 多智能体礼物推荐系统全栈开发教程:用 TaoToken 统一 Key 打通 HelloAgents 与 SimpleAgent 1. GiftGenius 多智能体礼物推荐系统到底解决什么问题GiftGenius 是一个用多智能体协作完成“送礼决策”的全栈小系统输入一份收礼人画像性别、年龄、MBTI、星座、预算、节日、自定义偏好输出一份带商品名、价格、推荐理由、图片和购买链接的 Markdown 礼物清单。它要解决的是“送什么礼物”这个现实难题——不是简单丢一句“送口红”而是根据人格画像和预算区间去全网实时检索商品信息再生成图文并茂、价格透明的推荐报告。适合谁跟做有 Python 基础、想入门多智能体Multi-Agent协作的开发者想给电商/推荐场景做 Agent 原型的同学以及已经在用 HelloAgents、SimpleAgent 这类框架但被“模型 Key 分散、Base URL 各写各的”折腾过的朋友。整套链路里模型调用统一走 TaoToken 的 Key/API 通道搜索侧用 Tavily 或百度优选 MCP 二选一代码逻辑负责价格准确性模型负责创意文案。核心结构是“三智能体流水线”军师Profiler负责分析用户画像、生成 3 个精准搜索关键词猎人BatchSearchTool负责全网检索商品数据编辑Pitcher负责生成种草文案。三者通过 HelloAgents 的 SimpleAgent 封装模型统一由 HelloAgentsLLM 调用。我试过把这套流程拆开跑最深的体会是别让 LLM 直接吐 JSON 当最终数据价格、图片这类硬数据交给 Python 正则去抓模型只做它擅长的创意部分幻觉会少一大截。三大亮点值得单独说双流架构把“硬数据搜索”价格提取和“软文案生成”卖点编写拆成两条并行流水线减少上下文干扰代码级防幻觉用正则从搜索结果里暴力提取价格和图片代码逻辑负责准确性动态策略修正的“价格守门员”机制——商品均价超预算时自动触发军师重新制定“平替”策略低于预算时触发生成“升级款”方案。技术栈上HelloAgents 做多智能体编排SimpleAgent 做单智能体封装HelloAgentsLLM 做模型统一调用搜索侧 Tavily 走通用/海外商品、百度优选 MCP 走电商/国内商品异步支持用 nest_asyncio asyncio 解决 Jupyter 里跑异步代码的问题。2. 用 TaoToken 统一 Key 打通 HelloAgents 与 SimpleAgent 的前置准备在写业务代码之前先把模型调用这一层收口。HelloAgents 的 HelloAgentsLLM 兼容 OpenAI API 格式需要三个参数MODEL_ID、API_KEY、BASE_URL。传统做法是每个项目各自去申请模型服务、各自填 Base URL项目一多Key 散落在各个 .env 里换模型要改一堆地方。这里统一到 TaoToken 的 Key/API 通道好处是一个 Key 覆盖多个模型Base URL 固定HelloAgents 和 SimpleAgent 都从同一份环境变量读取切换模型只改 MODEL_ID。前置准备分三步。第一步拿到 TaoToken 的 API Key。访问 https://taotoken.net/api 对应的控制台入口在 API Keys 页面创建一个 Key复制保存。第二步确认 Base URL。TaoToken 的 API 入口是 https://taotoken.net/api在 HelloAgentsLLM 里作为 base_url 传入。第三步确认你要用的 Model ID比如 DeepSeek 系列、Qwen 系列等填到 LLM_MODEL_ID 里。系统要求Windows / macOS / Linux 均可Python 3.10 或更高推荐 3.10.x运行环境 Jupyter Notebook 或 JupyterLab。Python 安装Windows 用户去 python.org/downloads 下载 3.10 安装包安装时务必勾选 “Add Python to PATH”macOS 用户用brew install python3.10LinuxUbuntu/Debian用sudo apt update sudo apt install python3.10 python3.10-venv python3-pip。装完 Jupyterpip install jupyter。验证python --version应输出 Python 3.10.x 或更高jupyter --version能打印版本号即可。搜索侧二选一Tavily Search API 去 tavily.com 注册有免费额度进 Dashboard → API Keys → 创建新 Key百度优选 MCP Token 去百度优选 MCP 服务获取 Token用于 SSE 连接进行电商商品搜索。国内用户推荐百度优选电商搜索更精准海外用户用 Tavily。项目目录结构先建好mkdir GiftGeniusAgent cd GiftGeniusAgent mkdir data outputs完整目录如下GiftGeniusAgent/ ├── .env # 环境变量配置含 API 密钥 ├── .env.example # 配置模板可安全提交 Git ├── .gitignore ├── README.md ├── requirements.txt ├── main.ipynb # 主程序 ├── data/ │ └── test_cases.json # 用户画像输入 └── outputs/ └── gift_plan_output.md # 生成的礼物推荐报告依赖安装创建 requirements.txthello-agents tavily-python mcp nest_asyncio python-dotenv numpy安装国内用户可加清华镜像加速pip install -r requirements.txt # 或 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple3. 可复制的环境变量与 Base URL 配置片段这一步是整个项目能不能跑通的关键。先创建.env.example模板# # GiftGenius Agent 环境变量配置模板 # 复制此文件为 .env 并填入你的真实密钥 # # --- 大模型参数必填统一走 TaoToken--- LLM_MODEL_ID yourmodel LLM_API_KEY yourkey LLM_BASE_URL https://taotoken.net/api # --- Tavily 搜索 API二选一--- TAVILY_API_KEY yourTavilyKey # --- 百度优选 MCP Token二选一--- BAIDU_MCP_TOKEN yourtoken复制成真实配置cp .env.example .env编辑.env填入真实密钥。以 TaoToken 统一通道为例LLM_MODEL_ID deepseek-chat LLM_API_KEY sk-xxxxxxxxxxxxxxxxxxxxxxxx LLM_BASE_URL https://taotoken.net/api # 搜索引擎二选一 TAVILY_API_KEY tvly-xxxxxxxxxxxxxxxx BAIDU_MCP_TOKEN your_baidu_token_here注意.env文件包含敏感密钥切勿提交到 Git确保.gitignore中包含.env。这里三件套要写全——Base URL 是https://taotoken.net/apiKey 是你在控制台创建的 API KeyModel ID 是你选用的模型名。HelloAgents 的 HelloAgentsLLM 会读取这三个值SimpleAgent 实例化时传入同一个 llm 对象所以军师和编辑两个 Agent 共用一份模型配置不需要各写各的。如果你用 Cline MCP 或 Claude Code 这类工具做辅助开发配置逻辑一致Base URL 填https://taotoken.net/apiKey 填同一个Model ID 按需选。Codex 的 auth.json 场景同理把 base_url 和 api_key 指向 TaoToken 即可。核心原则是模型通道只维护一份配置业务代码只引用环境变量。4. 多智能体角色分工代码骨架与端到端验证先看环境配置 Cellfrom hello_agents import SimpleAgent, HelloAgentsLLM, ToolRegistry from hello_agents.tools import Tool, ToolParameter from typing import Dict, Any, List from tavily import TavilyClient import os, json, re, numpy as np, asyncio, nest_asyncio from dotenv import load_dotenv from mcp.client.sse import sse_client from mcp.client.session import ClientSession load_dotenv() LLM_MODEL_ID os.getenv(LLM_MODEL_ID) LLM_API_KEY os.getenv(LLM_API_KEY) LLM_BASE_URL os.getenv(LLM_BASE_URL) TAVILY_API_KEY os.getenv(TAVILY_API_KEY, ) BAIDU_TOKEN os.getenv(BAIDU_MCP_TOKEN, ) INPUT_FILENAME data/test_cases.json os.environ[SEARCH_PROVIDER] baidu # 或 tavily print(环境配置完成)统一搜索工具 BatchSearchTool 封装 Tavily 和百度优选两种引擎返回标准化的List[Dict]nest_asyncio.apply() class BatchSearchTool(Tool): def __init__(self): super().__init__(namebatch_search, description统一搜索工具) self.provider os.environ.get(SEARCH_PROVIDER, tavily).lower() def run(self, parameters: Any) - str: return 请使用 Python 代码直接调用 search_raw 方法获取数据。 def search_raw(self, query: str) - List[Dict]: if self.provider baidu: return self._search_baidu(query) return self._search_tavily(query) def _search_tavily(self, query: str) - List[Dict]: api_key os.environ.get(TAVILY_API_KEY) if not api_key: return [] try: tavily TavilyClient(api_keyapi_key) response tavily.search(query, max_results5, include_imagesTrue) results [] for r in response.get(results, []): results.append({title: r[title], url: r[url], content: r[content], type: text, img: }) if response.get(images): results.append({images: response[images][:3], type: image}) return results except Exception as e: print(fTavily 异常: {e}) return [] def _search_baidu(self, query: str) - List[Dict]: token os.environ.get(BAIDU_MCP_TOKEN) if not token: return [] try: raw asyncio.run(self._async_baidu_call(query, token)) return self._parse_baidu_response(raw) except Exception as e: print(f百度 MCP 异常: {e}) return [] async def _async_baidu_call(self, query: str, token: str) - str: sse_url fhttps://mcp-youxuan.baidu.com/mcp/sse?key{token} async with sse_client(sse_url) as (read, write): async with ClientSession(read, write) as session: await session.initialize() result await session.call_tool(goods_search, arguments{query: query}) return result.content[0].text if result.content else def _parse_baidu_response(self, json_str: str) - List[Dict]: results, images [], [] try: data json.loads(json_str) for item in (data if isinstance(data, list) else [])[:5]: title item.get(goodsName) or item.get(title) or 未知商品 price item.get(price) or item.get(minPrice) or shop item.get(shopName) or item.get(mall) or url item.get(detailUrl) or item.get(url) or # img item.get(imgUrl) or item.get(picUrl) or item.get(img) results.append({title: title, url: url, content: f价格: {price}元。店铺: {shop}, type: text, img: img}) if img: images.append(img) if images: results.append({images: images[:3], type: image}) except json.JSONDecodeError: print(百度返回非 JSON 数据) return results def get_parameters(self): return [ToolParameter(namequery, typestring, description关键词)] tool_registry ToolRegistry() tool_registry.register_tool(BatchSearchTool()) print(统一搜索工具已加载)创建两个智能体共用同一个 llm 对象llm HelloAgentsLLM() PROFILER_PROMPT 你是一个精通 MBTI 人格分析与消费市场趋势的送礼军师。 你的任务是根据用户提供的多维度画像制定 3 个**极度精准**的搜索关键词。 【时效性死命令】当前时间视作 2025年11月严禁推荐过时旧款。 【关键词生成要求】 1. 必须具体格式为 [品牌] [产品名/系列] [限定/属性]。 2. 拒绝大词严禁搜索礼物口红玩具这种泛词。 3. 必须包含品牌根据预算推断合适的品牌。 【输出格式】只输出 3 行搜索关键词每行一个不要输出分析过程不要序号。 profiler_agent SimpleAgent(llmllm, nameAgent_Profiler, system_promptPROFILER_PROMPT) PITCHER_PROMPT 你是一个**金牌种草文案**。 用户会给你一个**商品名称**。 ### 关键要点 1. 痛点直击一句话说清楚为什么买它。 2. 情绪价值使用绝绝子氛围感心动等高频热词。 3. 字数限制严格控制在 40字以内。 4. Emoji必须包含 1-2 个 emoji。 请为商品写一句朋友圈风格种草语。 pitcher_agent SimpleAgent(llmllm, nameAgent_Pitcher, system_promptPITCHER_PROMPT) print(智能体初始化完成)读取用户数据def load_user_profile(filename): if not os.path.exists(filename): default_data {性别: 女, 年龄: 24岁, MBTI: ENFP, 星座: 天秤座, 预算: 500元以内, 节日: 恋爱一周年纪念日, 自定义: 喜欢二次元平时喜欢喝咖啡不要送太实用的家电} with open(filename, w, encodingutf-8) as f: json.dump(default_data, f, ensure_asciiFalse, indent4) return default_data with open(filename, r, encodingutf-8) as f: return json.load(f) user_input_data load_user_profile(INPUT_FILENAME)核心业务逻辑包含预算解析、价格提取和四重防御机制def parse_budget_range(budget_str): nums [float(x) for x in re.findall(r\d, str(budget_str).replace(,, ))] if not nums: return 0, 999999 if 以内 in budget_str or 以下 in budget_str: return 0, nums[0] if 以上 in budget_str: return nums[0], 999999 if len(nums) 2: return min(nums), max(nums) return 0, nums[0] def extract_all_prices(raw_results): prices [] for res in raw_results: if res.get(type) text: text res.get(title, ) res.get(content, ) for m in re.findall(r(?:¥||\$|HK\$|NT\$)\s*(\d(?:,\d{3})*(?:\.\d)?), text): val float(m.replace(,, )) if 10 val 100000 and val not in [2024, 2025, 2026]: prices.append(val) for m in re.findall(r(\d(?:,\d{3})*(?:\.\d)?)\s*元, text): val float(m.replace(,, )) if 10 val 100000 and val not in [2024, 2025, 2026]: prices.append(val) return prices主执行循环b_min, b_max parse_budget_range(user_input_data.get(预算, )) profile_text \n.join([f- {k}: {v if v else 未知/不限} for k, v in user_input_data.items()]) search_strategy profiler_agent.run(f请根据以下用户画像制定搜索策略\n\n{profile_text}) keywords [k.strip() for k in search_strategy.replace(, ,).replace(\n, ,).split(,) if k.strip()] final_items, hunter [], BatchSearchTool() for index, kw in enumerate(keywords): valid_result, price_status, final_kw find_best_product(hunter, profiler_agent, kw, b_min, b_max) if not valid_result: continue product_name valid_result.get(title, final_kw) pitch pitcher_agent.run(f商品{product_name}\n价格{price_status}\n卖点片段{valid_result.get(content, )[:200]}...\n请写一句30字以内的种草文案。) final_items.append({name: final_kw, title_full: product_name, price: price_status, desc: pitch.replace(\n, ).strip(), img: valid_result.get(img, ), link: valid_result.get(url, )})验证请求启动jupyter notebook main.ipynb依次运行每个 Cell。预期返回结构是控制台打印“环境配置完成”“统一搜索工具已加载”“智能体初始化完成”军师输出 3 行关键词每个商品处理时打印“第1次搜索: xxx 价格”最终在outputs/gift_plan_output.md生成 Markdown 表格包含礼物名称、价格、种草理由、图片/链接四列。如果看到“任务完成”且文件存在说明端到端链路跑通。5. 本篇常见报错排查401、local proxy failed、reading choices、OAuth跑这套系统最容易卡在几个报错上逐个对照。401 Unauthorized / API key is required模型调用返回 401说明 Key 没被正确读取。先确认.env在项目根目录且load_dotenv()在读取环境变量之前执行。检查 Key 有没有多余空格或引号LLM_API_KEY sk-xxx这种写法在 python-dotenv 里会带上引号建议写成LLM_API_KEYsk-xxx。如果用的是 TaoToken 通道确认 Base URL 是https://taotoken.net/apiKey 是在控制台创建的。改完.env后必须重启 Jupyter Kernel否则旧环境变量还在内存里。local proxy failed / connection refused这类报错通常是网络层问题。先确认 Base URL 拼写正确没有多斜杠或少斜杠。如果是百度 MCP 的 SSE 连接超时检查BAIDU_MCP_TOKEN是否有效或者临时切到 Tavilyos.environ[SEARCH_PROVIDER] tavily。注意不要在任何配置里写代理相关的东西TaoToken 通道本身是直连的。Error reading choices / reading choices 报错这是模型返回结构不符合预期常见于 Model ID 填错或模型不支持当前调用格式。确认LLM_MODEL_ID是 TaoToken 通道支持的模型名别填成别的平台的模型 ID。如果返回体里没有choices字段多半是 Base URL 指向了错误的端点检查是不是漏了/api或者多写了/v1。OAuth / 认证失败如果你在 Claude Code 或 Cline MCP 里配置出现 OAuth 相关报错说明认证方式选错了。这类工具应该用 API Key 方式而不是 OAuth 流程。配置三件套写全Base URL 填https://taotoken.net/apiKey 填控制台创建的 API KeyModel ID 按需选。Codex 的 auth.json 场景同理把 base_url 和 api_key 指向 TaoToken不要走 OAuth 回调。ModuleNotFoundError: No module named hello_agents没装 HelloAgents 框架pip install hello-agents。RuntimeError: This event loop is already running百度 MCP 用异步调用和 Jupyter 事件循环冲突。确保代码开头执行了nest_asyncio.apply()。搜索结果为空关键词过于具体或搜索 API 限制。系统机制 3 会自动触发军师换词如果仍失败尝试修改test_cases.json中的预算范围或自定义描述让关键词更宽泛。生成的价格明显不合理正则匹配到了非价格数字。extract_all_prices()已内置过滤逻辑排除年份 2024/2025/2026、过滤极端值如有问题可调整过滤阈值10 val 100000。6. 把模型通道收口之后这套系统还能怎么用整套 GiftGenius 跑通之后你会发现真正省事的地方在于模型调用层被收口了。HelloAgents 和 SimpleAgent 共用一份HelloAgentsLLM配置Base URL 固定指向 TaoToken 的 API 通道换模型只改LLM_MODEL_ID一个值。军师和编辑两个 Agent 的 Prompt 各自独立但底层模型通道是同一份调试时不用在两个地方改 Key。如果你想继续扩展几个方向比较自然前端交互可以开发 Web 页面替代 Jupyter Notebook提供更好的用户体验数据源深度集成可以完全接入百度优选 MCP 的比价与历史价格接口获取更精准的实时价格和库存信息实现“全网比价”丰富选项可以增加更多个人喜好选项如喜欢的商品类型、品牌等支持更细粒度的偏好定制。实际用下来这套四重防御机制超预算找平替、低预算找升级款、无数据换词、最终兜底是整套系统最值得复用的部分。它把“模型可能不靠谱”这件事用代码逻辑兜住了——模型负责创意代码负责准确性。你可以把这套模式搬到任何需要“检索 生成”的 Agent 场景里比如旅游攻略、课程推荐、选品助手。模型通道统一到 TaoToken 之后切换模型做 A/B 对比也方便改一个环境变量就能换一个模型跑同一套流程对比不同模型在关键词生成和文案创作上的表现差异。
返回列表