Commit d7152516 authored by Kantz's avatar Kantz
Browse files

math_intent_LLM.py überarbeitet.

parent 39de7efd
......@@ -65,3 +65,4 @@ Retrieval settings:
## Testing
python -m test.hint_test ...
python -m test.vector_store_test --query "Was ist eine Teilmenge?" --k 8 --expand
python -m test.math_intent_test --input "Integrate x^2" --input "Was ist 2+2?"
import json
import sympy as sp
from ollama import chat
from app.deterministic_services import llm_client
def sympy_solve(task: str, input: str, symbols: list[str] | None = None) -> str:
"""
task: simplify|solve|diff|integrate
input: SymPy-Expression als String, z.B. '((1/a)+a)/(a+1) - (a-1)/(a+1)'
symbols: z.B. ['a']
"""
symbols = symbols or []
locals_map = {name: sp.Symbol(name) for name in symbols}
expr = sp.sympify(input, locals=locals_map)
MATH_INTENT_PROMPT = (
"Du bist ein Parser fuer Matheaufgaben. Entscheide, ob sympy_solve genutzt "
"werden soll. Wenn ja, gib ein JSON-Objekt mit {\"use_math\": true, "
"\"task\": \"solve|simplify|diff|integrate\", \"input\": \"...\", "
"\"symbols\": [\"x\", ...]} zurueck. Wenn nein, gib "
"{\"use_math\": false} zurueck. Antworte nur mit JSON."
)
if task == "simplify":
return str(sp.simplify(expr))
if task == "diff":
if not symbols:
raise ValueError("diff requires symbols[0]")
return str(sp.diff(expr, locals_map[symbols[0]]))
if task == "integrate":
if not symbols:
raise ValueError("integrate requires symbols[0]")
return str(sp.integrate(expr, locals_map[symbols[0]]))
if task == "solve":
if not symbols:
raise ValueError("solve requires symbols[0]")
return str(sp.solve(sp.Eq(expr, 0), locals_map[symbols[0]]))
raise ValueError(f"Unknown task: {task}")
def extract_math_request(user_text: str) -> dict | None:
result = llm_client.chat(
messages=[
{"role": "system", "content": MATH_INTENT_PROMPT},
SYSTEM = """
Du bist ein Mathe-Assistent.
Wenn eine Rechnung nötig ist, nutze das Tool sympy_solve.
Wichtig: Übergib in input eine gültige SymPy-Expression (kein LaTeX).
Antworte final mit dem vereinfachten Ergebnis (kein Doppelbruch).
"""
def solve_with_tools(user_text: str, model: str = "ministral-3") -> str:
messages = [
{"role": "system", "content": SYSTEM},
{"role": "user", "content": user_text},
],
use_ollama=True,
)
content = llm_client.get_message_content(result)
try:
payload = json.loads(content)
except json.JSONDecodeError:
return None
if not payload.get("use_math"):
return None
task = payload.get("task")
input_text = payload.get("input")
symbols = payload.get("symbols") or []
if not task or not input_text:
return None
return {"task": task, "input": input_text, "symbols": symbols}
]
# 1) Modell darf Toolcalls erzeugen
resp = chat(model=model, messages=messages, tools=[sympy_solve], stream=False)
messages.append(resp.message)
# 2) Toolcalls ausführen und Ergebnisse zurückgeben
if resp.message.tool_calls:
for call in resp.message.tool_calls:
if call.function.name == "sympy_solve":
result = sympy_solve(**call.function.arguments)
else:
result = f"Unknown tool: {call.function.name}"
messages.append({
"role": "tool",
"tool_name": call.function.name,
"content": str(result),
})
# 3) Finalen Antwort-Call (Modell integriert Tool-Ergebnis)
final = chat(model=model, messages=messages, tools=[sympy_solve], stream=False)
return final.message.content
# Falls kein Toolcall: direkt zurück
return resp.message.content
import argparse
import json
from typing import Iterable
from app.LLM_services import math_intent_LLM
def _iter_inputs(args: argparse.Namespace) -> Iterable[str]:
if args.input_file:
with open(args.input_file, "r", encoding="utf-8") as handle:
for line in handle:
text = line.strip()
if text:
yield text
return
for text in args.input:
text = text.strip()
if text:
yield text
def main() -> None:
parser = argparse.ArgumentParser(description="Isolierter Math-Intent Test.")
parser.add_argument(
"--input",
action="append",
default=[],
help="Eingabe fuer den Math-Intent (mehrfach angeben).",
)
parser.add_argument(
"--input-file",
help="Textdatei mit einer Eingabe pro Zeile.",
)
args = parser.parse_args()
if not args.input and not args.input_file:
raise ValueError("Bitte --input oder --input-file angeben.")
for text in _iter_inputs(args):
result = math_intent_LLM.solve_with_tools(text)
print("INPUT:", text)
print("OUTPUT:", json.dumps(result, ensure_ascii=True))
if __name__ == "__main__":
main()
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment