LangChain多智能体之Skills:用TaoToken统一Key打通配置骨架
发布时间:2026/9/26 13:12:17来源:尧图网络
1. 多智能体 Skills 场景下Key 分散到底有多痛LangChain 的多智能体 Skills 结构本质是把「专项能力」封装成可被 agent 按需调用的技能单元。每个技能由专用提示词驱动agent 根据上下文动态加载而不是一次性把所有能力塞进系统提示词。这套渐进式披露progressive disclosure的思路和 Agent Skills、llms.txt 的设计理念高度一致——通过工具调用实现文档的渐进式暴露只不过技能模式把这种「渐进式暴露」用在了专用提示词和领域知识上。问题出在落地阶段。当你按官方教程搭一个 SQL 助手代码里会同时出现好几个模型入口主 agent 用ChatOpenAI(modelgpt-4.1)某个技能内部可能想换成 Claude 做长文审阅另一个技能想用本地小模型做分类。于是环境变量里躺着OPENAI_API_KEY、ANTHROPIC_API_KEY、DASHSCOPE_API_KEY……每加一个技能就多一份 Key 管理成本。本地开发时更乱.env文件散落在多个目录settings.json和config.toml各写一份改一个模型要翻三个文件。我试过在一台机器上同时跑三个 Skills demo结果因为 Key 前缀写错、base_url 漏配agent 在load_skill之后调用模型直接 401排查了半小时才发现是环境变量没生效。这类问题不涉及算法纯粹是配置骨架没搭好。这篇就聚焦一件事用 TaoToken 统一 Key 和 API 通道把 LangChain 多智能体 Skills 的配置收敛成一份可复制的骨架并给出启动后验证调用链是否连通的检查动作。适合谁看正在本地开发或调试 LangChain 多智能体、被多模型 Key 分散困扰、想要一份能直接抄的settings.json/config.toml配置的开发者。读完你能拿到两套配置模板、一段可运行的 Skills 加载代码以及一套验证调用链的检查清单。2. TaoToken 前置统一 Key 与 API 通道TaoToken 在这里扮演的角色很单纯它是一个统一的模型接入通道。你不需要为每个模型厂商单独维护 Key而是用一份 TaoToken 的 API Key通过统一的 base_url 去调用不同模型。对 LangChain 来说这意味着ChatOpenAI、ChatAnthropic这些类的base_url和api_key可以指向同一个入口模型名通过参数区分。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 。注意 API 地址不带 UTM 参数配置里直接写这个。你需要先拿到 API Key。进入控制台创建https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 然后在 API Keys 页面生成https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。生成后复制那串sk-开头的字符串后面配置里会用到。注意API Key 只显示一次生成后立刻保存到本地配置文件或密码管理器。不要提交到 Git 仓库。如果你只是想先验证模型能不能通可以直接用模型对话页面测一下https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。确认通道可用后再往下做 LangChain 集成。对于长期跑编码任务或 Agent 的场景可以考虑 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 遇到参数细节可以对照查。3. 可复制配置骨架settings.json 与 config.toml配置骨架的目标是一份文件管住所有模型的 Key 和 base_urlSkills 代码只读配置不硬编码。下面给两套按你的项目习惯选一套即可。3.1 settings.json 骨架适合 Python 项目用pydantic-settings或直接json.load读取。放在项目根目录的config/settings.json{ taotoken: { api_key: sk-你的TaoToken密钥, base_url: https://taotoken.net/api, default_model: gpt-4.1, timeout: 60, max_retries: 2 }, models: { main_agent: { model: gpt-4.1, temperature: 0.2 }, skill_sql: { model: gpt-4.1, temperature: 0.0 }, skill_review: { model: claude-3-5-sonnet-20241022, temperature: 0.3 } }, skills: { enabled: [sales_analytics, inventory_management], load_tool_name: load_skill } }读取代码import json from pathlib import Path def load_settings(path: str config/settings.json) - dict: with open(Path(path), r, encodingutf-8) as f: return json.load(f) settings load_settings() tt settings[taotoken]3.2 config.toml 骨架如果你偏好 TOML放在config/config.toml[taotoken] api_key sk-你的TaoToken密钥 base_url https://taotoken.net/api default_model gpt-4.1 timeout 60 max_retries 2 [models.main_agent] model gpt-4.1 temperature 0.2 [models.skill_sql] model gpt-4.1 temperature 0.0 [models.skill_review] model claude-3-5-sonnet-20241022 temperature 0.3 [skills] enabled [sales_analytics, inventory_management] load_tool_name load_skill读取代码Python 3.11 自带 tomllibimport tomllib from pathlib import Path def load_config(path: str config/config.toml) - dict: with open(Path(path), rb) as f: return tomllib.load(f) config load_config() tt config[taotoken]3.3 把配置接到 LangChain 模型上关键点所有模型类都指向同一个base_url和api_key模型名从配置里取。import os from langchain_openai import ChatOpenAI def build_model(cfg: dict, role: str main_agent) - ChatOpenAI: tt cfg[taotoken] m cfg[models][role] return ChatOpenAI( modelm[model], temperaturem.get(temperature, 0.2), api_keytt[api_key], base_urltt[base_url], timeouttt.get(timeout, 60), max_retriestt.get(max_retries, 2), ) main_model build_model(config, main_agent) sql_model build_model(config, skill_sql)这样 Skills 中间件和load_skill工具都不需要关心 Key 从哪来只从config里拿模型实例。新增一个技能时只在models段加一条代码零改动。提示base_url末尾不要带/v1TaoToken 的 API 入口是https://taotoken.net/apiSDK 会自己拼接路径。如果你用的是 Anthropic SDKbase_url 同样填这个模型名用claude-3-5-sonnet-20241022这类标识。4. 验证请求Skills 调用链是否连通配置写完不算完要验证「agent → load_skill → 模型 → 返回」这条链真的通了。下面给一个最小可运行的 Skills 骨架然后给检查动作。4.1 最小 Skills 骨架from typing import TypedDict from langchain.tools import tool from langchain.agents import create_agent from langchain.agents.middleware import ModelRequest, ModelResponse, AgentMiddleware from langchain.messages import SystemMessage from langgraph.checkpoint.memory import InMemorySaver from typing import Callable class Skill(TypedDict): name: str description: str content: str SKILLS: list[Skill] [ { name: sales_analytics, description: 用于销售数据分析的数据库结构和业务逻辑包括客户、订单和收入。, content: # 销售分析 Schema\n## 表结构\n### customers\n- customer_id (主键)\n- name\n- email\n- status (active/inactive)\n### orders\n- order_id (主键)\n- customer_id (外键)\n- total_amount\n- status (pending/completed/cancelled)\n## 业务逻辑\n高价值订单total_amount 1000\n收入计算仅统计 status completed 的订单, }, { name: inventory_management, description: 用于库存跟踪的数据库结构和业务逻辑包括产品、仓库和库存水平。, content: # 库存管理 Schema\n## 表结构\n### products\n- product_id (主键)\n- product_name\n- reorder_point\n- discontinued (布尔值)\n### inventory\n- product_id (外键)\n- warehouse_id (外键)\n- quantity_on_hand\n## 业务逻辑\n需要补货的产品总库存 reorder_point, }, ] tool def load_skill(skill_name: str) - str: 将技能的完整内容加载到智能体上下文中。 当需要详细了解如何处理某类请求时使用此工具。 参数: skill_name: 要加载的技能名称 for skill in SKILLS: if skill[name] skill_name: return f已加载技能: {skill_name}\n\n{skill[content]} available , .join(s[name] for s in SKILLS) return f未找到技能 {skill_name}。可用技能{available} class SkillMiddleware(AgentMiddleware): tools [load_skill] def __init__(self): skills_list [f- **{s[name]}**: {s[description]} for s in SKILLS] self.skills_prompt \n.join(skills_list) def wrap_model_call( self, request: ModelRequest, handler: Callable[[ModelRequest], ModelResponse], ) - ModelResponse: skills_addendum ( f\n\n## 可用技能\n\n{self.skills_prompt}\n\n 当需要详细了解如何处理某类请求时请使用 load_skill 工具。 ) new_content list(request.system_message.content_blocks) [ {type: text, text: skills_addendum} ] new_system_message SystemMessage(contentnew_content) modified_request request.override(system_messagenew_system_message) return handler(modified_request) agent create_agent( main_model, system_prompt你是一个 SQL 查询助手帮助用户针对业务数据库编写查询语句。, middleware[SkillMiddleware()], checkpointerInMemorySaver(), )4.2 检查动作一模型通道连通先不跑 agent单独测模型resp main_model.invoke(回复 OK 两个字母) print(resp.content)预期输出包含OK。如果报 401检查api_key是否复制完整如果报 404检查base_url是否写成了https://taotoken.net/api不要带/v1。4.3 检查动作二load_skill 工具可调用print(load_skill.invoke({skill_name: sales_analytics})[:80])预期输出以已加载技能: sales_analytics开头。如果返回「未找到技能」说明SKILLS列表里的name和调用参数不一致。4.4 检查动作三完整调用链import uuid thread_id str(uuid.uuid4()) config {configurable: {thread_id: thread_id}} result agent.invoke( { messages: [ { role: user, content: 写一个 SQL 查询找出上个季度收入排名前 10 的客户, } ] }, config, ) for message in result[messages]: if hasattr(message, pretty_print): message.pretty_print() else: print(f{message.type}: {message.content})预期输出顺序Human Message → Ai Message含load_skill的 Tool Calls→ Tool Message已加载技能: sales_analytics→ Ai Message最终 SQL。只要看到 Tool Calls 里出现load_skill且 Tool Message 返回了技能内容就说明调用链连通。5. 本篇常见错排查5.1 401 Unauthorized最常见。原因通常是api_key没读到或者读到了空字符串。检查config加载后tt[api_key]是否以sk-开头。如果你用环境变量覆盖确认os.environ里没有残留的旧 Key 把配置覆盖掉。5.2 404 Not Foundbase_url写错。正确值是https://taotoken.net/api。不要写成https://taotoken.net/api/v1也不要漏掉/api。如果你用的是ChatAnthropic同样填这个 base_url。5.3 load_skill 没被调用agent 直接回答了没有走工具。原因可能是系统提示词里没有明确告诉它「有技能可用」。检查SkillMiddleware的wrap_model_call是否真的把skills_addendum拼进了 system message。可以在wrap_model_call里加一行print(new_system_message.content)确认。5.4 技能加载了但 SQL 不对技能内容里的表结构和业务逻辑要写清楚。比如「高价值订单」的定义、收入只算completed状态这些必须写进content。如果 agent 加载了技能还是写错检查content里有没有把关键字段名和状态值列全。5.5 多技能切换时模型串了如果你给不同技能配了不同模型确认build_model是按role取的。常见错误是SkillMiddleware里硬编码了main_model导致所有技能都用同一个模型。把模型实例通过构造函数传进中间件而不是在中间件里 import 全局变量。5.6 配置改了但没生效Python 进程缓存了旧配置。如果你在 Jupyter 里改settings.json需要重新执行load_settings()。如果是脚本确认没有在模块顶层把config存成全局变量后被其他模块 import 缓存。6. 继续往下走配置骨架搭好之后下一步是把技能内容从代码里挪出去。现在SKILLS是硬编码的 list实际项目里应该从文件系统或数据库加载。你可以把每个技能写成一个 Markdown 文件load_skill改成读文件这样新增技能不用改代码。模型通道方面如果你要跑更长的编码任务或 Agent 工作流可以看 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。接入细节和参数说明在文档里https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。需要新建 Key 或管理多个项目的 Key去 API Keys 页面https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。最后提醒一个实操细节把settings.json和config.toml加进.gitignore只提交一份settings.example.json作为模板。Key 泄露的代价远高于多写一行忽略规则。
网站建设高端定制企业官网