CI / lint / typecheck / import-linter / tests / secrets (push) Canceled after 0s
- agent: ag_conversation/ag_message 表(迁移0007),上下文组装注入最近报告画像摘要 (report.profile.latest_profile_summary 经 apps 层闭包注入,同层不互调),历史带最近 AGENT_HISTORY_TURNS=10 轮;POST/GET /agent/conversations 与消息历史接口 - agent 修复:ChatRequest.conversation_id 改 str(雪花ID超2^53,JS Number丢精度); _build_context 挪进 reserve commit 后同一 try,异常走 refund 兜底 - report: rp_feedback(维度反馈 upsert,认同率/修正率 SQL 可算,T-P3-21 最小版—— L1 记忆未建,不回写结论)+ rp_reservation(预约留资幂等,T-P3-22,预约率口径 行数/full_report.card_view 去重曝光,门槛≥8%),迁移0008 - 测试:全量 606 passed;ruff/mypy/lint-imports 全绿;E2E 真实 deepseek-v4-flash 验证 画像注入与历史携带
58 lines
2.6 KiB
Python
58 lines
2.6 KiB
Python
"""上下文组装(架构 §7.2 步骤③)的纯逻辑:无 IO、无 LLM 调用,可单测。
|
|
|
|
预算分配(packages/agent/README.md 的预算表):
|
|
|
|
- 画像摘要 ≤ 500 token —— 按中文约 1.6 字符/token 保守取 800 字符上限,
|
|
摘要本身的生产侧(report 域)按 ``PROFILE_SUMMARY_MAX_CHARS`` 裁剪;
|
|
- 历史轮数默认 10 轮(``AGENT_HISTORY_TURNS``),一轮 = user + assistant 两条。
|
|
|
|
缓存纪律:画像与历史都是**逐用户逐轮变化**的内容,一律走 gateway 的
|
|
``messages`` 通道排在固定 system 前缀之后,绝不进 ``system_prefix``——
|
|
否则缓存命中单价 1/30 的红利会被画像差异完全打掉(README「两件容易踩的事」)。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Sequence
|
|
|
|
from packages.llm.types import Message
|
|
|
|
#: 画像摘要载荷上限(字符),对应 ≤ 500 token 的预算行。
|
|
PROFILE_SUMMARY_MAX_CHARS = 800
|
|
|
|
#: 画像摘要的消息壳。摘要是 JSON 素材(report 域 compose_prompt_material 的
|
|
#: 产物),需要这句说明告诉模型怎么用它;措辞保持中性,不引入新规则。
|
|
_PROFILE_MESSAGE_TEMPLATE = (
|
|
"以下是该用户最近一份美学诊断报告的画像摘要(JSON),"
|
|
"回答时据此给出贴合其条件的建议;用户未问及时不要主动复述全文。\n"
|
|
)
|
|
|
|
#: 单条历史消息的字符上限:用户输入已被 ChatRequest 卡在 2000 字符,
|
|
#: assistant 回复被提示词约束在 300 字以内,这里只做兜底截断防脏数据。
|
|
_HISTORY_MESSAGE_MAX_CHARS = 2000
|
|
|
|
|
|
def build_profile_message(profile_summary: str) -> Message:
|
|
return Message(role="system", content=_PROFILE_MESSAGE_TEMPLATE + profile_summary)
|
|
|
|
|
|
def build_context_messages(
|
|
*,
|
|
profile_summary: str | None,
|
|
history: Sequence[Message],
|
|
history_turns: int,
|
|
) -> list[Message]:
|
|
"""组装 gateway ``messages`` 通道的内容(固定前缀与当前输入由 gateway 自己拼)。
|
|
|
|
- 画像摘要在最前(无画像用户为 None 即不注入,走通用建议降级路径 FR-AGT-10);
|
|
- 历史按时间正序,只保留最近 ``history_turns`` 轮(一轮 = user+assistant 两条),
|
|
截尾不截头——越早的轮次对当前回答价值越低。
|
|
"""
|
|
messages: list[Message] = []
|
|
if profile_summary:
|
|
messages.append(build_profile_message(profile_summary))
|
|
tail = list(history)[-(history_turns * 2) :] if history_turns > 0 else []
|
|
for item in tail:
|
|
messages.append(Message(role=item.role, content=item.content[:_HISTORY_MESSAGE_MAX_CHARS]))
|
|
return messages
|