跳到主要内容

使用非OpenAI客户端的对话式国际象棋

Open In Colab Open on GitHub

本笔记本提供使用非OpenAI模型时使用函数/工具的提示。

该代码基于此笔记本,该笔记本提供了关于工具使用的嵌套聊天的详细解析。请参考该笔记本以了解更多关于嵌套聊天的内容,因为本文将集中于调整以提高非OpenAI模型的性能。

该笔记本代表了两名玩家之间的国际象棋游戏,通过嵌套聊天来确定可用的移动并选择要进行的移动。

这个游戏包含了一些LLMs必须正确使用的函数/工具:- get_legal_moves 用于获取当前合法的移动列表。- make_move 用于进行移动。

将使用两个代理来代表白方和黑方玩家,每个代理与不同的LLM云提供商和模型相关联:- Anthropic的Sonnet 3.5将作为Player_White - Mistral的Mixtral 8x7B(使用Together.AI)将作为Player_Black

由于这涉及函数调用,我们使用来自这些供应商的更大型、更强大的模型。

嵌套聊天将由一个代理板支持,该代理板被设置为执行工具并管理游戏。

提升这些非OpenAI模型性能的技巧将以粗体标注。

安装

首先,你需要安装autogen-agentchat~=0.2chess包来使用AutoGen。我们将包括Anthropic和Together.AI库。

! pip install -qqq autogen-agentchat[anthropic,together]~=0.2 chess

设置LLMs

我们将使用Anthropic(api_typeanthropic)和Together.AI(api_typetogether)的客户端类,以及它们各自的模型,这些模型都支持函数调用。

import os

import chess
import chess.svg
from IPython.display import display
from typing_extensions import Annotated

from autogen import ConversableAgent, register_function

# Let's set our two player configs, specifying clients and models

# Anthropic's Sonnet for player white
player_white_config_list = [
{
"api_type": "anthropic",
"model": "claude-3-5-sonnet-20240620",
"api_key": os.getenv("ANTHROPIC_API_KEY"),
"cache_seed": None,
},
]

# Mistral's Mixtral 8x7B for player black (through Together.AI)
player_black_config_list = [
{
"api_type": "together",
"model": "mistralai/Mixtral-8x7B-Instruct-v0.1",
"api_key": os.environ.get("TOGETHER_API_KEY"),
"cache_seed": None,
},
]

我们将设置游戏变量和两个函数,用于获取可用的移动然后进行移动。

# Initialize the board.
board = chess.Board()

# Keep track of whether a move has been made.
made_move = False


def get_legal_moves() -> Annotated[
str,
"Call this tool to list of all legal chess moves on the board, output is a list in UCI format, e.g. e2e4,e7e5,e7e8q.",
]:
return "Possible moves are: " + ",".join([str(move) for move in board.legal_moves])


def make_move(
move: Annotated[
str,
"Call this tool to make a move after you have the list of legal moves and want to make a move. Takes UCI format, e.g. e2e4 or e7e5 or e7e8q.",
],
) -> Annotated[str, "Result of the move."]:
move = chess.Move.from_uci(move)
board.push_uci(str(move))
global made_move
made_move = True
# Display the board.
display(
chess.svg.board(board, arrows=[(move.from_square, move.to_square)], fill={move.from_square: "gray"}, size=200)
)
# Get the piece name.
piece = board.piece_at(move.to_square)
piece_symbol = piece.unicode_symbol()
piece_name = (
chess.piece_name(piece.piece_type).capitalize()
if piece_symbol.isupper()
else chess.piece_name(piece.piece_type)
)
return f"Moved {piece_name} ({piece_symbol}) from {chess.SQUARE_NAMES[move.from_square]} to {chess.SQUARE_NAMES[move.to_square]}."

创建代理

接下来创建我们的主要玩家代理,并进行一些调整以帮助我们的模型进行游戏:

  • 明确告诉代理他们的名字(因为名字字段不会被发送到LLM)。
  • 提供关于函数顺序的简单说明(并非所有模型都需要)。
  • 要求LLM在回复中包含他们的名字,这样消息内容就会包含他们的名字,帮助LLM理解是谁进行了哪一步。
  • 确保代理名称中没有空格,以便在对话中区分它们的名称。
