Skip to content

实战:研究型 Agent 🔥

前面几页分别讲了 Agent、Toolkit、上下文压缩、Workspace 沙箱与 Plan 工具。这一页把它们组合成一个 完整可跑的研究型 Agent:给它一个主题和一个资料目录,它会自主拆解任务、读取资料、产出一份中文摘要 报告。这是 AgentScope 2.x 五大支柱在同一个脚本里协同工作的最小闭环。

版本基线:本文示例以 agentscope 2.0.4(PyPI,2026-07-07)为准,要求 Python >=3.11。 导入路径为 from agentscope.agent import Agent, ContextConfigfrom agentscope.tool import Toolkit, Bash, Read, Write, Edit, Glob, Grep, TaskCreate, TaskGet, TaskList, TaskUpdatefrom agentscope.workspace import LocalWorkspacefrom agentscope.middleware import TracingMiddleware (源:src/agentscope/agent/__init__.pysrc/agentscope/tool/__init__.pysrc/agentscope/workspace/__init__.pysrc/agentscope/middleware/__init__.py)。

调用真实 LLM 会产生费用

本页示例会调用真实模型 API,按 provider 计费产生费用。研究型 Agent 会多轮调用模型(规划、读文件、 写报告),token 消耗显著高于单轮问答。如果想零成本跑通,可改用下方 Ollama 本地模型 变体,它在本地推理、不需要 API key、不产生云端费用。

目标

完成后你会组合五个构建块,得到一个能独立完成"资料调研 -> 摘要报告"任务的 Agent:

  1. Agent 驱动 ReAct 循环,把模型、工具、上下文、工作区串成一条执行链。
  2. Toolkit 装配内置文件工具(Read / Write / Edit / Glob / Grep)与 Plan 工具 (TaskCreate / TaskGet / TaskList / TaskUpdate),让 Agent 能规划进度并读写文件。
  3. ContextConfig 配置上下文压缩阈值,长任务逼近上限时自动压缩历史并卸载到 Workspace。
  4. LocalWorkspace 同时承担工具执行环境与上下文卸载目标两个角色。
  5. TracingMiddleware(可选)挂载全生命周期 OpenTelemetry 追踪,无后端时自动降级为 no-op。

前端类比

可以把这个研究型 Agent 类比为一个带任务看板的 Node CLI 脚本TaskCreate 是往看板上贴卡片, Read / Grepfs.readFile / grepWritefs.writeFileContextConfig 像一个自动 归档旧 log 的滚动策略,LocalWorkspace 是脚本的工作目录,TracingMiddleware 像一个挂载在中间件 链上的 OpenTelemetry 插桩。

AgentScope 原生语义:这不是脚本,而是一个事件驱动的 ReAct 循环。Agent 调用模型生成推理与工具 调用,工具在 Workspace 中执行后把结果回灌进上下文,循环直到模型不再产出工具调用。Plan 工具不是 外部看板,而是被 Toolkit 装配、状态写入 AgentState.tasks_contextFunctionTool 子类; ContextConfig 的压缩由 Agent 在 ReAct 循环特定节点自动触发,不是手动 setTimeout。把前端类比 作为理解入口即可,不要把脚本同步执行模型硬套到异步事件循环上。

实战架构

下面这张图说明一次研究任务如何穿过五个构建块。图前先说明:输入是一条 UserMsg(主题 + 资料目录), 输出是最终 Msg(含报告路径与摘要),中间穿插任务规划、文件读取、上下文压缩与报告写入。

节点解释:

  • Agent(ReAct 循环) 是核心引擎。它消费 UserMsg,调用模型生成推理与工具调用,把工具结果 回灌进上下文,直到产出最终回复。
  • TaskCreate / TaskList:Agent 先用 TaskCreate 把"调研主题"拆成若干子任务(如"列出目录文件"、 "逐个读取关键文件"、"撰写摘要"),再用 TaskList 回顾全局进度,决定下一步。任务状态存在 AgentState.tasks_context 里,跨多轮推理可见。
  • Glob / Grep / Read:Agent 用 Glob 按通配符列出文件、用 Grep 搜索关键词定位、用 Read 读取命中的文件内容。这些工具在 LocalWorkspace.workdir 下执行。
  • ContextConfig 压缩:当 token 占用超过 trigger_ratio × model.context_size 时,Agent 自动 把旧消息总结并卸载到 offloader(即 LocalWorkspace),保留 reserve_ratio 比例的最近消息。
  • Write:Agent 调用 Write 把中文摘要报告写到工作区,路径通常为 report.md
  • TaskUpdate:每完成一项子任务,Agent 调用 TaskUpdate 把状态推进到 completed
  • reply 返回:模型不再产出工具调用时,reply 返回最终 Msg,其中包含报告路径与简要摘要。

