Skip to content
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

[RPG GAME]FunctionAgent Version #236

Open
wants to merge 18 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/modules/file.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ async def demo_function():
```
5. 配置 `GlobalFileManagerHandler`从而在Agent中直接获取相关文件,详见[Agent](https://ernie-bot-agent.readthedocs.io/zh-cn/latest/modules/agents/#22-function-agent)中的**使用function agent调用输入、输出中包含文件的tool**部分。

<<<<<<< HEAD
```python
from erniebot_agent.file import GlobalFileManagerHandler

Expand All @@ -159,3 +160,12 @@ async def demo_function():
# 您可以通过AgentResponse.steps[-1]获取agent的最后一个步骤,然后最后一步的输出文件;或者在save_dir中找到所有文件
files = response.steps[-1].output_files
```
=======
async def demo_function():
await GlobalFileManagerHandler().configure(save_dir='your_path') # 需要在事件循环最开始配置
... # 此处省略agent创建过程
response = await agent.async_run('请帮我画一张北京市的图')
# 您可以通过AgentResponse.steps[-1]获取agent的最后一个步骤,然后最后一步的输出文件;或者在save_dir中找到所有文件
files = response.steps[-1].output_files
```
>>>>>>> origin/app
39 changes: 39 additions & 0 deletions erniebot-agent/applications/gradio_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import argparse
import os

from erniebot_agent.agents import FunctionAgent
from erniebot_agent.chat_models import ERNIEBot
from erniebot_agent.tools import RemoteToolkit


def parse_args():
parser = argparse.ArgumentParser(prog="erniebot-RPG")
parser.add_argument("--access-token", type=str, default=None, help="Access token to use.")
parser.add_argument("--model", type=str, default="ernie-3.5", help="Model name")
return parser.parse_args()


if __name__ == "__main__":
os.environ["EB_AGENT_LOGGING_LEVEL"] = "info"
args = parse_args()

if os.getenv("EB_AGENT_ACCESS_TOKEN") is None and args.access_token is None:
raise RuntimeError(
"Please set EB_AGENT_ACCESS_TOKEN in environment variables"
"or parse it in command line by --access-token."
)

if args.access_token is not None:
access_token = args.access_token
elif os.getenv("EB_AGENT_ACCESS_TOKEN") is not None:
access_token = os.getenv("EB_AGENT_ACCESS_TOKEN")

llm = ERNIEBot(
model=args.model, api_type="aistudio", access_token=access_token, enable_multi_step_tool_call=True
)
tool = RemoteToolkit.from_aistudio("texttospeech").get_tools()[0]
agent = FunctionAgent(
llm=llm,
tools=[tool],
)
agent.launch_gradio_demo()
84 changes: 84 additions & 0 deletions erniebot-agent/applications/rpg_game/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# RPGGameAgent

## 介绍

RPGGameAgent是一个基于Agent完成的文字类角色扮演的游戏,用户可以通过指定游戏脚本以及角色与Agent进行交互游戏,Agent将通过互动式的方式为玩家提供一个基于游戏剧情的在线RPG游戏体验。在互动过程中,Agent主要采用文心模型生成场景以及游戏发展的选择,并结合文生图工具生成场景图片,以丰富游戏体验。

目前该Agent提供两种方式进行

* 基于FunctionAgent,通过instruction来进行触发工具(暂不稳定,待tool choice上线)。
* 基于Prompt通过ToolFormat语句运行工具实现Agent。

## 如何开始

通过bash运行:通过执行脚本启动RPGGameAgent,并指定模型、剧情和访问令牌等参数。

```bash
export EB_AGENT_LOGGING_LEVEL='info'
python rpg_game_agent.py --access-token YOUR_ACCESS_TOKEN --game 射雕英雄传 --model ernie-3.5
```

## 通过FunctionAgent+Instruction实现
通过Instruction指示通过FunctionAgent如何调用工具,实现GameAgent的结果生成,先通过ChatStory工具生成最终的互动结果,然后调用ImageGenerateTool工具根据场景生成图片,最终截取ChatStory工具生成的结果作为最终输出。

### 关键步骤
1. 工具准备:
需要一个ChatStory工具用来生成故事情节以及一个ImageGenerateTool工具生成场景图片
2. 通过以下instruction指示Agent来达到触发

```markdown
你是《{SCRIPT}》沉浸式图文RPG场景助手,能够生成图文剧情。\
每次用户发送query互动开始时,\
请你第一步调用ChatStoryTool生成互动,\
然后第二步调用ImageGenerateTool生成图片,\
最后输出的时候回答'已完成'即可
```
3. 直接调用Agent,获得包括<场景描述>、<场景图片>和<选择>的互动结果。

## 通过ToolFormat实现手动编排Agent

