feat: 记录并展示每次生成消耗的LLM调用次数(llm_calls)

This commit is contained in:
Sakurasan
2026-09-02 14:10:49 +08:00
parent 734a449037
commit fefb1b4736
6 changed files with 17 additions and 7 deletions
+2
View File
@@ -83,6 +83,7 @@ CREATE TABLE IF NOT EXISTS ai_reports (
model TEXT NOT NULL,
tokens_used INTEGER,
generation_count INTEGER NOT NULL DEFAULT 1,
llm_calls INTEGER,
created_at TEXT NOT NULL DEFAULT (datetime('now','localtime')),
updated_at TEXT,
UNIQUE(trade_date, report_type)
@@ -121,6 +122,7 @@ def init_db():
for alter_sql in (
"ALTER TABLE ai_reports ADD COLUMN generation_count INTEGER NOT NULL DEFAULT 1",
"ALTER TABLE ai_reports ADD COLUMN updated_at TEXT",
"ALTER TABLE ai_reports ADD COLUMN llm_calls INTEGER",
):
try:
conn.execute(alter_sql)
+1 -1
View File
@@ -144,7 +144,7 @@ async def admin_list_reports(request: Request):
try:
rows = conn.execute(
"SELECT id, trade_date, report_type, title, summary, tools_used, model, tokens_used, "
"generation_count, created_at, updated_at "
"generation_count, llm_calls, created_at, updated_at "
"FROM ai_reports ORDER BY trade_date DESC, id DESC LIMIT 50"
).fetchall()
items = []
+1 -1
View File
@@ -64,7 +64,7 @@ async def list_reports():
try:
rows = conn.execute(
"SELECT id, trade_date, report_type, title, summary, tools_used, model, tokens_used, "
"generation_count, created_at, updated_at "
"generation_count, llm_calls, created_at, updated_at "
"FROM ai_reports ORDER BY trade_date DESC, id DESC LIMIT 50"
).fetchall()
items = []
+11 -5
View File
@@ -227,11 +227,13 @@ async def collect_ai_analysis(trade_date: str) -> dict:
# ── 阶段一:工具轮(只获取数据,模型若直接开写报告则丢弃,由阶段二重写) ──
tools_used = []
total_tokens = 0
llm_calls = 0
was_truncated = False
max_rounds = 8
for i in range(max_rounds):
response = await call_llm(messages, tools=TOOLS)
llm_calls += 1
total_tokens += response.get("usage", {}).get("total_tokens", 0)
choice = response["choices"][0]
@@ -277,6 +279,7 @@ async def collect_ai_analysis(trade_date: str) -> dict:
"content": part_prompt.format(title=trade_date) if part_idx == 0 else part_prompt,
}]
response = await call_llm(part_messages)
llm_calls += 1
total_tokens += response.get("usage", {}).get("total_tokens", 0)
choice = response["choices"][0]
part_content = choice["message"].get("content") or ""
@@ -292,9 +295,10 @@ async def collect_ai_analysis(trade_date: str) -> dict:
final_content += (final_content and "\n\n" or "") + part_content
summary = _extract_summary(final_content)
report_id = _save_report(trade_date, final_content, summary, tools_used, total_tokens)
report_id = _save_report(trade_date, final_content, summary, tools_used, total_tokens, llm_calls)
print(f"[ai-service] 生成完成:LLM调用 {llm_calls} 次,tokens {total_tokens}")
return {"id": report_id, "tokens_used": total_tokens, "tools_used": tools_used, "truncated": was_truncated}
return {"id": report_id, "tokens_used": total_tokens, "llm_calls": llm_calls, "tools_used": tools_used, "truncated": was_truncated}
def _extract_summary(content: str) -> str:
@@ -416,14 +420,14 @@ def _get_prev_snapshot_section(trade_date: str) -> str:
conn.close()
def _save_report(trade_date: str, content: str, summary: str, tools_used: list, tokens_used: int) -> int:
def _save_report(trade_date: str, content: str, summary: str, tools_used: list, tokens_used: int, llm_calls: int = 0) -> int:
"""保存报告到数据库(同日重生成:覆盖内容、generation_count+1、tokens 记当次消耗)"""
conn = get_connection()
try:
conn.execute(
"""INSERT INTO ai_reports
(trade_date, report_type, title, content, summary, tools_used, model, tokens_used, updated_at)
VALUES (?, 'daily', ?, ?, ?, ?, ?, ?, datetime('now','localtime'))
(trade_date, report_type, title, content, summary, tools_used, model, tokens_used, llm_calls, updated_at)
VALUES (?, 'daily', ?, ?, ?, ?, ?, ?, ?, datetime('now','localtime'))
ON CONFLICT(trade_date, report_type) DO UPDATE SET
title = excluded.title,
content = excluded.content,
@@ -431,6 +435,7 @@ def _save_report(trade_date: str, content: str, summary: str, tools_used: list,
tools_used = excluded.tools_used,
model = excluded.model,
tokens_used = excluded.tokens_used,
llm_calls = excluded.llm_calls,
updated_at = excluded.updated_at,
generation_count = ai_reports.generation_count + 1""",
(
@@ -441,6 +446,7 @@ def _save_report(trade_date: str, content: str, summary: str, tools_used: list,
json.dumps(tools_used),
AI_MODEL,
tokens_used,
llm_calls,
),
)
conn.commit()
+1
View File
@@ -15,6 +15,7 @@ export interface AiReport {
model: string;
tokens_used: number;
generation_count?: number;
llm_calls?: number | null;
issue_number?: number;
created_at: string;
updated_at?: string | null;
+1
View File
@@ -132,6 +132,7 @@ function AiAnalysisPage() {
<span className="truncate">{report.updated_at || report.created_at}</span>
</span>
<span>{report.tokens_used?.toLocaleString()} tokens</span>
{report.llm_calls ? <span>{report.llm_calls} 次 LLM 调用</span> : null}
{(report.generation_count ?? 1) > 1 && (
<span>第 {report.generation_count} 次生成</span>
)}