LLM 输出路径

August 28, 2026 · View on GitHub

本页标出普通聊天与接话的代码入口,方便改接线。用户向说明见 LLM 对话与复读

普通 @ 聊天走 Bot Provider,在 Bot 进程内完成;不要为这条路径增加 Pallas-Bot-AI / :9099 / HTTP callback。媒体与遗留 RWKV 另见 Agent 生命周期 与运维文档。

两条出口

群消息
 ├─ 统一 ingress 怒气门控 → 记录时间线;静默时停止后续副作用
 │  └─ @ / to_me → packages/llm_chat/chat_message.py
 │     persona +【表达参考】→ client.submit_chat_task

 └─ 非 @ 接话 → packages/repeater/handlers/message.py
       → 原始候选检索、人格加权、过滤与去重
       → Repeater 直接投递原语料

普通聊天在 Bot 进程内执行:submit_chat_task 安排 kernel_runner。通常由后者调用 Provider、运行工具循环,并通过 pallas/product/llm/delivery.pydeliver_llm_chat_result 交给既有投递入口;若 semantic style 给出通过相关性与近期回复去重的 direct_candidate,并通过滚动窗口 15% 配额,kernel 会直接投递该真实语料而不调用 Provider。该判断不对语料内容作额外价值判断。Repeater 日常接话自身不创建 LLM 任务。

工具循环会在模型提出 tool call 后执行工具、将结果追加回上下文并继续补全。默认工具集会按场景选择;延迟公开的工具可由 tools.find 发现,并在后续轮次加入可调用集合。延迟完成的外部工具只派发任务;任务结果由其自身通道回传,不阻塞当前 LLM 回复。

LLM 输出管线

LLM 输出管线与表达数据粒度

@ 对话在 Bot 进程内完成:Provider 返回文本后,从生成到发进群依次经过:

步骤位置说明
表达语料直投kernel_runner.py表达库 direct_candidate 通过去重与配额时直接投递真实语料,跳过 Provider
生成 + 工具循环complete_with_tool_loop模型提 tool call → 执行工具 → 结果回填上下文继续补全
人设输出防火墙pallas/product/llm/persona_output_firewall.py命中规则可带修正指令重试,或回落 fallback
JSON 契约解析structured_reply.py parse_structured_reply期望 reply_segments 数组逐条成气泡;纯文本退化单段
输出过滤output_filter.py语料污染词、续写残片、角色 / 形态守卫、长度硬闸(由 reply_shape 的 p50 段长推导 reply_max_length,超限找干净断点压短,否则回落 fallback)
短气泡兜底拆分reply_postprocess.py split_short_reply_segmentsshort 取向但只有单段时,按句末标点 / 换行拆成多气泡
轻量后处理apply_reply_postprocess错别字、句尾句号
多气泡投递delivery.py deliver_llm_callback_success逐条发送,气泡间按上句长度叠加随机抖动(0.5~3.5s,模拟真人节奏)
学习回写会话 / behavior_store / repeater_feedback / auto_episode投递成功后写历史、行为与表达

LLM turn telemetry

LLM turn telemetry 从消息进入 llm_chat handler 后开始,以随机 turn_id 关联 ingress、speak perception、reply gate、necessity、submit、Provider、output 和 delivery 各阶段。首期不覆盖完全未匹配 llm_chat rule 的入站消息,也不改变任何门控、生成或投递决策。

事件写入独立的 data/pb_webui/llm_telemetry/ JSONL 文件,并由按日 report 聚合。事件只保留固定 allowlist、文本形态与长度分桶,以及运行时 HMAC hash;不写入用户消息、Bot 回复、prompt、异常正文或原始 Bot/群/用户/消息 ID。turn_id 会随异步 TaskManager metadata 贯穿到 Provider 和 callback delivery。

Telemetry 是 best-effort 的旁路观测:写 key、序列化、目录或文件失败时只记录限频运维日志,不阻断聊天。完整 prompt 和消息内容仍属于独立的 runtime snapshot/trace 调试路径,不能把两类数据混为同一份报告。

表达数据粒度

数据存储粒度影响
表达风格锚点 / 例句repeater_semantic_style.pyprofiles.json每 bot × 每群 独立(key bot_id:group_id:scene注入「群表达指导」block;重置命令只清本 bot 本群
回复画像(气泡数 / 节奏 / 长度)group config style_profilegroup_profiler.py群维度共享决定 reply_shape 的段数、节奏与长度取向;其 p50 段长再参与推导 reply_max_length 硬上限

同群不同 bot 的表达指导互不共享;回复画像是群统计,同群所有 bot 共用。WebUI 管理入口见 packages/pb_webui/llm_product_api.py

Prompt 组装

at-chat 系统提示词 pallas/product/persona/at_chat_system_prompt.txt 只承载背景 / 输出边界 / 群聊边界等不变原则,不再内嵌具体对话示范;接话的差异化由语义风格按 bot × 群 注入(见上表「群表达指导」「真人接话参考」)。ChatPromptAssemblerpallas/product/llm/assembler/chat_prompt.py)按变化频率从低到高依次组装:persona 核心 → 群表达指导 / 真人接话参考(随 profile 有数据才注入)→ 近期上下文(检索块 → 群时间线)→ reply_shape(回复形状与输出契约)→ turn policy → 当前时间 → 工具上下文,使支持前缀缓存的 Provider 可命中更长的稳定前缀。

关键锚点

步骤位置
Repeater 候选与投递packages/repeater/responder.pypackages/repeater/handlers/message.py
LLM 群级表达指导pallas/product/llm/repeater_semantic_style.py(注入消费);pallas/product/llm/group_insight_processor.py(从 message 表重建成对样本,批量标注落盘)
表达库存取 / 学习pallas/product/persona/expression_*.py
进程内投递pallas/product/llm/delivery.pydeliver_llm_chat_result);kernel_runner.py 调用 delivery
媒体 / HTTP callback 壳pallas/core/platform/ai_callback/runner.py(薄壳,复用 delivery)
配置键pallas/product/llm/config.py;WebUI 段见 env_sections.py(侧栏 AI 配置

群洞察的调度、8 个候选对的批量含义、持久化游标、预算和记忆层批量边界见群洞察与语义风格指导器

约束

  • 怒气门控发生在 direct runtime 与 matcher 之前。静默不是丢弃入站消息:消息仍持久化并带 suppressed_by_rage=true,但不会被视为 Bot 已回复,也不会进入 LLM、工具或 Repeater 处理。

  • 攻击增量由攻击词数量、短窗口连续攻击次数和当前怒气共同决定;75 分进入静默,低于 75 才恢复。静默期间不重复累积怒气、不重复扣好感、不延长截止时间。

  • 日常接话只使用 Repeater 语料,不调用 LLM 生成、选句、润色或拼接。

  • @、follow-up 与工具回合独立走 llm_chat

  • Repeater 学到的群级表达可以只读注入 llm_chat;其中有界 direct_candidate 仅替代本次 llm_chat Provider 补全,不反向控制 Repeater 候选与投递。

  • 在线链路不再存在 Repeater 的 select、polish 或 fallback LLM 任务。

  • 表达库当前是单群;跨群另开任务,不要默认同库检索。

后续阅读