SONUB
ZH English 한국어 日本語 中文 हिन्दी বাংলা اردو Español Português Français Deutsch Русский العربية Bahasa Indonesia Tiếng Việt ไทย Türkçe

如何开启通知

此浏览器或网址无法使用通知。请使用支持通知的浏览器,通过安全连接访问SONUB。

如果通知被屏蔽,请在浏览器设置中允许通知。

  1. 打开地址栏旁的站点设置或浏览器的站点设置,将此网站的通知设为允许。
  2. 在设备设置中允许浏览器发送通知,并检查勿扰模式或专注模式。
  3. 返回SONUB并刷新页面。通知开启后,铃铛将不再显示。

在iPhone或iPad上,将SONUB添加到主屏幕,从主屏幕打开后允许通知。

登录 退出登录 显示主题 默认主题 深色主题 粉色主题 聊天 1:1 聊天 群聊 论坛 公告 新闻区 建议区 自我介绍 主菜单

现在,让我们打造属于你自己的人工智能吧。

亲手做一个聊天,完成整条流程。写好 xchat.py,发出一个经由你的 到达自己的的问题。

一排词语积木的最后是一个空格。空格上方有三块候选积木,各带一根高低不同的柱子;其中一块被选中,接到这一排的末尾,一个箭头又绕回去,再选下一个。
9

创建XChat

是界面,是执行服务,是。给问题加格式,通过获取回答。

初版在运行,每题独立,不发送历史。下一步可在小限制内增加历史。重点是请求真正经过自己的模型。

请求经过的路——从 XChat 到权重

在 XChat 输入 hi 并按 Enter,会依次发生这些事。

  • xchat.py 把问题包成训练格式。"Q: hi" 的下一行放 "A: "。
  • 生成 {"": …, "": 24}, 到 http://127.0.0.1:8765/generate。
  • Runner 的 do_POST 读取并检查正文,然后 generate。
  • generate 用生成编号,用中的 逐个抽取词元,在处停止。
  • Runner 用 {"text": …} 响应,xchat.py 把它显示在 XSLM> 后面。

这条路上任何一处断了,对话就进行不了。所以出问题时,沿着这条路逐一检查:Runner 是否在运行( ),能否生成(curl /generate),XChat 的地址和是否正确。

XChat 客户端——输入循环与 HTTP 请求

xchat.py 分两部分。

  • ask(question):发送一个请求并返回回答。用 Request 构造包含地址、正文、头部的 POST 请求,用 发送,再用 json.load 读取响应正文,取出 text。timeout=120 表示 2 分钟内没有回答就放弃。为了在慢速上能等长时间的生成,设得比较宽裕。
  • 输入:用 while True 不断显示 You>,逐行读取。/exit 就结束,空行跳过,其余交给 ask,在 XSLM> 后输出回答。

每个问题都重新读取 settings.json。提示词格式("Q: " … "A: ")由客户端添加。如果做成由添加格式,客户端就不需要知道格式。无论哪种,格式都只能在一个地方决定,才不会错位。

处理错误——不编造假回答

xchat.py 这样分类处理错误。

  • EOFError、KeyboardInterrupt:按了 (输入结束)或 。结束循环,回到 。
  • URLError:没能连接 Runner( 等)。Runner 没开,或端口不对。
  • HTTPError:连上了,但 Runner 用 400 这样的错误码回答。它是 URLError 的一种,所以在同一行被捕获。
  • TimeoutError:在规定时间内没有回答。

无论哪种情况,都显示 "Runner: 错误内容",然后等待下一个问题。连不上时,不用事先准备好的句子来掩盖。这样才能马上知道哪里坏了。关掉 Runner 再提问试试(应该出错才正常),再启动它,确认对话恢复。

附上对话记录——上下文长度的限制

现在的 XChat 每个问题都是独立的。模型不知道前面说过的话。真实看起来记得前面的对话,是因为每次都把过去的整个对话放到提示词前面一起发送。模型本身没有。

用 XSLM 试试,很快就会碰壁。下面的实验在一轮对话(Q: hi / A: hi friend.)后面接上新问题 cat。提示词有 21 个词元,但模型只看最后 12 个词元,实际看到的文字从 "iend." 开始。前面的对话被截掉了。

所以要附上,还要一起做这些事。

  • 从最旧的对话开始丢弃,使其放进上下文长度内。
  • 新训练一个 context 更大的模型(位置表变大,计算变慢)。
  • 训练资料里也要放入多轮连续的对话,模型才能学会那种形状。

下一个挑战:在 xchat.py 中设一个 history ,把过去的问答附上一起发送。数一数词元数,超过 12 就丢掉前面的部分。

动手验证 lab/context.py
import json
from pathlib import Path
from tokenizer import BPE

tok = BPE(**json.loads(Path('data/tokenizer.json').read_text()))
size = json.loads(Path('settings.json').read_text())['context']
history = 'Q: hi\nA: hi friend.\nQ: cat\nA: '
ids = tok.encode(history)
print(len(ids), 'tokens; the model sees the last', size)
print(repr(tok.decode(ids[-size:])))
cd ~/xslm
mkdir -p lab
micro lab/context.py
python3 -m lab.context

运行结果

21 tokens; the model sees the last 12
'iend.\nQ: cat\nA: '

真实的对话模型怎么做——预训练之后的阶段

