feat(bot): chat agent on Gemini 2.5 Flash-Lite — grounded first turn, current-prescription defaults
CI / ruff · pytest (pull_request) Successful in 2m5s
CI / ruff · pytest (pull_request) Successful in 2m5s
Live-tested on OpenRouter: Flash-Lite answers in 3–8 s with correct findings at ~$0.10/$0.40 per 1M tokens (qwen3.7-flash and gpt-oss-120b took 26–32 s). Force a tool call on the first turn, give the model the current prescription, let check_drug_for_patient default to it and return composition, intolerance check and general interactions (alcohol); retry once on an empty final message. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+26
-5
@@ -77,8 +77,9 @@ TOOL_SPECS: list[dict[str, Any]] = [
|
||||
),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {"drug": {"type": "string"}},
|
||||
"required": ["drug"],
|
||||
"properties": {
|
||||
"drug": {"type": "string", "description": "Название препарата; пусто — текущее назначение пациента"}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -157,7 +158,12 @@ def _drug_info(ctx: ToolContext, name: str) -> dict[str, Any]:
|
||||
|
||||
|
||||
async def _check(ctx: ToolContext, name: str) -> dict[str, Any]:
|
||||
entry = find_drug(name)
|
||||
entry = find_drug(name) if name.strip() else None
|
||||
if entry is None:
|
||||
# "мои таблетки" / no name → the current psychiatric prescription from the record.
|
||||
rec = await ctx.record()
|
||||
current = [find_drug(p.drug) for p in (rec.current_prescriptions if rec else [])]
|
||||
entry = next((e for e in current if e is not None), None) if not find_drug(name) else None
|
||||
if entry is None:
|
||||
return {"found": False, "drug": name, "note": "Препарата нет в справочнике — отвечать «уточните у врача»."}
|
||||
rec = await ctx.record()
|
||||
@@ -165,13 +171,28 @@ async def _check(ctx: ToolContext, name: str) -> dict[str, Any]:
|
||||
return {"found": True, "inn": entry.inn, "record": False, "findings": []}
|
||||
ctx.cite(entry.source)
|
||||
ctx.cite("ЕМИАС: медицинская карта")
|
||||
findings = check_patient(entry, rec, load_db())
|
||||
db = load_db()
|
||||
findings = check_patient(entry, rec, db)
|
||||
comp = entry.composition
|
||||
intolerances = [a.name for a in rec.allergies]
|
||||
intolerance_check = None
|
||||
if comp is not None and intolerances:
|
||||
hit = {t for a in rec.allergies for t in a.tags} & set(comp.excipient_tags)
|
||||
intolerance_check = f"Непереносимость из карты ({', '.join(intolerances)}): " + (
|
||||
"вещество ЕСТЬ в составе."
|
||||
if hit
|
||||
else "в примере состава этого вещества нет; состав зависит от производителя."
|
||||
)
|
||||
return {
|
||||
"found": True,
|
||||
"inn": entry.inn,
|
||||
"record": True,
|
||||
"findings": [f.model_dump() for f in findings],
|
||||
"note": "Пустой список не означает, что препарат безопасен: решение о приёме принимает врач.",
|
||||
"intolerance_check": intolerance_check,
|
||||
"composition": comp.model_dump(exclude={"excipient_tags"}) if comp else None,
|
||||
"general_interactions": [i.text for i in entry.interactions], # incl. alcohol — for questions about it
|
||||
"contraindications": entry.contraindications,
|
||||
"note": "Пустой findings не означает, что препарат безопасен: решение о приёме принимает врач.",
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user