本教程展示如何使用渐进式披露——一种上下文管理技术,代理按需加载信息而不是预先加载——来实现技能(基于专门提示的指令)。代理通过工具调用加载技能,而不是动态更改系统提示,只发现和加载每个任务所需的技能。 用例: 想象构建一个代理来帮助在大型企业的不同业务垂直领域编写 SQL 查询。您的组织可能每个垂直领域有独立的数据存储,或者一个包含数千个表的单一整体数据库。无论哪种方式,预先加载所有模式都会压垮上下文窗口。渐进式披露通过仅在需要时加载相关模式来解决这个问题。这种架构还使不同的产品所有者和利益相关者能够独立地为各自特定的业务垂直领域贡献和维护技能。 您将构建的内容: 一个具有两个技能(销售分析和库存管理)的 SQL 查询助手。代理在其系统提示中看到轻量级技能描述,然后仅在与用户查询相关时通过工具调用加载完整的数据库模式和业务逻辑。
有关带有查询执行、错误纠正和验证的 SQL 代理的完整示例,请参阅我们的 SQL Agent 教程。本教程专注于渐进式披露模式,该模式可应用于任何领域。
渐进式披露由 Anthropic 推广作为一种构建可扩展代理技能系统的技术。这种方法使用三级架构(元数据 → 核心内容 → 详细资源),代理仅在需要时加载信息。有关此技术的更多信息,请参阅 用 Agent Skills 为现实世界装备代理

工作原理

当用户请求 SQL 查询时,流程如下: 为什么选择渐进式披露:
  • 减少上下文使用 - 只加载任务所需的 2-3 个技能,而非所有可用技能
  • 实现团队自治 - 不同团队可以独立开发专门技能(类似于其他多代理架构)
  • 高效扩展 - 添加数十或数百个技能而不压垮上下文
  • 简化对话历史 - 具有单个对话线程的单一代理
什么是技能: 技能,由 Claude Code 推广普及,主要是基于提示的:用于特定业务任务的独立专门指令单元。在 Claude Code 中,技能作为文件系统上的目录暴露,通过文件操作发现。技能通过提示指导行为,可以提供有关工具使用的信息或包含供编码代理执行的示例代码。
具有渐进式披露的技能可以被视为 RAG(检索增强生成) 的一种形式,其中每个技能都是一个检索单元——尽管不一定由嵌入或关键词搜索支持,而是通过浏览内容的工具(如文件操作或本教程中的直接查找)。
权衡:
  • 延迟:按需加载技能需要额外的工具调用,这为需要每个技能的第一次请求增加了延迟
  • 工作流控制:基本实现依靠提示来引导技能使用——如果不添加自定义逻辑,您无法强制执行”始终先尝试技能 A 再尝试技能 B”之类的硬约束
实现您自己的技能系统在构建您自己的技能实现时(本教程中的做法),核心概念是渐进式披露——按需加载信息。在此基础上,您在实现上有完全的灵活性:
  • 存储:数据库、S3、内存数据结构或任何后端
  • 发现:直接查找(本教程)、大规模技能集合的 RAG、文件系统扫描或 API 调用
  • 加载逻辑:自定义延迟特性并添加搜索技能内容或排名相关性的逻辑
  • 副作用:定义技能加载时发生的情况,例如暴露与该技能关联的工具(第 8 节介绍)
这种灵活性让您可以根据性能、存储和工作流控制的具体要求进行优化。

设置

安装

本教程需要 langchain 包:
pip install langchain
有关更多详细信息,请参阅我们的安装指南

LangSmith

设置 LangSmith 以检查代理内部发生的事情。然后设置以下环境变量:
export LANGSMITH_TRACING="true"
export LANGSMITH_API_KEY="..."

选择 LLM

从 LangChain 的集成套件中选择一个聊天模型:
👉 Read the OpenAI chat model integration docs
pip install -U "langchain[openai]"
import os
from langchain.chat_models import init_chat_model

os.environ["OPENAI_API_KEY"] = "sk-..."

model = init_chat_model("gpt-5.2")

1. 定义技能

首先,定义技能的结构。每个技能有一个名称、一个简短描述(显示在系统提示中)和完整内容(按需加载):
from typing import TypedDict

class Skill(TypedDict):
    """A skill that can be progressively disclosed to the agent."""
    name: str    # 技能的唯一标识符
    description: str    # 显示在系统提示中的 1-2 句描述
    content: str    # 包含详细指令的完整技能内容
