sophia / chat.py
Arain119's picture
Upload chat.py with huggingface_hub
aecc34c verified
Raw History Blame
4.11 kB
"""Talk to Sophia.
python -m ml.cli.chat --checkpoint <ckpt.pt>
The decoding defaults are the ones the temperature sweep chose, not library
defaults. They matter more than usual here: greedy makes this policy loop and
a hot sample makes it incoherent, so the useful setting is neither end.
She decides per turn whether to think (~5% of turns); think markup never
reaches the visible answer -- unclosed or stray tags are routed to the think
field instead.
`/reset` starts a new conversation, `/think` toggles reasoning display, and
Ctrl-D exits.
"""
from __future__ import annotations
import argparse
import sys
import time
from ml.training.rl.engine import RolloutEngine, chat_turn, load_policy
BANNER = """Sophia — 输入即可对话
/reset 开始新对话 /think 思考块显示开关
/temp <x> 调整温度 Ctrl-D 退出
"""
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--checkpoint", required=True)
parser.add_argument("--model-spec", default="configs/model/sophia.json")
parser.add_argument("--tokenizer-path", default="ml/modeling/text")
parser.add_argument("--temperature", type=float, default=0.7)
parser.add_argument("--top-p", type=float, default=0.92)
parser.add_argument("--max-new-tokens", type=int, default=320)
parser.add_argument("--show-think", action="store_true")
args = parser.parse_args()
started = time.time()
model, tokenizer, meta = load_policy(
checkpoint=args.checkpoint,
model_spec=args.model_spec,
tokenizer_path=args.tokenizer_path,
batch_size=1,
)
engine = RolloutEngine(
model=model, tokenizer=tokenizer, max_batch=1, max_new_tokens=args.max_new_tokens
)
print(
"loaded step={} in {:.1f}s".format(meta.get("step"), time.time() - started),
file=sys.stderr,
)
print(BANNER)
history: list[dict[str, str]] = []
show_think = bool(args.show_think)
temperature = float(args.temperature)
while True:
try:
line = input("你 > ").strip()
except (EOFError, KeyboardInterrupt):
print()
return
if not line:
continue
if line == "/reset":
history = []
print("(已开始新对话)\n")
continue
if line == "/think":
show_think = not show_think
print("(思考块 %s)\n" % ("显示" if show_think else "隐藏"))
continue
if line.startswith("/temp"):
try:
temperature = float(line.split()[1])
print(f"(温度 = {temperature:.2f})\n")
except (IndexError, ValueError):
print("(用法:/temp 0.7)\n")
continue
history.append({"role": "user", "content": line})
started = time.time()
sample = chat_turn(
engine,
tokenizer,
history,
temperature=temperature,
top_p=float(args.top_p),
max_new_tokens=int(args.max_new_tokens),
)
think = sample.think
answer = sample.answer
if show_think and think:
print("\033[2m[think] " + think + "\033[0m")
print("Sophia > " + (answer or "(空)"))
print(
f"\033[2m {sample.new_tokens} tok / {time.time() - started:.1f}s"
f"{'' if sample.hit_eos else ' / 未自然结束'}\033[0m\n"
)
history.append(
{
"role": "assistant",
"content": (
"<think>" + think + "</think>" + answer if think else answer
),
}
)
# A 4096-token window with a long tail of history eventually crowds out
# the reply; dropping the oldest exchange keeps the reply budget intact.
while len(history) > 16:
history = history[2:]
if __name__ == "__main__":
main()