用到的构建块

构建块本实战作用
Agent驱动 ReAct 循环,串联模型、工具、上下文、工作区
Toolkit(内置 + Plan)装配文件工具与任务工具,让 Agent 能规划进度并读写文件
ContextConfig配置压缩阈值,长任务逼近上限时自动压缩历史并卸载
LocalWorkspace工具执行环境 + 上下文卸载目标,报告文件也落在这里
TracingMiddleware(可选)全生命周期 OTel 追踪,无 TracerProvider 时自动降级为 no-op

5. 完整代码

下面是一个完整可跑的脚本。把它存为 research_agent.py,准备一个资料目录(如 ./materials,里面 放几个 .md.txt 文件),设置好环境变量后执行 python research_agent.py

python
import asyncio
import os

from agentscope.agent import Agent, ContextConfig
from agentscope.credential import DashScopeCredential
from agentscope.message import UserMsg
from agentscope.middleware import TracingMiddleware
from agentscope.model import DashScopeChatModel
from agentscope.tool import (
    Toolkit,
    Bash,
    Read,
    Write,
    Edit,
    Glob,
    Grep,
    TaskCreate,
    TaskGet,
    TaskList,
    TaskUpdate,
)
from agentscope.workspace import LocalWorkspace

# 资料目录与报告路径(相对于 workdir)
MATERIALS_DIR = "./materials"
REPORT_PATH = "report.md"

SYSTEM_PROMPT = """你是一个严谨的中文研究型 Agent。你的工作流程:

1. 先用 TaskCreate 把任务拆解为可执行的子任务(如"列出资料目录文件"、"定位关键内容"、
   "逐个读取关键文件"、"撰写中文摘要报告")。
2. 用 TaskList 回顾进度,每开始一项就用 TaskUpdate 标记为 in_progress,完成后再标记 completed。
3. 用 Glob 列出文件、用 Grep 搜索关键词、用 Read 读取文件内容。所有文件操作限制在资料目录内。
4. 综合读取到的资料,用 Write 把中文摘要报告写到工作区,路径由用户指定。
5. 报告须为中文,结构包含:概述、关键发现(分点)、结论与建议。

完成后用一句话告诉用户报告已写入哪个路径。"""


async def main() -> None:
    # 1. 构造并初始化工作区(同时作为工具执行环境与上下文卸载目标)
    ws = LocalWorkspace(workdir="./research_workspace")
    await ws.initialize()

    # 2. 装配 Toolkit:内置文件工具 + Plan 工具
    toolkit = Toolkit(
        tools=[
            Bash(),
            Read(),
            Write(),
            Edit(),
            Glob(),
            Grep(),
            TaskCreate(),
            TaskGet(),
            TaskList(),
            TaskUpdate(),
        ],
    )

    # 3. 构造 Agent,组合五个构建块
    agent = Agent(
        name="research_agent",
        system_prompt=SYSTEM_PROMPT,
        model=DashScopeChatModel(
            credential=DashScopeCredential(
                api_key=os.environ["DASHSCOPE_API_KEY"],
            ),
            model="qwen-plus",
        ),
        toolkit=toolkit,
        context_config=ContextConfig(
            trigger_ratio=0.8,
            reserve_ratio=0.1,
        ),
        offloader=ws,
        middlewares=[TracingMiddleware()],
    )

    # 4. 发起研究任务
    topic = "AgentScope 2.x 的核心设计目标与五大支柱"
    result = await agent.reply(
        UserMsg(
            name="user",
            content=(
                f"请调研以下主题:{topic}\n\n"
                f"资料目录:{MATERIALS_DIR}\n"
                f"把中文摘要报告写到:{REPORT_PATH}"
            ),
        ),
    )
    print(result.get_text_content())

    # 5. 关闭工作区(LocalWorkspace 会断开有状态 MCP 连接,workdir 保留)
    await ws.close()


asyncio.run(main())
python
import asyncio

from agentscope.agent import Agent, ContextConfig
from agentscope.message import UserMsg
from agentscope.middleware import TracingMiddleware
from agentscope.model import OllamaChatModel
from agentscope.tool import (
    Toolkit,
    Bash,
    Read,
    Write,
    Edit,
    Glob,
    Grep,
    TaskCreate,
    TaskGet,
    TaskList,
    TaskUpdate,
)
from agentscope.workspace import LocalWorkspace

