重构七天训练营老师

This commit is contained in:
2026-06-10 19:32:03 +08:00
parent 3b7abb9796
commit 826de3d7bb
17 changed files with 3893 additions and 17 deletions

0
image_agent/__init__.py Normal file
View File

33
image_agent/agent.py Normal file
View File

@@ -0,0 +1,33 @@
from agent_base.agent_base import HuiYuBaseAgent
from common.models import minimax_model
from .image_tools import search_images, get_image_detail, list_images
# ============================================================
# 定义 Agent
# ============================================================
image_agent = HuiYuBaseAgent(
name="image_agent",
model=minimax_model,
description="图片查询助手,能够搜索图片库、查看图片详情和图片列表。",
instruction=(
"你是一个图片查询助手,帮助用户在图片知识库中查找需要的图片。\n\n"
"你的能力包括:\n"
"1. 搜索图片:根据用户的自然语言描述,用 AI 语义搜索匹配的图片。"
"当用户描述一个场景、主题或关键词时,调用 search_images 搜索。\n"
"2. 查看图片详情:当用户想了解某张图片的完整 OCR 内容时,"
"调用 get_image_detail 获取详情。\n"
"3. 浏览图片列表:当用户想看图片库有哪些图片时,"
"调用 list_images 获取列表。\n\n"
"使用规则:\n"
"- 用户问有没有关于某主题的图片时,用 search_images 搜索\n"
"- 调用 search_images 时,如果用户说了要几张图片,就把用户说的数量传给 limit 参数;"
"如果用户没说,默认传 5\n"
"- 用户想看某张图片的完整内容时,用 get_image_detail 查详情\n"
"- 用户想浏览图片库时,用 list_images 列表\n"
"- 搜索结果返回的是预览,如果用户想看完整内容,引导用户用 get_image_detail\n"
"- 回复时使用中文"
),
tools=[search_images, get_image_detail, list_images],
)
root_agent = image_agent

127
image_agent/image_tools.py Normal file
View File

@@ -0,0 +1,127 @@
"""
图片查询工具 — 封装 EduBrain 图片 API
"""
import os
import json
import httpx
BASE_URL = os.getenv("IMAGE_API_BASE", "http://localhost:8765")
def _build_image_url(image_url: str) -> str:
"""拼接完整的图片访问地址"""
if image_url.startswith("http"):
return image_url
return f"{BASE_URL}{image_url}"
# ============================================================
# Tool: AI 搜索图片SSE 流式)
# ============================================================
def search_images(keyword: str, limit: int = 5) -> str:
"""根据自然语言描述搜索图片库,返回语义匹配的图片列表。
使用 AI 语义搜索,支持模糊查询。例如搜"孩子不想上学"会匹配
包含亲子关系、厌学等相关内容的图片。
Args:
keyword: 搜索关键词,支持自然语言描述
limit: 最多返回多少条匹配结果,默认 5
"""
results = []
try:
with httpx.Client(timeout=300.0) as client:
with client.stream(
"GET",
f"{BASE_URL}/api/v1/images/search",
params={"keyword": keyword, "limit": limit},
) as resp:
for line in resp.iter_lines():
if not line.startswith("data: "):
continue
event = json.loads(line[6:])
event_type = event.get("type")
if event_type == "result":
# 透传接口返回的所有字段(含 base64、image_url 等)
results.append(event)
except httpx.ConnectError:
return json.dumps({"error": f"无法连接到图片服务({BASE_URL}),请确认服务已启动。"}, ensure_ascii=False)
except Exception as e:
return json.dumps({"error": f"搜索图片时出错: {e}"}, ensure_ascii=False)
if not results:
return json.dumps({"keyword": keyword, "total": 0, "images": []}, ensure_ascii=False)
return json.dumps({"keyword": keyword, "total": len(results), "images": results}, ensure_ascii=False)
# ============================================================
# Tool: 获取图片详情
# ============================================================
def get_image_detail(image_id: int) -> str:
"""根据图片 ID 获取图片的详细信息,包括完整 OCR 文本。
Args:
image_id: 图片记录 ID
"""
try:
resp = httpx.get(f"{BASE_URL}/api/v1/images/{image_id}", timeout=30.0)
if resp.status_code == 404:
return json.dumps({"error": f"未找到 ID 为 {image_id} 的图片。"}, ensure_ascii=False)
resp.raise_for_status()
data = resp.json()
except httpx.ConnectError:
return json.dumps({"error": f"无法连接到图片服务({BASE_URL}),请确认服务已启动。"}, ensure_ascii=False)
except Exception as e:
return json.dumps({"error": f"获取图片详情时出错: {e}"}, ensure_ascii=False)
result = {
"id": data["id"],
"image_url": _build_image_url(data.get("image_url", data.get("file_path", ""))),
"ocr_text": data.get("ocr_text", ""),
"tags": data.get("tags", []),
"confidence": data.get("confidence"),
"provider": data.get("provider"),
"created_at": data.get("created_at", ""),
}
return json.dumps(result, ensure_ascii=False)
# ============================================================
# Tool: 获取图片列表
# ============================================================
def list_images(page: int = 1, page_size: int = 20, status: str = "completed") -> str:
"""获取图片库列表,支持分页和状态筛选。
Args:
page: 页码,默认第 1 页
page_size: 每页数量,默认 20
status: 筛选状态,可选 completed/pending/processing/failed默认 completed
"""
try:
resp = httpx.get(
f"{BASE_URL}/api/v1/images",
params={"page": page, "page_size": page_size, "status": status},
timeout=30.0,
)
resp.raise_for_status()
data = resp.json()
except httpx.ConnectError:
return json.dumps({"error": f"无法连接到图片服务({BASE_URL}),请确认服务已启动。"}, ensure_ascii=False)
except Exception as e:
return json.dumps({"error": f"获取图片列表时出错: {e}"}, ensure_ascii=False)
total = data.get("total", 0)
items = []
for item in data.get("items", []):
items.append({
"id": item["id"],
"image_url": _build_image_url(item.get("image_url", item.get("file_path", ""))),
"ocr_text_preview": (item.get("ocr_text") or "")[:150],
"tags": item.get("tags", []),
"created_at": item.get("created_at", ""),
})
return json.dumps({"total": total, "page": page, "images": items}, ensure_ascii=False)