Aby nadać AI więcej kontekstu, napisałem serię wiadomości (używając placu zabaw OpenAI), aby symulować poprawnie rozegraną grę między asystentem AI a użytkownikiem. Następnie zakodowałem je na stałe na serwerze, jak pokazano na rysunku

Następnie ponownie uruchomiłem serwer i spróbowałem rozegrać nową grę za pomocą polecenia curl. Nowa gra rozpoczęła się poprawnie, ale przy pierwszym ruchu AI odpowiedziała, że powinienem rozpocząć nową grę, aby kontynuować grę, jak pokazano na rysunku.

Stało się tak, ponieważ poprzednie monity w konwersacji nie są wysyłane do serwera. Ponieważ serwer nie ma możliwości śledzenia sesji między indywidualnym użytkownikiem a AI, najlepszym miejscem do wdrożenia stanu sesji jest klient. Zanim jednak zacznę pracę nad klientem, muszę skonfigurować serwer tak, aby łączył monity zakodowane na stałe na serwerze z monitami pochodzącymi od klienta. Zapisałem monit systemowy i przykładową grę w zmiennej, a następnie dodałem to do wiadomości, które aplikacja kliencka wysyła do serwera. Uprościłem również przykładową grę, tak aby AI zwracała tylko numer pola, na którym chce umieścić O. Ta zmiana ułatwia kodowanie aplikacji klienckiej i ma dodatkową zaletę w postaci znacznego zmniejszenia liczby tokenów niezbędnych do rozegrania gry. Gotowa aplikacja serwerowa jest pokazana .na listingu
Ukończony API Server
import express from ‘express’;
import OpenAI from ‘openai’;
import ‘dotenv/config’;
import cors from ‘cors’;
const app = express();
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
app.use(express.json());
app.use(cors());
app.post(‘/chat’, async (req, res) => {
const context = [
{
role: ‘system’,
content:
“You are an AI tic-tac-toe player. You are always ‘O’ and
I’m always ‘X’.\n\nI’ll provide you with my move as a number
on this grid:\n\n0 | 1 | 2\n3 | 4 | 5\n6 | 7 | 8\n\nYou’ll
respond with only your move, which must not be a number that
has already been played in the current game.\n\nWhen I say
‘new(10)’ start a new game and set the difficulty level to
10, meaning that you will always choose the best move. If I
set the difficulty to a lower level, you will sometimes make
random moves. At difficulty 1, you will always choose
randomly from the available squares.”,
},
{
role: ‘user’,
content: ‘new(10)’,
},
{
role: ‘assistant’,
content: ‘new game, level 10’,
},
{
role: ‘user’,
content: ‘0’,
},
{
role: ‘assistant’,
content: ‘4’,
},
{
role: ‘user’,
content: ‘1’,
},
{
role: ‘assistant’,
content: ‘2’,
},
{
role: ‘user’,
content: ‘6’,
},
{
role: ‘assistant’,
content: ‘8’,
},
{
role: ‘user’,
content: ‘5’,
},
{
role: ‘assistant’,
content: ‘3’,
},
{
role: ‘user’,
content: ‘7’,
},
];
const newMessage = req.body.messages;
const messages = […context, …newMessage];
const response = await openai.chat.completions.create({
model: ‘gpt-4’,
messages: messages,
temperature: 0.5,
max_tokens: 255,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0,
});
res.json({ response });
});
app.listen(3000, () => {
console.log(‘Server listening on port 3000’);
});