# 资料目录与报告路径(相对于 workdir)
MATERIALS_DIR = "./materials"
REPORT_PATH = "report.md"

SYSTEM_PROMPT = """你是一个严谨的中文研究型 Agent。你的工作流程:

1. 先用 TaskCreate 把任务拆解为可执行的子任务(如"列出资料目录文件"、"定位关键内容"、
   "逐个读取关键文件"、"撰写中文摘要报告")。
2. 用 TaskList 回顾进度,每开始一项就用 TaskUpdate 标记为 in_progress,完成后再标记 completed。
3. 用 Glob 列出文件、用 Grep 搜索关键词、用 Read 读取文件内容。所有文件操作限制在资料目录内。
4. 综合读取到的资料,用 Write 把中文摘要报告写到工作区,路径由用户指定。
5. 报告须为中文,结构包含:概述、关键发现(分点)、结论与建议。

完成后用一句话告诉用户报告已写入哪个路径。"""


async def main() -> None:
    # 1. 构造并初始化工作区(同时作为工具执行环境与上下文卸载目标)
    ws = LocalWorkspace(workdir="./research_workspace")
    await ws.initialize()

    # 2. 装配 Toolkit:内置文件工具 + Plan 工具
    toolkit = Toolkit(
        tools=[
            Bash(),
            Read(),
            Write(),
            Edit(),
            Glob(),
            Grep(),
            TaskCreate(),
            TaskGet(),
            TaskList(),
            TaskUpdate(),
        ],
    )

    # 3. 构造 Agent,组合五个构建块(Ollama 本地推理,零云端费用)
    agent = Agent(
        name="research_agent",
        system_prompt=SYSTEM_PROMPT,
        model=OllamaChatModel(
            model="qwen2.5:7b",
        ),
        toolkit=toolkit,
        context_config=ContextConfig(
            trigger_ratio=0.8,
            reserve_ratio=0.1,
        ),
        offloader=ws,
        middlewares=[TracingMiddleware()],
    )

    # 4. 发起研究任务
    topic = "AgentScope 2.x 的核心设计目标与五大支柱"
    result = await agent.reply(
        UserMsg(
            name="user",
            content=(
                f"请调研以下主题:{topic}\n\n"
                f"资料目录:{MATERIALS_DIR}\n"
                f"把中文摘要报告写到:{REPORT_PATH}"
            ),
        ),
    )
    print(result.get_text_content())

    # 5. 关闭工作区(LocalWorkspace 会断开有状态 MCP 连接,workdir 保留)
    await ws.close()


asyncio.run(main())

代码要点

  • await ws.initialize() 必须在构造 Agent 之前调用,完成 MCP 恢复与 Skill 播种。LocalWorkspace 也支持 async with LocalWorkspace(...) as ws: 语法,进入时自动 initialize()、退出时自动 close()
  • offloader=wsLocalWorkspace 同时作为工具执行环境与上下文卸载目标。若你已改用 DockerWorkspaceE2BWorkspace 做沙箱,直接把同一个实例传给 offloader 即可。
  • ContextConfig(trigger_ratio=0.8, reserve_ratio=0.1) 是默认值,这里显式写出以便调整。当 token 占用超过 0.8 × model.context_size 时自动压缩,压缩后保留 0.1 比例的最近消息。
  • TracingMiddleware() 无条件挂载是安全的:进程未注册 TracerProvider 时它会自动降级为 no-op,不产出 span 也不产生开销。需要采集时配置 OTel exporter 即可。
  • Plan 工具的状态存在默认自动创建的 AgentState.tasks_context 里,不需要手动构造 TaskContextTaskCreate / TaskList 等是 FunctionTool 子类,必须显式装进 Toolkit 才能被 Agent 调用。

6. 运行与期望输出

准备资料目录:

bash
mkdir -p materials
# 在 materials/ 下放几个 .md 或 .txt 文件,内容与调研主题相关
echo "AgentScope 2.x 以安全、高效、灵活、完备为目标..." > materials/intro.md
echo "五大支柱:ReAct Agent、Toolkit、Context、Sandbox、Agent as Service..." > materials/pillars.md

运行脚本(DashScope 版本):

bash
export DASHSCOPE_API_KEY="你的密钥"
python research_agent.py