现在为 SQL 查询助手定义示例技能。技能的目的是在描述上轻量级(预先显示给代理)但在内容上详细(仅在需要时加载):
SKILLS: list[Skill] = [
    {
        "name": "sales_analytics",
        "description": "Database schema and business logic for sales data analysis including customers, orders, and revenue.",
        "content": """# Sales Analytics Schema

## 表

### customers
- customer_id (PRIMARY KEY)
- name
- email
- signup_date
- status (active/inactive)
- customer_tier (bronze/silver/gold/platinum)

### orders
- order_id (PRIMARY KEY)
- customer_id (FOREIGN KEY -> customers)
- order_date
- status (pending/completed/cancelled/refunded)
- total_amount
- sales_region (north/south/east/west)

### order_items
- item_id (PRIMARY KEY)
- order_id (FOREIGN KEY -> orders)
- product_id
- quantity
- unit_price
- discount_percent

## 业务逻辑

**Active customers**: status = 'active' AND signup_date <= CURRENT_DATE - INTERVAL '90 days'

**Revenue calculation**: Only count orders with status = 'completed'. Use total_amount from orders table, which already accounts for discounts.

**Customer lifetime value (CLV)**: Sum of all completed order amounts for a customer.

**High-value orders**: Orders with total_amount > 1000

## 示例查询

-- Get top 10 customers by revenue in the last quarter
SELECT
    c.customer_id,
    c.name,
    c.customer_tier,
    SUM(o.total_amount) as total_revenue
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
WHERE o.status = 'completed'
  AND o.order_date >= CURRENT_DATE - INTERVAL '3 months'
GROUP BY c.customer_id, c.name, c.customer_tier
ORDER BY total_revenue DESC
LIMIT 10;
""",
    },
    {
        "name": "inventory_management",
        "description": "Database schema and business logic for inventory tracking including products, warehouses, and stock levels.",
        "content": """# Inventory Management Schema

## 表

### products
- product_id (PRIMARY KEY)
- product_name
- sku
- category
- unit_cost
- reorder_point (minimum stock level before reordering)
- discontinued (boolean)

### warehouses
- warehouse_id (PRIMARY KEY)
- warehouse_name
- location
- capacity

### inventory
- inventory_id (PRIMARY KEY)
- product_id (FOREIGN KEY -> products)
- warehouse_id (FOREIGN KEY -> warehouses)
- quantity_on_hand
- last_updated

### stock_movements
- movement_id (PRIMARY KEY)
- product_id (FOREIGN KEY -> products)
- warehouse_id (FOREIGN KEY -> warehouses)
- movement_type (inbound/outbound/transfer/adjustment)
- quantity (positive for inbound, negative for outbound)
- movement_date
- reference_number

## 业务逻辑

**Available stock**: quantity_on_hand from inventory table where quantity_on_hand > 0

**Products needing reorder**: Products where total quantity_on_hand across all warehouses is less than or equal to the product's reorder_point

**Active products only**: Exclude products where discontinued = true unless specifically analyzing discontinued items

**Stock valuation**: quantity_on_hand * unit_cost for each product

## 示例查询

-- Find products below reorder point across all warehouses
SELECT
    p.product_id,
    p.product_name,
    p.reorder_point,
    SUM(i.quantity_on_hand) as total_stock,
    p.unit_cost,
    (p.reorder_point - SUM(i.quantity_on_hand)) as units_to_reorder
FROM products p
JOIN inventory i ON p.product_id = i.product_id
WHERE p.discontinued = false
GROUP BY p.product_id, p.product_name, p.reorder_point, p.unit_cost
HAVING SUM(i.quantity_on_hand) <= p.reorder_point
ORDER BY units_to_reorder DESC;
""",
    },
]

2. 创建技能加载工具

创建一个按需加载完整技能内容的工具:
from langchain.tools import tool

@tool
def load_skill(skill_name: str) -> str:
    """Load the full content of a skill into the agent's context.

    Use this when you need detailed information about how to handle a specific
    type of request. This will provide you with comprehensive instructions,
    policies, and guidelines for the skill area.

    Args:
        skill_name: The name of the skill to load (e.g., "expense_reporting", "travel_booking")
    """
    # Find and return the requested skill
    for skill in SKILLS:
        if skill["name"] == skill_name:
            return f"Loaded skill: {skill_name}\n\n{skill['content']}"

    # Skill not found
    available = ", ".join(s["name"] for s in SKILLS)
    return f"Skill '{skill_name}' not found. Available skills: {available}"