player_white = ConversableAgent(
name="Player_White",
system_message="You are a chess player and you play as white, your name is 'Player_White'. "
"First call the function get_legal_moves() to get list of legal moves. "
"Then call the function make_move(move) to make a move. "
"Then tell Player_Black you have made your move and it is their turn. "
"Make sure you tell Player_Black you are Player_White.",
llm_config={"config_list": player_white_config_list, "cache_seed": None},
)

player_black = ConversableAgent(
name="Player_Black",
system_message="You are a chess player and you play as black, your name is 'Player_Black'. "
"First call the function get_legal_moves() to get list of legal moves. "
"Then call the function make_move(move) to make a move. "
"Then tell Player_White you have made your move and it is their turn. "
"Make sure you tell Player_White you are Player_Black.",
llm_config={"config_list": player_black_config_list, "cache_seed": None},
)

现在我们创建一个代理代理,它将用于在棋盘上移动棋子。

# Check if the player has made a move, and reset the flag if move is made.
def check_made_move(msg):
global made_move
if made_move:
made_move = False
return True
else:
return False


board_proxy = ConversableAgent(
name="Board_Proxy",
llm_config=False,
# The board proxy will only terminate the conversation if the player has made a move.
is_termination_msg=check_made_move,
# The auto reply message is set to keep the player agent retrying until a move is made.
default_auto_reply="Please make a move.",
human_input_mode="NEVER",
)

我们的函数随后被分配给代理,这样它们可以被传递给LLM进行选择。

我们调整了描述,以提供更多关于何时使用它的指导。

register_function(
make_move,
caller=player_white,
executor=board_proxy,
name="make_move",
description="Call this tool to make a move after you have the list of legal moves.",
)

register_function(
get_legal_moves,
caller=player_white,
executor=board_proxy,
name="get_legal_moves",
description="Call this to get a legal moves before making a move.",
)

register_function(
make_move,
caller=player_black,
executor=board_proxy,
name="make_move",
description="Call this tool to make a move after you have the list of legal moves.",
)

register_function(
get_legal_moves,
caller=player_black,
executor=board_proxy,
name="get_legal_moves",
description="Call this to get a legal moves before making a move.",
)

快完成了,我们现在在玩家和棋盘代理之间创建嵌套聊天,以解决可用的移动并进行移动。

player_white.register_nested_chats(
trigger=player_black,
chat_queue=[
{
# The initial message is the one received by the player agent from
# the other player agent.
"sender": board_proxy,
"recipient": player_white,
# The final message is sent to the player agent.
"summary_method": "last_msg",
}
],
)

player_black.register_nested_chats(
trigger=player_white,
chat_queue=[
{
# The initial message is the one received by the player agent from
# the other player agent.
"sender": board_proxy,
"recipient": player_black,
# The final message is sent to the player agent.
"summary_method": "last_msg",
}
],
)

玩游戏

现在游戏可以开始了!

# Clear the board.
board = chess.Board()

chat_result = player_black.initiate_chat(
player_white,
message="Let's play chess! Your move.",
max_turns=10,
)
Player_Black (to Player_White):

Let's play chess! Your move.

--------------------------------------------------------------------------------

>>>>>>>> USING AUTO REPLY...

********************************************************************************
Starting a new chat....

********************************************************************************
Board_Proxy (to Player_White):

Let's play chess! Your move.

--------------------------------------------------------------------------------

>>>>>>>> USING AUTO REPLY...
Player_White (to Board_Proxy):

Certainly! I'd be happy to play chess with you. As White, I'll make the first move. Let me start by checking the legal moves available to me.
***** Suggested tool call (toolu_015sLMucefMVqS5ZNyWVGjgu): get_legal_moves *****
Arguments:
{}
*********************************************************************************

--------------------------------------------------------------------------------

>>>>>>>> EXECUTING FUNCTION get_legal_moves...
Board_Proxy (to Player_White):

Board_Proxy (to Player_White):

***** Response from calling tool (toolu_015sLMucefMVqS5ZNyWVGjgu) *****
Possible moves are: g1h3,g1f3,b1c3,b1a3,h2h3,g2g3,f2f3,e2e3,d2d3,c2c3,b2b3,a2a3,h2h4,g2g4,f2f4,e2e4,d2d4,c2c4,b2b4,a2a4
***********************************************************************