运行后 Agent 的典型行为序列:

  1. 规划阶段:调用 TaskCreate 创建若干子任务(列出文件、定位关键内容、读取文件、撰写报告), 调用 TaskList 回顾,调用 TaskUpdate 把第一项标记为 in_progress
  2. 读取阶段:调用 Glob 列出 ./materials 下的文件,调用 Grep 搜索关键词,调用 Read 读取 命中文件的内容。每读完一项调用 TaskUpdate 推进状态。
  3. 压缩阶段(可选):若资料较多、token 占用超过 0.8 × context_size,Agent 自动压缩旧消息并 卸载到 ./research_workspace,保留最近消息继续推理。
  4. 写入阶段:调用 Write 把中文摘要报告写到 report.md,调用 TaskUpdate 标记最后一项 completed。
  5. 返回阶段:模型不再产出工具调用,reply 返回最终 Msg,打印类似:
已完成调研。中文摘要报告已写入 report.md,涵盖 AgentScope 2.x 的四大设计目标(安全、高效、灵活、
完备)与五大支柱(ReAct Agent、Toolkit、Context、Sandbox Isolation、Agent as Service)。

报告文件 report.md 会出现在 ./research_workspace 目录下(即 LocalWorkspace.workdir)。具体 措辞与结构由模型决定,不必与示例完全一致。

7. 扩展点

  • DockerWorkspace 做强隔离:把 LocalWorkspace 换成 DockerWorkspace,工具在容器内执行, 宿主文件系统不受影响。构造方式与 offloader 传法完全一致,见 Workspace 沙箱
  • Permission 限制写路径:默认 LocalWorkspace 无强隔离,Agent 可以在 workdir 内任意写。 若要限制只能写 report.md、禁止执行危险 Bash 命令,装配 PermissionContext 与路径规则,见 权限系统
  • 加 RAG 注入外部知识:若资料不在本地文件而在向量库,用 RAGMiddleware 在推理前检索相关片段 注入上下文,替代 Read / Grep,见 RAG
  • 加长期记忆跨会话复用:用 Mem0 / ReMe 中间件把调研结论沉淀为长期记忆,下次同主题任务可 复用,见 长期记忆
  • 加 Token 预算控制:研究型 Agent 多轮调用模型容易超预算,挂载预算中间件在超限时终止循环, 见 中间件
  • 流式观察执行过程:把 reply 换成 reply_stream,逐个消费 ToolCallStartEvent / ToolResultEndEvent / TextBlockDeltaEvent,实时展示规划与读取进度,见 流式事件

8. 常见错误

模型不支持 tool calling

装了 toolkit 却发现 Agent 永远不调用 TaskCreate / Read 等工具,直接用文本"假装"完成了任务。 原因是所选模型不支持 function calling。AgentScope 的 ChatModelBase 子类要求模型原生支持 tool calling。qwen-plusgpt-4.1qwen2.5:7b 均支持;部分小模型或基座模型不支持。换模型即可。

未装 Plan 工具却期望 Agent 规划

TaskCreate 等是 FunctionTool 子类,必须显式装进 Toolkittools=[...] 才能被 Agent 调用。 只写 system_prompt 里"请先规划任务"不会触发任何工具调用--Agent 只能用文本"想",无法把任务状态 写入 AgentState.tasks_context。Plan 工具的详细语义见 计划模式

LocalWorkspace workdir 权限问题

await ws.initialize() 会在 workdir 下创建子目录结构。若 workdir 路径父目录无写权限,会抛 PermissionError。确保运行进程对 workdir 父目录有写权限,或把 workdir 指向用户可写目录 (如 ~/.cache/agentscope/research_workspace)。

费用超预期

研究型 Agent 会多轮调用模型:规划 1 次 + 每读一个文件 1~2 次 + 压缩 1 次 + 写报告 1 次。资料目录 文件多时 token 消耗显著。控制成本的三个手段:

  1. ReActConfig(max_iters=...) 限制最大迭代次数,防止 Agent 陷入无限工具调用。
  2. 调低 ContextConfig.reserve_ratio,压缩后保留更少消息,但会丢失更多细节。
  3. 改用 Ollama 本地模型,零云端费用(但推理速度与质量取决于本地硬件)。

误用 1.x 调用方式

agent(msg)__call__)、ReActAgentsys_prompt= 在 2.x 已全部移除。2.x 统一用 Agent + await agent.reply(msg)DashScopeModel / model_name= 也已移除,改用 DashScopeChatModel(credential=..., model=...)。详见 1.x 到 2.x 迁移

先修

如果你从 1.x 迁移而来,可先读 1.x 到 2.x 迁移 建立 API 对照,再回到本页组合实战。

下一步

官方参考

学习文档整合站点