mirror of
https://github.com/wassname/Open-Assistant.git
synced 2026-07-15 01:00:53 +08:00
Add infty prompting + prompt-lottery (#1055)
* first bits of prompt-lottery * add tree prompt lottery * minor text changes
This commit is contained in:
+27
@@ -0,0 +1,27 @@
|
||||
"""add won_prompt_lottery_date to mts
|
||||
|
||||
Revision ID: f60958968ff8
|
||||
Revises: 7b8f0011e0b0
|
||||
Create Date: 2023-02-01 10:10:38.301707
|
||||
|
||||
"""
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "f60958968ff8"
|
||||
down_revision = "7b8f0011e0b0"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column("message_tree_state", sa.Column("won_prompt_lottery_date", sa.DateTime(timezone=True), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column("message_tree_state", "won_prompt_lottery_date")
|
||||
# ### end Alembic commands ###
|
||||
@@ -13,7 +13,7 @@ class TreeManagerConfiguration(BaseModel):
|
||||
No new initial prompt tasks are handed out to users if this
|
||||
number is reached."""
|
||||
|
||||
max_tree_depth: int = 6
|
||||
max_tree_depth: int = 3
|
||||
"""Maximum depth of message tree."""
|
||||
|
||||
max_children_count: int = 3
|
||||
@@ -22,7 +22,7 @@ class TreeManagerConfiguration(BaseModel):
|
||||
num_prompter_replies: int = 1
|
||||
"""Number of prompter replies to collect per assistant reply."""
|
||||
|
||||
goal_tree_size: int = 15
|
||||
goal_tree_size: int = 12
|
||||
"""Total number of messages to gather per tree."""
|
||||
|
||||
num_reviews_initial_prompt: int = 3
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
|
||||
import sqlalchemy as sa
|
||||
@@ -46,6 +48,9 @@ class State(str, Enum):
|
||||
BACKLOG_RANKING = "backlog_ranking"
|
||||
"""Imported tree ready to be activated and ranked by users (currently inactive)."""
|
||||
|
||||
PROMPT_LOTTERY_WAITING = "prompt_lottery_waiting"
|
||||
"""Initial prompt has passed spam check, waiting to be drawn to grow."""
|
||||
|
||||
|
||||
VALID_STATES = (
|
||||
State.INITIAL_PROMPT_REVIEW,
|
||||
@@ -63,6 +68,7 @@ TERMINAL_STATES = (
|
||||
State.SCORING_FAILED,
|
||||
State.HALTED_BY_MODERATOR,
|
||||
State.BACKLOG_RANKING,
|
||||
State.PROMPT_LOTTERY_WAITING,
|
||||
)
|
||||
|
||||
|
||||
@@ -78,3 +84,4 @@ class MessageTreeState(SQLModel, table=True):
|
||||
state: str = Field(nullable=False, max_length=128, index=True)
|
||||
active: bool = Field(nullable=False, index=True)
|
||||
origin: str = Field(sa_column=sa.Column(sa.String(1024), nullable=True))
|
||||
won_prompt_lottery_date: Optional[datetime] = Field(sa_column=sa.Column(sa.DateTime(timezone=True), nullable=True))
|
||||
|
||||
@@ -21,6 +21,7 @@ from oasst_backend.utils.hugging_face import HfClassificationModel, HfEmbeddingM
|
||||
from oasst_backend.utils.ranking import ranked_pairs
|
||||
from oasst_shared.exceptions.oasst_api_error import OasstError, OasstErrorCode
|
||||
from oasst_shared.schemas import protocol as protocol_schema
|
||||
from oasst_shared.utils import utcnow
|
||||
from sqlmodel import Session, func, not_, or_, text, update
|
||||
|
||||
|
||||
@@ -153,7 +154,7 @@ class TreeManager:
|
||||
|
||||
def _determine_task_availability_internal(
|
||||
self,
|
||||
num_active_trees: int,
|
||||
num_missing_prompts: int,
|
||||
extendible_parents: list[ExtendibleParentRow],
|
||||
prompts_need_review: list[Message],
|
||||
replies_need_review: list[Message],
|
||||
@@ -161,8 +162,7 @@ class TreeManager:
|
||||
) -> dict[protocol_schema.TaskRequestType, int]:
|
||||
task_count_by_type: dict[protocol_schema.TaskRequestType, int] = {t: 0 for t in protocol_schema.TaskRequestType}
|
||||
|
||||
num_missing_prompts = max(0, self.cfg.max_active_trees - num_active_trees)
|
||||
task_count_by_type[protocol_schema.TaskRequestType.initial_prompt] = num_missing_prompts
|
||||
task_count_by_type[protocol_schema.TaskRequestType.initial_prompt] = max(1, num_missing_prompts)
|
||||
|
||||
task_count_by_type[protocol_schema.TaskRequestType.prompter_reply] = len(
|
||||
list(filter(lambda x: x.parent_role == "assistant", extendible_parents))
|
||||
@@ -194,6 +194,72 @@ class TreeManager:
|
||||
|
||||
return task_count_by_type
|
||||
|
||||
def _prompt_lottery(self, lang: str) -> int:
|
||||
MAX_RETRIES = 5
|
||||
retry = 0
|
||||
while True:
|
||||
num_active_trees = self.query_num_active_trees(lang=lang, exclude_ranking=True)
|
||||
num_missing_prompts = self.cfg.max_active_trees - num_active_trees
|
||||
if num_missing_prompts <= 0:
|
||||
return 0
|
||||
|
||||
# select among distinct users
|
||||
authors_qry = (
|
||||
self.db.query(Message.user_id)
|
||||
.select_from(MessageTreeState)
|
||||
.join(Message, MessageTreeState.message_tree_id == Message.id)
|
||||
.filter(
|
||||
MessageTreeState.state == message_tree_state.State.PROMPT_LOTTERY_WAITING,
|
||||
Message.lang == lang,
|
||||
not_(Message.deleted),
|
||||
Message.review_result,
|
||||
)
|
||||
.distinct(Message.user_id)
|
||||
)
|
||||
|
||||
author_ids = authors_qry.all()
|
||||
if len(author_ids) == 0:
|
||||
logger.info(
|
||||
f"No prompts for prompt lottery available ({num_missing_prompts} trees missing for {lang=})."
|
||||
)
|
||||
return num_missing_prompts
|
||||
|
||||
# first select an authour
|
||||
prompt_author_id: UUID = random.choice(author_ids)["user_id"]
|
||||
logger.info(f"Selected random prompt author {prompt_author_id} among {len(author_ids)} candidates.")
|
||||
|
||||
# select random prompt of author
|
||||
qry = (
|
||||
self.db.query(MessageTreeState, Message)
|
||||
.select_from(MessageTreeState)
|
||||
.join(Message, MessageTreeState.message_tree_id == Message.id)
|
||||
.filter(
|
||||
MessageTreeState.state == message_tree_state.State.PROMPT_LOTTERY_WAITING,
|
||||
Message.user_id == prompt_author_id,
|
||||
Message.lang == lang,
|
||||
not_(Message.deleted),
|
||||
Message.review_result,
|
||||
)
|
||||
.limit(100)
|
||||
)
|
||||
|
||||
prompt_candidates = qry.all()
|
||||
if len(prompt_candidates) == 0:
|
||||
retry += 1 # not sure if this can happen with repeatable read isolation level, just in case we retry
|
||||
if retry < MAX_RETRIES:
|
||||
continue
|
||||
else:
|
||||
logger.warning("Max retries in prompt lottery reached.")
|
||||
return num_missing_prompts
|
||||
|
||||
winner_prompt = random.choice(prompt_candidates)
|
||||
message: Message = winner_prompt.Message
|
||||
logger.info(f"Prompt lottery winner: {message.id=}")
|
||||
|
||||
mts: MessageTreeState = winner_prompt.MessageTreeState
|
||||
self._enter_state(mts, message_tree_state.State.GROWING)
|
||||
self.db.flush()
|
||||
|
||||
def determine_task_availability(self, lang: str) -> dict[protocol_schema.TaskRequestType, int]:
|
||||
self.pr.ensure_user_is_enabled()
|
||||
|
||||
@@ -201,14 +267,14 @@ class TreeManager:
|
||||
lang = "en"
|
||||
logger.warning("Task availability request without lang tag received, assuming lang='en'.")
|
||||
|
||||
num_active_trees = self.query_num_active_trees(lang=lang, exclude_ranking=True)
|
||||
num_missing_prompts = self._prompt_lottery(lang=lang)
|
||||
extendible_parents, _ = self.query_extendible_parents(lang=lang)
|
||||
prompts_need_review = self.query_prompts_need_review(lang=lang)
|
||||
replies_need_review = self.query_replies_need_review(lang=lang)
|
||||
incomplete_rankings = self.query_incomplete_rankings(lang=lang)
|
||||
|
||||
return self._determine_task_availability_internal(
|
||||
num_active_trees=num_active_trees,
|
||||
num_missing_prompts=num_missing_prompts,
|
||||
extendible_parents=extendible_parents,
|
||||
prompts_need_review=prompts_need_review,
|
||||
replies_need_review=replies_need_review,
|
||||
@@ -238,7 +304,8 @@ class TreeManager:
|
||||
lang = "en"
|
||||
logger.warning("Task request without lang tag received, assuming 'en'.")
|
||||
|
||||
num_active_trees = self.query_num_active_trees(lang=lang, exclude_ranking=True)
|
||||
num_missing_prompts = self._prompt_lottery(lang=lang)
|
||||
|
||||
prompts_need_review = self.query_prompts_need_review(lang=lang)
|
||||
replies_need_review = self.query_replies_need_review(lang=lang)
|
||||
extendible_parents, active_tree_sizes = self.query_extendible_parents(lang=lang)
|
||||
@@ -256,7 +323,7 @@ class TreeManager:
|
||||
num_ranking_tasks=len(incomplete_rankings),
|
||||
num_replies_need_review=len(replies_need_review),
|
||||
num_prompts_need_review=len(prompts_need_review),
|
||||
num_missing_prompts=max(0, self.cfg.max_active_trees - num_active_trees),
|
||||
num_missing_prompts=num_missing_prompts,
|
||||
num_missing_replies=num_missing_replies,
|
||||
)
|
||||
|
||||
@@ -268,7 +335,7 @@ class TreeManager:
|
||||
)
|
||||
else:
|
||||
task_count_by_type = self._determine_task_availability_internal(
|
||||
num_active_trees=num_active_trees,
|
||||
num_missing_prompts=num_missing_prompts,
|
||||
extendible_parents=extendible_parents,
|
||||
prompts_need_review=prompts_need_review,
|
||||
replies_need_review=replies_need_review,
|
||||
@@ -611,7 +678,7 @@ class TreeManager:
|
||||
)
|
||||
else:
|
||||
self.enter_low_grade_state(msg.message_tree_id)
|
||||
self.check_condition_for_growing_state(msg.message_tree_id)
|
||||
self.check_condition_for_prompt_lottery(msg.message_tree_id)
|
||||
elif msg.review_count >= self.cfg.num_reviews_reply:
|
||||
if not msg.review_result and acceptance_score > self.cfg.acceptance_threshold_reply:
|
||||
msg.review_result = True
|
||||
@@ -649,6 +716,8 @@ class TreeManager:
|
||||
if len(incomplete_rankings) < self.cfg.min_active_rankings_per_lang:
|
||||
self.activate_backlog_tree(lang=root_msg.lang)
|
||||
else:
|
||||
if mts.state == message_tree_state.State.GROWING and mts.won_prompt_lottery_date is None:
|
||||
mts.won_prompt_lottery_date = utcnow()
|
||||
logger.info(f"Tree entered '{mts.state}' state ({mts.message_tree_id=})")
|
||||
|
||||
def enter_low_grade_state(self, message_tree_id: UUID) -> None:
|
||||
@@ -656,8 +725,8 @@ class TreeManager:
|
||||
mts = self.pr.fetch_tree_state(message_tree_id)
|
||||
self._enter_state(mts, message_tree_state.State.ABORTED_LOW_GRADE)
|
||||
|
||||
def check_condition_for_growing_state(self, message_tree_id: UUID) -> bool:
|
||||
logger.debug(f"check_condition_for_growing_state({message_tree_id=})")
|
||||
def check_condition_for_prompt_lottery(self, message_tree_id: UUID) -> bool:
|
||||
logger.debug(f"check_condition_for_prompt_lottery({message_tree_id=})")
|
||||
|
||||
mts = self.pr.fetch_tree_state(message_tree_id)
|
||||
if not mts.active or mts.state != message_tree_state.State.INITIAL_PROMPT_REVIEW:
|
||||
@@ -670,7 +739,7 @@ class TreeManager:
|
||||
logger.debug(f"False {initial_prompt.review_result=}")
|
||||
return False
|
||||
|
||||
self._enter_state(mts, message_tree_state.State.GROWING)
|
||||
self._enter_state(mts, message_tree_state.State.PROMPT_LOTTERY_WAITING)
|
||||
return True
|
||||
|
||||
def check_condition_for_ranking_state(self, message_tree_id: UUID) -> bool:
|
||||
@@ -1097,7 +1166,7 @@ LEFT JOIN message_reaction mr ON mr.task_id = t.id AND mr.payload_type = 'Rankin
|
||||
f"Checking state of {len(prompt_review_trees)} active message trees in 'initial_prompt_review' state."
|
||||
)
|
||||
for t in prompt_review_trees:
|
||||
self.check_condition_for_growing_state(t.message_tree_id)
|
||||
self.check_condition_for_prompt_lottery(t.message_tree_id)
|
||||
|
||||
growing_trees: list[MessageTreeState] = (
|
||||
self.db.query(MessageTreeState)
|
||||
@@ -1288,11 +1357,17 @@ DELETE FROM message WHERE message_tree_id = :message_tree_id;
|
||||
logger.debug(f"purge_message_tree({message_tree_id=}) {r.rowcount} rows.")
|
||||
|
||||
def _reactivate_tree(self, mts: MessageTreeState):
|
||||
self._enter_state(mts, message_tree_state.State.INITIAL_PROMPT_REVIEW)
|
||||
if mts.state == message_tree_state.State.PROMPT_LOTTERY_WAITING:
|
||||
return
|
||||
|
||||
tree_id = mts.message_tree_id
|
||||
if self.check_condition_for_growing_state(tree_id):
|
||||
if mts.won_prompt_lottery_date is not None:
|
||||
self._enter_state(mts, message_tree_state.State.GROWING)
|
||||
if self.check_condition_for_ranking_state(tree_id):
|
||||
self.check_condition_for_scoring_state(tree_id)
|
||||
else:
|
||||
self._enter_state(mts, message_tree_state.State.INITIAL_PROMPT_REVIEW)
|
||||
self.check_condition_for_prompt_lottery(tree_id)
|
||||
|
||||
@managed_tx_method(CommitMode.FLUSH)
|
||||
def purge_user_messages(
|
||||
|
||||
Reference in New Issue
Block a user