load_skill 工具将完整技能内容作为字符串返回,这作为 ToolMessage 成为对话的一部分。有关创建和使用工具的更多详细信息,请参阅工具指南

3. 构建技能中间件

创建自定义中间件,将技能描述注入系统提示。此中间件使技能可被发现,而无需预先加载其完整内容。
本指南演示如何创建自定义中间件。有关中间件概念和模式的综合指南,请参阅自定义中间件文档
from langchain.agents.middleware import ModelRequest, ModelResponse, AgentMiddleware
from langchain.messages import SystemMessage
from typing import Callable

class SkillMiddleware(AgentMiddleware):
    """Middleware that injects skill descriptions into the system prompt."""

    # 将 load_skill 工具注册为类变量
    tools = [load_skill]

    def __init__(self):
        """Initialize and generate the skills prompt from SKILLS."""
        # 从 SKILLS 列表构建技能提示
        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:
        """Sync: Inject skill descriptions into system prompt."""
        # 构建技能附录
        skills_addendum = (
            f"\n\n  ## 可用技能\n\n{self.skills_prompt}\n\n"
            "Use the load_skill tool when you need detailed information "
            "about handling a specific type of request."
        )

        # 追加到系统消息内容块
        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)
中间件将技能描述追加到系统提示,使代理知道可用的技能而不加载其完整内容。load_skill 工具注册为类变量,使其对代理可用。
生产环境考虑:为简单起见,本教程在 __init__ 中加载技能列表。在生产系统中,您可能希望在 before_agent 钩子中加载技能,允许它们定期刷新以反映最新更改(例如,当添加新技能或修改现有技能时)。有关详细信息,请参阅 before_agent 钩子文档

4. 创建具有技能支持的代理

现在使用技能中间件和检查点保存器创建代理以保持状态持久性:
from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver

# 使用技能支持创建代理
agent = create_agent(
    model,
    system_prompt=(
        "You are a SQL query assistant that helps users "
        "write queries against business databases."
    ),
    middleware=[SkillMiddleware()],
    checkpointer=InMemorySaver(),
)
现在代理可以在其系统提示中访问技能描述,并且可以在需要时调用 load_skill 来检索完整技能内容。检查点保存器在多轮对话中保持对话历史。

5. 测试渐进式披露

使用需要特定技能知识的问题测试代理:
from langchain_core.utils.uuid import uuid7

# 此对话线程的配置
thread_id = str(uuid7())
config = {"configurable": {"thread_id": thread_id}}

# 请求 SQL 查询
result = agent.invoke(
    {
        "messages": [
            {
                "role": "user",
                "content": (
                    "Write a SQL query to find all customers "
                    "who made orders over $1000 in the last month"
                ),
            }
        ]
    },
    config
)

# Print the conversation
for message in result["messages"]:
    if hasattr(message, 'pretty_print'):
        message.pretty_print()
    else:
        print(f"{message.type}: {message.content}")
预期输出:
================================ Human Message =================================

Write a SQL query to find all customers who made orders over $1000 in the last month
================================== Ai Message ==================================
Tool Calls:
  load_skill (call_abc123)
 Call ID: call_abc123
  Args:
    skill_name: sales_analytics
================================= Tool Message =================================
Name: load_skill

Loaded skill: sales_analytics

# 销售分析模式

## 表

### customers
- customer_id (PRIMARY KEY)
- name
- email
- signup_date
- status (active/inactive)
- customer_tier (bronze/silver/gold/platinum)

### orders
- order_id (PRIMARY KEY)
- customer_id (FOREIGN KEY -> customers)
- order_date
- status (pending/completed/cancelled/refunded)
- total_amount
- sales_region (north/south/east/west)

[... rest of schema ...]

## 业务逻辑

**High-value orders**: Orders with `total_amount > 1000`
**Revenue calculation**: Only count orders with `status = 'completed'`

================================== Ai Message ==================================

Here's a SQL query to find all customers who made orders over $1000 in the last month:

