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
+19 -5
View File
@@ -10,7 +10,7 @@ from src.agent.collect import CollectReplyError, run_collect
from src.agent.llm import FakeLLMService
from src.agent.prompts import COLLECTION, load_prompt, render_prompt
WORKFLOW = Path(__file__).resolve().parents[2] / "workflow/20261021/事故信息采集2025118.json"
WORKFLOW = Path(__file__).resolve().parents[2] / "workflow/20261022/事故信息采集2025118.json"
NODES = {
"collection": "事故信息收集",
"single_photo": "单车拍照",
@@ -35,9 +35,10 @@ def test_archived_prompt_matches_workflow(prompt, node_name):
def test_render_replaces_time_and_person_variables():
now = datetime(2026, 10, 20, 12, 0, tzinfo=timezone.utc)
rendered = render_prompt(COLLECTION, {}, now=now)
assert "2026-10-20 12:00:00 +0000" in rendered
# 20261022:collection/extraction 提示词本体不含变量(动态上下文走
# user 消息的 <turn_context>);拍照/确认提示词尾部仍渲染人员变量。
rendered = render_prompt(COLLECTION, {})
assert "{{$" not in rendered
rendered = render_prompt("dual_confirm", {
"person_fields": {"hphm1": "测试A", "hphm2": "测试B", "sfzmwh1": "1234"}
})
@@ -47,6 +48,17 @@ def test_render_replaces_time_and_person_variables():
assert "未提供" in rendered
def test_user_message_carries_turn_context():
from src.agent.collect import _build_user_message
from datetime import datetime, timezone
now = datetime(2026, 10, 22, 8, 0, tzinfo=timezone.utc)
message = _build_user_message({"input_text": "两辆"}, now=now)
assert "<turn_context>" in message
assert "本轮参考时间:2026-10-22 08:00:00 +0000" in message
assert "<user_input>" in message
assert "两辆" in message
@pytest.mark.asyncio
async def test_short_answer_does_not_override_model_routing():
# “在”可能是明确回答;运行时不得按字数一律拒绝分流。
@@ -80,7 +92,9 @@ async def test_collect_sends_history_as_messages():
"stage_code": "1002", "input_text": "两辆", "dialogue": history,
}, llm)
assert llm.calls[0]["history"] == history
assert llm.calls[0]["user_message"] == "两辆"
# 20261022 格式:<turn_context> + <user_input>
assert "<turn_context>" in llm.calls[0]["user_message"]
assert "<user_input>\n两辆\n</user_input>" in llm.calls[0]["user_message"]
assert "没有人受伤" not in llm.calls[0]["user_message"]