Automated commit

This commit is contained in:
gitea_admin 2026-06-11 11:04:38 +00:00
parent b33a2761a2
commit 22f1cb8015
1 changed files with 91 additions and 63 deletions

View File

@ -1,85 +1,113 @@
"""Agent template — customize this for your domain. """Vergunningzoeker agent — agentic search over permits.
This is where you define what the AI assistant can do. The default Receives questions, generates search queries, searches the permit
implementation provides a simple Q&A agent. Replace or extend the database, and synthesizes answers. Each step is logged for transparency.
`run_agent` function with your own logic.
The agent receives:
- question: the user's message
- history: previous messages in the conversation
- db: SQLAlchemy database session (for querying your app's data)
The agent returns:
- answer: the text response to show the user
- steps: list of transparency steps (shown in the UI)
Each step has:
- type: "search", "query", "tool", "reasoning", etc.
- label: human-readable description
- detail: the raw data (search terms, query results, etc.)
Example customization for a permit search app:
def run_agent(question, history, db):
steps = []
# Step 1: Generate search terms
terms = ask_llm_for_search_terms(question)
steps.append({"type": "search", "label": "Zoektermen", "detail": terms})
# Step 2: Query database
results = search_permits(db, terms)
steps.append({"type": "query", "label": f"{len(results)} resultaten", "detail": [...]})
# Step 3: Synthesize answer
answer = ask_llm_to_answer(question, results)
return {"answer": answer, "steps": steps}
""" """
import json
from druppie_sdk import DruppieClient from druppie_sdk import DruppieClient
from app.models import Permit
druppie = DruppieClient() druppie = DruppieClient()
def run_agent(question: str, history: list[dict], db) -> dict: def run_agent(question: str, history: list[dict], db) -> dict:
"""Process a user question and return an answer with transparency steps.
Override this function with your domain-specific agent logic.
The default implementation is a simple LLM Q&A with conversation context.
Args:
question: The user's current message.
history: List of {"role": "user"|"assistant", "content": "..."} dicts.
db: SQLAlchemy database session for querying app data.
Returns:
{"answer": str, "steps": list[dict]}
"""
steps = [] steps = []
# Build conversation context # Build conversation context
context_messages = "" context_str = ""
if history: if history:
recent = history[-6:] # last 3 exchanges recent = history[-4:]
context_messages = "\n".join( context_str = "\n".join(
f"{'Gebruiker' if m['role'] == 'user' else 'Assistent'}: {m['content']}" f"{'Gebruiker' if m['role'] == 'user' else 'Assistent'}: {m['content'][:200]}"
for m in recent for m in recent
) )
# Call LLM # Step 1: Generate search queries
prompt = question full_prompt = question
if context_messages: if context_str:
prompt = f"Eerdere berichten:\n{context_messages}\n\nNieuwe vraag: {question}" full_prompt = f"Gesprekscontext:\n{context_str}\n\nNieuwe vraag: {question}"
steps.append({"type": "reasoning", "label": "Vraag naar LLM gestuurd", "detail": None}) query_result = druppie.call("llm", "chat", {
"prompt": (
"De gebruiker stelt een vraag over vergunningen in een database. "
"Genereer 1-3 zoektermen (komma-gescheiden) waarmee relevante "
"vergunningen gevonden kunnen worden. Antwoord ALLEEN met de zoektermen.\n\n"
f"Vraag: {full_prompt}"
),
"system": "Je genereert zoektermen voor een vergunningendatabase. Antwoord alleen met komma-gescheiden zoektermen.",
})
search_terms = [t.strip() for t in query_result.get("answer", question).split(",") if t.strip()]
result = druppie.call("llm", "chat", { steps.append({
"prompt": prompt, "type": "search",
"label": f"Zoektermen: {', '.join(search_terms)}",
"detail": search_terms,
})
# Step 2: Search database with each term
found = {}
search_details = []
for term in search_terms[:3]:
like = f"%{term}%"
results = db.query(Permit).filter(
Permit.permit_number.ilike(like)
| Permit.applicant_name.ilike(like)
| Permit.permit_holder_name.ilike(like)
| Permit.location.ilike(like)
| Permit.permit_type.ilike(like)
| Permit.applicable_law.ilike(like)
| Permit.work_type.ilike(like)
| Permit.extracted_text.ilike(like)
).limit(10).all()
new_ids = [p.id for p in results if p.id not in found]
for p in results:
found[p.id] = p
search_details.append(f'"{term}"{len(results)} resultaten ({len(new_ids)} nieuw)')
steps.append({
"type": "query",
"label": f"{len(found)} vergunningen gevonden",
"detail": search_details,
})
# Step 3: Build context from found permits
if found:
context_parts = []
for p in found.values():
parts = [f"Vergunning #{p.id}: {p.permit_number or 'geen nummer'}"]
if p.applicant_name: parts.append(f" Aanvrager: {p.applicant_name}")
if p.permit_holder_name: parts.append(f" Houder: {p.permit_holder_name}")
if p.permit_type: parts.append(f" Type: {p.permit_type}")
if p.location: parts.append(f" Locatie: {p.location}")
if p.issue_date: parts.append(f" Datum: {p.issue_date}")
if p.archive_status: parts.append(f" Archiefstatus: {p.archive_status}")
if p.applicable_law: parts.append(f" Wet: {p.applicable_law}")
if p.work_type: parts.append(f" Type werk: {p.work_type}")
if p.extracted_text:
parts.append(f" Tekst (fragment): {p.extracted_text[:400]}")
context_parts.append("\n".join(parts))
context = "\n\n".join(context_parts)
else:
context = "Geen vergunningen gevonden in de database."
# Step 4: LLM synthesizes answer
steps.append({"type": "reasoning", "label": "Antwoord genereren", "detail": None})
answer_result = druppie.call("llm", "chat", {
"prompt": (
f"Beantwoord de volgende vraag op basis van de vergunningendata.\n\n"
f"Vraag: {full_prompt}\n\n"
f"Gevonden vergunningen ({len(found)} resultaten):\n\n{context}"
),
"system": ( "system": (
"Je bent een behulpzame assistent. Beantwoord vragen in het Nederlands. " "Je bent een assistent voor waterschap-medewerkers. Beantwoord vragen "
"Wees beknopt maar volledig." "over vergunningen op basis van de aangeleverde data. Wees specifiek "
"en verwijs naar vergunningnummers. Als de data onvoldoende is, zeg dat eerlijk."
), ),
}) })
answer = result.get("answer", "Geen antwoord ontvangen.") return {
return {"answer": answer, "steps": steps} "answer": answer_result.get("answer", "Geen antwoord ontvangen."),
"steps": steps,
}