XSLM 用 Q/A 格式的文字从零训练。、 这样的对话模型通常要经过几个阶段。

  • (pre-training):用海量文字做。和 XSLM 的 train.py 做的事相同,只是规模不同。
  • 指令训练(, instruction tuning):用问题和好答案的对再训练,养成遵循指令的习惯。区分用户和助手轮次的对话格式()也在这时学会。
  • 偏好训练( 等):调整模型,使其偏向人们选出的更好的回答。

需要最新信息时,不重新训练,而用 。用问题检索出文档,一起放进提示词,模型看着这些文档回答。在资料格式中设置像 [DOC] 这样的文档栏,事先学会参考文档来回答的形状,以后就能把检索结果放进那一栏使用。

下一个挑战——让 XSLM 变大的方法

用完成的 XSLM 可以做的实验。每次只改一项,记录和回答。

  • 增加资料:问题用多种说法,答案用相同格式,写几十到几百行。
  • 增加训练:改变和训练次数,比较训练和。
  • 扩大模型:把 width 改成 16,context 改成 24。测量数量和每一步的时间如何变化。
  • 叠块:把 model.py 的 + 封装成,每个块各自建,让它经过两次。
  • 分头:把宽度 8 分成每头 4 格的两个头,分别做注意力后再拼接。
  • 加 :在 generate 中做一个按截断候选的选项。
  • 输出和对话记录:加到 Runner 和 XChat 上试试。

能做到这里,就在自己电脑上用 重写同样的结构。用计算,就能快几千倍,训练几千万个参数。 的 、build-nanogpt 也是很好的下一步教材。

动手输入并实验

保持Runner运行,编写并运行xchat.py,在You>输入hi。先/exit回到bash,再执行。

cd ~/xslm
micro xchat.py
python3 xchat.py
hi
/exit
kill "$(cat runner.pid)"
在终端中练习
xchat.py需要亲手编写的完整源码

input读取问题,Request发送JSON POST,urlopen读取真实响应;失败时显示错误。

import json
from pathlib import Path
from urllib.request import Request, urlopen
from urllib.error import URLError


def ask(question):
    cfg = json.loads(Path('settings.json').read_text())
    body = {'prompt': 'Q: ' + question + '\nA: ', 'tokens': cfg['tokens']}
    request = Request('http://127.0.0.1:' + str(cfg['port']) + '/generate',
                      data=json.dumps(body).encode(),
                      headers={'Content-Type': 'application/json'})
    with urlopen(request, timeout=120) as response:
        return json.load(response)['text']


if __name__ == '__main__':
    print('XChat -> Runner -> XSLM | /exit')
    while True:
        try:
            question = input('You> ').strip()
            if question == '/exit':
                break
            if question:
                print('XSLM>', ask(question))
        except (EOFError, KeyboardInterrupt):
            break
        except (URLError, TimeoutError) as error:
            print('Runner:', error)

逐行拆解代码

xchat.py ask——发送一个问题

def ask(question):
    cfg = json.loads(Path('settings.json').read_text())
    body = {'prompt': 'Q: ' + question + '\nA: ', 'tokens': cfg['tokens']}
    request = Request('http://127.0.0.1:' + str(cfg['port']) + '/generate',
                      data=json.dumps(body).encode(),
                      headers={'Content-Type': 'application/json'})
    with urlopen(request, timeout=120) as response:
        return json.load(response)['text']

每个问题都读取 settings.json,获得词元数和端口。把问题包成 "Q: " + 问题 + 换行 + "A: ",对齐训练格式。给 Request 传入 就成为 POST,正文是 JSON ,头部是 。with urlopen(…) 读完响应后会关闭连接。json.load 把响应读成,ask 只返回 text。

xchat.py 对话循环

if __name__ == '__main__':
    print('XChat -> Runner -> XSLM | /exit')
    while True:
        try:
            question = input('You> ').strip()
            if question == '/exit':
                break
            if question:
                print('XSLM>', ask(question))
        except (EOFError, KeyboardInterrupt):
            break
        except (URLError, TimeoutError) as error:
            print('Runner:', error)

输出开场提示,用 while True 接收问题。input 显示 You>,读取一行直到 Enter,用 strip 去掉首尾空格。/exit 就用 break 结束,空问题跳过。Ctrl+D 以 EOFError、Ctrl+C 以 KeyboardInterrupt 进来,同样结束。Runner 连接错误和超时会告知,然后等待下一个问题。

检查理解

展示XChat→Runner→权重→生成文本。停Runner应报连接错误,重启后恢复。

遇到问题时

不要在XChat里输入kill,它会成为问题。先退出,完成后导出项目。

常见问题

在 XChat 里输入了 kill,Runner 却没关掉。

在 You> 输入的文字不是,而是作为问题发给 Runner。先用 /exit 或 Ctrl+D 结束 XChat,回到 bash 提示符($),再输入 kill 命令。

出现 Runner: <urlopen error [Errno 111] Connection refused>。

Runner 没开,或者还在启动中。用 cat runner.log 确认启动信息(XSLM Runner: …),看 curl -s http://127.0.0.1:8765/health 是否有回应,然后再提问。如果刷新过页面,需要重新启动 Runner。

回答和问题无关。是连接出错了吗?

只要 XSLM> 后面出现了任何生成的文字,连接就是对的。内容是模型的实力。用 generate.py --prompt 直接运行同一个问题试试。设置和 seed 相同,结果会和经过 Runner 的回答完全一样。

学习指南

人工智能

智能体工具

Vibe 编程

AI 应用

AI证书

AI课堂

IT 基础

聊天

论坛

创作

社区

更多

术语词典

选一个你不认识的词吧,可以看到简单的解释和相关术语。

还没有匹配的术语。

选择一个术语即可查看解释。