概述
本指南演示如何使用深度代理构建数据分析代理。数据分析任务通常需要多步骤推理、代码执行以及处理工件(如脚本、报告和图表),而深度代理正是为处理此类任务而设计的。 你将构建的代理能够:- 接受CSV文件进行分析
- 通过可选启用的待办事项列表来规划和跟踪分析步骤
- 执行探索性数据分析并生成可视化图表
- 将结果分享至Slack频道
Slack集成是可选的。你可以修改代理,使其在本地保存工件或通过其他渠道分享结果。
核心概念
本教程涵盖:- 用于沙盒化代码执行的后端
- 用于外部集成的自定义工具
- 使用
TodoListMiddleware实现可选启用的任务规划
设置
安装
安装核心依赖项:pip
pip install deepagents
可选依赖项
在本教程中,我们将使用:- Slack Python SDK 用于分享结果(令牌设置)
- LangSmith 沙盒 用于代码执行
pip
pip install "langsmith[sandbox]" slack-sdk
这些服务是可选的,尽管对于任何生产环境使用,强烈建议使用沙盒化环境。你也可以选择使用本地shell后端(请注意重要的安全注意事项)或直接从后端下载工件。
LangSmith
使用LangChain构建的许多应用程序都包含多个步骤和多次LLM调用。随着这些应用程序变得越来越复杂,能够检查链或代理内部到底发生了什么变得至关重要。实现这一点的最佳方式是使用LangSmith。 在上面的链接注册后,请确保设置环境变量以开始记录跟踪信息:export LANGSMITH_TRACING="true"
export LANGSMITH_API_KEY="..."
import getpass
import os
os.environ["LANGSMITH_TRACING"] = "true"
os.environ["LANGSMITH_API_KEY"] = getpass.getpass()
设置后端
深度代理使用后端在沙盒化环境中执行代码。 下面的示例使用LangSmith沙盒。如需了解其他提供商,请参阅可用提供商。- LangSmith
- 本地shell
- AgentCore
- Daytona
- E2B
- Modal
- Runloop
pip install "langsmith[sandbox]"
uv add "langsmith[sandbox]"
from deepagents.backends.langsmith import LangSmithSandbox
from langsmith.sandbox import SandboxClient
client = SandboxClient()
ls_sandbox = client.create_sandbox()
backend = LangSmithSandbox(sandbox=ls_sandbox)
此后端提供不受限制的文件系统和shell访问权限。仅限在受控的开发和测试环境中使用。更多详情请参阅安全注意事项。
from deepagents.backends import LocalShellBackend
backend = LocalShellBackend(
root_dir=".",
virtual_mode=True,
env={"PATH": "/usr/bin:/bin"},
)
pip install langchain-agentcore-codeinterpreter
uv add langchain-agentcore-codeinterpreter
from bedrock_agentcore.tools.code_interpreter_client import CodeInterpreter
from langchain_agentcore_codeinterpreter import AgentCoreSandbox
interpreter = CodeInterpreter(region="us-west-2")
interpreter.start()
backend = AgentCoreSandbox(interpreter=interpreter)
pip install langchain-daytona
uv add langchain-daytona
from daytona import Daytona
from langchain_daytona import DaytonaSandbox
sandbox = Daytona().create()
backend = DaytonaSandbox(sandbox=sandbox)
result = backend.execute("echo ready")
print(result)
# ExecuteResponse(output='ready', exit_code=0, ...)
pip install langchain-e2b
uv add langchain-e2b
from e2b import Sandbox
from langchain_e2b import E2BSandbox
e2b_sandbox = Sandbox.create()
backend = E2BSandbox(sandbox=e2b_sandbox)
import modal
from langchain_modal import ModalSandbox
app = modal.App.lookup("your-app")
modal_sandbox = modal.Sandbox.create(app=app)
backend = ModalSandbox(sandbox=modal_sandbox)
pip install langchain-runloop
uv add langchain-runloop
from runloop_api_client import RunloopSDK
from langchain_runloop import RunloopSandbox
api_key = "..."
client = RunloopSDK(bearer_token=api_key)
devbox = client.devbox.create()
backend = RunloopSandbox(devbox=devbox)
上传样本数据
创建并上传样本销售数据到后端:import csv
import io
# 创建示例销售数据
data = [
["Date", "Product", "Units Sold", "Revenue"],
["2025-08-01", "Widget A", 10, 250],
["2025-08-02", "Widget B", 5, 125],
["2025-08-03", "Widget A", 7, 175],
["2025-08-04", "Widget C", 3, 90],
["2025-08-05", "Widget B", 8, 200],
]
# 转换为 CSV 字节流
text_buf = io.StringIO()
writer = csv.writer(text_buf)
writer.writerows(data)
csv_bytes = text_buf.getvalue().encode("utf-8")
text_buf.close()
# 上传到后端
backend.upload_files([("/root/data/sales_data.csv", csv_bytes)])
实现自定义工具
数据分析任务可能会产生工件,如报告或图表。 下面的简单工具使用backend.download_files下载它们,然后使用Slack SDK上传。
我们也可以要求代理列出相关的文件路径而不是上传它们,以便相关方根据需要自行获取。
import os
from langchain.tools import tool
from slack_sdk import WebClient
slack_token = os.environ["SLACK_USER_TOKEN"]
slack_client = WebClient(token=slack_token)
channel = "C0123456ABC" # 请在此处指定你自己的频道
@tool(parse_docstring=True)
def slack_send_message(text: str, file_path: str | None = None) -> str:
"""发送消息,可选包含如图片等附件。
Args:
text: (str) 消息的文本内容
file_path: (str) 文件系统中附件的文件路径。
"""
if not file_path:
slack_client.chat_postMessage(channel=channel, text=text)
else:
fp = backend.download_files([file_path])
slack_client.files_upload_v2(
channel=channel,
content=fp[0].content,
initial_comment=text,
)
return "消息已发送。"
通常,避免在沙盒中添加凭据和其他机密信息是一个好习惯。在这里,我们在沙盒外通过一个工具管理Slack令牌。
启用任务规划
任务规划是可选启用的。数据分析通常涉及冗长、多步骤的工作,因此在创建代理时请传递TodoListMiddleware。这使代理拥有一个write_todos工具,用于跟踪探索性分析、可视化和分享步骤。
from langchain.agents.middleware import TodoListMiddleware
create_deep_agent调用中包含此中间件。
运行代理
让我们实例化一个代理:from langchain_core.utils.uuid import uuid7
from deepagents import create_deep_agent
from langchain.agents.middleware import TodoListMiddleware
from langgraph.checkpoint.memory import InMemorySaver
checkpointer = InMemorySaver()
agent = create_deep_agent(
model="google_genai:gemini-3.6-flash",
tools=[slack_send_message],
backend=backend,
checkpointer=checkpointer,
middleware=[TodoListMiddleware()],
)
thread_id = str(uuid7())
config = {"configurable": {"thread_id": thread_id}}
input_message = {
"role": "user",
"content": (
"分析当前目录下的 ./data/sales_data.csv 并生成一张精美的图表。 "
"完成后,使用工具将你的分析结果和图表发送到Slack。"
),
}
stream = agent.stream_events(
{"messages": [input_message]},
config,
version="v3",
)
for snapshot in stream.values:
snapshot["messages"][-1].pretty_print()
================================== Ai 消息 ==================================
[{'text': "我将帮助你分析销售数据并创建一张精美的图表,然后将结果发送到Slack。让我先探索数据。", 'type': 'text'}, {'id': 'toolu_01LRot5h6WkhdpDQ1SG6EQGQ', 'input': {'file_path': './data/sales_data.csv'}, 'name': 'read_file', 'type': 'tool_use'}]
工具调用:
read_file (toolu_01LRot5h6WkhdpDQ1SG6EQGQ)
调用 ID: toolu_01LRot5h6WkhdpDQ1SG6EQGQ
参数:
file_path: ./data/sales_data.csv
================================= 工具消息 =================================
名称: read_file
错误: 文件 '/data/sales_data.csv' 未找到
================================== Ai 消息 ==================================
[{'text': '让我先检查当前目录结构:', 'type': 'text'}, {'id': 'toolu_018DSeF8Dx714Dh2M5vJ1JuK', 'input': {'command': 'pwd'}, 'name': 'execute', 'type': 'tool_use'}, {'id': 'toolu_01As782aRsVB3mJpKPKNwg9c', 'input': {'path': '/'}, 'name': 'ls', 'type': 'tool_use'}]
工具调用:
execute (toolu_018DSeF8Dx714Dh2M5vJ1JuK)
调用 ID: toolu_018DSeF8Dx714Dh2M5vJ1JuK
参数:
command: pwd
ls (toolu_01As782aRsVB3mJpKPKNwg9c)
调用 ID: toolu_01As782aRsVB3mJpKPKNwg9c
参数:
path: /
================================= 工具消息 =================================
名称: execute
/root
[命令成功执行,退出代码为 0]
================================= 工具消息 =================================
名称: ls
['/bin', '/boot', '/dev', '/etc', '/home', '/lib', '/lib64', '/media', '/mnt', '/opt', '/proc', '/root', '/run', '/sbin', '/srv', '/sys', '/tmp', '/usr', '/var', '/.dockerenv']
================================== Ai 消息 ==================================
[{'id': 'toolu_01Sv4ut1P2XFsjrzVmQbJLpr', 'input': {'path': '/root'}, 'name': 'ls', 'type': 'tool_use'}]
工具调用:
ls (toolu_01Sv4ut1P2XFsjrzVmQbJLpr)
调用 ID: toolu_01Sv4ut1P2XFsjrzVmQbJLpr
参数:
path: /root
================================= 工具消息 =================================
名称: ls
['/root/.bash_logout', '/root/.bashrc', '/root/.profile', '/root/data']
================================== Ai 消息 ==================================
[{'text': "太好了!我看到有一个data目录。让我检查其内容:", 'type': 'text'}, {'id': 'toolu_01WN6V9RZjGGoDXzuWdEgB1z', 'input': {'path': '/root/data'}, 'name': 'ls', 'type': 'tool_use'}]
工具调用:
ls (toolu_01WN6V9RZjGGoDXzuWdEgB1z)
调用 ID: toolu_01WN6V9RZjGGoDXzuWdEgB1z
参数:
path: /root/data
================================= 工具消息 =================================
名称: ls
['/root/data/sales_data.csv']
================================== Ai 消息 ==================================
[{'text': '完美!现在让我读取销售数据:', 'type': 'text'}, {'id': 'toolu_01RFmneg7mua1G5csH3rH2Zq', 'input': {'file_path': '/root/data/sales_data.csv'}, 'name': 'read_file', 'type': 'tool_use'}]
工具调用:
read_file (toolu_01RFmneg7mua1G5csH3rH2Zq)
调用 ID: toolu_01RFmneg7mua1G5csH3rH2Zq
参数:
file_path: /root/data/sales_data.csv
================================= 工具消息 =================================
名称: read_file
1 日期,产品,销售量,收入
2 2025-08-01,部件 A,10,250
3 2025-08-02,部件 B,5,125
4 2025-08-03,部件 A,7,175
5 2025-08-04,部件 C,3,90
6 2025-08-05,部件 B,8,200
================================== Ai 消息 ==================================
[{'text': "太棒了!我看到了销售数据。现在我将创建一个Python脚本来分析数据并生成一张精美的图表。让我创建一个包含可视化的综合分析:", 'type': 'text'}, {'id': 'toolu_01JcBjEXgPpCPuaGxn9ALwMg', 'input': {'file_path': '/root/analyze_sales.py', 'content': 'import pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom datetime import datetime\n\n# 设置图表样式\nsns.set_style("whitegrid")\nplt.rcParams[\'figure.figsize\'] = (14, 10)\nplt.rcParams[\'font.size\'] = 11\n\n# 读取数据\ndf = pd.read_csv(\'/root/data/sales_data.csv\')\ndf[\'Date\'] = pd.to_datetime(df[\'Date\'])\n\n# 分析\nprint("=" * 60)\nprint("销售数据分析报告")\nprint("=" * 60)\nprint("\\n1. 数据概览")\nprint("-" * 60)\nprint(f"日期范围: {df[\'Date\'].min().strftime(\'%Y-%m-%d\')} 至 {df[\'Date\'].max().strftime(\'%Y-%m-%d\')}")\nprint(f"总记录数: {len(df)}")\nprint(f"产品: {\', \'.join(df[\'Product\'].unique())}")\n\nprint("\\n2. 汇总统计")\nprint("-" * 60)\nprint(f"总收入: ${df[\'Revenue\'].sum():,.2f}")\nprint(f"总销售量: {df[\'Units Sold\'].sum()}")\nprint(f"平均日收入: ${df[\'Revenue\'].mean():.2f}")\nprint(f"平均每次销售数量: {df[\'Units Sold\'].mean():.2f}")\n\nprint("\\n3. 产品表现")\nprint("-" * 60)\nproduct_stats = df.groupby(\'Product\').agg({\n \'Revenue\': [\'sum\', \'mean\'],\n \'Units Sold\': [\'sum\', \'mean\']\n}).round(2)\nprint(product_stats)\n\nprint("\\n4. 最佳表现日")\nprint("-" * 60)\nbest_day = df.loc[df[\'Revenue\'].idxmax()]\nprint(f"日期: {best_day[\'Date\'].strftime(\'%Y-%m-%d\')}")\nprint(f"产品: {best_day[\'Product\']}")\nprint(f"收入: ${best_day[\'Revenue\']:.2f}")\nprint(f"销售量: {best_day[\'Units Sold\']}")\n\n# 创建可视化\nfig = plt.figure(figsize=(16, 12))\nfig.suptitle(\'销售数据分析仪表板\', fontsize=20, fontweight=\'bold\', y=0.995)\n\n# 1. 每日收入\nax1 = plt.subplot(2, 3, 1)\ncolors = sns.color_palette("husl", len(df))\nbars = ax1.bar(df[\'Date\'].dt.strftime(\'%m-%d\'), df[\'Revenue\'], color=colors, edgecolor=\'black\', linewidth=1.5)\nax1.set_title(\'每日收入\', fontsize=14, fontweight=\'bold\', pad=10)\nax1.set_xlabel(\'日期\', fontsize=12, fontweight=\'bold\')\nax1.set_ylabel(\'收入 ($)\', fontsize=12, fontweight=\'bold\')\nax1.grid(axis=\'y\', alpha=0.3)\nfor bar in bars:\n height = bar.get_height()\n ax1.text(bar.get_x() + bar.get_width()/2., height,\n f\'${int(height)}\',\n ha=\'center\', va=\'bottom\', fontsize=9, fontweight=\'bold\')\nplt.setp(ax1.xaxis.get_majorticklabels(), rotation=45)\n\n# 2. 每日销售量\nax2 = plt.subplot(2, 3, 2)\nbars = ax2.bar(df[\'Date\'].dt.strftime(\'%m-%d\'), df[\'Units Sold\'], color=colors, edgecolor=\'black\', linewidth=1.5)\nax2.set_title(\'每日销售量\', fontsize=14, fontweight=\'bold\', pad=10)\nax2.set_xlabel(\'日期\', fontsize=12, fontweight=\'bold\')\nax2.set_ylabel(\'数量\', fontsize=12, fontweight=\'bold\')\nax2.grid(axis=\'y\', alpha=0.3)\nfor bar in bars:\n height = bar.get_height()\n ax2.text(bar.get_x() + bar.get_width()/2., height,\n f\'{int(height)}\',\n ha=\'center\', va=\'bottom\', fontsize=9, fontweight=\'bold\')\nplt.setp(ax2.xaxis.get_majorticklabels(), rotation=45)\n\n# 3. 按产品分布的收入(饼图)\nax3 = plt.subplot(2, 3, 3)\nproduct_revenue = df.groupby(\'Product\')[\'Revenue\'].sum()\ncolors_pie = sns.color_palette("Set2", len(product_revenue))\nwedges, texts, autotexts = ax3.pie(product_revenue, labels=product_revenue.index, autopct=\'%1.1f%%\',\n colors=colors_pie, startangle=90, textprops={\'fontsize\': 11, \'fontweight\': \'bold\'},\n explode=[0.05] * len(product_revenue))\nax3.set_title(\'按产品分布的收入\', fontsize=14, fontweight=\'bold\', pad=10)\nfor autotext in autotexts:\n autotext.set_color(\'white\')\n autotext.set_fontsize(12)\n\n# 4. 按产品分类的总收入(条形图)\nax4 = plt.subplot(2, 3, 4)\nproduct_revenue_sorted = product_revenue.sort_values(ascending=False)\ncolors_product = sns.color_palette("coolwarm", len(product_revenue_sorted))\nbars = ax4.barh(product_revenue_sorted.index, product_revenue_sorted.values, color=colors_product, edgecolor=\'black\', linewidth=1.5)\nax4.set_title(\'按产品分类的总收入\', fontsize=14, fontweight=\'bold\', pad=10)\nax4.set_xlabel(\'收入 ($)\', fontsize=12, fontweight=\'bold\')\nax4.set_ylabel(\'产品\', fontsize=12, fontweight=\'bold\')\nax4.grid(axis=\'x\', alpha=0.3)\nfor i, (product, revenue) in enumerate(product_revenue_sorted.items()):\n ax4.text(revenue, i, f\' ${int(revenue)}\', va=\'center\', fontsize=10, fontweight=\'bold\')\n\n# 5. 按产品分类的总销售量\nax5 = plt.subplot(2, 3, 5)\nproduct_units = df.groupby(\'Product\')[\'Units Sold\'].sum().sort_values(ascending=False)\ncolors_units = sns.color_palette("viridis", len(product_units))\nbars = ax5.barh(product_units.index, product_units.values, color=colors_units, edgecolor=\'black\', linewidth=1.5)\nax5.set_title(\'按产品分类的总销售量\', fontsize=14, fontweight=\'bold\', pad=10)\nax5.set_xlabel(\'数量\', fontsize=12, fontweight=\'bold\')\nax5.set_ylabel(\'产品\', fontsize=12, fontweight=\'bold\')\nax5.grid(axis=\'x\', alpha=0.3)\nfor i, (product, units) in enumerate(product_units.items()):\n ax5.text(units, i, f\' {int(units)}\', va=\'center\', fontsize=10, fontweight=\'bold\')\n\n# 6. 产品分布\nax6 = plt.subplot(2, 3, 6)\nproduct_counts = df[\'Product\'].value_counts()\ncolors_count = sns.color_palette("muted", len(product_counts))\nwedges, texts, autotexts = ax6.pie(product_counts, labels=product_counts.index, autopct=\'%1.1f%%\',\n colors=colors_count, startangle=45, textprops={\'fontsize\': 11, \'fontweight\': \'bold\'},\n explode=[0.05] * len(product_counts))\nax6.set_title(\'按产品分布的销售交易\', fontsize=14, fontweight=\'bold\', pad=10)\nfor autotext in autotexts:\n autotext.set_color(\'white\')\n autotext.set_fontsize(12)\n\nplt.tight_layout()\nplt.savefig(\'/root/sales_analysis_plot.png\', dpi=300, bbox_inches=\'tight\', facecolor=\'white\')\nprint("\\n" + "=" * 60)\nprint("图表已保存为: sales_analysis_plot.png")\nprint("=" * 60)\n'}, 'name': 'write_file', 'type': 'tool_use'}]
工具调用:
write_file (toolu_01JcBjEXgPpCPuaGxn9ALwMg)
调用 ID: toolu_01JcBjEXgPpCPuaGxn9ALwMg
参数:
file_path: /root/analyze_sales.py
content: import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime
# 设置图表样式
sns.set_style("whitegrid")
plt.rcParams['figure.figsize'] = (14, 10)
plt.rcParams['font.size'] = 11
# 读取数据
df = pd.read_csv('/root/data/sales_data.csv')
df['Date'] = pd.to_datetime(df['Date'])
# 分析
print("=" * 60)
print("销售数据分析报告")
print("=" * 60)
print("\n1. 数据概览")
print("-" * 60)
print(f"日期范围: {df['Date'].min().strftime('%Y-%m-%d')} 至 {df['Date'].max().strftime('%Y-%m-%d')}")
print(f"总记录数: {len(df)}")
print(f"产品: {', '.join(df['Product'].unique())}")
print("\n2. 汇总统计")
print("-" * 60)
print(f"总收入: ${df['Revenue'].sum():,.2f}")
print(f"总销售量: {df['Units Sold'].sum()}")
print(f"平均日收入: ${df['Revenue'].mean():.2f}")
print(f"平均每次销售数量: {df['Units Sold'].mean():.2f}")
print("\n3. 产品表现")
print("-" * 60)
product_stats = df.groupby('Product').agg({
'Revenue': ['sum', 'mean'],
'Units Sold': ['sum', 'mean']
}).round(2)
print(product_stats)
print("\n4. 最佳表现日")
print("-" * 60)
best_day = df.loc[df['Revenue'].idxmax()]
print(f"日期: {best_day['Date'].strftime('%Y-%m-%d')}")
print(f"产品: {best_day['Product']}")
print(f"收入: ${best_day['Revenue']:.2f}")
print(f"销售量: {best_day['Units Sold']}")
# 创建可视化
fig = plt.figure(figsize=(16, 12))
fig.suptitle('销售数据分析仪表板', fontsize=20, fontweight='bold', y=0.995)
# 1. 每日收入
ax1 = plt.subplot(2, 3, 1)
colors = sns.color_palette("husl", len(df))
bars = ax1.bar(df['Date'].dt.strftime('%m-%d'), df['Revenue'], color=colors, edgecolor='black', linewidth=1.5)
ax1.set_title('每日收入', fontsize=14, fontweight='bold', pad=10)
ax1.set_xlabel('日期', fontsize=12, fontweight='bold')
ax1.set_ylabel('收入 ($)', fontsize=12, fontweight='bold')
ax1.grid(axis='y', alpha=0.3)
for bar in bars:
height = bar.get_height()
ax1.text(bar.get_x() + bar.get_width()/2., height,
f'${int(height)}',
ha='center', va='bottom', fontsize=9, fontweight='bold')
plt.setp(ax1.xaxis.get_majorticklabels(), rotation=45)
# 2. 每日销售量
ax2 = plt.subplot(2, 3, 2)
bars = ax2.bar(df['Date'].dt.strftime('%m-%d'), df['Units Sold'], color=colors, edgecolor='black', linewidth=1.5)
ax2.set_title('每日销售量', fontsize=14, fontweight='bold', pad=10)
ax2.set_xlabel('日期', fontsize=12, fontweight='bold')
ax2.set_ylabel('数量', fontsize=12, fontweight='bold')
ax2.grid(axis='y', alpha=0.3)
for bar in bars:
height = bar.get_height()
ax2.text(bar.get_x() + bar.get_width()/2., height,
f'{int(height)}',
ha='center', va='bottom', fontsize=9, fontweight='bold')
plt.setp(ax2.xaxis.get_majorticklabels(), rotation=45)
# 3. 按产品分布的收入(饼图)
ax3 = plt.subplot(2, 3, 3)
product_revenue = df.groupby('Product')['Revenue'].sum()
colors_pie = sns.color_palette("Set2", len(product_revenue))
wedges, texts, autotexts = ax3.pie(product_revenue, labels=product_revenue.index, autopct='%1.1f%%',
colors=colors_pie, startangle=90, textprops={'fontsize': 11, 'fontweight': 'bold'},
explode=[0.05] * len(product_revenue))
ax3.set_title('按产品分布的收入', fontsize=14, fontweight='bold', pad=10)
for autotext in autotexts:
autotext.set_color('white')
autotext.set_fontsize(12)
# 4. 按产品分类的总收入(条形图)
ax4 = plt.subplot(2, 3, 4)
product_revenue_sorted = product_revenue.sort_values(ascending=False)
colors_product = sns.color_palette("coolwarm", len(product_revenue_sorted))
bars = ax4.barh(product_revenue_sorted.index, product_revenue_sorted.values, color=colors_product, edgecolor='black', linewidth=1.5)
ax4.set_title('按产品分类的总收入', fontsize=14, fontweight='bold', pad=10)
ax4.set_xlabel('收入 ($)', fontsize=12, fontweight='bold')
ax4.set_ylabel('产品', fontsize=12, fontweight='bold')
ax4.grid(axis='x', alpha=0.3)
for i, (product, revenue) in enumerate(product_revenue_sorted.items()):
ax4.text(revenue, i, f' ${int(revenue)}', va='center', fontsize=10, fontweight='bold')
# 5. 按产品分类的总销售量
ax5 = plt.subplot(2, 3, 5)
product_units = df.groupby('Product')['Units Sold'].sum().sort_values(ascending=False)
colors_units = sns.color_palette("viridis", len(product_units))
bars = ax5.barh(product_units.index, product_units.values, color=colors_units, edgecolor='black', linewidth=1.5)
ax5.set_title('按产品分类的总销售量', fontsize=14, fontweight='bold', pad=10)
ax5.set_xlabel('数量', fontsize=12, fontweight='bold')
ax5.set_ylabel('产品', fontsize=12, fontweight='bold')
ax5.grid(axis='x', alpha=0.3)
for i, (product, units) in enumerate(product_units.items()):
ax5.text(units, i, f' {int(units)}', va='center', fontsize=10, fontweight='bold')
# 6. 产品分布
ax6 = plt.subplot(2, 3, 6)
product_counts = df['Product'].value_counts()
colors_count = sns.color_palette("muted", len(product_counts))
wedges, texts, autotexts = ax6.pie(product_counts, labels=product_counts.index, autopct='%1.1f%%',
colors=colors_count, startangle=45, textprops={'fontsize': 11, 'fontweight': 'bold'},
explode=[0.05] * len(product_counts))
ax6.set_title('按产品分布的销售交易', fontsize=14, fontweight='bold', pad=10)
for autotext in autotexts:
autotext.set_color('white')
autotext.set_fontsize(12)
plt.tight_layout()
plt.savefig('/root/sales_analysis_plot.png', dpi=300, bbox_inches='tight', facecolor='white')
print("\n" + "=" * 60)
print("图表已保存为: sales_analysis_plot.png")
print("=" * 60)
================================= 工具消息 =================================
名称: write_file
文件 /root/analyze_sales.py 已更新
================================== Ai 消息 ==================================
[{'text': '现在让我运行分析脚本:', 'type': 'text'}, {'id': 'toolu_015xkZr21TuzCTEKGzSqgnbp', 'input': {'command': 'cd /root && python analyze_sales.py'}, 'name': 'execute', 'type': 'tool_use'}]
工具调用:
execute (toolu_015xkZr21TuzCTEKGzSqgnbp)
调用 ID: toolu_015xkZr21TuzCTEKGzSqgnbp
参数:
command: cd /root && python analyze_sales.py
================================= 工具消息 =================================
名称: execute
============================================================
销售数据分析报告
============================================================
1. 数据概览
------------------------------------------------------------
日期范围: 2025-08-01 至 2025-08-05
总记录数: 5
产品: Widget A, Widget B, Widget C
2. 汇总统计
------------------------------------------------------------
总收入: $840.00
总销售量: 33
平均日收入: $168.00
平均每次销售数量: 6.60
3. 产品表现
------------------------------------------------------------
Revenue Units Sold
sum mean sum mean
Product
Widget A 425 212.5 17 8.5
Widget B 325 162.5 13 6.5
Widget C 90 90.0 3 3.0
4. 最佳表现日
------------------------------------------------------------
日期: 2025-08-01
产品: Widget A
收入: $250.00
销售量: 10
============================================================
图表已保存为: sales_analysis_plot.png
============================================================
[命令成功执行,退出代码为 0]
================================== Ai 消息 ==================================
[{'text': '太棒了!分析已完成,图表也已生成。现在让我将分析结果和图表发送到Slack:', 'type': 'text'}, {'id': 'toolu_01Qust5a8DECKPZuU9pBBvkz', 'input': {'text': '📊 **销售数据分析报告** 📊\n\n**1. 数据概览**\n• 日期范围: 2025年8月1-5日 (5天)\n• 分析的产品: Widget A, Widget B, Widget C\n\n**2. 关键指标**\n💰 总收入: $840.00\n📦 总销售量: 33件\n📈 平均日收入: $168.00\n📊 平均每次销售数量: 6.60\n\n**3. 产品表现**\n🏆 Widget A (表现最佳)\n - 总收入: $425 (占总收入的50.6%)\n - 总销售量: 17件 (平均每笔交易8.5件)\n\n🥈 Widget B\n - 总收入: $325 (占总收入的38.7%)\n - 总销售量: 13件 (平均每笔交易6.5件)\n\n🥉 Widget C\n - 总收入: $90 (占总收入的10.7%)\n - 总销售量: 3件 (平均每笔交易3.0件)\n\n**4. 最佳表现日**\n🌟 2025年8月1日\n - 产品: Widget A\n - 收入: $250.00\n - 销售量: 10件\n\n**关键洞察:**\n✅ Widget A 是明显的领导者,贡献了超过50%的总收入\n✅ Widget B 表现出色,销售情况稳定\n⚠️ Widget C 有改进空间 - 销售量和收入最低\n📊 日收入范围从$90到$250\n\n请查看附带的可视化仪表板以获取详细图表! 📈', 'file_path': '/root/sales_analysis_plot.png'}, 'name': 'slack_send_message', 'type': 'tool_use'}]
工具调用:
slack_send_message (toolu_01Qust5a8DECKPZuU9pBBvkz)
调用 ID: toolu_01Qust5a8DECKPZuU9pBBvkz
参数:
text: 📊 **销售数据分析报告** 📊
**1. 数据概览**
• 日期范围: 2025年8月1-5日 (5天)
• 分析的产品: Widget A, Widget B, Widget C
**2. 关键指标**
💰 总收入: $840.00
📦 总销售量: 33件
📈 平均日收入: $168.00
📊 平均每次销售数量: 6.60
**3. 产品表现**
🏆 Widget A (表现最佳)
- 总收入: $425 (占总收入的50.6%)
- 总销售量: 17件 (平均每笔交易8.5件)
🥈 Widget B
- 总收入: $325 (占总收入的38.7%)
- 总销售量: 13件 (平均每笔交易6.5件)
🥉 Widget C
- 总收入: $90 (占总收入的10.7%)
- 总销售量: 3件 (平均每笔交易3.0件)
**4. 最佳表现日**
🌟 2025年8月1日
- 产品: Widget A
- 收入: $250.00
- 销售量: 10件
**关键洞察:**
✅ Widget A 是明显的领导者,贡献了超过50%的总收入
✅ Widget B 表现出色,销售情况稳定
⚠️ Widget C 有改进空间 - 销售量和收入最低
📊 日收入范围从$90到$250
请查看附带的可视化仪表板以获取详细图表! 📈
file_path: /root/sales_analysis_plot.png
================================= 工具消息 =================================
名称: slack_send_message
消息已发送。
================================== Ai 消息 ==================================
太棒了!我已成功完成分析并将所有内容发送到Slack。以下是我所做工作的总结:
## 总结
**分析已完成:**
- 分析了2025年8月1日至5日的销售数据
- 处理了3种产品(部件A、B和C)的数据
- 生成了全面的统计信息和洞察
**主要发现:**
1. **总收入:** $840,持续5天
2. **最佳产品:** 部件A($425收入,占总收入的50.6%)
3. **最佳日期:** 8月1日,收入$250
4. **总销售量:** 33件
**生成的可视化图表:**
一个精美的6面板仪表板,包含:
- 每日收入趋势
- 每日销售量
- 按产品分布的收入(饼图)
- 按产品分类的总收入(水平条形图)
- 按产品分类的总销售量(水平条形图)
- 销售交易分布(饼图)
**已发送至Slack:**
✅ 包含关键指标和洞察的综合分析报告
✅ 高分辨率可视化仪表板(已保存为PNG)
分析显示,部件A是表现最佳的产品,而部件C有改进空间。所有结果均已发送至您的Slack工作区!
结果
代理成功分析了数据,并将包含可视化图表的综合报告分享到了Slack:
代理生成的分析报告和可视化仪表板已发送至Slack
你可以直接从后端下载工件,无需使用外部工具:
backend.download_files(list_of_filepaths)
完成操作后如何清理沙盒,请参阅提供商指南。
后续步骤
既然你已经构建了一个数据分析代理,可以探索以下资源来扩展其功能:- 后端:了解深度代理的后端系统
- 沙盒:回顾用于沙盒化代码执行的后端,包括安全注意事项和高级配置
- 自定义:探索如何使用不同的模型、工具、提示词和可选任务规划来定制你的代理
- 代码:尝试将深度代理代码用作终端编码代理,以在本地协助数据分析和其他代理任务
- 技能:为你的代理配备用于常见工作流的可复用技能
- 人机协作:为数据分析工作流中的关键操作添加交互式审批步骤
Connect these docs to Claude, VSCode, and more via MCP for real-time answers.

