feat: 记录并展示每次生成消耗的LLM调用次数(llm_calls)
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user