Skip to content

Commit b57d099

Browse files
hakatashiclaude
andcommitted
fix(tahoiya): 任意たほいやAI参加者のプロンプトを改善
isMimicryAllowedによらず常に正解禁止を指示するため、生成プロンプトから 不要になったisMimicryAllowedパラメータを削除。また、任意お題モードでは 模範解答が唯一の正解とは限らないため、正解判定プロンプトで別解も正解と して扱うよう改良。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vn8UKMnHrk2KyCGhAbL4Ed
1 parent 8aa7c4f commit b57d099

3 files changed

Lines changed: 33 additions & 20 deletions

File tree

tahoiya/Tahoiya.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,6 @@ export class Tahoiya extends ChannelLimitedBot {
595595
getArbitraryAIAnswer(
596596
arbitraryTheme.question,
597597
arbitraryTheme.answer,
598-
arbitraryTheme.isMimicryAllowed ?? false,
599598
).then((decoyAnswer) => {
600599
if (!decoyAnswer) {
601600
return;

tahoiya/arbitraryAibot.test.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,32 +34,44 @@ describe('tahoiya/arbitraryAibot', () => {
3434
.mockResolvedValueOnce(mockContent('{"decoyAnswer": "さよならプラスティックワールド"}'))
3535
.mockResolvedValueOnce(mockContent('{"isCorrect": false}'));
3636

37-
const result = await getArbitraryAIAnswer('実在するPerfumeのシングルは?', 'ポリリズム', false);
37+
const result = await getArbitraryAIAnswer('実在するPerfumeのシングルは?', 'ポリリズム');
3838

3939
expect(result).toBe('さよならプラスティックワールド');
4040
expect(openai.chat.completions.create).toHaveBeenCalledTimes(2);
4141
});
4242

43-
it('always instructs the model not to answer correctly, regardless of isMimicryAllowed', async () => {
43+
it('always instructs the model not to answer correctly', async () => {
4444
jest.mocked(openai.chat.completions.create)
4545
.mockResolvedValueOnce(mockContent('{"decoyAnswer": "誤答"}'))
4646
.mockResolvedValueOnce(mockContent('{"isCorrect": false}'));
4747

48-
await getArbitraryAIAnswer('質問', '正解', true);
48+
await getArbitraryAIAnswer('質問', '正解');
4949

5050
const [[generationCall]] = jest.mocked(openai.chat.completions.create).mock.calls;
5151
const prompt = generationCall.messages[0].content as string;
5252
expect(prompt).toContain('質問に対して正解となるような回答をしてはいけません');
5353
});
5454

55+
it('instructs the judge to also treat alternative correct answers as correct', async () => {
56+
jest.mocked(openai.chat.completions.create)
57+
.mockResolvedValueOnce(mockContent('{"decoyAnswer": "誤答"}'))
58+
.mockResolvedValueOnce(mockContent('{"isCorrect": false}'));
59+
60+
await getArbitraryAIAnswer('質問', '正解');
61+
62+
const [, [judgeCall]] = jest.mocked(openai.chat.completions.create).mock.calls;
63+
const prompt = judgeCall.messages[0].content as string;
64+
expect(prompt).toContain('別解');
65+
});
66+
5567
it('regenerates up to 2 times when judged as correct, and returns the answer once judged incorrect', async () => {
5668
jest.mocked(openai.chat.completions.create)
5769
.mockResolvedValueOnce(mockContent('{"decoyAnswer": "誤答1"}'))
5870
.mockResolvedValueOnce(mockContent('{"isCorrect": true}'))
5971
.mockResolvedValueOnce(mockContent('{"decoyAnswer": "誤答2"}'))
6072
.mockResolvedValueOnce(mockContent('{"isCorrect": false}'));
6173

62-
const result = await getArbitraryAIAnswer('質問', '正解', false);
74+
const result = await getArbitraryAIAnswer('質問', '正解');
6375

6476
expect(result).toBe('誤答2');
6577
expect(openai.chat.completions.create).toHaveBeenCalledTimes(4);
@@ -74,7 +86,7 @@ describe('tahoiya/arbitraryAibot', () => {
7486
.mockResolvedValueOnce(mockContent('{"decoyAnswer": "誤答3"}'))
7587
.mockResolvedValueOnce(mockContent('{"isCorrect": true}'));
7688

77-
const result = await getArbitraryAIAnswer('質問', '正解', false);
89+
const result = await getArbitraryAIAnswer('質問', '正解');
7890

7991
expect(result).toBeNull();
8092
expect(openai.chat.completions.create).toHaveBeenCalledTimes(6);
@@ -83,7 +95,7 @@ describe('tahoiya/arbitraryAibot', () => {
8395
it('returns null and does not throw when the generation call fails', async () => {
8496
jest.mocked(openai.chat.completions.create).mockRejectedValueOnce(new Error('API error'));
8597

86-
const result = await getArbitraryAIAnswer('質問', '正解', false);
98+
const result = await getArbitraryAIAnswer('質問', '正解');
8799

88100
expect(result).toBeNull();
89101
});
@@ -93,15 +105,15 @@ describe('tahoiya/arbitraryAibot', () => {
93105
.mockResolvedValueOnce(mockContent('{"decoyAnswer": "誤答"}'))
94106
.mockRejectedValueOnce(new Error('API error'));
95107

96-
const result = await getArbitraryAIAnswer('質問', '正解', false);
108+
const result = await getArbitraryAIAnswer('質問', '正解');
97109

98110
expect(result).toBeNull();
99111
});
100112

101113
it('returns null when the response does not contain valid JSON', async () => {
102114
jest.mocked(openai.chat.completions.create).mockResolvedValueOnce(mockContent('申し訳ありませんが回答できません'));
103115

104-
const result = await getArbitraryAIAnswer('質問', '正解', false);
116+
const result = await getArbitraryAIAnswer('質問', '正解');
105117

106118
expect(result).toBeNull();
107119
});

tahoiya/arbitraryAibot.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ const extractJson = (content: string): unknown => {
3131
const buildGenerationPrompt = (
3232
question: string,
3333
answer: string,
34-
isMimicryAllowed: boolean,
3534
previousAttempts: string[],
3635
): string => stripIndent`
3736
あなたは「たほいや」という言葉遊びゲームの「任意お題モード」に、他のプレイヤーに混じって参加するAIです。
@@ -53,10 +52,9 @@ const buildGenerationPrompt = (
5352
4. 選んだ候補の内容が、正解と実質的に同じ意味になっていないかを再確認し、もし同じ意味であれば候補を修正する。
5453
5554
# 重要な注意事項(必ず守ること)
56-
- どのような場合であっても、質問に対して正解となるような回答をしてはいけません。これはこのゲームの設定(正解を答えることが許可されているかどうか)に関わらず、常に守ってください。
55+
- どのような場合であっても、質問に対して正解となるような回答をしてはいけません。
5756
- 誤答選択肢は日本語で、正解と同程度の分量・自然さにしてください。
5857
- 誤答選択肢は${MAX_ANSWER_LENGTH}文字以内にしてください。
59-
${isMimicryAllowed ? '- このゲームでは人間の参加者が正解をそのまま登録することも許可されていますが、あなたは必ず誤答を作成してください。' : ''}
6058
${previousAttempts.length > 0 ? stripIndent`
6159
6260
# 補足
@@ -72,19 +70,25 @@ const buildGenerationPrompt = (
7270

7371
const buildJudgePrompt = (question: string, answer: string, candidateAnswer: string): string => stripIndent`
7472
あなたは「たほいや」という言葉遊びゲームにおける、回答の正解判定を行う審判です。
75-
以下の「質問」と「正解」に対して、「判定対象の回答」が正解として扱われるべきかどうかを判定してください。
73+
以下の「質問」と「参考正解」に対して、「判定対象の回答」が正解として扱われるべきかどうかを判定してください。
7674
7775
# 質問
7876
${question}
7977
80-
# 正解
78+
# 参考正解
8179
${answer}
8280
8381
# 判定対象の回答
8482
${candidateAnswer}
8583
86-
表記ゆれ・言い回しの違い・言語の違いなどは無視し、意味内容が正解と実質的に同じであれば true 、
87-
正解とは異なる内容であれば false としてください。
84+
この任意お題モードでは、質問に対する正解は「参考正解」の一つに限定されるとは限りません。「参考正解」はあくまで
85+
正解の一例であり、判定対象の回答が「参考正解」と文字列としては異なっていても、あなたの知識に基づいて質問に
86+
対する事実として正しい別解であると判断できる場合は、正解として扱ってください。
87+
一方で、判定対象の回答が「参考正解」とも別解とも言えず、質問に対して誤った内容である場合は、誤答として
88+
扱ってください。
89+
90+
表記ゆれ・言い回しの違い・言語の違いなどは無視し、意味内容が正解(別解を含む)と実質的に同じであれば true 、
91+
正解・別解のいずれでもない誤った内容であれば false としてください。
8892
8993
以下のJSON形式のみを出力してください。それ以外の文章は一切出力しないでください。
9094
\`\`\`
@@ -95,13 +99,12 @@ const buildJudgePrompt = (question: string, answer: string, candidateAnswer: str
9599
const generateDecoyAnswer = async (
96100
question: string,
97101
answer: string,
98-
isMimicryAllowed: boolean,
99102
previousAttempts: string[],
100103
): Promise<string | null> => {
101104
const response = await openai.chat.completions.create({
102105
model: MODEL,
103106
messages: [
104-
{role: 'user', content: buildGenerationPrompt(question, answer, isMimicryAllowed, previousAttempts)},
107+
{role: 'user', content: buildGenerationPrompt(question, answer, previousAttempts)},
105108
],
106109
max_tokens: 1024,
107110
});
@@ -139,15 +142,14 @@ const judgeIsCorrect = async (question: string, answer: string, candidateAnswer:
139142
export const getArbitraryAIAnswer = async (
140143
question: string,
141144
answer: string,
142-
isMimicryAllowed: boolean,
143145
): Promise<string | null> => {
144146
const previousAttempts: string[] = [];
145147

146148
for (let attempt = 1; attempt <= MAX_GENERATION_ATTEMPTS; attempt++) {
147149
let decoyAnswer: string | null = null;
148150

149151
try {
150-
decoyAnswer = await generateDecoyAnswer(question, answer, isMimicryAllowed, previousAttempts);
152+
decoyAnswer = await generateDecoyAnswer(question, answer, previousAttempts);
151153
} catch (error) {
152154
log.error(`Failed to generate decoy answer (attempt ${attempt}): ${(error as Error)?.message ?? error}`);
153155
return null;

0 commit comments

Comments
 (0)