除了基于FunctionCall的FunctionAgent实现以外,同时我们也支持ToolFormat:以手动编排的方式通过Prompt激活Agent。

即:通过事先定义Agent想要操作的步骤,然后通过指定的tool识别范式来运行tool。

### 关键步骤

1. Planning:通过Prompt事先指定相应的指令作为Plan,在Plan中具体指定哪一步要做什么以及工具调用。

```python
INSTRUCTION = """你的指令是为我提供一个基于《{SCRIPT}》剧情的在线RPG游戏体验。\
在这个游戏中,玩家将扮演《{SCRIPT}》剧情关键角色,你可以自行决定玩家的角色。\
游戏情景将基于《{SCRIPT}》剧情。这个游戏的玩法是互动式的,并遵循以下特定格式:

<场景描述>:根据玩家的选择,故事情节将按照《{SCRIPT}》剧情的线索发展。你将描述角色所处的环境和情况。场景描述不少于50字。

<场景图片>:对于每个场景,你将创造一个概括该情况的图像。在这个步骤你需要调用画图工具ImageGenerationTool并按json格式输出相应调用详情。\
ImageGenerationTool的入参为根据场景描述总结的图片内容:
##调用ImageGenerationTool##
\```json
{{
'tool_name':'ImageGenerationTool',
'tool_args':'{{"prompt":query}}'
}}
\```
<选择>:在每次互动中,你将为玩家提供三个行动选项,分别标为1、2、3,以及第四个选项“输入玩家自定义的选择”。故事情节将根据玩家选择的行动进展。
如果一个选择不是直接来自《{SCRIPT}》剧情,你将创造性地适应故事,最终引导它回归原始情节。

整个故事将围绕《{SCRIPT}》丰富而复杂的世界展开。每次互动必须包括<场景描述>、<场景图片>和<选择>。所有内容将以中文呈现。
你的重点将仅仅放在提供场景描述,场景图片和选择上,不包含其他游戏指导。场景尽量不要重复,要丰富一些。

当我说游戏开始的时候,开始游戏。每次只要输出【一组】互动,【不要自己生成互动】。"""
```

2. Execute Tool:通过在流式输出的过程中遇到ToolFormat的部分(在此例子中为 \```json\```),开始异步执行相应的工具。

需要在INSTRUCTION中讲述清楚具体的相关参数,格式为json,tool_name为调用工具名称,tool_args为工具所有入参(json)。

```
{
'tool_name':'ImageGenerationTool',
'tool_args':'{{"prompt":query}}'
}
```

3. 等待工具执行完成,获得包括<场景描述>、<场景图片>和<选择>的互动结果,以及文生图工具生成结果。
Empty file.
29 changes: 29 additions & 0 deletions erniebot-agent/applications/rpg_game/chat_story_tool.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from typing import Type

from pydantic import Field

from erniebot_agent.agents import Agent
from erniebot_agent.tools.base import Tool, ToolParameterView


class ChatStoryToolInputView(ToolParameterView):
query: str = Field(description="用户的指令")


class ChatStoryToolOutputView(ToolParameterView):
return_story: str = Field(description="生成的包括<场景描述>、<场景图片>和<选择>的互动内容")


class ChatStoryTool(Tool):
description: str = "结合用户的选择、{GAME}背景故事以及玩家角色,按要求生成接下来的故事情节"
input_type: Type[ToolParameterView] = ChatStoryToolInputView
ouptut_type: Type[ToolParameterView] = ChatStoryToolOutputView

def __init__(self, agent, game: str) -> None:
super().__init__()
self.agent: Agent = agent
self.description = self.description.format(GAME=game)

async def __call__(self, query: str) -> str:
response = await self.agent.run(query)
return {"return_story": response.text}
27 changes: 27 additions & 0 deletions erniebot-agent/applications/rpg_game/img_gen_tool.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from typing import Type

from pydantic import Field

from erniebot_agent.file import GlobalFileManagerHandler
from erniebot_agent.tools.base import Tool, ToolParameterView


class ImageGenerateToolInputView(ToolParameterView):
query: str = Field(description="当前场景图片的描述")


class ImageGenerateToolOutputView(ToolParameterView):
output_image: str = Field(description="返回的图片文件,格式为file-xxxx, 不包括<file></file>")


class ImageGenerateTool(Tool):
description: str = "根据用户的选择以及当前的互动内容,按照场景图片部分的内容生成图片。"
input_type: Type[ToolParameterView] = ImageGenerateToolInputView
otuput_story: Type[ToolParameterView] = ImageGenerateToolOutputView

async def __call__(self, query: str) -> str:
# output_dir = query
file_manager = GlobalFileManagerHandler().get()
# self.file_manager.create_file_from_bytes()
file = await file_manager.create_file_from_path("/Users/tanzhehao/Desktop/git.png") # for mimic
return {"output_image": file.id}