\`\`\`sql
SELECT DISTINCT
    c.customer_id,
    c.name,
    c.email,
    c.customer_tier
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
WHERE o.total_amount > 1000
  AND o.status = 'completed'
  AND o.order_date >= CURRENT_DATE - INTERVAL '1 month'
ORDER BY c.customer_id;
\`\`\`

This query:
- Joins customers with their orders
- Filters for high-value orders (>$1000) using the total_amount field
- Only includes completed orders (as per the business logic)
- Restricts to orders from the last month
- Returns distinct customers to avoid duplicates if they made multiple qualifying orders
代理在其系统提示中看到轻量级技能描述,识别出该问题需要销售数据库知识,调用 load_skill("sales_analytics") 获取完整模式和业务逻辑,然后使用该信息编写遵循数据库约定的正确查询。

6. 高级:使用自定义状态添加约束

您可以添加约束来强制只有在特定技能加载后才可使用某些工具。这需要跟踪自定义代理状态中已加载的技能。

定义自定义状态

首先,扩展代理状态以跟踪已加载的技能:
from langchain.agents.middleware import AgentState

class CustomState(AgentState):
    skills_loaded: NotRequired[list[str]]    # 跟踪已加载的技能  #

更新 load_skill 以修改状态

修改 load_skill 工具以在技能加载时更新状态:
from langgraph.types import Command    
from langchain.tools import tool, ToolRuntime
from langchain.messages import ToolMessage    

@tool
def load_skill(skill_name: str, runtime: ToolRuntime) -> Command:
    """Load the full content of a skill into the agent's context.

    Use this when you need detailed information about how to handle a specific
    type of request. This will provide you with comprehensive instructions,
    policies, and guidelines for the skill area.

    Args:
        skill_name: The name of the skill to load
    """
    # Find and return the requested skill
    for skill in SKILLS:
        if skill["name"] == skill_name:
            skill_content = f"Loaded skill: {skill_name}\n\n{skill['content']}"

            return Command(
                update={
                    "messages": [
                        ToolMessage(
                            content=skill_content,
                            tool_call_id=runtime.tool_call_id,
                        )
                    ],
                    "skills_loaded": [skill_name],
                }
            )

    # Skill not found
    available = ", ".join(s["name"] for s in SKILLS)
    return Command(
        update={
            "messages": [
                ToolMessage(
                    content=f"Skill '{skill_name}' not found. Available skills: {available}",
                    tool_call_id=runtime.tool_call_id,
                )
            ]
        }
    )

创建约束工具

创建一个仅在特定技能加载后才可使用的工具:
@tool
def write_sql_query(
    query: str,
    vertical: str,
    runtime: ToolRuntime,
) -> str:
    """Write and validate a SQL query for a specific business vertical.

    This tool helps format and validate SQL queries. You must load the
    appropriate skill first to understand the database schema.

    Args:
        query: The SQL query to write
        vertical: The business vertical (sales_analytics or inventory_management)
    """
    # 检查是否已加载所需的技能
    skills_loaded = runtime.state.get("skills_loaded", [])

    if vertical not in skills_loaded:
        return (
            f"Error: You must load the '{vertical}' skill first "
            f"to understand the database schema before writing queries. "
            f"Use load_skill('{vertical}') to load the schema."
        )

    # 验证并格式化查询
    return (
        f"SQL Query for {vertical}:\n\n"
        f"```sql\n{query}\n```\n\n"
        f"✓ Query validated against {vertical} schema\n"
        f"Ready to execute against the database."
    )

更新中间件和代理

更新中间件以使用自定义状态模式:
class SkillMiddleware(AgentMiddleware[CustomState]):
    """Middleware that injects skill descriptions into the system prompt."""

    state_schema = CustomState    
    tools = [load_skill, write_sql_query]

    # ... 中间件实现的其余部分保持不变
使用注册了约束工具的中间件创建代理:
agent = create_agent(
    model,
    system_prompt=(
        "You are a SQL query assistant that helps users "
        "write queries against business databases."
    ),
    middleware=[SkillMiddleware()],
    checkpointer=InMemorySaver(),
)
现在,如果代理在加载所需技能之前尝试使用 write_sql_query,它将收到一条错误消息,提示它首先加载适当的技能(例如 sales_analyticsinventory_management)。这确保代理在尝试验证查询之前具有必要的模式知识。

完整示例

以下是整合本教程所有内容的完整可运行实现:
from langchain_core.utils.uuid import uuid7
from typing import TypedDict, NotRequired
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):
    """A skill that can be progressively disclosed to the agent."""
    name: str
    description: str
    content: str

# 定义具有模式和业务逻辑的技能
SKILLS: list[Skill] = [
    {
        "name": "sales_analytics",
        "description": "Database schema and business logic for sales data analysis including customers, orders, and revenue.",
        "content": """# Sales Analytics Schema

## 表

### customers
- customer_id (PRIMARY KEY)
- name
- email
- signup_date
- status (active/inactive)
- customer_tier (bronze/silver/gold/platinum)

### orders
- order_id (PRIMARY KEY)
- customer_id (FOREIGN KEY -> customers)
- order_date
- status (pending/completed/cancelled/refunded)
- total_amount
- sales_region (north/south/east/west)

### order_items
- item_id (PRIMARY KEY)
- order_id (FOREIGN KEY -> orders)
- product_id
- quantity
- unit_price
- discount_percent

## 业务逻辑

**Active customers**: status = 'active' AND signup_date <= CURRENT_DATE - INTERVAL '90 days'

**Revenue calculation**: Only count orders with status = 'completed'. Use total_amount from orders table, which already accounts for discounts.

**Customer lifetime value (CLV)**: Sum of all completed order amounts for a customer.

**High-value orders**: Orders with total_amount > 1000

## 示例查询

-- Get top 10 customers by revenue in the last quarter
SELECT
    c.customer_id,
    c.name,
    c.customer_tier,
    SUM(o.total_amount) as total_revenue
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
WHERE o.status = 'completed'
  AND o.order_date >= CURRENT_DATE - INTERVAL '3 months'
GROUP BY c.customer_id, c.name, c.customer_tier
ORDER BY total_revenue DESC
LIMIT 10;
""",
    },
    {
        "name": "inventory_management",
        "description": "Database schema and business logic for inventory tracking including products, warehouses, and stock levels.",
        "content": """# Inventory Management Schema

## 表

### products
- product_id (PRIMARY KEY)
- product_name
- sku
- category
- unit_cost
- reorder_point (minimum stock level before reordering)
- discontinued (boolean)

### warehouses
- warehouse_id (PRIMARY KEY)
- warehouse_name
- location
- capacity

### inventory
- inventory_id (PRIMARY KEY)
- product_id (FOREIGN KEY -> products)
- warehouse_id (FOREIGN KEY -> warehouses)
- quantity_on_hand
- last_updated

### stock_movements
- movement_id (PRIMARY KEY)
- product_id (FOREIGN KEY -> products)
- warehouse_id (FOREIGN KEY -> warehouses)
- movement_type (inbound/outbound/transfer/adjustment)
- quantity (positive for inbound, negative for outbound)
- movement_date
- reference_number

## 业务逻辑

**Available stock**: quantity_on_hand from inventory table where quantity_on_hand > 0

**Products needing reorder**: Products where total quantity_on_hand across all warehouses is less than or equal to the product's reorder_point

**Active products only**: Exclude products where discontinued = true unless specifically analyzing discontinued items

**Stock valuation**: quantity_on_hand * unit_cost for each product

## 示例查询

-- Find products below reorder point across all warehouses
SELECT
    p.product_id,
    p.product_name,
    p.reorder_point,
    SUM(i.quantity_on_hand) as total_stock,
    p.unit_cost,
    (p.reorder_point - SUM(i.quantity_on_hand)) as units_to_reorder
FROM products p
JOIN inventory i ON p.product_id = i.product_id
WHERE p.discontinued = false
GROUP BY p.product_id, p.product_name, p.reorder_point, p.unit_cost
HAVING SUM(i.quantity_on_hand) <= p.reorder_point
ORDER BY units_to_reorder DESC;
""",
    },
]

# 创建技能加载工具
@tool
def load_skill(skill_name: str) -> str:
    """Load the full content of a skill into the agent's context.

    Use this when you need detailed information about how to handle a specific
    type of request. This will provide you with comprehensive instructions,
    policies, and guidelines for the skill area.

    Args:
        skill_name: The name of the skill to load (e.g., "sales_analytics", "inventory_management")
    """
    # Find and return the requested skill
    for skill in SKILLS:
        if skill["name"] == skill_name:
            return f"Loaded skill: {skill_name}\n\n{skill['content']}"

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

# Create skill middleware
class SkillMiddleware(AgentMiddleware):
    """Middleware that injects skill descriptions into the system prompt."""

    # Register the load_skill tool as a class variable
    tools = [load_skill]

    def __init__(self):
        """Initialize and generate the skills prompt from SKILLS."""
        # Build skills prompt from the SKILLS list
        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:
        """Sync: Inject skill descriptions into system prompt."""
        # Build the skills addendum
        skills_addendum = (
            f"\n\n## Available Skills\n\n{self.skills_prompt}\n\n"
            "Use the load_skill tool when you need detailed information "
            "about handling a specific type of request."
        )

        # Append to system message content blocks
        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)

# 示例:from langchain_anthropic import ChatAnthropic
# model = ChatAnthropic(model="claude-3-5-sonnet-20241022")
# model = ChatAnthropic(model="claude-3-5-sonnet-20241022")
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-4")

# Create the agent with skill support
agent = create_agent(
    model,
    system_prompt=(
        "You are a SQL query assistant that helps users "
        "write queries against business databases."
    ),
    middleware=[SkillMiddleware()],
    checkpointer=InMemorySaver(),
)

# 此对话线程的配置
if __name__ == "__main__":
    # Configuration for this conversation thread
    thread_id = str(uuid7())
    config = {"configurable": {"thread_id": thread_id}}

    # Ask for a SQL query
    result = agent.invoke(
        {
            "messages": [
                {
                    "role": "user",
                    "content": (
                        "Write a SQL query to find all customers "
                        "who made orders over $1000 in the last month"
                    ),
                }
            ]
        },
        config
    )

    # Print the conversation
    for message in result["messages"]:
        if hasattr(message, 'pretty_print'):
            message.pretty_print()
        else:
            print(f"{message.type}: {message.content}")
此完整示例包括:
  • 具有完整数据库模式的技能定义
  • 用于按需加载的 load_skill 工具
  • 将技能描述注入系统提示的 SkillMiddleware
  • 使用中间件和检查点保存器创建代理
  • 示例用法,展示代理如何加载技能和编写 SQL 查询
要运行此示例,您需要:
  1. 安装所需包:pip install langchain langchain-openai langgraph
  2. 设置您的 API 密钥(例如 export OPENAI_API_KEY=...
  3. 用您首选的 LLM 提供商替换模型初始化

实现变体

本教程将技能实现为通过工具调用加载的内存 Python 字典。但是,有几种方法可以实现带有技能的渐进式披露:存储后端:
  • 内存中(本教程):技能定义为 Python 数据结构,快速访问,无 I/O 开销
  • 文件系统(Claude Code 方法):技能作为带文件的目录,通过文件操作(如 read_file)发现
  • 远程存储:技能在 S3、数据库、Notion 或 API 中,按需获取
技能发现(代理如何了解存在哪些技能):
  • 系统提示列表:技能描述在系统提示中(本教程使用的方法)
  • 基于文件:通过扫描目录发现技能(Claude Code 方法)
  • 基于注册表:查询技能注册表服务或 API 以获取可用技能
  • 动态查找:通过工具调用列出可用技能
渐进式披露策略(如何加载技能内容):
  • 单次加载:在一个工具调用中加载整个技能内容(本教程使用的方法)
  • 分页:分多页/块加载大技能内容
  • 基于搜索:在特定技能内容中搜索相关部分(例如,在技能文件上使用 grep/读取操作)
  • 分层:首先加载技能概述,然后深入特定子部分
大小考虑(未校准的心理模型——根据您的系统进行优化):
  • 小型技能(< 1K tokens / ~750 词):可以直接包含在系统提示中,并使用提示缓存以节省成本和加快响应
  • 中型技能(1-10K tokens / ~750-7.5K 词):受益于按需加载以避免上下文开销(本教程)
  • 大型技能(> 10K tokens / ~7.5K 词,或 > 上下文窗口的 5-10%):应使用分页、基于搜索的加载或分层探索等渐进式披露技术,以避免消耗过多上下文
选择取决于您的要求:内存中最快,但需要重新部署才能更新技能,而基于文件或远程存储支持动态技能管理,无需更改代码。

渐进式披露和上下文工程

渐进式披露本质上是一种**上下文工程技术**——您正在管理哪些信息对代理可用以及何时可用。本教程专注于加载数据库模式,但相同的原则适用于其他类型的上下文。

与少样本提示结合

对于 SQL 查询用例,您可以扩展渐进式披露以动态加载与用户查询相关的少样本示例示例方法:
  1. 用户问:“查找 6 个月未下单的客户”
  2. 代理加载 sales_analytics 模式(如本教程所示)
  3. 代理还加载 2-3 个相关示例查询(通过语义搜索或基于标签的查找):
    • 查找非活跃客户的查询
    • 具有基于日期过滤的查询
    • 连接 customers 和 orders 表的查询
  4. 代理使用模式知识和示例模式编写查询
这种渐进式披露(按需加载模式)和动态少样本提示(加载相关示例)的组合创建了一个强大的上下文工程模式,可以扩展到大型知识库,同时提供高质量、基于事实的输出。

下一步