--------------------------------------------------------------------------------

>>>>>>>> USING AUTO REPLY...
Player_White (to Board_Proxy):

Thank you for initiating a game of chess! As Player_White, I'll make the first move. After analyzing the legal moves, I've decided to make a classic opening move.
***** Suggested tool call (toolu_01VjmBhHcGw5RTRKYC4Y5MeV): make_move *****
Arguments:
{"move": "e2e4"}
***************************************************************************

--------------------------------------------------------------------------------

>>>>>>>> EXECUTING FUNCTION make_move...
Board_Proxy (to Player_White):

Board_Proxy (to Player_White):

***** Response from calling tool (toolu_01VjmBhHcGw5RTRKYC4Y5MeV) *****
Moved pawn (♙) from e2 to e4.
***********************************************************************

--------------------------------------------------------------------------------

>>>>>>>> USING AUTO REPLY...
Player_White (to Board_Proxy):

Hello, Player_Black! I'm Player_White, and I've just made my move. I've chosen to play the classic opening move e2e4, moving my king's pawn forward two squares. This opens up lines for both my queen and king's bishop, and stakes a claim to the center of the board. It's now your turn to make a move. Good luck!

--------------------------------------------------------------------------------
Player_White (to Player_Black):

Hello, Player_Black! I'm Player_White, and I've just made my move. I've chosen to play the classic opening move e2e4, moving my king's pawn forward two squares. This opens up lines for both my queen and king's bishop, and stakes a claim to the center of the board. It's now your turn to make a move. Good luck!

--------------------------------------------------------------------------------

>>>>>>>> USING AUTO REPLY...

********************************************************************************
Starting a new chat....

********************************************************************************
Board_Proxy (to Player_Black):

Hello, Player_Black! I'm Player_White, and I've just made my move. I've chosen to play the classic opening move e2e4, moving my king's pawn forward two squares. This opens up lines for both my queen and king's bishop, and stakes a claim to the center of the board. It's now your turn to make a move. Good luck!

--------------------------------------------------------------------------------

>>>>>>>> USING AUTO REPLY...
Player_Black (to Board_Proxy):

***** Suggested tool call (call_z6jagiqn59m784w1n0zhmiop): get_legal_moves *****
Arguments:
{}
********************************************************************************

--------------------------------------------------------------------------------

>>>>>>>> EXECUTING FUNCTION get_legal_moves...
Board_Proxy (to Player_Black):

Board_Proxy (to Player_Black):

***** Response from calling tool (call_z6jagiqn59m784w1n0zhmiop) *****
Possible moves are: g8h6,g8f6,b8c6,b8a6,h7h6,g7g6,f7f6,e7e6,d7d6,c7c6,b7b6,a7a6,h7h5,g7g5,f7f5,e7e5,d7d5,c7c5,b7b5,a7a5
**********************************************************************

--------------------------------------------------------------------------------

>>>>>>>> USING AUTO REPLY...
Player_Black (to Board_Proxy):

***** Suggested tool call (call_59t20pl0ab68z4xx2workgbc): make_move *****
Arguments:
{"move":"g8h6"}
**************************************************************************

--------------------------------------------------------------------------------

>>>>>>>> EXECUTING FUNCTION make_move...
Board_Proxy (to Player_Black):

Board_Proxy (to Player_Black):

***** Response from calling tool (call_59t20pl0ab68z4xx2workgbc) *****
Moved knight (♞) from g8 to h6.
**********************************************************************

--------------------------------------------------------------------------------

>>>>>>>> USING AUTO REPLY...
Player_Black (to Board_Proxy):

***** Suggested tool call (call_jwv1d86srs1fnvu33cky9tgv): make_move *****
Arguments:
{"move":"g8h6"}
**************************************************************************

--------------------------------------------------------------------------------
Player_Black (to Player_White):



--------------------------------------------------------------------------------

>>>>>>>> USING AUTO REPLY...

>>>>>>>> USING AUTO REPLY...

在这个阶段,很难说谁会赢,但他们表现得很好,并且正确地使用了这些功能。