Skills实现方案-LangChain1.0.md 10.1 KB

Skills 渐进式展开实现方案(LangChain 1.0+)

一、需求概述

Skills 替代零散的工具调用,实现渐进式展开(Progressive Disclosure):
Agent 在 system prompt 中只看到技能摘要,按需加载详细技能内容,减少 token 消耗、提升扩展性。

技能 英文标识 职责
查找相关商品 lookup_related 基于文本/图片查找相似或相关商品(图片需先分析风格)
搜索商品 search_products 按自然语言描述搜索商品
检验商品 check_product 检验商品是否符合用户要求
结果包装 result_packaging 格式化、排序、筛选并呈现结果
售后相关 after_sales 退换货、物流、保修等售后问题

二、LangChain 1.0 中的 Skills 实现方式

2.1 两种实现路线

方式 适用场景 依赖
方式 A:create_agent + 自定义 Skill 中间件 购物导购等业务 Agent langchain>=1.0langgraph>=1.0
方式 B:Deep Agents + SKILL.md 依赖文件系统、多技能目录 deepagents

购物导购场景推荐方式 A,更易与现有 Search API 等服务集成。

2.2 核心思路:Progressive Disclosure

用户请求 → Agent 看轻量描述 → 判断需要的技能 → load_skill → 拿到完整说明 → 执行工具 → 回复
  • 启动时:只注入技能名称 + 简短描述(1–2 句)
  • 按需加载:Agent 调用 load_skill(skill_name) 获取完整指令
  • 执行:按技能说明调用对应工具

三、实现架构

3.1 技能定义结构

from typing import TypedDict

class Skill(TypedDict):
    """可渐进式展开的技能"""
    name: str          # 唯一标识
    description: str   # 1-2 句,展示在 system prompt
    content: str      # 完整指令,仅在 load_skill 时返回

3.2 五个技能定义示例

