fix: 修复热点摘要超长上下文并统一 Windows 启动文档

为 http_request 增加响应体截断与头部精简,避免门户首页触发 LLM 上下文超限;同时新增政务/媒体及教育批量 Agent 脚本,并将 Windows 启停说明合并为唯一指南,补充本次超时故障复盘与标准重启流程。

Made-with: Cursor
This commit is contained in:
renjianbo
2026-04-30 00:10:19 +08:00
parent 63b54116a5
commit cadeb2dc32
10 changed files with 1265 additions and 187 deletions

View File

@@ -34,6 +34,9 @@ class Settings(BaseSettings):
LOCAL_FILE_READ_MAX_BYTES: int = 2_097_152 # 单次读取上限(默认 2MB)
LOCAL_FILE_WRITE_MAX_BYTES: int = 2_097_152 # 单次写入内容上限(UTF-8 字节)
# http_request 工具:写入 LLM 上下文的响应体最大字符数(HTML/JSON 过大时截断,避免超过模型 context)
HTTP_REQUEST_MAX_BODY_CHARS: int = 32_000
# 图片 OCR(file_read 对 png/jpg 等):Tesseract 可执行文件路径,Windows 示例 C:/Program Files/Tesseract-OCR/tesseract.exe
TESSERACT_CMD: str = ""
# 自定义 tessdata 目录(内含 chi_sim.traineddata 等)。留空时若 LOCAL_FILE_TOOLS_ROOT/tessdata 下存在 .traineddata 则自动使用

View File

@@ -67,11 +67,74 @@ def _resolve_path_under_workspace(file_path: str) -> Tuple[Optional[Path], Optio
return p, None
_HTTP_RESPONSE_HEADER_ALLOWLIST = frozenset(
{
"content-type",
"content-length",
"content-encoding",
"date",
"last-modified",
"location",
"server",
"cache-control",
}
)
def _compact_http_response_headers(response: httpx.Response) -> Dict[str, str]:
"""减少 Set-Cookie 等大字段进入 LLM 上下文。"""
out: Dict[str, str] = {}
for key, value in response.headers.multi_items():
lk = key.lower()
if lk in ("set-cookie", "cookie"):
continue
if lk in _HTTP_RESPONSE_HEADER_ALLOWLIST:
out[key] = value if len(value) <= 2048 else value[:2048] + "..."
if not out:
n = 0
for key, value in response.headers.multi_items():
lk = key.lower()
if lk in ("set-cookie", "cookie"):
continue
if n >= 12:
break
out[key] = value if len(value) <= 512 else value[:512] + "..."
n += 1
return out
def _truncate_http_body_for_tool(body: Any, max_chars: int) -> Tuple[Any, bool, Optional[str]]:
"""
将 HTTP 正文限制在 max_chars 字符以内,避免门户首页等大 HTML 撑爆模型 context。
返回 (可能被截断后的 body, 是否截断, 说明文案)
"""
if max_chars <= 0:
max_chars = 32_000
note: Optional[str] = None
if isinstance(body, str):
if len(body) <= max_chars:
return body, False, None
note = (
f"正文已截断:原始约 {len(body)} 字符,仅保留前 {max_chars} 字符。"
"门户/频道首页通常过大,摘要请优先使用具体文章页 URL。"
)
return body[:max_chars], True, note
try:
serialized = json.dumps(body, ensure_ascii=False)
except (TypeError, ValueError):
serialized = str(body)
if len(serialized) <= max_chars:
return body, False, None
note = f"JSON 响应已截断:序列化长度约 {len(serialized)} 字符,仅保留前 {max_chars} 字符。"
return serialized[:max_chars], True, note
async def http_request_tool(
url: str,
method: str = "GET",
headers: Optional[Dict[str, str]] = None,
body: Any = None
body: Any = None,
max_body_chars: Optional[int] = None,
) -> str:
"""
HTTP请求工具
@@ -81,12 +144,18 @@ async def http_request_tool(
method: HTTP方法 (GET, POST, PUT, DELETE)
headers: 请求头
body: 请求体(POST/PUT时使用)
max_body_chars: 响应正文写入工具结果的最大字符数;默认读取配置 HTTP_REQUEST_MAX_BODY_CHARS
Returns:
JSON格式的响应结果
"""
try:
async with httpx.AsyncClient(timeout=30.0) as client:
limit = max_body_chars
if limit is None:
limit = int(getattr(settings, "HTTP_REQUEST_MAX_BODY_CHARS", 32_000) or 32_000)
limit = max(4096, min(limit, 200_000))
async with httpx.AsyncClient(timeout=30.0, follow_redirects=True) as client:
method_upper = method.upper()
if method_upper == "GET":
@@ -103,15 +172,20 @@ async def http_request_tool(
# 尝试解析JSON响应
try:
response_body = response.json()
except:
except Exception:
response_body = response.text
result = {
truncated_body, truncated, trunc_note = _truncate_http_body_for_tool(response_body, limit)
result: Dict[str, Any] = {
"status_code": response.status_code,
"headers": dict(response.headers),
"body": response_body
"headers": _compact_http_response_headers(response),
"body": truncated_body,
}
if truncated:
result["body_truncated"] = True
if trunc_note:
result["truncation_note"] = trunc_note
return json.dumps(result, ensure_ascii=False)
except Exception as e:
logger.error(f"HTTP请求工具执行失败: {str(e)}")
@@ -1036,7 +1110,14 @@ HTTP_REQUEST_SCHEMA = {
"body": {
"type": "object",
"description": "请求体(POST/PUT时使用,可选)"
}
},
"max_body_chars": {
"type": "integer",
"description": (
"响应正文写入结果的最大字符数(可选)。"
"门户首页等大 HTML 默认会按平台配置截断;摘要单篇文章可适当调大(如 80000),仍可能受模型总上下文限制。"
),
},
},
"required": ["url", "method"]
}