-
Notifications
You must be signed in to change notification settings - Fork 13
docs: add AgentScope 2.0 tutorials #38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Osier-Yi
wants to merge
3
commits into
agentscope-ai:main
Choose a base branch
from
Osier-Yi:tutorial-dev
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| # Tutorial 01: Hello AgentScope — 你的第一个 Agent | ||
|
|
||
| > **什么时候需要这个?** 第一次接触 AgentScope 2.0,想最快搞清楚"用几行代码创建一个 Agent 并跟它对话"到底涉及哪些组件。后面所有章节都从这里的最小 Agent 出发。 | ||
|
|
||
| ## 你将学到 | ||
|
|
||
| - AgentScope 2.0 的设计哲学与核心四要素 | ||
| - 如何创建和配置一个最基本的 Agent | ||
| - `reply()` 与 `reply_stream()` 两种交互方式 | ||
| - 如何切换不同的模型提供商 | ||
|
|
||
| ## 前置要求 | ||
|
|
||
| - Python 3.11+ | ||
| - 安装 AgentScope:`pip install agentscope==2.0.4` | ||
| - 至少一个 LLM API Key(DashScope / OpenAI / Ollama 等) | ||
|
|
||
| ## 核心概念 | ||
|
|
||
| ### AgentScope 2.0 设计哲学 | ||
|
|
||
| AgentScope 2.0 的核心理念是**利用模型能力,而非约束模型**。 | ||
|
|
||
| 与许多框架用严格的 prompt 和固定编排来"控制"模型不同,AgentScope 2.0 信任模型的推理和工具使用能力,提供最少必要的抽象,让模型自由发挥。 | ||
|
|
||
| ### 核心四要素 | ||
|
|
||
| 创建一个 Agent 需要四个要素: | ||
|
|
||
| ``` | ||
| Credential → Model → Toolkit → Agent | ||
| (认证凭据) (LLM模型) (工具集) (智能体) | ||
| ``` | ||
|
|
||
| 1. **Credential** — 管理 API 密钥等认证信息 | ||
| 2. **Model** — 指定使用哪个 LLM(如 qwen-plus, gpt-4o) | ||
| 3. **Toolkit** — 注册 Agent 可以使用的工具(本教程暂不添加) | ||
| 4. **Agent** — 将上述组件组合起来的智能体 | ||
|
|
||
| ### 异步编程 | ||
|
|
||
| AgentScope 2.0 是**全异步**的。所有 Agent 方法都需要使用 `async/await` 语法: | ||
|
|
||
| ```python | ||
| import asyncio | ||
|
|
||
| async def main(): | ||
| result = await agent.reply(msg) # await 等待异步操作完成 | ||
|
|
||
| asyncio.run(main()) # 启动异步事件循环 | ||
| ``` | ||
|
|
||
| ### 两种交互方式 | ||
|
|
||
| | 方法 | 返回值 | 适用场景 | | ||
| |------|--------|----------| | ||
| | `agent.reply(msg)` | 最终的 `Msg` 对象 | 后台自动化,不需要实时输出 | | ||
| | `agent.reply_stream(msg)` | `AgentEvent` 事件流 | 交互式 UI,需要实时显示 | | ||
|
|
||
| ### 消息类型 | ||
|
|
||
| AgentScope 2.0 提供了三种快捷消息工厂函数: | ||
|
|
||
| ```python | ||
| from agentscope.message import UserMsg, AssistantMsg, SystemMsg | ||
|
|
||
| # 用户消息 | ||
| msg = UserMsg(name="user", content="你好") | ||
|
|
||
| # 助手消息 | ||
| msg = AssistantMsg(name="agent", content="你好!有什么可以帮你的?") | ||
|
|
||
| # 系统消息 | ||
| msg = SystemMsg(name="system", content="你是一个数据分析助手。") | ||
| ``` | ||
|
|
||
| ## 示例:DataMuse 的诞生 | ||
|
|
||
| 本期我们创建 **DataMuse** 的最初版本 —— 一个能进行基本对话的数据分析助手。 | ||
|
|
||
| ### 步骤 1:创建最简 Agent | ||
|
|
||
| ```python | ||
| from agentscope.agent import Agent | ||
| from agentscope.credential import DashScopeCredential | ||
| from agentscope.model import DashScopeChatModel | ||
|
|
||
| agent = Agent( | ||
| name="DataMuse", | ||
| system_prompt="You are DataMuse, a helpful data analysis assistant.", | ||
| model=DashScopeChatModel( | ||
| credential=DashScopeCredential(api_key=os.environ["DASHSCOPE_API_KEY"]), | ||
| model="qwen-plus", | ||
| ), | ||
| ) | ||
| ``` | ||
|
|
||
| ### 步骤 2:使用 reply() 进行对话 | ||
|
|
||
| ```python | ||
| from agentscope.message import UserMsg | ||
|
|
||
| msg = UserMsg(name="user", content="What is the best chart type for showing trends over time?") | ||
| result = await agent.reply(msg) | ||
| print(result.get_text_content()) | ||
| ``` | ||
|
|
||
| `reply()` 会阻塞直到 Agent 完成回复,然后返回完整的 `Msg` 对象。 | ||
|
|
||
| ### 步骤 3:使用 reply_stream() 进行流式对话 | ||
|
|
||
| ```python | ||
| from agentscope.event import EventType | ||
|
|
||
| async for event in agent.reply_stream(msg): | ||
| match event.type: | ||
| case EventType.TEXT_BLOCK_DELTA: | ||
| print(event.delta, end="", flush=True) | ||
| case EventType.REPLY_END: | ||
| print("\n[Done]") | ||
| ``` | ||
|
|
||
| `reply_stream()` 返回一个异步迭代器,逐步产出事件。你可以实时处理每个事件(如打印文本片段)。 | ||
|
|
||
| ### 步骤 4:切换模型提供商 | ||
|
|
||
| 只需更换 Credential 和 Model 类即可切换提供商: | ||
|
|
||
| ```python | ||
| # OpenAI | ||
| from agentscope.credential import OpenAICredential | ||
| from agentscope.model import OpenAIChatModel | ||
|
|
||
| model = OpenAIChatModel( | ||
| credential=OpenAICredential(api_key=os.environ["OPENAI_API_KEY"]), | ||
| model="gpt-4o", | ||
| ) | ||
|
|
||
| # Ollama (本地模型) | ||
| from agentscope.credential import OllamaCredential | ||
| from agentscope.model import OllamaChatModel | ||
|
|
||
| model = OllamaChatModel( | ||
| credential=OllamaCredential(), | ||
| model="qwen3:8b", | ||
| ) | ||
| ``` | ||
|
|
||
| ## 运行示例 | ||
|
|
||
| ```bash | ||
| # 默认用 DashScope | ||
| export DASHSCOPE_API_KEY="your-key-here" | ||
|
|
||
| # 运行 | ||
| cd tutorials/01_hello_agentscope | ||
| python main.py | ||
| ``` | ||
|
|
||
| > 想用 OpenAI?按 [main.py](main.py) 顶部 docstring 的提示替换 `main()` 里的 4 行 model 配置即可。后续章节会用一个 `create_model()` helper 自动切换 provider,这里先保持最简结构。 | ||
|
|
||
| ## 进一步探索 | ||
|
|
||
| - 尝试修改 `system_prompt`,让 DataMuse 具有不同的个性 | ||
| - 尝试使用不同的模型提供商,比较回复质量 | ||
| - 观察 `reply()` 返回的 `Msg` 对象有哪些字段 | ||
|
|
||
| ## 下一期预告 | ||
|
|
||
| **Tutorial 02: Message & Event** — 深入理解 AgentScope 的消息和事件系统,掌握 Agent 通信的核心协议。 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| # -*- coding: utf-8 -*- | ||
| """Tutorial 01: Hello AgentScope — Your first Agent. | ||
|
|
||
| This tutorial demonstrates: | ||
| - Creating a basic Agent with AgentScope 2.0 | ||
| - Using reply() for blocking responses | ||
| - Using reply_stream() for streaming responses | ||
|
|
||
| Using OpenAI instead? Swap the 4 model lines in main() for: | ||
| from agentscope.credential import OpenAICredential | ||
| from agentscope.model import OpenAIChatModel | ||
| model = OpenAIChatModel( | ||
| credential=OpenAICredential(api_key=os.environ["OPENAI_API_KEY"]), | ||
| model="gpt-4o", | ||
| ) | ||
| """ | ||
| # pylint: disable=missing-function-docstring | ||
| import asyncio | ||
| import os | ||
|
|
||
| from agentscope.agent import Agent | ||
| from agentscope.credential import DashScopeCredential | ||
| from agentscope.event import EventType | ||
| from agentscope.message import UserMsg | ||
| from agentscope.model import DashScopeChatModel | ||
|
|
||
|
|
||
| async def main() -> None: | ||
| agent = Agent( | ||
| name="DataMuse", | ||
| system_prompt=( | ||
| "You are DataMuse, a friendly data analysis assistant. " | ||
| "Keep responses concise and actionable." | ||
| ), | ||
| model=DashScopeChatModel( | ||
| credential=DashScopeCredential( | ||
| api_key=os.environ["DASHSCOPE_API_KEY"], | ||
| ), | ||
| model="qwen-plus", | ||
| ), | ||
| ) | ||
|
|
||
| # --- reply(): blocking, returns the full Msg when done --- | ||
| print("\n--- reply() ---") | ||
| result = await agent.reply( | ||
| UserMsg( | ||
| name="user", | ||
| content="What chart type best shows trends over time? " | ||
| "Answer in 2 sentences.", | ||
| ), | ||
| ) | ||
| print(result.get_text_content()) | ||
|
|
||
| # --- reply_stream(): async iterator, yields events as they arrive --- | ||
| print("\n--- reply_stream() ---") | ||
| async for event in agent.reply_stream( | ||
| UserMsg(name="user", content="And for comparing categories?"), | ||
| ): | ||
| if event.type == EventType.TEXT_BLOCK_DELTA: | ||
| print(event.delta, end="", flush=True) | ||
| print() | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| asyncio.run(main()) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| # Tutorial 02: Message & Event — Agent 的通信协议 | ||
|
|
||
| > **什么时候需要这个?** 你要做 UI、做日志、做调试,需要看清 Agent 内部到底发生了什么;或者你想理解 `reply_stream()` 返回的事件长什么样、怎么从事件流重建一条消息。后面所有"流式 UI / 中间件 / 服务" 都依赖你看懂这套协议。 | ||
|
|
||
| ## 本章基于前序章节 | ||
|
|
||
| - **T01 — Agent 与 `reply_stream`**:本章在 T01 的最小 Agent 之上,深入看它产出的事件流和最终消息。 | ||
|
|
||
| ## 你将学到 | ||
|
|
||
| - `Msg` 消息的完整结构和六种 ContentBlock | ||
| - Event 事件系统的生命周期模式(start → delta → end) | ||
| - 消息-事件对偶性:事件流如何重建完整消息 | ||
| - 用 `append_event()` 从事件流构建消息 | ||
|
|
||
| ## 前置要求 | ||
|
|
||
| - 完成 Tutorial 01 | ||
| - 理解 async/await 基础 | ||
|
|
||
| ## 核心概念 | ||
|
|
||
| ### 消息 (Msg) | ||
|
|
||
| `Msg` 是 Agent 之间通信的基本单位。每条消息包含以下字段: | ||
|
|
||
| | 字段 | 类型 | 说明 | | ||
| |------|------|------| | ||
| | `id` | `str` | 唯一标识符 | | ||
| | `name` | `str` | 发送者名称 | | ||
| | `role` | `"user" / "assistant" / "system"` | 发送者角色 | | ||
| | `content` | `list[ContentBlock]` | 内容块列表 | | ||
| | `metadata` | `dict` | 任意键值对元数据 | | ||
| | `created_at` | `str` | ISO 8601 创建时间 | | ||
| | `finished_at` | `str \| None` | ISO 8601 完成时间 | | ||
| | `usage` | `Usage \| None` | Token 使用量 | | ||
|
|
||
| ### 六种 ContentBlock | ||
|
|
||
| 消息的 `content` 是一个内容块列表。每种块有不同的角色约束: | ||
|
|
||
| | Block 类型 | 说明 | 允许的角色 | | ||
| |-----------|------|-----------| | ||
| | `TextBlock` | 文本内容 | user, assistant, system | | ||
| | `DataBlock` | 二进制数据(图片/音频等) | user, assistant | | ||
| | `ThinkingBlock` | 思维链推理过程 | assistant | | ||
| | `ToolCallBlock` | 工具调用请求 | assistant | | ||
| | `ToolResultBlock` | 工具执行结果 | assistant | | ||
| | `HintBlock` | Agent 内部指导提示 | assistant | | ||
|
|
||
| 角色约束在构造时强制验证: | ||
| - **user** 消息只能包含 `TextBlock` 和 `DataBlock` | ||
| - **system** 消息只能包含 `TextBlock` | ||
| - **assistant** 消息可以包含所有类型 | ||
|
|
||
| ### 事件 (Event) | ||
|
|
||
| Event 是消息的流式视图。Agent 执行过程中会产生一系列事件,这些事件最终组成一条完整的助手消息。 | ||
|
|
||
| **核心原则**:一次 `reply` 调用 = 一条助手消息 = 一个事件流 | ||
|
|
||
| 多数流式内容块遵循 **start → delta → end** 的生命周期模式; | ||
| `HintBlockEvent` 是一次性事件,不拆分为 start / delta / end: | ||
|
|
||
| ``` | ||
| ReplyStartEvent | ||
| ├── ModelCallStartEvent | ||
| │ ├── ThinkingBlockStartEvent → ThinkingBlockDeltaEvent... → ThinkingBlockEndEvent | ||
| │ ├── TextBlockStartEvent → TextBlockDeltaEvent... → TextBlockEndEvent | ||
| │ └── ToolCallStartEvent → ToolCallDeltaEvent... → ToolCallEndEvent | ||
| │ ModelCallEndEvent | ||
| │ | ||
| ├── ToolResultStartEvent → ToolResultTextDeltaEvent... → ToolResultEndEvent | ||
| │ | ||
| ├── HintBlockEvent(一次性提示) | ||
| │ | ||
| └── (下一轮推理-执行循环...) | ||
| ReplyEndEvent | ||
| ``` | ||
|
|
||
| ### 消息-事件对偶性 | ||
|
|
||
| 事件流可以用 `msg.append_event(event)` 逐步重建完整消息。这是 AgentScope 前后端分离的基础:后端流式推送事件,前端实时重建消息。 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 可以提一下ts版本的库,用于前端重建 Msg 对象 |
||
|
|
||
| ```python | ||
| msg = AssistantMsg(name="agent", content=[], id=event.reply_id) | ||
| async for event in agent.reply_stream(user_msg): | ||
| msg.append_event(event) | ||
| # msg 现在包含完整的助手回复 | ||
| ``` | ||
|
|
||
| 浏览器或 Node.js 客户端可以使用 TypeScript 包 | ||
| `@agentscope-ai/agentscope` 完成同样的重建: | ||
|
|
||
| ```bash | ||
| npm install @agentscope-ai/agentscope@0.0.13 | ||
| ``` | ||
|
|
||
| ```typescript | ||
| import { EventType } from "@agentscope-ai/agentscope/event"; | ||
| import { | ||
| appendEvent, | ||
| AssistantMsg, | ||
| } from "@agentscope-ai/agentscope/message"; | ||
|
|
||
| let reply; | ||
|
|
||
| for await (const event of eventStream) { | ||
| if (event.type === EventType.REPLY_START) { | ||
| reply = AssistantMsg({ | ||
| id: event.reply_id, | ||
| name: event.name, | ||
| content: [], | ||
| }); | ||
| } | ||
|
|
||
| if (reply) { | ||
| appendEvent(reply, event); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## 示例:探索 DataMuse 的消息和事件 | ||
|
|
||
| 本期示例让 DataMuse 回答数据分析问题,我们在客户端侧: | ||
| 1. 逐一观察每种事件类型 | ||
| 2. 用 `append_event()` 从事件流重建消息 | ||
| 3. 对比流式事件和最终消息的内容 | ||
|
|
||
| ## 运行示例 | ||
|
|
||
| ```bash | ||
| cd tutorials/02_message_and_event | ||
| python main.py | ||
| ``` | ||
|
|
||
| ## 进一步探索 | ||
|
|
||
| - 观察不同模型(如支持 thinking 的模型)会产生哪些不同的事件 | ||
| - 尝试给 Agent 添加工具,观察 ToolCall / ToolResult 事件 | ||
| - 尝试构造一个包含 `DataBlock`(图片)的 UserMsg | ||
|
|
||
| ## 下一期预告 | ||
|
|
||
| **Tutorial 03: Tool 系统** — 赋予 DataMuse 读写文件、执行脚本的能力,让它真正能分析数据。 | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HintBlock here