SKILLS: list[Skill] = [
    {
        "name": "lookup_related",
        "description": "查找与某商品相关的其他商品,支持文本相似、同品类推荐。",
        "content": """# 查找相关商品

## 适用场景
- 用户上传图片要求「找类似的」
- 用户说「和这个差不多」「搭配的裤子」
- 用户已有一件商品,想找相关款

## 操作步骤
1. **有图片**:先调用 `analyze_image_style` 理解风格,再调用 `search_products` 用描述搜索
2. **无图片**:用 `search_products` 描述品类+风格+颜色
3. 可结合上下文中的商品 ID、品类做同品类推荐

## 可用工具
- `search_products(query, limit)`:文本搜索
- `analyze_image_style(image_path)`:分析图片风格""",
    },
    {
        "name": "search_products",
        "description": "按自然语言描述搜索商品,如「红色连衣裙」「运动鞋」等。",
        "content": """# 搜索商品

## 适用场景
- 用户用文字描述想要什么
- 如「冬天穿的外套」「正装衬衫」「跑步鞋」

## 操作步骤
1. 将用户描述整理成结构化 query(品类+颜色+风格+场景)
2. 调用 `search_products(query, limit)`,limit 默认 5–10
3. 如有图片,可先 `analyze_image_style` 提炼关键词再搜索

## 可用工具
- `search_products(query, limit)`:自然语言搜索""",
    },
    {
        "name": "check_product",
        "description": "检验商品是否符合用户要求,如尺寸、材质、场合、价格区间等。",
        "content": """# 检验商品是否符合要求

## 适用场景
- 用户问「这款适合我吗」「有没有 XX 材质的」
- 用户提出约束:尺寸、价格、场合、材质

## 操作步骤
1. 从对话中提取约束条件(尺寸、材质、场合、价格等)
2. 对已召回商品做筛选或二次搜索
3. 调用 `search_products` 时在 query 中带上约束
4. 回复时明确说明哪些符合、哪些不符合

## 注意
- 无专门工具时,用 search_products 的 query 表达约束
- 可结合商品元数据(baseColour, season, usage 等)做简单筛选""",
    },
    {
        "name": "result_packaging",
        "description": "对搜索结果进行格式化、排序、筛选并呈现给用户。",
        "content": """# 结果包装

## 适用场景
- 工具返回多条商品后需要整理呈现
- 用户要求「按价格排序」「只要前 3 个」

## 操作步骤
1. 按相关性/相似度排序
2. 限制展示数量(通常 3–5 个)
3. **必须使用以下格式**呈现每个商品:

  1. [Product Name] ID: [Product ID Number] Category: [Category] Color: [Color] Gender: [Gender] Season: [Season] Usage: [Usage] Relevance: [XX%] ```
  1. ID 字段不可省略,用于前端展示图片""", }, { "name": "after_sales", "description": "处理退换货、物流、保修、尺码建议等售后问题。", "content": """# 售后相关

适用场景

  • 退换货政策、运费、签收时间
  • 尺码建议、洗涤说明
  • 保修、客服联系方式

操作步骤

  1. 此类问题无需调用商品搜索工具
  2. 按平台统一售后政策回答
  3. 涉及具体商品时,可结合商品 ID 查询详情后再回答
  4. 复杂问题引导用户联系客服""", }, ] ```

四、核心代码实现

4.1 load_skill 工具

from langchain.tools import tool

@tool
def load_skill(skill_name: str) -> str:
    """加载技能的完整内容到 Agent 上下文中。

    当需要处理特定类型请求时,调用此工具获取该技能的详细说明和操作步骤。

    Args:
        skill_name: 技能名称,可选值:lookup_related, search_products, check_product, result_packaging, after_sales
    """
    for skill in SKILLS:
        if skill["name"] == skill_name:
            return f"Loaded skill: {skill_name}\n\n{skill['content']}"

    available = ", ".join(s["name"] for s in SKILLS)
    return f"Skill '{skill_name}' not found. Available: {available}"

4.2 SkillMiddleware(注入技能描述)

from langchain.agents.middleware import AgentMiddleware, ModelRequest, ModelResponse
from langchain.messages import SystemMessage
from typing import Callable

class ShoppingSkillMiddleware(AgentMiddleware):
    """将技能描述注入 system prompt,使 Agent 能发现并按需加载技能"""

    tools = [load_skill]

    def __init__(self):
        skills_list = []
        for skill in SKILLS:
            skills_list.append(f"- **{skill['name']}**: {skill['description']}")
        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(content=new_content)
        modified_request = request.override(system_message=new_system_message)
        return handler(modified_request)

4.3 创建带 Skills 的 Agent

from langchain.agents import create_agent
from langgraph.checkpoint.memory import MemorySaver

# 基础工具(搜索、风格分析等)
from app.tools.search_tools import search_products, analyze_image_style

agent = create_agent(
    model="gpt-4o-mini",
    tools=[
        load_skill,           # 技能加载
        search_products,
        analyze_image_style,
    ],
    system_prompt="""你是智能时尚购物助手。根据用户需求,先判断使用哪个技能,必要时用 load_skill 加载技能详情。

处理商品结果时,必须遵守 result_packaging 技能中的格式要求。""",
    middleware=[ShoppingSkillMiddleware()],
    checkpointer=MemorySaver(),
)

五、与工具的关系

能力 技能 工具
查找相关 lookup_related search_products, analyze_image_style
搜索商品 search_products search_products
检验商品 check_product search_products(用 query 表达约束)
结果包装 result_packaging 无(纯 prompt 约束)
售后 after_sales 无(或对接客服 API)
  • 技能:提供「何时用、怎么用」的说明,支持渐进式加载。
  • 工具:实际执行搜索、分析等操作。

六、可选:技能约束(进阶)

若希望「先加载技能再使用工具」,可结合 ToolRuntime 和 state 做约束:

from langchain.tools import tool, ToolRuntime
from langgraph.types import Command
from langchain.messages import ToolMessage
from typing_extensions import NotRequired

class CustomState(AgentState):
    skills_loaded: NotRequired[list[str]]

@tool
def load_skill(skill_name: str, runtime: ToolRuntime) -> Command:
    """..."""
    for skill in SKILLS:
        if skill["name"] == skill_name:
            content = f"Loaded skill: {skill_name}\n\n{skill['content']}"
            return Command(update={
                "messages": [ToolMessage(content=content, tool_call_id=runtime.tool_call_id)],
                "skills_loaded": [skill_name],
            })
    # ...

# 在 check_product 等工具中检查 skills_loaded

七、依赖与版本

# requirements.txt
langchain>=1.0.0
langchain-openai>=0.2.0
langchain-core>=0.3.0
langgraph>=1.0.0
  • Python 3.10+
  • 若使用 Deep Agents 的 SKILL.md,需额外安装 deepagents

八、总结

项目 说明
效果 系统 prompt 只放简短技能描述,按需加载完整内容,减少 token、便于扩展
流程 轻量描述 → load_skill → 完整说明 → 调用工具 → 回复
实现 SkillMiddleware + load_skill + create_agent
技能 lookup_related, search_products, check_product, result_packaging, after_sales

完整示例可参考官方教程:Build a SQL assistant with on-demand skills