feat(agent): align with workflow@20261022 - turn_context messages and prompt tails

- merge main (b0ff2e0..c7ca781): workflow/20261022 moves dynamic context
  out of fixed prompts - collection/extraction prompts carry no inline vars;
  reference time and current form travel in the user message <turn_context>
  block; photo/confirm data kept at prompt tails
- prompts: all 8 files regenerated from 20261022 (byte-identity tests
  point at the new export)
- collect: user message = <turn_context>(本轮参考时间) + <user_input>;
  extraction message adds 当前表单; single trusted clock per turn threads
  through reply/extraction/repair
- photo: raw input only (20261022 photo nodes use system_text, no wrapper)
- workflow fake llm: unwraps <user_input> before event parsing
- fields: accident_time normalized to extraction format (YYYY年M月D日H点m分,
  strip zero padding) - fixes form assertion mismatch with padded output
- evals/run.py: trust_env=False - bypass Windows system proxy (registry
  proxy at 192.168.0.4:7897 was intercepting localhost and returning 503)
- verified: 172 unit tests; ALL golden suites pass on real model
  (46/46): collection_skip 12/12, photo_skip 4/4, no_false 2/2,
  button_guidance 12/12, non_motor_vehicle 14/14, time_confirmation 2/2
This commit is contained in:
Eric Wang
2026-10-22 12:28:24 +08:00
parent f9ec20cd81
commit e72d9c9bc0
15 changed files with 205 additions and 99 deletions
+25 -8
View File
@@ -130,9 +130,22 @@ def context_prompt(state: AgentState, *, time_context: dict | None = None) -> st
}, ensure_ascii=False)
def _build_user_message(state: AgentState) -> str:
"""对齐工作流 Text Editor#2:只传用户本轮原始文本。"""
return state.get("input_text", "")
def _format_turn_context(moment: datetime, extra: dict | None = None) -> str:
"""workflow@20261022 的 <turn_context> 块:动态上下文经 user 消息传递。"""
lines = [f"本轮参考时间:{moment.strftime('%Y-%m-%d %H:%M:%S %z')}"]
for key, value in (extra or {}).items():
lines.append(f"{key}:{value}")
return "<turn_context>\n" + "\n".join(lines) + "\n</turn_context>"
def _build_user_message(state: AgentState, *, now: datetime) -> str:
"""对齐 workflow@20261022 采集节点 userChatInput:
<turn_context>(本轮参考时间)+ <user_input>(原始输入)。
"""
return (
f"{_format_turn_context(now)}\n\n"
f"<user_input>\n{state.get('input_text', '')}\n</user_input>"
)
@@ -148,9 +161,9 @@ async def _extract_turn_fields(
) -> dict:
"""独立提取调用(计划作业 4-4:调用计数可审计——每轮在对话调用之外多一次)。
提示词为工作流「文本内容提取事故信息」原文(含当前时间与当前表单
注入),模型只输出 JSON;校验见 fields.validate_form_update。
提取失败不阻塞对话(返回 {})。
提示词为工作流「文本内容提取事故信息」原文(20261022 起时间/表单
经 content 的 <turn_context> 传递);模型只输出 JSON;
校验见 fields.validate_form_update。提取失败不阻塞对话(返回 {})。
"""
system = (
_EXTRACTION_MARKER
@@ -158,10 +171,14 @@ async def _extract_turn_fields(
+ render_prompt(EXTRACTION, state, now=now)
+ context_prompt(state, time_context=time_context)
)
message = (
f"{_format_turn_context(now, {'当前表单': json.dumps(state.get('accident_fields') or {}, ensure_ascii=False)})}\n\n"
f"<user_input>\n{state.get('input_text', '')}\n</user_input>"
)
try:
raw = await llm.complete(
system,
state.get("input_text", ""),
message,
history=conversation_history(state),
)
data = json.loads(raw.strip())
@@ -245,7 +262,7 @@ async def run_collect(state: AgentState, llm: LLMService, *, now: datetime | Non
moment = observation_time(now)
evidence = time_evidence(state, moment)
system_prompt = render_prompt(COLLECTION, state, now=moment) + context_prompt(state, time_context=evidence)
user_message = _build_user_message(state)
user_message = _build_user_message(state, now=moment)
current = state.get("stage_code") or COLLECT_STAGE
raw, stage = await validated_reply(
llm, system_prompt, user_message, current, history=conversation_history(state),